1. 从“能跑就行”到“意图对齐”:AIcoding 落地中最容易被忽视的一环
过去大半年,我一直在团队内部推动 AIcoding 的落地。从最初让每个人装个插件、写几句 prompt 试试水,到后来把 AI 生成代码正式纳入 SDLC 流程,中间踩的坑比想象中多得多。最典型的一个现象是:AI 生成的代码单测能过、编译能过,但 review 的时候总觉得“哪里不对”——它实现的东西和需求文档里想表达的东西,存在一层微妙的偏差。这种偏差在传统开发里靠口头沟通就能抹平,但在 AIcoding 场景下,因为生成速度太快、量太大,反而被放大了。
后来我们引入了一个叫intent.md的东西,配合一套持续评测机制,才算把这个问题按住。这篇文章就把我们内部项目改造的完整过程拆开讲,包括intent.md到底该写什么、和CLAUDE.md这类上下文文件是什么关系、持续评测怎么搭、以及那些只有真正跑过一轮才会知道的坑。如果你正在团队里推 AIcoding,或者正在准备 AIcoding 相关的笔试题、面试题,这套东西应该能给你一个可复现的参考框架。
先说清楚适用人群:这篇文章不是给“刚听说 AIcoding”的人看的科普,而是给已经动手、但发现效果不稳定、想把它工程化的人看的。你需要对 SDLC 有基本认知,知道 CI/CD 大概怎么跑,最好已经用过至少一种 AI 编码工具。至于intent.md这个命名,它不是某个官方标准,是我们内部约定的一种文件形态,你可以叫它spec.md、task.md,核心思想是一样的。
2. intent.md 到底是什么:和 CLAUDE.md、需求文档的边界在哪
2.1 为什么已有的上下文文件不够用
很多人第一反应是:我已经有CLAUDE.md了,里面写了项目结构、技术栈、编码规范,为什么还要再搞一个intent.md?这个问题我一开始也问过自己。实际用下来发现,CLAUDE.md解决的是“这个项目长什么样”的问题,它是一份长期稳定的项目上下文,描述的是代码库的静态特征:目录结构、依赖版本、命名约定、构建命令。它不会随着某个具体任务变化。
而intent.md解决的是“这一次改动到底要达成什么”的问题,它是任务级的意图声明。举个具体的例子:CLAUDE.md里会写“本项目使用 TypeScript,禁止使用 any”,但intent.md里会写“本次改造要把订单查询接口的响应时间从 800ms 降到 200ms 以内,允许引入缓存层,但缓存失效策略必须保证最终一致性”。前者是约束,后者是目标加取舍。
需求文档(PRD)和intent.md的区别更微妙。PRD 是给人看的,它允许模糊、允许留白,因为人可以追问、可以脑补。但 AI 不会追问,它只会按字面理解去生成。所以intent.md本质上是把 PRD 里那些“人默认懂、但没写出来”的部分,显式地翻译成 AI 能消费的形式。我通常说,intent.md是 PRD 的“可执行投影”。
2.2 intent.md 的核心结构:四段式写法
经过几轮迭代,我们把intent.md固定成了四个部分。这个结构不是拍脑袋定的,每一段都对应一类 AI 容易跑偏的场景。
第一段是目标声明(Goal)。用一句话说清楚这次改动要达成什么可验证的结果。注意是“可验证”,不是“优化用户体验”这种没法测的表述。比如“将用户登录接口的 P99 延迟降低到 300ms 以下”就是可验证的,“提升登录体验”就不是。
第二段是约束条件(Constraints)。这里放那些“不能碰”的东西:不能改数据库 schema、不能引入新的外部依赖、必须保持向后兼容。这一段是防止 AI“过度发挥”的关键。我见过太多次 AI 为了达成目标,顺手把不相关的模块重构了,结果引入一堆回归问题。
第三段是验收标准(Acceptance Criteria)。用 checklist 的形式列出,每条都要能被自动化测试覆盖。这一段直接决定了后面持续评测怎么写。
第四段是上下文补充(Context)。放那些 AI 需要知道、但不适合写进CLAUDE.md的一次性信息,比如“这个模块下周要迁移,所以本次改动尽量局部化”。
2.3 一个真实的 intent.md 示例
光说结构太抽象,直接上一个我们内部改造订单模块时的真实文件(脱敏后):
# Intent: 订单查询接口性能优化 ## Goal 将 GET /api/orders/{id} 的 P99 响应时间从 800ms 降至 200ms 以下。 ## Constraints - 不得修改 orders 表的 schema - 不得引入新的外部服务依赖 - 必须保持现有 API 响应结构完全兼容 - 缓存层必须支持手动失效 ## Acceptance Criteria - [ ] P99 延迟 < 200ms(压测脚本 bench/order_query.js) - [ ] 现有 47 个集成测试全部通过 - [ ] 缓存命中率 > 85%(基于生产流量回放) - [ ] 缓存失效后 5 秒内数据一致 ## Context - 该模块计划 Q3 迁移到新服务,本次改动保持局部 - 现有 Redis 集群已有 30% 余量,可直接复用这份文件大概 200 字,但它把 AI 生成代码时的决策空间压缩到了一个很窄的范围内。实测下来,有了这份文件,AI 首次生成代码的可用率从大概 40% 提升到了 75% 左右。这个数字不是精确统计,是 review 时“基本不用大改”的比例。
3. 持续评测机制:让 AIcoding 从“一次性生成”变成“可回归”
3.1 为什么单次评测不够
AIcoding 有个很反直觉的特点:同一个 prompt,今天生成的结果和明天生成的结果可能不一样。模型在更新、上下文在变化、甚至温度参数的微小差异都会导致输出漂移。所以如果你只在引入 AIcoding 的第一周做一次评测,得出“效果不错”的结论,那这个结论两周后就失效了。
持续评测的核心思路,是把 AI 生成代码的质量当成一个需要持续监控的指标,而不是一次性的验收动作。这跟传统软件里“性能回归测试”的逻辑是一样的:你不是测一次性能就完事,而是每次改动都跑一遍,确保没有退化。
3.2 评测集的构建:三层结构
我们的评测集分三层,从粗到细。
第一层是冒烟评测(Smoke Eval),大概 20 个用例,覆盖最常见的任务类型:新增一个 CRUD 接口、修改一个已有函数、写一个单测、重构一段代码。这一层跑得很快,几分钟出结果,主要看 AI 有没有“基本能力退化”。
第二层是意图对齐评测(Intent Alignment Eval),这是核心。针对每个intent.md,我们准备 3 到 5 个变体,测试 AI 在不同表述下是否能稳定理解意图。比如同一个性能优化目标,分别用“降低延迟”“提升响应速度”“优化 P99”三种说法,看生成结果是否一致。这一层能暴露 AI 对意图理解的稳定性问题。
第三层是边界评测(Edge Eval),专门测那些容易出错的场景:约束条件冲突时 AI 怎么取舍、验收标准里有互相矛盾的条目时 AI 怎么处理、上下文信息不完整时 AI 会不会瞎猜。这一层用例不多,但每个都是踩过坑之后补上去的。
3.3 评测的执行:怎么和 CI 集成
持续评测要真正“持续”,必须进 CI。我们的做法是在 PR 流程里加一个ai-eval的 job,触发条件是:当 PR 里包含 AI 生成的代码标记时(我们在 commit message 里约定了一个[ai-gen]前缀),自动跑评测集。
这里有个细节值得说:评测不是跑一次就完,而是跑两次。第一次用生成代码时的原始intent.md,第二次用一个“扰动版”的intent.md(把表述换一下、顺序调一下)。两次结果如果差异超过阈值,就标记为“意图理解不稳定”,需要人工介入。这个双跑机制帮我们抓出了好几个隐蔽的问题。
评测结果不阻塞合并,但会作为一个 comment 自动贴到 PR 上,包含通过率、失败用例、和上次评测的对比。我们内部有个约定:如果意图对齐评测通过率低于 80%,reviewer 必须重点看 AI 生成的部分。
4. 内部项目改造实录:从零搭起这套流程
4.1 改造前的状态和痛点
我们改造的是一个内部运营后台,大概 15 万行 TypeScript 代码,5 个开发维护。引入 AIcoding 之前,大家的用法很随意:有人直接在 IDE 里让 AI 补全,有人把需求贴到对话框里让 AI 生成整个文件。问题集中在三个地方。
第一是风格漂移。不同人用 AI 生成的代码风格差异很大,有的用async/await,有的用 Promise 链,review 时经常要花时间统一。第二是意图偏差,前面说过了,AI 实现的东西和需求有微妙差异。第三是无法回归,AI 生成的代码改完之后,没人知道下次 AI 生成同样需求会不会又出问题,因为根本没有评测基线。
4.2 改造的三个阶段
我们分三个阶段推。第一阶段是规范期,大概两周。这个阶段不追求效率提升,只做一件事:让所有人按统一格式写intent.md。我们定了一个模板,要求每个用 AI 生成代码的任务,必须先写intent.md,写完才能开始生成。这个阶段大家怨声载道,觉得多了一道手续,但两周后回头看,正是这道手续把意图偏差问题压下去了。
第二阶段是评测期,大概一个月。这个阶段开始搭评测集、接 CI。一开始评测集只有 10 个用例,跑起来经常误报,我们花了不少时间调阈值、补用例。这个阶段的产出是一套能稳定跑的评测流程,以及一份“AI 生成代码质量基线”。
第三阶段是优化期,持续进行。有了基线之后,我们开始做针对性优化:哪些任务类型 AI 表现好、哪些差,差的就补intent.md模板、补评测用例、或者干脆规定这类任务不用 AI。这个阶段的核心是数据驱动,不再凭感觉。
4.3 改造后的量化变化
说几个能拿出来的数字。AI 生成代码的首次可用率从 40% 左右提升到 75%。Review 时间平均缩短了 30%,因为风格统一了、意图清晰了,reviewer 不用再猜“这段代码想干嘛”。回归问题数量下降了大概一半,因为持续评测把很多问题在合并前就拦住了。
但也要说清楚代价:写intent.md本身要花时间,平均每个任务多花 10 到 15 分钟。评测集的维护也要投入,我们大概每周花 2 小时补用例、调阈值。所以这套东西不是免费的,它适合那些 AIcoding 用量已经比较大、问题已经开始显现的团队。如果只是偶尔用用,可能不值得上这套。
5. 踩过的坑和排查技巧
5.1 intent.md 写太细反而效果差
一开始我们觉得intent.md越详细越好,有人写了 2000 字,把每个函数签名都规定死了。结果 AI 生成出来的代码确实符合要求,但完全没有发挥 AI 的优势——它变成了一个“按模板填空”的工具,遇到intent.md没覆盖的边界情况就卡住。
后来我们定了个经验值:intent.md控制在 300 到 500 字,只写目标、约束、验收标准、关键上下文,具体实现留给 AI。这个长度下,AI 有足够的决策空间,同时意图又足够清晰。
5.2 评测用例的“过拟合”问题
评测集跑久了会出现一种情况:AI 生成的代码越来越“擅长”通过评测,但实际质量没提升。这是因为评测用例本身被 AI“记住”了——如果评测用例和训练数据有重叠,或者用例太固定,AI 会针对性地优化。
我们的解法是定期轮换评测用例,大概每两个月换掉 30%。同时保留一部分“隐藏用例”,不放在公开的评测集里,只在最终验收时跑。这样能测出 AI 的真实泛化能力,而不是“应试能力”。
5.3 常见问题速查表
| 问题现象 | 可能原因 | 排查方向 |
|---|---|---|
| AI 生成代码风格不一致 | CLAUDE.md 约束不够具体 | 补充命名、格式、依赖使用的硬性规定 |
| 意图对齐评测通过率骤降 | 模型版本更新或 prompt 模板改动 | 对比评测日志,定位变化点 |
| 评测误报率高 | 阈值设置过严或用例本身有歧义 | 放宽阈值,重写有歧义的用例 |
| AI 忽略约束条件 | 约束写在 intent.md 靠后位置 | 把硬约束前置,用加粗强调 |
| 生成代码过度重构 | 目标描述太宽泛 | 收窄 Goal,增加“保持局部”类约束 |
5.4 一个容易被忽视的细节:intent.md 的版本管理
intent.md必须进版本库,和代码一起管理。我们一开始有人把intent.md放在本地不提交,结果出了问题回溯时找不到当时的意图声明,没法判断是 AI 理解错了还是意图本身写错了。现在我们的规矩是:intent.md和对应的代码改动在同一个 commit 里,commit message 里引用intent.md的路径。
这个细节看起来小,但在排查“为什么 AI 生成了这段奇怪的代码”时,能直接看到当时的意图,省掉大量猜测。
6. 关于 AI-native SDLC 的一点个人理解
最近“AI-native SDLC playbook”这个词被提得很多,我理解它的核心不是“用 AI 替代 SDLC 的某个环节”,而是“把 AI 当成 SDLC 里的一等公民来对待”。传统 SDLC 里,人是唯一的执行者,流程是为人设计的。AI-native 的意思是,流程要同时考虑人和 AI 的协作方式。
intent.md和持续评测,本质上就是在 SDLC 里给 AI 加的两个“接口”:一个负责输入意图,一个负责输出质量。这两个接口建好了,AI 才能真正融入流程,而不是作为一个外挂工具存在。
我在实际推这套东西的过程中最大的体会是:不要指望一步到位。先从一个任务类型开始,把intent.md写起来,把评测跑起来,跑顺了再扩到其他类型。那些一上来就想搞“全流程 AI 化”的,往往在第二周就推不动了。小步快跑,用数据说话,比什么方法论都管用。