1. 从“写代码”到“与AI结对编程”:角色变化与协作模式
前几年大家讨论AI会不会取代程序员,讨论的其实是"AI能不能独立写代码"。但真到了实际开发里,我发现事情根本不是那个方向——AI并没有取代任何人,它更像是一个坐在你旁边的结对搭档,你负责说清楚要去哪儿,它负责把路给你探出来,然后你再决定这条路能不能走、怎么走。这种关系,就是我现在理解的AI与编程的共生关系。
我最早尝试用AI编程时,心态跟大多数人一样:试探性地让它写几个排序算法、生成一段爬虫脚本,觉得挺新鲜,但心里也犯嘀咕——这玩意能不能在真实的项目里顶用?后来有一次,项目排期特别紧,眼睛都快花了,我试着把一个埋了三层的bug描述给AI听,它居然在几秒钟内定位到了可疑的函数,还直接给了修复补丁。那一瞬间我突然意识到,这不是工具和人的关系,这是两个人(一个负责想,一个负责查)在合作解决同一个问题。
1.1 我的AI结对编程日常
我现在的工作习惯已经变成这样:早上到了工位,先打开AI助手,把昨晚没想清楚的接口设计问题贴给它,让它列出几种方案;写代码时,我负责搭框架、把需求拆成小任务,AI负责把每个小任务填充成代码;遇到报错,我不再像以前那样一行行盯着日志看,而是把报错上下文复制给它,让它先给出排查方向,我再顺着方向验证。
这个过程听起来像是"程序员变懒了",但实际恰恰相反。我比以前更忙了——忙着表达需求、忙着审查代码、忙着跟AI争论"为什么这里要用异步而不是多线程"。AI把我们从繁琐的脚手架代码、格式调整、重复的CRUD操作中解放出来,但同时也把更高层次的职责推到了我们面前:你必须清楚知道自己要什么,才能让AI产出你想要的东西。
1.2 为什么说这不是替代而是共生
很多人担心AI会让初级程序员失业,这个担心我理解,但实际情况更微妙。所谓共生,就是双方都需要对方:AI需要人类的判断力来纠偏——它的输出经常看起来完美,但可能用了过时的API,或者忽略了边界条件;人类需要AI的信息检索和代码生成能力来拓展效率——一个人用传统方式可能要写一天的代码,现在半天就能做完,剩下的时间可以投入到系统设计、业务理解、代码审查这些更有价值的事情上。
我见过一个小团队,五个人维护一个超过二十万行的遗留系统,过去光是读懂业务逻辑就耗时巨大。引入AI助手后,他们用AI快速生成文档、分析调用链路、补写测试,硬是在一个季度内把系统的核心模块重写了一遍。这不是AI替他们写的功劳,而是AI让他们把精力集中在"判断怎么改对"这件事上。所以共生关系的本质是:AI放大你在擅长方向上的能力,而你用经验和判断力约束AI的随机性和幻觉。
2. 核心环节:AI辅助下的需求拆解与代码生成
有句话我在团队内部经常说:AI编程的时代,提问的能力就是编程的能力。你给AI的输入越模糊,它给你的输出就越像一件看似精致但穿不出去的衣服。反过来,如果你能把需求拆解成颗粒度足够小的任务,又能把每个任务的上下文、输入输出、边界条件讲清楚,AI产出的代码不仅正确率高,而且结构清晰。我这里把整个流程拆成两个关键环节。
2.1 如何正确给AI下“编程指令”
先看一个反面例子。假设你想让AI写个用户登录接口,直接说"帮我写一个登录接口",AI会给你一个通用答案:用某个框架、建一张用户表、写个接口定义,然后你还得自己改。这只能说它在"猜"你的需求,猜不中也正常。
更高效的方式是像给新同事交代任务一样说清楚五件事:一、技术栈和环境(比如"在Spring Boot 2.7项目里,使用MyBatis-Plus,数据库是MySQL 8");二、业务逻辑和约束(比如"登录时需要校验账号是否存在、密码是否经过BCrypt加密、连续失败三次后锁定账号十五分钟");三、输入输出定义(接口参数、返回值格式);四、异常处理策略(用户名不存在时返回什么错误码);五、不做什么(比如"暂时不管记住登录状态,后续再加")。
我把这五件事概括成"五要素提问法",用这套方法喂给AI,它生成的代码几乎可以直接进PR(代码评审)。如果它生成的第一版没有完全符合要求,不要急着说"不对",更不要直接放弃,而是像対人一样补充约束条件:"用户不存在的时候,不能直接抛异常,而是返回统一错误码"——这种迭代式对话,是AI编程里最出效率的环节。
2.2 生成代码后的必做审查清单
AI生成的代码,本质上是一个语言模型根据海量代码学习出来的"最像样的答案",它不是经过编译器验证、不是经过设计评审的产物。所以我把AI当成一个"能力很强但偶尔会说胡话"的新同事,给它提的所有代码都必须过一遍我的审查清单。
我的清单有五项:
- 依赖和版本:AI倾向于使用它训练数据里最常见的库和版本,很可能跟你项目里的不一致。第一件事检查import和build配置文件。
- 安全与权限:AI生成的代码经常默认信任输入,SQL注入、文件路径穿越、反序列化漏洞这些坑在AI输出里并不少见,尤其是当你在没有上下文情况下让它拼接字符串时。
- 异常处理:它常常只写开心路径(happy path)。用户传了空值怎么办?超时怎么办?并发下数据不一致怎么办?这些你要自己补。
- 性能边界:如果AI生成了一段嵌套循环遍历数组,你要想想数据量大了之后会不会爆炸。它不知道你的真实数据规模。
- 可读性与风格:AI生成代码的命名大多还行,但偶尔会有连写缩写、意义不明的变量名。我会按团队规范调整之后才合入主干。
审查不是讨伐,而是为了让AI下一次生成更准确。当你把审查意见反馈给它,它会在同一个对话上下文中学习调整——这种人工反馈闭环,恰恰是共生关系中最有价值的部分。
3. 实操过程:用AI重构一个老旧模块的完整记录
光讲方法论太虚,我拿一个实际做过的重构任务来走一遍完整流程。这个案例我隐去了具体业务名称,但整个过程和步骤是真实的,非常有代表性。任务背景:一个老系统里有个服务模块,负责从外部同步数据并做清洗入库,代码历史超过四年,没有测试、没有文档,逻辑混乱到没人敢动。我们决定用AI辅助做一次重构。
3.1 场景设定与目标
这个模块的核心功能是:从上游接口拉取一批原始记录,对每条记录做字段校验、格式转换、去重、关联另一张配置表,最后批量写入本地数据库。老代码把所有这些逻辑全部揉在两个大方法里,每个方法快两百行,嵌套if-else少说有七八层。
重构目标有三个:第一,把逻辑拆分成职责单一的函数;第二,补齐单元测试;第三,保证对外行为不变。也就是说输出格式、数据库表结构、接口返回结构都不能变。这样定了目标后,我们没有急着写新代码,而是先把老代码丢给AI,让它帮忙做结构化分析。
3.2 步骤一:让AI梳理逻辑
我给AI的指令是这样的:"下面是一段Java方法,这段代码是从外部数据源同步记录并入库。请你先不要改代码,只做三件事:第一,概括这个方法的核心流程;第二,把每个if分支的作用解释清楚;第三,列出这段代码中潜在的问题(包括异常处理、性能、可维护性)。"
AI的输出非常有用。它把两百行方法拆成了五个阶段:网络请求与重试、字段映射与类型转换、重复记录判断、关联配置表的查询策略、批量写入与失败回退。每个阶段的输入输出都被列了出来。更关键的是,它指出了两个隐藏很深的问题:可能发生了空指针异常,因为配置表查询结果没有判空;还有内存泄漏隐患,因为有一个静态集合存在不断增长但没有清理。
这个过程让我意识到,AI在对已有代码做"阅读理解"方面,已经远超人的效率和耐心。过去我要自己读完整段代码才能理清脉络,现在AI先通读一遍并给出带注释的拆解,我只需要复核它理解得对不对。这就是共生关系里效率最大的那个跃升点。
3.3 步骤二:AI生成测试用例
理清逻辑之后,很自然地就能知道每个分支的组合条件。我让AI为每个函数生成单元测试用例,它基于参数组合自动生成了正常分支、边界分支、异常分支的测试代码,包括空值、超长字符串、重复主键、上游返回HTTP 500这些场景。
但我没有直接相信这些测试用例。我把它生成的测试代码逐条跟原逻辑做了对照,发现了两个问题:第一个是它有一个用例断言错了——它假设某字段为空时会跳过该记录,而实际上老代码是赋了一个默认值,这个行为差异必须修正;第二个是它对异常类型猜得不对,老代码捕获的是运行时异常的统一父类,而AI生成的用例预期的是具体子类,会导致测试误判失败。
我把这两个问题通过对话反馈给AI,它很快调整了用例。调整后的用例集加上我补充的几个边界用例,最终覆盖率从原来的0提升到了92%。这91%的增量里,AI贡献了大约八成,人类做了两成的纠偏——这是个让我特别舒服的分工比例。
3.4 步骤三:人工兜底与代码合并
重构代码本身也是我提交给AI的——我给定"保持原有行为不变"的约束,让它把拆分后的方法骨架填出来。AI生成了第一版,结构很漂亮,但我审查后发现了一个关键性能缺陷:它把原本在循环外执行的一次配置表查询,挪到了循环里,导致每条记录都要查一次数据库,这在数据量上万时会带来致命的性能下降。
我把这个问题指出来之后,AI先道了歉,然后立刻给出了修正版:将查询提到循环外,并加上了基于主键的缓存。这个纠正只花了三十秒,但如果我不会审查、不懂数据库访问策略,这段有问题的代码就会进入生产环境。这正是我一直强调的:AI提供起点,人类决定终点。
最终重构完成之后的代码,函数数量从2个变成11个,每个函数职责单一,行数控制在三十行以内。整套代码通过了测试、通过评审、并顺利上线。整个过程中,AI实际产生代码的时间不超过二十分钟,而人工参与的时间大概是两个下午——主要是做需求描述、逻辑核对、评审和补测试。
4. 踩坑实录:AI编程最容易翻车的4个场景
和AI配合了这么长时间,我整理过一份"AI编程翻车实录",这里挑四个最典型的场景分享。这些坑不是我一个人踩的,团队里的其他同事也遇到过,非常普遍。
4.1 幻觉API与过时依赖
AI最让人头痛的问题就是一本正经地编造不存在的API。你问它某个库有没有某个方法,它可能从训练数据里见过相似方法名,就自信地给你编一个出来。实际编译一跑,报错"找不到符号"。更隐蔽的情况是它给出的API确实存在,但只能在新版本里用,你项目里用的还是两年前的旧版本。
我的经验是:让AI写代码前先在同一个对话里明确告诉它"当前项目用的框架版本是X,依赖管理里锁定在Y",并明确要求"只准使用标准库和项目已有依赖"。即使这样,我也不会放弃编译验证这一关——任何AI生成的代码,第一步永远是让它在项目环境里真实编译跑一遍,而不是肉眼看。
4.2 上下文遗忘导致的连锁错误
AI的对话记忆有限,当你在一个长对话里连续提出多个需求时,它可能会在前面说"使用A方案",到了后面就忘了,又在某个地方写了B方案的代码。我遇到过最离谱的一次是让AI帮忙拆分一个文件,它拆前三个类用的都是同一个依赖路径,拆到第四个类时突然用了另一个路径,结果导致整个模块无法启动。
对付这个问题,我现在的做法是"一次对话只做一件事"。跨模块、跨文件的改动,我会在每次任务开始前把相关约定重新粘进对话,并且在关键节点用一句话确认:"请先总结一下目前我们约定的技术方案,再继续下一步。"让AI复述一遍,能筛掉绝大部分上下文错乱的问题。
4.3 代码“正确”但思路平庸
有些AI生成的代码能通过测试、也能运行,但它选择的方案非常粗糙,比如为了功能简单而引入了不必要的全局状态,或者在一个只需要用哈希表的地方强行建了一个完整的类。AI不会主动考虑架构演进——它擅长解决局部问题,但不擅长考虑这个局部问题在未来半年里会怎么生长。
我通常会在审查时问自己三个问题:这个代码放到三个月后的系统里,还成立吗?如果需要改动,改动点是不是能控制在一个函数内?有没有更简单的方案,只是AI不知道?如果答案不理想,我会把架构约束再喂给AI,让它重写,而不是守着那份"能跑就行"的代码自我安慰。
4.4 安全隐患藏在"看起来正常"的代码里
有一类AI通病特别危险——它的默认安全配置往往是最宽松的。比如生成一个文件上传接口,它可能在响应头里不设置任何限制,也没有校验文件类型和大小;比如拼接SQL时直接用字符串格式化,因为训练数据里这种方式最常见。这些代码放在具体业务里,可能就成了漏洞。
我们团队的安全评审规则很简单:凡是AI生成的代码,必须比人工写的代码过更严格的安全审查。尤其注意输入校验、鉴权逻辑、密钥管理这三个位置。AI可以帮你查出CVE(已知安全漏洞),但"避免引入新漏洞"这件事,人类经验依然不可替代。
5. 潜力边界:AI能做什么,不能做什么
用了这么久,我对AI编程的能力边界有了更清醒的认知。它能把很多原来让我秃头的事情变得轻而易举,但也有些事情,你会发现再强大的模型也帮不上忙,甚至帮倒忙。
5.1 AI擅长快速生成、解释与翻译
代码生成是最基础的能力,但它的出色程度依然超出预期。以前写一个Excel导入导出功能,我需要翻文档、查示例、改半天;现在让AI直接按我指定的格式和依赖生成,基本一次到位。AI也擅长解释零散代码。接手一个没有任何文档的老项目时,把一大段代码丢给它,它能把逻辑梳理成结构化说明,相当于免费获得了速读技能点。
另一种AI特别擅长的工作是"代码翻译",把一种语言或框架的实现转换成另一种。我做过一次把一整套工具脚本从Node.js迁移到Python的任务,AI在几分钟内完成了主体转换,我只需要修正部分差异,比如事件循环模型和类型系统的处理方式。这种跨语言翻译在过去手动做,少说一周起步。
5.2 AI不擅长做架构决策与需求分析
AI最大的弱点是"不知道我们为什么要写这段代码"。它能告诉你这段代码是干什么的,但给不了你"我们该不该用消息队列替代数据库轮询"这种层次的判断。架构决策依赖的是对业务的深度理解、对成本收益的权衡、对团队未来走向的预判——这些信息根本不存在于AI的训练语料里,只存在于你的脑子里。
需求分析呢?AI可以帮你补全遗漏的边界条件,但它不会主动告诉你要把用户的某个新需求做进系统里——它连用户长什么样都不知道,更别提从一句话里挖掘背后隐藏的诉求了。所以每当我听到"AI会取代软件工程师"的说法时,我总觉得对方大概率没在一个真实的软件项目里待过。
5.3 边界会不断移动,但共生关系不变
AI的能力边界不是静止的,今天需要人介入的环节,明年可能AI就能自动完成。比如代码生成这一块,两年前还需要人去搭很细致的提示词框架,现在已经可以做到用自然语言对话迭代修正。也许再过几年,AI在代码生成上能做到十次里有八次完全正确,人的工作重心会进一步向后移动——从写代码转向构建和维护"约束条件"。
但我认为有一点不会变:软件工程永远存在"目标定义"和"价值判断"。哪怕AI可以把整个系统的代码都生成出来,谁来决定做这个系统而不是那个系统?谁来评估做出来的东西到底好不好用?谁为长远维护负责?这些问题的答案,还是要落到人身上。
6. 给团队和个人的实用建议
最后这部分是经过实战沉淀下来的一些建议,既面向个人开发者,也面向正在尝试引入AI的小团队。
6.1 个人开发者先培养“提示词直觉”
不要一开始就想着让AI写整套系统,先从三个小练习开始。第一,用"五要素提问法"让AI写一个带参数的函数,比如发邮件通知、导出报表,体会需求描述的颗粒度;第二,故意给它一个模糊的指令,比如只写"处理一下这个数据",观察它的默认行为和盲区;第三,让它生成你手头代码的单测,逼自己在审查时快速读懂逻辑。这三件事做下来,你对AI的能力范围和失效模式的直觉会在两周内建立起来。
顺着这个思路,我个人的经验是尽量不要把AI当成"搜索引擎升级版"。搜索是找到别人写好的答案,而生成式AI是综合所有见过的代码来创造新答案。你越早转换这个心智模型,越能明白为什么它适合用来探索方案而不适合用来"问正确答案"。
6.2 团队层面要建立AI代码审查规范
如果团队开始大规模使用AI编程,我建议不要停留在"每个人自己随便用"的状态。我们内部的规范有三条:AI生成的代码必须走常规的代码评审流程,不允许直接合入主干;所有AI生成的关键模块必须配备测试,覆盖面不能低于人工编写的模块;定期分享"AI的翻车案例",让每个人了解当前AI工具的短板。
这个规范不是为了给同事添堵,而是因为AI代码和其他代码最大的区别是:它的"出身"决定了它不一定经过完整的思考链条。AI能写出设计清晰的代码,但它的设计是基于统计概率而不是经过严格逻辑推演。没有审查和测试把关,等于在质量体系里开了一道口子。
6.3 把AI当作“无限耐心的队友”
我在团队里反复说的一句话是:你可以半夜三点把AI喊起来,它不会有任何起床气;你也可以不厌其烦地告诉它同一个错误两遍、五遍、十遍,它都愿意重新配合。这种特质在人类结对编程里几乎不可能长期存在。利用好AI的耐心,意味着你可以放心地尝试各种方案,哪怕最后一版方案不合理,你也只是花了几分钟而不是几天。
与之对应的是,人类要给AI提供"真实世界的反馈"。AI不会因为你去生产现场实习过而理解什么叫"用户的耐心只有三秒",这些信息只能由你来补。沟通、反馈、约束、验证,这个循环走得越顺畅,你和AI的共生关系就越健康。
7. 写在最后:一段从质疑到共生的心路
老实说,我最初用AI辅助编码时,内心是有点抗拒的,总觉得自己是在"抄近道",写出来的东西没有含金量。但经历了几次真实项目的打磨后,我反而踏实了:AI替我解决的是那些重复性的、模板化的部分,而真正让方案成立、让系统稳定运行的人为判断,依然来自我自己的积累。
那段最老的重构项目至今还在线上稳定运行,每次看到它清晰的结构和齐整的测试,我都会想起当时和AI隔着屏幕反复确认逻辑的那个下午。现在我已经不再纠结"AI会不会替代程序员"这种问题了——因为替代问题本质上是个伪命题。真正值得我们关心的,是每个人如何找到自己与AI最佳的分工点,把对方的优势嵌入自己的工作流,同时用自己的判断力去兜住那些模型看不见的风险。
如果你也想试一下类似的协作方式,我给你三个立刻就能用的建议:第一,找个你喜欢但一直没时间重构的老代码,让AI先帮你理一遍逻辑;第二,给AI一个明确的约束,比如"前提条件是什么、边界条件是什么、不允许用什么",看看它的表现会出现什么不同;第三,大胆地在代码评审会里讨论AI给出的方案,把它当成同事的方案来客观看待。你很快会发现,它不是无所不能,也不是一无是处——它是你座舱里新增的副驾驶,方向盘和目的地,依然需要你来握紧和确认。