标签

AI能力决定上限,工程控制守住下限

发布时间:2026-08-28 22:02阅读:1

祖传代码里藏着这样一段:

稍有经验的开发者看到都会摇头:魔法数字,得抽成枚举。AI 同样这么判断,于是它改成了:

从代码质量维度评价,这是一次毫无瑕疵的优化。编译通过,测试绿灯,Diff 干净利落,可以直接合并。

然而问题在于3并非随手敲出的数值,它背负着一段历史契约:

而这个3被工厂的 PLC、财务的 ERP、两家外部系统,以及一批无人敢动版本的老客户端按原值死死绑定。抽枚举本身没毛病,毛病出在它顺带把对外序列化的那个值也一并替换了。

AI 并未犯技术层面的错。它犯的是信息层面的错——它不清楚这个数字已经出过远门。

这类事件的复盘总结通常写成"AI 还不算太聪明"。但换下一代模型、换更强的引擎,这一行依旧会被动掉。因为缺失的信息不在模型参数里,在你未曾告知它的角落里。

因此老项目里真正要攻克的难题,从头来都不是"如何让 AI 多产出代码",而是:

怎样让 AI 在一份无人完整通读过的代码库里,交付可控、可验证、可回滚的变更?

先抛结论,后续章节都在拆解它:

真实交付力 = AI 能力 × 上下文质量 × 约束质量 × 验证能力

若这是加法,那"换更强的模型"确实是桩合算的买卖 —— 第一项涨了,总分跟着涨。

但这是乘法。乘法的脾气是任何一项归零,结果即归零,而且第一项越强,后三项的零代价越高:

三句解释全部把锅甩给第一项,没有一次是第一项的过失。

而后三项,恰好对应三个可被工程化的动作:

这三层决定 AI 在你的项目里可信与否。下面逐层拆解。

很多人第一次接触 Claude Code,开场白往往是:

帮我把订单模块重写一下。

它自然会进入分析模式。但请先回答一个问题:它清楚你的订单模块为何演化成现在这样吗?

老项目里决定"代码必须这么写"的因素,绝大部分藏在代码之外 —— 历史需求、口口相传的业务规则、未清偿的技术债、为某个客户特制的兼容分支、部署环境的癖好、团队默契、以及数次线上事故烙下的伤痕。

代码只能回答"它现在长什么样"。回答不了"为何不能改成看似更合理的形态"。

让 AI 读懂项目,不是把全量代码灌输给它,而是帮它搭建一份足够精准的项目画像:

前三层 AI 自给能挖到七八成:代码它扫得比你快,业务能从代码反推一部分,技术栈和构建方式埋在配置文件中。唯有第四层它束手无策——type == 3的故事从未在任何一行代码里留痕。

开头那次事故,归根结底就是一次 Historical Context 的缺位。

绝大多数 AI Coding 的翻车,都源于同一个动作:接到需求立马动代码。

用户:把登录逻辑迁移到 OAuth2。AI:好的,我开始改造……

这句"好的"是危险信号。正确的节奏中间要嵌入四步:

需求 →探索→定位→理解→输出方案→确认→ 修改

前面五步一行代码不动。这一步的代价是几分钟等待,换来的是"改完才发现方向跑偏"的整轮返工。

要落地它,只需在第一句话尾巴加一句:暂时不要改动任何代码。

"既然 AI 需要上下文,那我就把所有东西喂给它" —— 这是另一个坑,且更隐蔽,因为它显得很勤奋。

超长 Prompt → 塞进大量无关信息 → 真正的约束被稀释 → AI 注意力下滑

结果是那句最关键的"不要改数据库结构",沉睡在第 400 行,和三十条无关背景一起被摊薄。

所以要的不是 Context 越多越好,而是Context 越对题越好。动手前把信息分三级 —— 以"修一个登录 bug"为例:

这就是 Context Engineering 在老项目里的现实含义:不是把上下文撑爆,是把它裁精。

假设理解这一层你做得很到位 —— AI 完全摸清了调用链、数据流和影响面。够了吗?

不够。因为理解只能解决"能不能做对",约束才能解决"会不会做多"。

AI 的天然倾向是:找到一个能搞定眼前问题的路径。而工程师要权衡的是:这个路径匹不匹配整个系统的长期约束。

比如它觉得最省事的路径是升级依赖版本。但你的项目是 JDK 8 + Spring Boot 2.x + 一个上古数据库驱动 + 必须兼容的老客户端 + Windows Server 部署环境。于是:

升级依赖 → 编译通过 → 测试通过 →线上启动失败

前三步全绿。AI 的"局部正确",并不等价于项目的"全局正确"。

前三类的共性是:它们不在代码里,所以 AI 推不出来。你不提,它就当不存在。

而第四类压根不是项目属性,是这一次任务的属性 —— 它不可能被写进任何文档,只能由你在每次会话里现给。这也是它最常被遗忘的原因。

看看第四类值多少钱。同一个需求:修复订单查询异常。

第一种说法:

"顺便"两个字就是一张空白授权书。AI 会动 Controller、改 Service、重构 Repository、优化 SQL、升级依赖、调整 DTO、删掉看似没用的旧代码。最终你拿到:

