ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

AI生成代码时代的软件工程:从编码范式到工程实践的全面重构

AI生成代码时代的软件工程:从编码范式到工程实践的全面重构

前几天做代码评审,旁边一位同学提交了一段生成函数,逻辑很精炼,测试也带上了。我随口问了一句,这段代码是你自己写的吗,他有点不好意思,说生成过程用了AI助手。当时我愣了一下,不是因为代码写得不好,而是因为我发现自己已经很难靠肉眼分辨一段代码到底是人工写的还是模型生成的。这个瞬间让我决定把CS146S这套学习笔记里关于AI与软件工程的部分好好整理一遍。

这份笔记想解决一个实际问题:当AI把“写代码”的门槛拉得越来越低,软件工程这个学科里哪些东西会变,哪些东西不会变。它不是某个工具的教程,而是一套思考方法和实践策略。无论你是刚入行的学生,还是工作多年的工程师,只要日常开发里已经出现AI生成代码的影子,这份笔记都值得看一看。我会尽量把理论内容、动手实践中的细节和踩过的坑放在一起讲,方便直接参考。

1. AI时代的软件工程:从“编码工具”到“开发范式”的转变

我最早接触AI辅助开发时,以为它只是让“打字”变快了一点。真正把CS146S的材料读进去之后才发现,事情远不止于此。这一章想聊的,就是软件工程这个学科在AI冲击下发生的底层变化,以及那些我们过去习以为常的默认假设,是怎么一步步失效的。

1.1 传统软件工程的默认假设,正在一个个失效

软件工程从诞生起就有一个隐含假设:代码是人类理性设计的结果,因此可以计划、可以度量、可以预测。需求分析、概要设计、详细设计、编码、测试、维护这条链路,本质上是在把不确定性逐级化简。经典的瀑布模型假定需求可以提前冻结,敏捷开发修正了这一点,但仍然假定代码由人主导编写,沟通和评审发生在人与人之间。

AI时代打破的是第二层假定。如今一段可运行的代码可以由自然语言描述直接生成,这就让以往以“编码”为中心的工程流程出现了一个裂口:如果代码的产出者不再是人,那我们过去的代码规范、复杂度度量、工作量估算,还有多大程度适用?这是我最初整理笔记时最强烈的感受——真正发生变化的并不是某行代码的写法,而是整条价值链上“人在哪、机器在哪”的重新分配。

这个变化会直接影响到项目管理的很多细节。以前估一个模块的开发时间,看的是代码量、接口数量、联调成本;现在AI生成代码之后,时间主要花在需求澄清、代码评审、测试验证和异常场景确认上。如果团队还按旧的节奏来排期,必然会出现“代码写得飞快、但评审和返工的时间反而拖长”的怪象。

1.2 AI在软件生命周期里的角色演化

我用三个阶段来描述AI角色的变化。第一阶段是代码补全,AI更像一个聪明一点儿的编辑器,只在你输入一半的时候猜出下一段是什么,人依然掌握全部意图。第二阶段是代码生成,你给出明确的函数签名、需求描述、示例,AI直接产出完整模块。到了这一步,人的角色从“编写者”变成了“审查者”。第三阶段是全流程协同,需求分析、测试用例、文档、发布说明、运维诊断都有AI参与,软件工程的组织形式开始改变:项目前期花在需求澄清和验收条件协商上的时间会增加,后期花在代码翻译上的时间会显著减少。

我自己过去半年最大的体感是:写一个原型模块的时间缩短了不止一半;但“确定这个模块到底该怎么设计、边界在哪里、异常怎么处理”的时间并没有变少。换句话说,AI压缩的是从想法到第一版代码之间的距离,而不是从模糊想法到清晰想法之间的距离。很多团队把AI当成“提速神器”,结果只提了写代码的速度,没有提决策的速度,因为决策这件事从来不是靠打字快就能解决的。

1.3 为什么“AI替代程序员”是个伪命题

我在笔记里专门对比过“写代码”和“做软件”这两件事。写代码是翻译——把需求翻译成机器能执行的语言。做软件是在不确定的环境中做决策:这个需求是否已经被正确理解?这个方案在半年后还能不能继续演化?线上流量翻十倍,这个模型是否还成立?这些决策无法被“生成”替代,只能被“辅助”。

拿AI生成代码的评审来说,模型可以快速给你一个高概率可运行的方案,但只有经历过线上事故的人才会追问:如果并发量高了两百倍,这个方案会不会打爆数据库?如果下游依赖超时,补偿逻辑在哪里?AI在这方面有“乐观偏差”,它倾向于生成看起来正确、但缺少边界处理的代码。所以与其担心被替代,不如把AI当成一个执行速度极快、但判断力欠佳的初级工程师。你需要做的是管理它、审查它,而不是惧怕它。

