上个月我们处理一个内部结算系统的区域拆单改造,AI coding 工具生成的代码看起来无可挑剔:注释齐全、命名规范、单测全绿。合到主干后,下游报表跑出来一列空数据,排查了一整天,最后定位到 AI 顺手改掉了一个缓存 key 的生成规则。改的人不是不认真,是它根本不知道这个 key 被三个老接口共享着。
这类事不是个例。最近被问得最多的一个问题就是:AIcoding 到底怎么落地?尤其是把 AI 塞进内部存量系统的改造流程里,为什么总是一改就出幺蛾子?大家看到的成功案例大多是新项目、绿地项目,脚手架一拉,AI 从头写,当然顺。但真实的存量改造,代码是不同年份、不同人、不同风格叠出来的,业务规则藏在工单、评审记录和老同事的脑子里。AI 一进场,往往就是灾难现场。
这篇文章我不聊方法论,只聊我们团队这两个月在内部项目改造里做的两件事:用 intent.md 把每次改造的意图、边界、验收标准显式地交给 AI;再用一套持续评测流水线,把 AI 产生的每一行改动都变成可追踪、可回滚、可复盘的数据。如果你正准备把 AI coding 引入存量系统,或者正在为“AI 改完代码没人敢合”发愁,这篇东西应该能给你一个可以抄作业的框架。落地的步骤拆开其实也很简单:先写清边界,再让 AI 动手,最后跑评测,三步循环。
1. 老项目改造里,AIcoding 为什么容易翻车
1.1 新项目上的顺畅,掩盖了真实的差距
我们团队在新项目上用 AI 是真的很爽:生成 CRUD 接口、补测试脚手架、写配置模板,速度肉眼可见地快。原因很简单——新项目从零开始,代码风格统一、上下文就在当前目录、每个文件都是 AI 自己写的,它对自己造出来的东西门儿清。
但内部项目改造完全是另一回事。代码是 2018 年的 Java、2021 年的 SQL 存储过程、2023 年的配置中心分发逻辑拼起来的;核心业务规则没有文档,或者在需求评审记录里,或者在工单备注里,或者在某个已经离职的老同事的聊天记录里。AI coding 工具在处理这类代码时,最大的问题不是“不会写”,而是“过度自信”地补全——它会把一段不存在的业务假设当成既定事实写进代码。
我给我们团队打过一个比方:AI 像一个能力很强但刚入职的新同事。你让它去把报表的统计口径改一下,它顺手把校验规则也“优化”了一遍。你以为是它负责,其实是它分不清边界。在新项目里没什么存量逻辑需要保护,这种“自由发挥”的毛病不明显;到老项目里,每一次自由发挥都是在踩雷。
1.2 存量系统的三个隐性杀手
老项目改造翻车,翻来覆去就是三个原因。
第一个是隐性业务规则。一个订单什么状态允许拆单、金额精度保留到几位、不同商户类型的数据范围怎么控制,这些约束往往不在代码里,而散落在各种历史上下文里。AI 看不到,就会用默认的“合理逻辑”去填充。你告诉它“按区域拆分订单”,它自己脑补了一套“区域编号从订单表取出”,实际上区域编号要查三个配置表才能拿到。
第二个是上下文碎片化。一个完整的业务动作经常分散在 Controller、Service、DAO、配置项、存储过程甚至定时任务里。AI 如果只被喂了其中两个文件,改出来的代码大概率跟其余部分脱节。更麻烦的是,存量代码的命名早就失真了——一个方法叫getOrderInfo,里面实际上塞了金额试算和风控校验,AI 从名字上根本看不出来。
第三个是弱回归验证。很多存量系统的核心链路没有自动化测试,甚至测试环境的数据构造都是靠人肉导库。AI 改完代码后,能证明“没改坏”的手段非常有限。我们会遇到一种情况:静态检查过了、编译过了、单元测试全绿,但业务方的验收 case 一跑就挂。这不是 AI 能力不行,而是组织根本没有给它搭好“上下文边界”和“验证闭环”。
1.3 改造失败的代价,是团队信任的透支
第一回翻车可以说“试试水”,第二回、第三回就会在团队里催生一个结论:“AI 生成的代码不能用在核心系统上。”我见过不少团队,第一次 AI 改造失败后,直接退回纯人工,之后再也不敢用。这种信任透支对技术团队的影响是长期的,甚至比改坏代码本身更严重。
所以,如果要让 AIcoding 在内部项目里真正落地,最好从一开始就配套两件事:显式的意图定义(intent.md)和持续的验证机制(评测流水线)。不是等出了问题再补墙,而是在 AI 动手之前就立好边界,在它动手之后用数据盯着每一步。下面先讲我们做 intent.md 的具体设计。
2. intent.md:给 AI 划定边界的一页纸
2.1 先想清楚它是什么:不是需求文档,是施工图
我们最初也犯过错误,把 intent.md 当需求文档来写,洋洋洒洒几千字,贴在任务描述里。结果 AI 没看,人也没看,任务照旧翻车。后来想明白一个关键点:intent.md 的读者有两个,一个是 AI,一个是未来接手的同事。所以它必须短、必须精确、必须能被“执行”而不是被“阅读”。
我建议的定义:intent.md 是一次改造任务的意图声明。它只回答四个问题:
- 这次只做什么?
- 这次明确不做什么?
- 做完之后用什么标准判断完成?
- 动手之前必须读哪些代码和文档?
形式上就是一个 Markdown 文件,文件名就叫intent.md,放在任务目录或者仓库的docs/intents/下。它不替代需求文档,而是需求的“压缩版本”加“边界版本”。需求文档还允许你看完想一想,intent.md 则要求你一看到就知道下一步怎么执行。对 AI 来说尤其如此。
2.2 字段拆解与设计原因
我们落地的 intent.md 字段不算多,但每个字段都是踩坑踩出来的。先看模板结构,再讲为什么这么设计。
| 字段 | 必填? | 内容示例 | 为什么这么设计 |
|---|---|---|---|
| 任务编号 | 必填 | ORD-8823 | 用于回溯、评测记录关联、后续统计 |
| 意图(一句话) | 必填 | 把订单拆单规则从“按商户维度”增加到“按区域维度” | 给 AI 一个明确的锚点,防止它自己脑补任务 |
| 期望结果 | 必填 | 区域维度拆分后,原有商户维度历史单仍按原规则拆分 | 把“目标态”写清楚,AI 才知道做完了没有 |
| 改造范围 | 必填 | 允许修改的目录/文件清单 | 物理边界,代码层面的“施工范围” |
| 禁止事项 | 选填,有就写 | 不得修改数据库脚本、缓存 key、对外接口签名 | 明确指出禁区,减少 AI“顺手优化”的概率 |
| 必读上下文索引 | 必填 | PaymentContext.java、OrderStatusEnum.java | 防止 AI 漏读关键存量逻辑 |
| 验收标准 | 必填 | 编译通过、新增区域拆单单测 12 条、存量拆单回归保持率为 100% | 让评测流水线有据可依 |
| 风险提示 | 选填 | 该逻辑被报表模块复用,改动后需人工核对报表 sum | 告诉人工抽检重点看哪里 |
| AI 自检清单 | 选填 | 改动前是否逐条列出修改点?是否有范围外改动? | 把“自查”成本转嫁给 AI,减少人的重复劳动 |
每个字段背后都有原因。比如“禁止事项”为什么要单独存在?因为我们发现大模型对“不做什么”的指令敏感度往往不如“做什么”,如果你只说“把拆单改为按区域拆分”,它很容易顺手把拆单里的支付校验逻辑也改了。但一旦你明确列出“禁止修改支付模块、缓存 key、数据库脚本”,越界概率立刻大幅下降。
“必读上下文索引”也非常重要。老项目里一个字段被三处共用,AI 根本不知道,但只要你把相关的类列在“必读”里,它就能在读代码阶段捕获这部分信息。相当于给 AI 画了一幅小地图,告诉它要施工的楼在哪、楼里的管线图在哪。
2.3 放置位置、生命周期和谁来维护
推荐路径是docs/intents/2025-W37-ORD8823-intent.md,按周次加任务编号组织,这样归档后还能按时间回溯。也可以把文件放到任务分支里,合入主干后随分支保留。这里有一个关键经验:intent.md 一定得是 AI coding 工具真正能读到的内容,而不是挂在仓库里当摆设。
很多 AI 编程平台支持“上下文文件”或“规则文件”的能力,比如 Cursor 的规则文件机制。如果你用的是这类工具,把 intent.md 路径配置到附加上下文中。如果不支持,最土的办法是在初始提示词里明确写“开始前必须读取 docs/intents/xxx.md,并用最多 100 字复述任务意图”,然后人工确认 AI 真的读了。这一点后面会专门展开讲。
生命周期上,我们的做法是:任务启动时由负责人创建,AI 改完代码后由人更新“完成状态”,合并主干后归档。谁来维护也要明确——意图本身必须人来定,AI 可以帮忙润色措辞,但任务边界不是 AI 的职责,它越俎代庖就会把原本清晰的边界改糊涂。
2.4 一份好 intent.md 和一份坏 intent.md
先看好的例子:
# intent.md 任务编号: ORD-8823 意图: 仅将订单拆单规则中的“按商户维度拆分”扩展为“按区域维度拆分”,其余规则保持不变。 期望结果: 区域维度拆分时,原有商户维度历史单仍按原逻辑拆分;现有拆单接口对外行为不变。 改造范围: 允许: - order/controller/OrderSplitController.java - order/service/impl/OrderSplitServiceImpl.java - order/service/split/AreaSplitRule.java 禁止: - 支付模块 - 数据库脚本 - 缓存 key 生成逻辑 必读上下文: - order/service/PaymentContext.java - order/domain/OrderStatusEnum.java 验收标准: - 编译通过 - 区域维度拆分逻辑单测新增 12 条 - 存量商户维度拆单回归通过率 100% - 拆单接口响应结构无变化 风险提示: - 该拆单结果被报表模块复用,上线后需人工核对报表 sum 数据 注意: - 任务启动说明: 开始前先复述上面的意图,改动后逐条列出修改点这份文件 AI 能执行,人能复核,评测流水线也能拿它当判断依据——三个角色各取所需。再看反面教材:
任务描述: 优化拆单逻辑,提升性能。没了。范围不写、验收不写、禁区不写。你让 AI 去优化,它就把整个拆单链路翻了个底朝天,改完你根本不知道它会碰多少东西。性能有没有提升不知道,但一堆边界行为肯定变了。我们团队内部明确一条规矩:intent.md 超过一页就说明任务太大,必须拆分重写;写这份文件连编带改不超过 10 分钟,超过也说明任务没想清楚。
2.5 一个立刻见效的小技巧:让 AI 先复述任务
在 AI 提交代码之前,强制它在回复里用最多 100 字复述这次任务的意图与边界,并列出全部改动文件清单。如果复述内容跟 intent.md 偏差大,直接打回重做。这等于给 AI 加了一道“理解性测试”。
我们后来把这步做成了评测流水线的第一道门,效果非常好。很多问题其实不是 AI 写不对,而是它从一开始就跑偏了。让它先说出“我打算做什么”,你立刻就知道它到底有没有读懂你的意图。这个动作完全不需要额外写代码,只是一个小提示词规则,但能拦住一半以上的低级返工。
3. 持续评测:把 AI 改动变成可追踪的数据
3.1 为什么是“持续评测”,而不是“一次性验收”
不少团队用 AI coding 的方式是“一次性验收”:AI 生成完,人工审查一遍,没问题就合并。这在存量项目上不够用。原因有两个:第一,人工审查面对一个大 diff 很难保持全程专注,尤其当 AI 改了几十个文件时,reviewer 看着看着就麻木了;第二,有些业务问题不是 review 能看出来的,比如历史脏数据兼容、下游系统对字段格式的隐式依赖,这些只能靠更多层次的验证暴露出来。
我们做的是“持续评测”:每次 AI 迭代都跑同一套门禁,把质量变化用数据记下来。它跟一次性验收的核心区别是,评测不是终点而是循环。AI 每改一版,流水线就自动拉一次静态检查、测试、意图比对、风险提示,把所有结果沉淀下来。出了问题能回溯到具体某个版本、某个环节、某个文件,而不是大家对着一个巨大的 diff 互相甩锅。
3.2 评测的五个层次
我按照从机械到智能、从自动到人工的顺序,把评测拆成五层。每一层都有明确的动作和目的。
第一层:静态与安全扫描。命令包括 lint、secret 扫描、复杂度检查、依赖检查。作用是快速挡住明显的低级问题。这一层有个 AI 特有的坑需要重点盯:大模型特别喜欢在修改时顺手引入一个新的 UUID 库、日期工具库或者 JSON 解析库,依赖检查一旦发现非预期新增依赖,直接标红。
第二层:编译与测试。存量测试全部跑一遍。老项目如果根本没有测试,至少保证编译和烟雾测试通过。我们内部还额外做了一件事:把“AI 生成的单测是否真的覆盖了意图”也放进这一层。因为 AI 写测试的时候有一种偷懒倾向,会生成一堆断言宽松、没有意义但能通过的单测来凑数。
第三层:意图一致性校验。用脚本解析 git diff,跟 intent.md 里的改造范围做比对:有没有范围外文件被修改?AI 有没有碰了禁止事项?然后让 AI 生成自检说明,逐条解释每个改动对应验收标准里的哪一条。这一步是 AI coding 时代特有的门禁,人审代码时经常只顾着看代码质量,忘了对照“本来要做什么”。
第四层:人工抽样评审。不是全量 review,而是抽三类文件重点看:高风险文件(涉及金额、状态机、并发)、范围外但被改动的文件、以及 AI 自检说明写得含糊的文件。评审按固定 checklist 走,避免 reviewer 被庞大的 diff 淹没。
第五层:集成验证与灰度监控。部署到测试环境后跑核心链路对账;上线后用监控曲线对比核心接口的错误率、耗时、数据正确性。存量系统里,能走到这一层的改动才允许合入主干。
3.3 指标怎么定:别只看代码行数
持续评测不能凭感觉,要落成指标。这是我们现在每份评测报告里都会记录的基础指标。
| 指标 | 算法 | 目标 |
|---|---|---|
| 意图符合率 | 范围外改动文件数 / 总改动文件数 | = 0 |
| 一次通过率 | 没有二次返工就通过的 PR 比例 | 越高越好 |
| 缺陷密度 | 新增缺陷数 / 新增代码行数 | 对比历史基线 |
| 有效评审意见占比 | 有效意见数 / 总评审意见数 | 无效噪音意见占比下降 |
| 修复耗时 | 从反馈到修复合入的平均时间 | 越短越好 |
| 回滚率 | 回滚次数 / 合并次数 | 0 |
意图符合率是最容易自动化、也最能反映“AI 有没有越界”的指标。我们专门写了一个check_scope.py脚本,不到 200 行,读取 intent.md 里的允许修改清单,再解析 git diff,发现任何范围外文件直接失败。一次通过率、修复耗时这些则可以从 CI 工具的记录里拉出来。缺陷密度和有效评审意见占比没法全自动,需要有人定期登记,但哪怕一周登记一次,也能看出趋势——AI 是在越改越稳,还是越改越飘。
3.4 流水线落地示例
用伪代码描述我们目前在跑的流水线,大概率和你平时看到的 CI YAML 长得差不多,但里面有几段是特意为 AI 改动加的:
pipeline: stage_static: - run: make lint - run: gitleaks scan --staged - run: python tools/check_scope.py --intent docs/intents/ORD-8823.md stage_test: - run: make test - run: python tools/gen_unit_summary.py stage_ai_check: - run: python tools/ask_ai_summary.py - rule: "summary must mention intent id ORD-8823" - rule: "all changed files must be listed" stage_review: - human_review: true - focus_files: auto-assign by risk score stage_integration: - deploy: staging - run: scripts/core_link_check.sh重点看两个位置。第一,check_scope.py放在了 stage_static 里,这意味着任何越界改动在代码评审之前就会被拦下。第二,ask_ai_summary.py会解析 AI 每次提交时附带的说明文本,检查它是否提到了任务编号、是否逐条列出了改动文件。回答含糊的直接判失败,让 AI 重写提交说明。别小看这一道,它能有效倒逼 AI 在提交前多做一次自查。
3.5 数据要沉淀,不然等于白测
每完成一个任务,把评测报告写进docs/evals/ORD-8823.md,内容包括改动规模、五个层级的通过情况、评审意见、上线后一周内的缺陷记录。每个月底,团队会花小半天复盘:这个月哪些问题是被评测拦住的,哪些是从评测漏过去的。漏过去的问题就是下一阶段要加的门禁。
这里想强调一点:持续评测的意义不在于“全绿”这个结果,而在于让你知道每一层门禁各自的拦截率。如果发现第三层意图一致性校验一个月拦下了 20 次越界改动,你会确信这层门禁值得留;如果发现某个检查天天全绿,说明它已经成了摆设,该替换成更有价值的校验了。
4. 踩坑实录:intent 写了、评测跑了,还是出了五件意外
4.1 坑 1:intent.md 写了,AI 根本不看
现象:intent.md 挂在仓库里,可 AI 生成的代码完全脱离范围,直接改了禁止文件。我们一开始很懵:文件明明写了,为什么它不看?
排查链路一步一步走下来:先查工具配置,发现我们用的 AI coding 工具没有把docs/intents/加到附加上下文里。很多工具默认只分析当前打开的文件或项目索引,不会主动读一个仓库根目录下的 md 文件。再查提示词,团队当初把 intent.md 放在了 PR 描述里,但模型读的是分支上的代码,跟 PR 描述是两套上下文。最后定位到根因——我们自建的 Agent 只把鼠标选中的代码块交给模型,intent.md 根本就没出现在模型能看到的上下文里。
修复方法是双保险:第一,在初始提示词里显式写“开始前必须读取 docs/intents/ORD-8823.md,并复述意图”;第二,在工具配置里把 intent.md 路径加入附加上下文。如果你的平台不支持上下文文件,那就直接在 system prompt 里拼上 md 的内容。核心经验只有一条:不要把 intent.md 当文档,要把它当作上下文的一部分,确保它出现在模型能看见的地方。
4.2 坑 2:AI 越界了,但评测没拦住
现象:scope 脚本把范围外文件报告出来了,但 reviewer 在 GitHub 上看漏了,最后还是合入了主干。我们回头一查,发现脚本确实在 PR 的流水线上跑了,可 AI 是在本地开发时直接提交到分支的,本地提交根本不会经过 PR 流水线。
修复方案是把 scope 检查改成双重关卡:一是 pre-push 钩子,在代码推送到远端之前就跑一次范围校验;二是 PR 上的必需 Status Check,不通过不允许合入。后来我们干脆加了一条硬性流程:凡是出现范围外改动的提交,一律置为失败,不允许人工豁免。真有人觉得必须改范围外的文件,就让他先单独申请并更新 intent.md 再跑。
这个坑给我们的启发是:技术门禁要跑在“AI 产出”的第一时间,而不是等人工评审开始的时候。你等得越久,越界代码被合入的概率就越大。
4.3 坑 3:评测全绿,但业务错了
现象:状态机里的一个流转判断从==改成了equals,测试全过,因为单测里的枚举值恰好没覆盖新增的 null 分支;结果老数据在页面上全部显示成“未知状态”。
排查链路是这样走的:业务反馈后,我们拉出“近 7 天状态流转分布”做对比,发现部分旧的未初始化状态被新逻辑误判了。原因很典型:存量系统里存在历史脏数据,AI 把校验逻辑“优化”掉了,原本对脏数据的兼容行为被连根拔除。代码看起来很规范、很“优化”,但业务上不可接受。
修复分两步:第一,把状态机、金额、时间这三类改动永远加入人工核心抽检,不接受全自动放行;第二,抽检人必须看“改动前后的行为差异说明”,而不只是看代码 diff。这个教训很重要:持续评测不能只靠自动测试,要保留一层“懂业务的人”做语义复核。对老项目来说,历史数据兼容永远优先于代码优雅。
4.4 坑 4:老项目根本没有测试,评测无从谈起
现象:一上流水线才发现,核心业务模块的测试覆盖率是两位数,编译过了基本就等于进入了黑洞。别说评测 AI 了,连人写的代码也只能靠线上出问题来暴露。
我们不能等测试补全了再上 AI,那样永远迈不出第一步。过渡方案分四步走:
- 先上最弱门禁:编译、lint、secret 扫描、改动文件白名单。先让门禁从“无”变成“有”。
- 让 AI 在每次改动时顺带为新改动的目标功能生成一组冒烟测试。不要求覆盖全量,只要求覆盖这次改动涉及的分支。
- 用接口 diff 和录制回放工具,对比改造前后同一个接口的响应报文。这一步能拦掉大量逻辑漂移,而且对存量代码几乎是无痛的。
- 把 AI 生成的测试逐步沉淀成存量回归资产,慢慢把覆盖率养起来。
这条路我们现在还在走,但至少它让“持续评测”有了第一块地基。如果你也面对零测试的老项目,别幻想一步到位,先把门禁从无变成有,再谈更多。
4.5 坑 5:多人并行 AI 任务,intent 文件相互打架
现象:两个 AI 任务同时各改一个共享的 DTO 字段,合并的时候互相覆盖,责任还不好分。第一个任务改完,第二个任务又把它改了回去,双方都觉得自己的版本是对的。
修复靠三条规则:第一,严格 git 分支隔离,每个 intent 任务一条分支;第二,共享文件的修改必须提前在任务里登记占位,任何人要动同一个文件之前先看一眼有没有其他任务在动;第三,合并顺序由人工控制,不允许两条 AI 分支自动合并。
这个坑让我看明白了一件事:intent.md 不只是给 AI 的指令,同时也是团队内部的任务协调工具。你把自己正在改什么、不能碰什么写清楚了,别人就知道避开。如果谁都能随便改一个共享文件,那再多评测也救不了。
5. 效果对比、适用范围与两个可以立刻上手的建议
5.1 改造前后,我们看到的内部数据
两个月下来,我们团队内部记录了一组对比数据,样本量不大,但趋势很真实:
- 单次改造的平均审查时间:从 2.5 小时左右降到 1 小时左右;
- 改动一次通过率:从约 30% 提到约 65%;
- “范围外改动”导致的返工比例:下降了 80% 以上;
- 上线后一周内与本次改动相关的缺陷数:从 5-6 个降到 1 个左右。
我最看重的是审查时间这块。它下降不是因为 AI 生成的代码质量突然变好了,而是因为评审人不再需要防备 AI“越界发挥”了。intent.md 把边界划好,评测流水线把范围外改动提前拦住,reviewer 的精力可以集中在自己真正该看的高风险 diff 上。这种体验跟之前每次都像在拆盲盒完全不一样。
5.2 这套机制适合什么样的团队
先说适合的:存量业务系统、老项目改造、AI coding 工具已经用起来但没人敢合并、团队有自动化测试基础或至少愿意补。这类场景下,intent.md 的“边界感”和评测的“数据感”带来的收益最明显。
再说不适合的:纯新项目脚手架、一次性脚本、快速原型验证。这类任务本来就是让 AI 自由发挥的,加一层 intent.md 反而碍手碍脚。另外也要提醒一句:别过度设计。我们最开始写 intent.md 时浪费了很多时间,后来定了规矩,超过一页必须拆分。一页这个数字不是随便说的,它逼着任务负责人把目标想清楚,写不清楚就说明任务还没到该让 AI 动手的时候。
5.3 两个可以立刻上手的动作
第一,挑一个最小改造任务,写一页 intent.md,完整走一遍“读文件—AI 生成代码—改动清单—范围检查—人工抽检”闭环。不需要等平台能力成熟,先跑通流程比什么都重要。哪怕最后发现某些环节是人工手动干的,也比没有强。
第二,把 intent.md 的质量变成你们团队的 AIcoding 实操考核题。我们最近招聘时就给候选人一个老项目代码片段和一份意图文件,让他们判断哪些改动越界、哪些验收标准不足。这个方式比单纯考“提示词怎么写”更能筛出真正会用 AI 的人。如果你也在准备团队内部的 AIcoding 笔试题,建议从“意图表达与边界判断”这个角度切入,效果会好很多。
回头再看这一整套折腾,最值钱的其实不是那几十行 YAML,也不是自动化门禁,而是 intent.md 倒逼我们把每次改造的“边界”想清楚了。以前人写代码,边界在脑袋里,一言不合能互相讨论;现在 AI 写代码,边界必须写出来,写不出来就是大家对同一件事抱了不同的预期。
如果只让我留一条建议:下一次让 AI 动手改任何存量代码之前,先花十分钟把意图、范围、禁止事项写成一页纸。你要是想不上来,说明这个任务还没到应该让 AI 动手的时候。就这样,去试试。