测试或许全过。但没人能审查 2000 行 Diff—— 你只能滚到底,然后点确认。这时候三层控制里的第三层已经名存实亡。

第二种说法:

结果:

50 行你会逐行审。所以:

AI 的自由度收窄,交付的可靠性反而上扬。

这句话反直觉的点在于,我们对人从来不这么管 —— 你不会给一位资深同事列六条禁令。但 AI 和资深同事的分歧不在能力,在于它不知道哪里不能碰,而且不会因犹豫停下来问你。

这是闭环里最关键的一层,因为它是唯一能兜住前两层疏漏的东西。

AI 生成的代码有一个特征:它极少写出明显错误的东西,却经常写出看似正确的东西。

举个具体的例子。AI 改了一段权限判断:

编译 PASS,单元测试 PASS。代码本身无可指摘 —— 空指针防护都做到了。

但这个系统真实的权限规则是:管理员、项目负责人、以及若干特定角色都有权限。于是结论是:技术正确,业务错误。而这类错误,编译器和既有测试都逮不到。

排序本身就是方法论:优先用低成本的手段尽早发现问题。一个能在git diff里被识别的越界改动,没有任何理由拖到集成测试才暴露。

第一层几乎是零成本,却最常被跳过。git diff要叩问的就六个问题:动了哪些文件?为何是这些文件?有没有碰无关代码?有没有删掉关键逻辑?有没有变更接口?有没有引发意外重构?

这六问全部指向同一件事 ——上一层的约束有没有切实生效。约束不是说出来就算数的,它需要在 Diff 里被验收。

因为它是唯一无法自动化、也无法委托给 AI 的一层。

需求:订单取消后恢复库存。AI 的实现干脆利落:

cancelOrder()→restoreStock()

测试通过。但真实业务规则是:只有"已支付但未发货"的订单才允许恢复库存。未支付订单、已发货订单、已完成订单,都不应走这条路径。

自动化测试永远不会爆这个错 —— 因为测试是照着实现写的,而实现是照着一句被简化的需求写的。这里唯一的检验手段是有人拿着真实业务规则,逐条核对边界条件和异常场景。

最后一层仍然是人,但很多人把这一层做成了"逐行重读 AI 写的代码"。那是最贵也最无效的用法 —— 如果你打算逐行重写,一开始就别让 AI 出手。

人工审查该查的是四件代码里读不出来的事:

意图—— 它理解的需求是你想要的那个需求吗?

边界—— 有没有碰不该碰的东西?

风险—— 有没有破坏历史兼容逻辑?

影响—— 有没有牵连到其他模块?

四个问题的共性:答案都不在这次 Diff 里面。这也正是它必须由人来做的原因。

三层拼起来是这样,注意那条回边:

没有回边的不是闭环,是一次性赌博。而回边指向的是"哪一层漏了",不是"再改一遍代码" —— 验证失败往往不是执行问题,是上下文给少了或约束没说清。

落到一个具体的小需求上:给 User 增加"最后登录时间"字段。

错误做法只有一句:"给 User 增加 lastLoginTime 字段。"然后 AI 会去动User.java、UserMapper.java、UserService.java、UserController.java、数据库、前端、测试,可能还顺手优化 DTO、VO 和 Repository。它不是失控,是没被告知边界。

正确做法是三段对话。

第一段 · 理解

第二段 · 约束(确认分析结果之后再发)

第三段 · 验证

三段话,加起来不到两分钟的打字量。它们买到的是:一份你看得明白的 Diff,和一份你敢签字的验证记录。

第 5 条尤其值得看一眼 —— "旧用户该字段为空时不会报错"。这条永远不会出现在需求文档里,因为提需求的人不知道数据库里躺着两百万条旧数据。这就是 Historical Context 在验证层的兑现方式。

回到那个乘法:

真实交付力 = AI 能力 × 上下文质量 × 约束质量 × 验证能力

你能买到的只有第一项,剩下三项只能自己搭。所以:

AI 的能力决定上限,工程控制决定下限。

再压一层,是一句可以直接拿去说服同事的话:

让 AI 自由执行,但不能自由决定。

搜索、分析、修改、执行、跑测试、修编译错误 —— 这些放手让它做,做错了有测试兜底。但目标由人定义、边界由人定义、关键决策由人确认、最终结果由人负责。这四条一条都不能外包,这也是 AI Coding 和自动补全最本质的分水岭。

不必改工作流,只需在下一次让 AI 动手之前,回答三个问题:

理解—— 它知道它应该知道的东西吗?(项目结构、调用链、业务规则、影响范围)

约束—— 它知道哪些事情不能做吗?(技术限制、架构限制、业务限制、修改范围、兼容要求)

验证—— 我有办法证明它做对了吗?(Diff、Build、Test、业务、人工审查)

三个都能答"是",这个任务才具备可控性。答不出来的那一个,就是这次的风险敞口所在。

再给一个更狠的自检:把上一次 AI 帮你改的那个需求,翻出 Diff 数一下行数。如果超过 300 行而你当时点了同意,那不是审查,那是签收。

你的项目现在有几层验证?如果答案是"只有编译",那第二个问题更值钱 —— 一个完全没有测试的老项目,你会怎么给它搭第一个最小验证闭环?评论区聊聊,这一步比任何 Prompt 技巧都难,也都值钱。