2. 需求到架构:AI如何参与项目的最前端

很多人以为AI辅助开发就是从写代码开始,但我在实测中发现,AI在需求分析和架构设计阶段的价值反而被严重低估。这个阶段的信息密度低、表达模糊,正是AI擅长“补全”的地方,但同时也是最容易引入错误假设的地方。

2.1 用AI做需求澄清和任务拆解,省下大量前期拉扯时间

我这学期尝试过一段很典型的流程:把一段客户发来的模糊描述,原封不动丢给AI,让它分别从“产品经理”“测试工程师”“架构师”三个角色各输出一版分析。产品经理视角的版本会列出需要澄清的问题清单,测试工程师视角会给出验收标准草案,架构师视角会指出高风险点。

效果出奇地好。AI最有价值的地方不是帮你作决定,而是帮你想起来“原来还有这些没确认的事”。比如一个订单系统的新需求,AI会追问退款时限、库存锁定策略、幂等键设计、审计日志要求——这些问题如果靠人肉穷举,往往要到开发中后期才发现。把这些问题前置,需求评审的质量会有明显提升。

但这里有一个必须注意的点:AI有“过度补全”倾向。你只是说“用户可以用优惠券下单”,它可能就在验收标准里写上一堆你完全没提过的规则。网上很多教程把它叫“幻觉”,我觉得在这个场景下更像“脑补”。每次AI输出之后,必须有一条人工确认环节,把“它替我加上的”和“客户真正要求的”区分开,否则需求评审反而会引入噪音。

2.2 架构设计中的AI辅助:给方案,也给风险清单

架构设计是AI介入比较深的领域,但也是最容易被误导的领域。我的用法是:让AI生成候选方案对比表,不要让它直接拍板。比如“订单系统需要支持秒杀场景下的高并发写入,库存扣减不能超卖,请给出三种可落地的技术方案,并对比延迟、一致性、运维复杂度、迁移成本”。AI通常能给出不错的初稿,覆盖缓存预热、消息队列削峰、分布式锁、数据库分片这些常见做法。

真正有价值的输出其实是风险清单。AI会列出一个生手很容易忘记的边界:缓存击穿、热点数据倾斜、分布式事务的回滚补偿。这些内容对团队讨论很有帮助,相当于一个知识面很广的顾问在给你做头脑风暴。

局限也很明显。模型不了解你们团队的实际状况,不知道哪套基础设施已经运行了几年,不知道某个方案需要哪个部门配合。更重要的是“历史包袱”——AI不知道你们代码库里哪些模块是祖传的、碰不得的,所以它给出的架构方案再漂亮,落地时也要做一轮“现状约束”过滤。我的建议是,把AI生成的对比表当作讨论的起点,而不是结论。

2.3 从Demo到系统设计:AI的边界在哪里

AI有一个被高估的能力叫“从描述到原型”,还有一个被低估的能力叫“从原型到可靠系统”。前者AI做得很好,后者仍然是人的主场。

举个例子,让AI写一个带认证和日志功能的用户服务Demo,它几分钟就能给出完整代码,甚至带注释和单元测试。但要把这个Demo变成生产系统,你需要考虑:密钥怎么管理?协议版本怎么兼容?日志怎么脱敏?监控指标怎么暴露?优雅停机怎么处理?这些问题AI不是完全不会答,但它答出来的东西往往是“通用最佳实践”,而不是“结合你现有环境的迁移方案”。跨界判断、历史兼容、团队节奏这些因素,模型获取不到,只能靠人来补。

所以我对架构设计的结论很简单:AI让“生成方案”变便宜了,但让“拍板方案”变贵了——因为选项变多了,你需要更强的判断力去排除那些看似合理但根本不合适的选项。

3. 编码提效:AI辅助开发的核心实践

编码环节是大家感知最强的部分,但对AI的使用方式不同,效果差异非常大。同样是AI编程助手,有人觉得它是个“高级补全工具”,有人觉得它能顶半个工程师,背后的差别在于你把它用在什么任务上、信任到什么程度。

3.1 三种使用姿势,对应三种不同的信任级别

把AI编程助手的使用方式拆成三类会很有用。

