AI编码之后:可靠性工程与代码审查才是真正的瓶颈
AI编码现在最容易被高估的地方,不是它能写多少代码,而是“写完代码之后怎么办”。我最近复盘了一个业务约束很强的项目,场景和 Maven Clinic 这类医疗健康服务平台很接近:用户预约、医生排班、保险校验、消息通知,每一步都涉及真实用户的安全和体验。团队也用 Cursor、Codex、AI Agent 做日常编码,结果发现一个有意思的事实:代码生成确实变便宜了,但团队的“争论成本”和“可靠性验证成本”反而变成了新的瓶颈。下面不比较哪个 AI 工具更强,而是聊当编码变廉价之后,一个 AI Engineer 真正要解决的问题是什么。
1. 先搞清楚:AI编码到底把哪部分变便宜了,哪部分反而更贵了
1.1 “编码变廉价”的真实含义:从写代码到审代码
AI编程现在已经不是一个概念,而是日常开发里很普通的事。用AI生成接口、写单元测试、重构旧代码、补文档,都是成熟用法。编码本身的人力成本确实在下降,尤其在有明确上下文的情况下:输入参数是什么、期望输出是什么、异常情况怎么处理,这些描述越具体,AI生成的代码可用率越高。
但编码便宜不意味着软件开发变便宜。它只是把成本从“写代码”转移到了“判断代码对不对”。在普通项目里,判断错了顶多返工;在类似 Maven Clinic 这种业务里,判断错了可能直接影响用户预约是否成功、医生是否收到提醒、保险信息是否被正确记录。这个差别非常大。
我一般会建议团队先做一个实验,不要直接上大模块。挑一个真实存在但影响范围可控的小功能,让AI生成完整实现,然后让一个资深工程师做 Code Review。记录两个数字:AI生成代码花了多久,Review 和修正花了多久。很多团队做完这个实验都会发现,后者往往不比前者短,甚至会超过写代码的时间。
这背后的原因不复杂。AI生成代码的能力,建立在“需求已经被表达清楚”这个前提上。但凡需求存在模糊,AI就会用自己训练数据里的常见模式去补全。补全出来的代码语法正确、结构合理,但业务语义可能是错的。这正是“AI幻觉”在工程里的真实表现:不是胡说八道,而是用一种非常自信的方式填了一个错误的空。
所以,如果你是一个刚准备引入AI编码的团队,第一个要搞清楚的问题是:你们缺的到底是写代码的人,还是能把需求边界说清楚的人。如果是后者,AI编码非但不会解决问题,还会放大问题。
1.2 便宜的是语法,贵的是确认成本
举一个非常常见的例子:预约状态流转。需求描述可能是“用户取消预约后,医生端要同步更新”。这句话看起来很简单,但落到代码里至少有这几个问题:
- 取消动作是用户触发,还是系统自动触发?
- 取消时如果已经进入医生确认阶段,要不要走审批?
- 医生端同步更新,是实时推送还是轮询?
- 更新失败怎么办,要不要重试?
- 取消之后排班时间是否释放,释放失败会不会造成重复预约?
这些问题如果不提前确认,AI会根据通用模式生成一个看起来合理的实现。它可能选了“直接改状态,然后推送通知”,但真实业务要求是“先进入待确认状态,等医生处理,再释放资源”。这就是典型的确认成本:代码生成只用了几分钟,但错误实现导致的返工、测试、讨论,可能要花掉好几天。
我的建议是把确认过程前置,并且用上下文来承载。可以要求AI在生成代码前先输出“需求理解”,列出它假设的边界条件,然后由业务方和工程师一起确认。这不复杂,但对降低返工率非常有效。
这里有几个小技巧可以试试:
- 给AI的时间不要太多,让它先给方案,不直接给代码。
- 要求AI列出它认为模棱两可的点,而不是让它默认替你决定。
- 把业务方的约束条件写进提示词,例如“用户取消后医生端状态不能直接变已完成,必须先进入待确认状态”。
- 让AI生成验收用例和代码,验收用例通过后再看实现。
- 每次生成代码前,把最新的需求决策记录贴进上下文,保持同步。
这些做法的目的都一样:把“确认”这一步从代码审查里提前到需求讨论里。确认越早,返工越少。
2. Maven Clinic这类项目里,“争论”为什么成为新瓶颈
2.1 业务方、工程方、AI助手三方共识
当一个团队开始高频使用AI编程后,会出现一个特殊现象:业务方、工程师、AI助手三者之间形成了一个新的三角关系。以前业务方提需求,工程师实现,问题不明确时讨论一下。现在业务方提需求,工程师把提示词写给AI,AI生成代码。看起来更快,但讨论环节并没有消失,只是换了一种形式。
AI生成代码后,业务方可能会发现实现结果和预期不一样。这时候容易出现争论:到底是需求没写清楚,还是提示词没写清楚,还是AI理解错了?表面上看是“AI的锅”,实际上争论的是业务语义到底应该由谁定义。
在业务约束比较强的场景里,这种争论尤其多。因为医疗健康业务里有很多专业概念:预约类型、保险覆盖范围、临床路径、隐私授权、通知偏好。这些术语在业务方脑海里是一套体系,在工程师脑海里是模型字段,在AI训练数据里又是一种常见模式。如果三方没有对齐,AI生成的代码大概率会偏离真实场景。
解决这个问题的方法不是禁止争论,而是把争论变得有产出。我通常会用“语义清单”的方式,把项目里最核心的术语列出来,每个术语都写清楚业务定义、技术字段、允许取值、边界条件、异常处理方式。这一份清单既给AI当上下文,也给团队当评审依据。争论发生的时候,先看清单,而不是先改代码。
2.2 把争论从口头层面,落到可验收的定义
我以前带AI编码项目时,最怕的不是争论本身,而是争论发生在代码实现之后。业务方说这不是我要的,工程师说AI就是这么生成的,AI又说我只是根据提示词操作。整个讨论没有结构,最后只能靠人的耐心来收场。
后来我总结出一个更稳妥的流程:任何一项需求进入开发之前,先完成三件套——边界定义、验收用例、否决条件。
边界定义写明“做什么、不做什么、什么情况下算完成”。验收用例采用 Given-When-Then 结构,直接描述业务行为。否决条件明确“什么情况下这个功能不能上线”,例如重复预约会导致医生排班冲突,这种场景就不能放过。
三件套写完之后,再交给AI生成代码。生成完之后,AI输出的测试代码如果和验收用例不一致,就直接说明理解错了。这样讨论的对象就从“谁说得对”变成了“验收用例能不能覆盖真实场景”。争论还是在,但至少有一个明确的裁判。
这里要注意,否决条件不能被AI自动生成。它应该来自业务方和合规、安全、运营团队的输入。AI能帮你把否决条件变成测试代码,但不能替你决定否决条件本身。这一点在医疗健康类项目里尤其重要。你可以在提示词里要求AI“根据以下否决条件生成回归测试”,但否决条件的来源必须是真实业务风险,不是模型猜测。
3. 可靠性不是功能项,是一套需要提前设计的工作流
3.1 可靠性的定义要先对齐
“可靠性”这个词在AI编码项目里特别容易被含糊使用。有人说“代码稳定,不崩溃”,有人说“用户操作后数据不会丢失”,有人说“系统挂了之后能恢复”。这些其实都不是一回事。
我建议在项目一开始就把可靠性拆成六个维度:
| 维度 | 关键问题 | 常见验收标准 |
|---|---|---|
| 数据一致性 | 用户看到的操作结果和真实状态是否一致 | 一个请求成功后,所有关联方都能看到一致状态 |
| 可用性 | 请求失败后用户是否还能继续业务 | 关键接口失败率可控,核心链路不能中断 |
| 幂等性 | 同一个操作执行多次是否产生相同结果 | 重复提交预约不会生成重复订单 |
| 可恢复性 | 失败后能否回到正确状态 | 预约失败后资源能释放,用户可以重试 |
| 可观测性 | 出问题时是否能快速定位 | 通过请求ID能查到完整调用链和失败原因 |
| 可逆性 | 上线后发现错误能否快速回滚 | 每个改动都能独立回滚,不影响其他功能 |
这六个维度不需要每个项目都做到同样强度,但至少要明确哪些是当前项目必须保证的。在类似 Maven Clinic 的场景里,数据一致性、幂等性、可观测性几乎是底线;如果是内部知识库工具,可逆性和可用性可能优先级更高。
AI生成的代码往往默认忽略这些维度,或者说不会替你判断优先级。它生成一个创建预约的接口时,很可能只写了基本的校验和保存逻辑,但没有考虑“用户重复点击”的幂等处理,也没有考虑“保存成功但通知失败”的一致性问题。你必须在系统设计层面提前定义好,再让AI在这个框架内生成代码。
3.2 在编码前先确定可靠性指标
既然AI编码速度很快,那么可靠性约束就应该前置,而不是等代码写完再补。具体做法是:把一个功能模块的可靠性方案先写出来,然后再进入实现。
拿预约创建接口来举例,可靠性方案至少要包含:
- 请求幂等:通过用户ID、预约时间段、设备端生成的 requestId 组合,避免重复提交。
- 状态机:预约状态至少包括待确认、已确认、已取消、已完成等几个关键状态,状态之间的流转规则要明确。
- 资源锁:医生排班时段的释放和占用,要保证不能同时被两个请求修改。
- 失败补偿:创建预约后发送通知失败,不应当回滚预约本身,而是记录失败,进入重试队列。
- 日志字段:每个请求都要有唯一的 traceId,日志中带上用户ID、医生ID、时间段、状态码。
把这份方案给AI之后,它生成的代码会明显更贴近生产环境。如果什么都不给,AI只会生产一个“看似功能完整、实则边界粗糙”的版本。
我遇到过不止一次这样的情况:AI生成接口时自动加了一个很不错的重试逻辑,但重试是同步的,会阻塞用户请求。这本身没有错,但在这个场景里不合适。如果项目里提前定义了“所有通知类操作使用异步队列”,这个问题就不会出现。可靠性设计的作用,就是给AI划定正确的工作边界。
4. 可靠性的落地点:从日志、测试、回归到可观测性
4.1 用“最小回归集”约束AI生成的改动
AI编码带来的一个直接问题是改动频率和改动范围都变大。一个普通工程师可能一天只改一两个文件,AI在几分钟之内就能把十几个文件全部修改一遍。如果你的测试体系跟不上,风险是成倍增长的。
我建议每个业务模块维护一个“最小回归集”。它不是全量测试集,而是包含核心链路和关键异常场景的少数用例。AI生成代码后,先跑最小回归集,再进入完整测试。
以预约模块为例,最小回归集至少包含:
- 用户提交有效预约请求,返回成功,状态为待确认。
- 同一个预约请求被重复提交两次,第二次被拦截,不生成重复记录。
- 医生拒绝预约后,状态变为已取消,排班时间释放。
- 保险校验失败时,预约不被创建,用户收到失败提示。
- 权限不足时,接口返回明确错误,不暴露内部异常信息。
- 通知服务超时后,预约状态仍然正确,失败记录进入重试队列。
这样的回归集不需要很多,但每次AI修改后都要跑一遍。如果回归集通过,再继续扩大改动范围;如果失败,先看是需求理解错误还是实现错误,而不是直接让AI重新生成一遍。
这里有个经验:AI重新生成的代码不一定比上一版好,甚至可能解决一个问题又引入另一个问题。所以不能把“让AI再试一次”当成默认策略。每次重新生成前,要把失败信息明确反馈给它:哪个用例失败、期望结果是什么、实际结果是什么、你觉得可能的原因是什么。这样重试才有价值。
4.2 日志和可观测性要作为验收条件
AI生成的代码里,最让我不放心的是日志部分。它经常生成非常基础的 print 或者 logger.info,但不会自动带上 traceId、业务字段、耗时、错误码这些在排障时真正有用的信息。
我建议把日志格式也写进编码规范或提示词里。例如在项目上下文中固定这样一段要求:
这段要求很普通,但效果非常明显。因为AI对上下文中的约束是相当敏感的,只要你写了,它就会尽量遵循。不写的话,它就按自己训练数据里的常规方式来,生成一堆可读性很差的日志。
判断日志和可观测性是否上线,可以用一个实际问题:如果你刚上线的功能出故障,一个不熟悉的同事,能不能根据一条报错信息在三分钟内找到请求对应的全部链路?如果能,说明可观测性基本合格;如果不行,优先补日志和 traceId,而不是继续加功能。
4.3 AI改动后出现问题时,按什么顺序排查
AI编码项目出问题时,团队很容易直接怀疑“是AI生成写错了”。这个判断不一定是错的,但排查顺序不对会浪费很多时间。我一般会按下面这个顺序查:
- 先看请求参数和输入数据。AI生成的代码经常忽略对空值、异常格式、超长文本的处理,很多问题在这一层就能发现。
- 再看状态流转。预约状态是不是进入了不该进入的状态,或者状态更新顺序不对。
- 再看外部依赖。数据库、消息队列、第三方接口,任何一个超时或返回异常都会让AI生成的代码表现得很怪。
- 再看代码逻辑。如果前三层都没问题,再审查AI生成的业务逻辑,看它对需求的假设是不是和真实业务一致。
- 最后再重新审视提示词和需求定义。如果代码整体逻辑合理但业务语义不对,那通常不是代码问题,而是上下文信息不足。
这套顺序的核心原因是:AI生成代码的错误大概有几种类型,输入处理不足、状态管理粗糙、外部依赖处理不当、需求理解偏差。其中需求理解偏差最危险,因为它不会直接报错,只会在真实业务场景里以错误结果的形式出现。所以排查的时候,不能只盯着代码报错,还要主动检查业务结果是否符合验收用例。
5. 团队协作与AI编码的边界:角色、流程、审查清单
5.1 角色职责要重新分
AI编码引入后,团队角色如果不调整,很容易出现“所有人都在写代码,没人对结果负责”的情况。尤其是AI生成代码的速度快,提交频率高,如果没有清晰的职责边界,审查就成了走过场。
我认为 AI Engineer 的核心职责不是“用AI生成更多代码”,而是四个字:上下文管理与输出验证。上下文管理指的是把需求语义、可靠性约束、编码规范、验收用例组织成AI能理解的信息。输出验证则是对AI生成结果做系统性的检查,确保它符合预期。
在团队里,我比较推荐 Driver-Reviewer 模式。Driver 负责任务拆解、提示词编写、AI生成结果整合。Reviewer 负责代码审查、验收用例核对、最小回归集检查。这两个角色不能是同一个人,因为AI生成代码后的自我检查往往缺少审视感。你可以让同一个工程师在不同任务里切换角色,但单个任务里要分开。
5.2 Code Review清单要针对AI生成代码调整
传统 Code Review 关注的是代码风格、性能、架构、可读性。AI生成代码在这些方面通常表现不错,所以如果 Review 还是只盯这些,意义不大。真正需要额外注意的是以下几点:
- 需求边界是否被误解,尤其是输入数据为 null、列表为空、超长文本、并发重复请求。
- 状态变化是否合理,是否有“越级状态”出现。
- 错误路径是否处理,失败时是抛异常、返回错误码,还是直接吞掉。
- 日志是否足够支撑排查,是否包含 traceId 和关键业务字段。
- 对外部依赖的失败处理是否合理,有没有超时、重试、熔断机制。
- 是否引入了不必要的新依赖,AI有时候会为了一个小功能引入一个大库。
我建议把这些点做成一个针对AI生成代码的 Review 清单,每次提交的时候逐项打勾。不用很复杂,表格就好。关键是让审查有标准,而不是凭感觉。
5.3 流程建议:小步提交、验收驱动、快速回滚
AI编码最容易出现的问题是“让AI一次性生成一个大功能,然后攒一个巨大的 PR”。这种模式在传统开发里已经很危险,在AI编码里会更危险,因为AI生成的代码量更大,错误更难定位,Review 压力也更大。
我的建议是保持小步提交。一次改动尽量限定在单一业务语义内,比如“预约创建接口增加幂等逻辑”就是一个独立提交,“用户主动取消预约后的状态流转”是另一个独立提交。每一个提交都绑定一个验收用例。代码合并前,跑一遍最小回归集。这样即使出了问题,也可以精准定位到哪一次改动引入的,回滚范围也更小。
“快速回滚”同样值得提前设计。每一个提交都应该是可回滚的,数据库迁移、配置变更、消息队列 topic 变更都不要和AI代码改动耦合在一起。否则一旦AI生成的业务逻辑有问题,你想回滚代码,却发现数据库结构已经变了,回滚就会非常麻烦。
6. 在类似Maven Clinic的场景里复制这套经验
6.1 落地前先回答的三个问题
如果你准备把AI编码引入到一个业务约束比较强的项目,先别急着写提示词,也别急着生成代码。我建议先回答三个问题:
第一个问题:需求边界是不是足够清楚?如果业务方自己都说不明白“用户取消预约后医生端应该显示什么状态”,那AI不可能替你把这个决定做对。你需要的不是更多提示词技巧,而是一次需求澄清会。
第二个问题:可靠性约束是不是已经前置?一个接口的幂等、状态机、超时、补偿、日志字段,这些在设计阶段是否已经定义。如果没有,AI生成的代码就会用自己的默认习惯填空,这些默认习惯不一定适合医疗健康类场景。
第三个问题:每次合并是否跑得过最小回归集?如果项目连一个最小回归集都没有,AI编码的每一次合并都像在开盲盒。代码生成越快,风险积累也越快。
这三个问题不是一次性工作,而是每次迭代都要重新确认的。因为AI生成代码后,需求理解可能发生偏移,可靠性约束也可能被局部改动破坏。只有持续用这三个问题当护栏,AI编码才不是昙花一现的玩具。
6.2 可以直接用的AI编码落地检查表
最后,我给出一份可以在项目里直接参考的检查表。不用全部做到,但核心项建议按顺序推进:
- 核心术语表:每个业务关键术语都有明确定义,并同步给AI做上下文。
- 验收用例:每个需求都至少有5到10个 Given-When-Then 用例,覆盖正常路径和异常路径。
- 否决条件:明确哪些场景出现时功能不能上线,并由业务方确认。
- 可靠性维度表:从数据一致性、幂等性、可恢复性、可观测性里选择当前模块必须保证的项。
- 提示词模板:固定上下文结构,包含业务背景、输入输出约束、可靠性要求、日志要求。
- 最小回归集:每个业务模块维护一份核心回归用例,AI改动后必跑。
- 日志规范:统一 JSON 格式,带 traceId 和业务字段,禁止输出隐私信息。
- Code Review 清单:按业务语义、状态流转、错误路径、日志、依赖、回滚六个方向审查。
- 小步提交:单个提交只做一件事,绑定一个验收用例。
- 回滚方案:每个提交独立可回滚,数据库变更和代码逻辑解耦。
这套检查表不是越多越好,而是让团队在AI编码的高速列车前面有路肩、有刹车、有应急出口。先跑通一个小功能,把这份检查表完整走一遍,再慢慢扩大AI的使用范围。不要为了提效跳过可靠性设计,因为AI编码省下来的时间,最后都会在误上线和返工里加倍还回去。
我自己在复盘类似 Maven Clinic 这类项目时,最深的感受是:AI编码改变的是执行速度,工程化的可靠性工作流才是决定项目成败的护栏。你想用AI提效,没问题,但先让它在明确的语义边界、可靠性约束和验收机制里稳定工作。这样,AI生成的每一行代码才不只是“看起来能用”,而是真正敢上线。