第一类是补全式,你在写代码的时候,它预测下一段。这种模式信任级别最低,但侵入性也最小,适合模板代码、重复性结构,比如DTO、Mapper、单元测试的骨架。第二类是对话式生成,你描述需求,它产出完整函数或模块,这是眼下使用率最高的方式,但也是翻车重灾区——因为输出越长,隐藏的假设越多。第三类是重构式,给定一段已有代码,让AI做简化、拆分、重命名、异常处理增强。重构模式隐含风险最大,因为AI可能改变原有行为而不告诉你。

使用方式信任级别适合场景必须做的检查
补全式低模板代码、重复结构直接采纳后自查
对话生成中新模块、整函数必须配单元测试
重构式高已有代码优化过评审、对比行为差异

我长期使用的原则:补全可以直接采纳,对话生成必须配测试,重构必须过评审。这不是保守,而是因为在三种模式中,补全的上下文最完整(你写了一半,意图很明确),对话生成的上下文最容易被误解,重构则涉及已有行为契约,改动面最难控制。

3.2 上下文工程:给AI喂什么,它才不瞎编

很多同学抱怨AI生成代码“看着像回事,一跑就报错”,原因往往不是模型不行,而是上下文没给够。模型不是读心术,它对你代码库的了解,完全取决于你贴了哪些材料。我在笔记里总结了一个五要素上下文模板,实测效果非常明显。

[背景] 项目是什么、技术栈是什么、已有模块有哪些 [任务] 要实现什么功能、输入输出是什么 [约束] 只能用哪些依赖、不能引入什么、必须遵守什么规范 [环境] 跑在什么环境上、数据库是什么、有没有特殊部署要求 [验收] 怎样才算完成、是否有边界条件和性能要求

比如我接过一个需求:“给订单服务新增一个查询接口,返回某时间区间内的订单总金额,支持分页和超时控制。”只发这一句,AI大概率会给出一个直接用COUNT查询的简单方法,甚至可能引入一个你们项目根本没用过的ORM扩展框架,那就只能返工。

但如果按五要素模板补全,说明技术栈是Java 17 + 主流Web框架,已有订单仓储层,查询要防止全表扫描,返回用统一的响应包装,那么AI生成的代码落地率会高得多。上下文不是写得越多越好,而是越“相关”越好。把无关的二十个类全部粘贴进去,反而会让模型混淆优先级。

3.3 让AI帮你审查代码:能发现一些Bug,但也有明显盲区

我发现一个特别有效的代码Review姿势:先让AI“解释这段代码做了什么”,再让AI“指出三个可能在极端条件下触发异常的场景”,最后让AI“建议一组单元测试用例,包含一个边界条件和一个失败路径”。

解释的过程会迫使模型逐行读代码,这比直接问“有没有bug”有效得多。因为“有没有bug”是个开放问题,模型会倾向于给一个“看起来没问题”的乐观回答;而“请指出三个极端场景”是具体任务,模型会认真去想空指针、并发竞态、超时、依赖挂掉这些情况。

但AI的盲区也很明确:业务语义错误、合规要求、多步事务的语义一致性、线上历史数据的兼容性。模型看不到生产环境的真实数据,也感受不到一个错误对用户体验的冲击强度。所以我的代码评审流程是三层:AI初筛负责格式问题、明显逻辑漏洞、边界遗漏;人工精审负责业务正确性、架构一致性、可维护性;测试兜底负责验证行为变化。这套流程下来,效率比过去全靠人肉看代码高不少,但始终没有把“人的判断”移出链路。

4. 测试、质量与运维:AI带来的新挑战

AI生成代码的引入,让质量和运维环节出现了一些过去不太会遇到的新问题。这一章的重点不是讲测试理论,而是讲AI生成代码之后,我们在测试、防幻觉和线上运维方面做出的针对性调整。

4.1 AI生成代码的测试策略:强制要求测试先写

AI生成的代码有一个非常典型的毛病:它倾向于写“乐观路径”。正常参数进去,一切顺利,返回正确结果;但参数为空、并发冲突、下游超时、数据不一致这些分支,它常常不去处理。原因不难理解,训练数据里的“好代码”大多来自教科书和开源项目,这些样本很少展示真实的异常处理泥潭。

所以策略变得很简单粗暴:凡是AI生成的代码,必须同时生成或补写测试。让AI生成测试用例时,我会要求它“给出正常路径、边界条件、异常路径三组用例”,然后人工检查断言的严格程度。

这里有个很隐蔽的坑:AI生成的测试不一定可靠。因为它惯例是“让测试通过”,所以断言的阈值常常很宽。比如一个查询接口返回订单列表,AI生成的测试只断言HTTP状态码是200,但不检查返回体里的订单数量、分页字段、错误码。这样的测试跑一遍全绿,实际等于没测。审查AI生成的测试时,重点看断言质量,而不是看覆盖率数字。

4.2 幻觉代码:模型一本正经地胡说八道

幻觉是AI生成代码时最需要警惕的问题。所谓幻觉,就是模型基于概率生成了一段结构正确、但引用根本不存在的API或配置的代码。它看起来完全正常,编译过不了,或者运行时才暴露。

我碰到过一次非常典型的翻车:让AI生成一个基于某种配置中心的服务密钥管理方案,它引用了一个我非常笃定在那个配置中心生态里不存在的SDK包名。我花了不少时间翻了几个依赖仓库的文档页面,最后确认那个包根本不存在。整个过程里,代码的缩进、命名风格、注释语气都极其专业,唯独关键依赖是假的。

减少幻觉的办法,我在笔记里列了几条:一是交叉验证,AI给的依赖、API、配置项,一律去官方文档核对;二是让AI标明“信息来源”,虽然模型不会真的告诉你出处,但这个要求会迫使它更保守;三是编译和测试兜底,所有AI生成代码必须能在本地跑通基础测试;四是锁定依赖版本,把AI建议的“最新版”改成项目里已经验证过的版本。把这四条养成习惯之后,被虚拟依赖坑到的情况会少很多。

4.3 运维阶段的AI应用:从日志分析到根因定位

软件工程的后半程是运维,AI在这里的形态完全不同。传统监控着重“告警”,告诉你有问题;AI辅助运维可以更进一步,尝试告诉你“问题大概在哪”。比如日志聚类、异常检测、调用链分析,已经有不少工具把大模型嵌进去,直接根据一堆堆日志文本自动产生疑似故障根因。

我实际用下来,AI在日志分析上的效果比预想好。它擅长从海量日志里抽取共同模式,概括出“某个接口的响应时间在某个时段明显抬高,且伴随数据库连接池超时错误”,这就把过去需要人肉翻半天日志的工作压缩到几分钟。但要小心:AI给出的“根因”只是基于文本关联的假设,不是因果关系。作为变更审核的输入可以,作为自动执行的依据还不行。生产环境的变更动作,依然应该由人来确认。这一点我在笔记里标成了红色。

5. 人和流程:AI时代软件工程师的关键能力

讲完工具和流程,要回到一个更根本的问题:AI时代,工程师的核心竞争力到底变成了什么?我以前觉得是“会写代码”、是“能加班”,现在更倾向于另一个答案:是在复杂局面里保持清醒判断的能力。

5.1 提示词之外的核心竞争力

AI时代最容易被低估的能力,不是“写提示词”,而是“判断AI输出是否值得信任”。提示词技巧一个月就能学会,但判断力需要长期积累。

我把它拆成四块。第一是批判性思维:看到一个AI方案,能不能先问“这个方案成立的前提是什么”。第二是领域知识:只有真正理解业务,才能在AI生成的多个方案中选出真正贴合的那一版。第三是架构取舍:知道“快”和“稳”在不同阶段如何权衡。第四是协作管理:把一个AI当成会快速产出、但容易误解任务的协作者,你需要会拆任务、定边界、做验收。

我在笔记里经常写一句话:AI把“亲自写代码”的成本降到接近零之后,程序员的核心价值就变成了“知道为什么要这样做、以及如何为后果负责”。这句话听起来有点抽象,但落到日常就是:别人扔给你一段AI生成的代码,你能不能在一分钟内说出它的风险点;线上出问题时,你能不能按照逻辑链快速定位,而不是在错误的方向上反复试。

5.2 团队协作与流程调整:把AI当作另一个“提交者”

团队层面,AI带来的最大变化是代码来源变得混杂。以前评审代码,默认这段代码是人写的;现在你默认它可能是AI生成的,评审的侧重点就要调整。

我们团队现在的做法是:不强制标记哪段代码是AI生成的,但特别关键的模块(支付、权限、数据迁移)会单独要求做一次“AI生成的额外校验”——也就是在常规评审之外,额外让一个不熟悉这段代码的人,从“如果这段代码是错的,会发生什么”的角度去审。因为最危险的AI生成代码,往往不在业务逻辑(业务逻辑反而容易被发现),而在那些看起来无关紧要的工具函数、配置变更、依赖更新里,它们一旦出错,影响面往往很大。

流程上还有一个调整:把“让AI做什么”和“不让AI做什么”写成团队的显式规范。比如禁止AI生成包含密钥硬编码、敏感权限操作、生产库变更的代码;AI提供的依赖必须先经过安全扫描。把这些规则写下来,不是为了限制使用,而是为了让AI产出进入代码库的路径更加可控。

5.3 知识库与模型微调:小团队先别急着微调

很多团队看到AI辅助效果好,就想着“要不要微调一个自己的模型”。我的建议是,团队规模还不够大的时候,先别微调。微调的代价不只在训练成本,更在维护成本:数据更新、效果回归、版本管理都是长期负担,而且微调模型对新知识的吸收速度也有限。

更划算的做法是走知识库增强(RAG)的路线:把团队的历史文档、设计文档、常见问题、代码规范做成可检索的知识库,让AI在回答问题前先检索相关上下文。这样既不需要重新训练模型,也能把团队的隐性知识注入到答案里。具体落地时,先从一个小的内部问答机器人开始,把高频问题做成文档片段,上线后再慢慢扩充。这条路我们已经跑通了几个场景:新人入职问答、历史模块结构查询、发布流程指引。收益很明显,而且风险完全可控。

6. 盲目信任AI输出的几个翻车现场与工作流建议

这一章放在最后,是想用最真实的方式提醒大家:AI生成代码不是银弹。我踩过的坑,大概率你也会遇到。我把它们写下来,希望你能绕开。

6.1 三个真实的翻车场景

先说第一个坑:让AI设计数据库索引。它给出的索引非常规范,从教科书角度挑不出任何毛病。但问题在于,它不知道我们表里有几千万行存量数据、不知道某个慢查询其实来自另一个历史字段,结果按它建议建完索引后,写入性能反而下降。索引不是越多越好,这道理人人都懂,但AI生成的建议太“像模像样”,很容易让人放松警惕。

第二个坑是修线上Bug。某段代码在并发场景下偶发数据不一致,我把错误日志丢给AI,它给出一套“看起来无懈可击”的修复方案,甚至配了单元测试。但按这个方案改完后,问题从偶发变成频繁,因为AI没有意识到,真正引发问题的不是它看到的那个异常分支,而是更早一层的事务边界没有控制好。那次之后我学会了一件事:AI的分析结果只能作为排查线索,不能直接当作根因结论。

第三个坑是盲目信任AI生成的测试。前面提过断言过宽的问题,那次是我自己踩的:AI生成了三十多个测试用例,跑起来全绿,我差点直接合入。后来人工抽查发现,大部分用例只断言了状态码和返回非空,真正该验证的业务结果、异常码、幂等行为全都漏了。从那以后,凡测试必查断言。这个教训花了一点时间才真正内化。

6.2 现在团队在用的稳健工作流

经过这些翻车,我们总结出一条适合多数团队的工作流。

第一层,需求阶段:用AI列出澄清问题和验收标准,人工确认后冻结。第二层,设计阶段:用AI生成候选方案和风险清单,架构师负责裁决。第三层,编码阶段:使用三要素上下文模板,AI生成代码必须带测试,关键模块额外校验。第四层,测试阶段:AI生成用例,人工检查断言质量。第五层,Review阶段:AI初筛逻辑问题,人工精审业务,测试兜底行为。第六层,上线阶段:AI辅助生成发布说明和回滚方案,但最终变更由人触发。

这套流程不复杂,但它把AI用在“最能提高效率的地方”,同时把“影响面大”的环节始终保留人的判断。工具更新换代很快,但这条“机器产出、人工负责”的主线不会变。

6.3 几个可以直接抄走的实操建议

最后放几条我实际用下来觉得最能直接提升质量的小建议。

第一,给AI写“不能做什么”,比写“要做什么”更重要。明确告诉它“不要修改现有接口签名”“不要引入新的依赖”“不要改变返回结构”,能大幅减少返工。第二,在代码库里为AI生成区域做标记。不需要太复杂,注释里加一个标签就行,未来出问题时可以快速回溯。第三,定期做“无AI日”练习。所谓无AI日,就是每隔一段时间,专门挑一天完全不用AI辅助,纯手写代码。这样做的目的是让基本功保持手感。我自己试过,坚持下来之后,对AI产物的判断力明显更敏锐了。

经验层面,我想分享一个特别实用的小技巧:在让AI做代码评审时,少问“有没有问题”,多问“在什么条件下会出问题”。两者的差别就像问“这个人可靠吗”和“他在什么压力下会失控”,后者得到的答案具体得多。这也是这份CS146S学习笔记里反复出现的一条主线:AI时代真正值钱的能力,是在不确定性里保持判断习惯。

如果你也正在摸索AI辅助开发的工作方式,建议从一个小模块开始,带着这套“机器产出、人工负责”的思路去试。工具迭代永远很快,笔记迟早会过时,但判断力不会。希望这份整理能帮你少走几步弯路。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进