如何约束AI写代码:Mode边界和证据链

如何约束AI写代码:Mode边界和证据链

让 AI 写代码,最重要的不是 prompt 写得花,而是任务边界写得硬。

很多人使用 AI 编程的方式,是把愿望丢给它:

1
帮我优化一下这个功能,注意代码质量。

这句话看似礼貌,实际很危险。它没有告诉 AI 这是什么类型的任务,也没有告诉它哪些文件能改、哪些不能改、哪些行为不能变、发现旁支问题时该停还是该修。

AI 收到这种指令,只能自己补全边界。补得好,是运气;补得坏,也不奇怪。

一、AI 的强项和危险是同一件事

AI 很擅长补全。

你给它一段不完整上下文,它会补全缺失逻辑。你给它一个模糊目标,它会补全任务范围。你给它一个失败测试,它会补全实现。你给它一组 diff,它会补全解释。

这就是它的力量,也是它的风险。

在人类开发里,模糊有时会停下来。因为人会问,或者会卡住,或者会因为不确定而慢一点。AI 不一定会卡住。它更可能生成一个看起来完整的答案。

越流畅,越容易让人忘记中间有多少猜测。

所以,AI 协作的第一原则不是“让它更聪明”,而是“让它必须暴露不确定性”。

二、先声明 Mode

每个 AI 开发任务,先声明 Mode。

Expansion:扩展能力。
Hold:修复、硬化、迁移、清理、提效,不扩大范围。
Reduction:收缩、下线、删除、降低复杂度。

Mode 不是标签。它是约束。

如果任务是 Hold,AI 就不应该顺手加新功能。
如果任务是 Reduction,AI 就不应该加一堆兼容分支让复杂度继续膨胀。
如果任务是 Expansion,AI 就必须考虑错误态、测试、发布和回滚。

你可以这样写:

1
2
3
4
5
Mode: Hold
目标:修复导出任务偶发失败。
为什么是 Hold:本次只修复和硬化已有导出链路,不新增导出格式。
为什么不是 Expansion:没有新增用户能力。
为什么不是 Reduction:没有下线旧能力。

这几行会让 AI 的工作方式完全不同。

三、边界要写成硬规则

不要对 AI 说“尽量别改太多”。

这句话太软。你应该写:

1
2
3
4
5
6
7
8
9
10
11
Allowed Changes:
- 修改 ExportService。
- 修改 ExportServiceTest。
- 如需新增 test helper,只能放在 test support 目录。

Forbidden Changes:
- 不改导出 UI。
- 不改 StorageClient 接口。
- 不新增导出格式。
- 不做全仓格式化。
- 不修 unrelated lint。

这种写法没有那么优雅,但非常有效。

AI 不是不听话,而是它不知道你的隐含边界。你不写,它就会推断;它一推断,就有可能把“相关”当成“应该做”。

边界越清楚,AI 越能发挥执行能力。

四、Research-first 是刹车

AI 开发最容易出事的时刻,是它还没理解代码库就开始改。

所以第一道 Harness 是 research-first:

1
2
3
4
5
6
先研究代码库现实,不写代码。
列出相关文件。
列出现有实现。
列出已有测试。
区分 Facts、Assumptions、Unknowns。
最多保留一个阻断问题。

这个阶段像刹车。不是为了停住,而是为了让后面的加速有方向。

Research-first 还有一个价值:它能让你提前看到 AI 是否理解错了。

很多错误如果等到 diff 出来才发现,已经晚了。如果 research 阶段就发现 AI 把项目结构、业务名词或失败路径理解错了,修正成本很低。

五、把事实、假设、未知分开

这是约束 AI 的关键动作。

你要让它明确输出:

1
2
3
4
5
6
7
8
9
10
11
12
Facts:
- 当前导出任务由 ExportWorker 执行。
- 测试只覆盖正常导出成功。
- 日志显示上传成功后出现状态写回超时。

Assumptions:
- 用户看到失败可能来自状态写回失败。
- 重试可能会重复生成文件。

Unknowns:
- 当前是否有幂等 key。
- 旧导出文件是否会清理。

这三类东西必须分开。

Fact 可以支撑设计。Assumption 需要验证、隔离或写进风险。Unknown 要么补研究,要么明确不阻塞当前阶段。

如果不分开,AI 很容易把假设写成事实语气。

六、Dirty Worktree 是协作边界

AI 工作时,脏工作区是一个重要信号。

脏工作区可能意味着:你正在做另一件事,另一个 agent 留下了中间产物,脚本生成了文件,或者当前任务已经有未提交改动。

AI 不能把脏工作区当噪音。

任务里应该写:

1
2
3
如果工作区有未提交改动,先报告与当前任务相关的文件。
不要覆盖无关用户改动。
如果某个脏文件是本任务必须修改的,先读懂它,再继续。

这条规则看似普通,但非常关键。没有它,AI 很可能在“整理代码”的过程中覆盖别人还没保存好的意图。

七、让 AI 输出证据,而不是情绪

AI 最差的收尾方式是:

1
已完成。

这句话没有价值。

好的 AI 收尾应该包含:

  • 改了哪些文件。
  • 为什么这么改。
  • 跑了哪些验证。
  • 验证结果是什么。
  • 哪些没测。
  • 剩余风险是什么。
  • 哪些发现属于后续任务。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
完成了 token 过期状态流修复。改动集中在 AuthSessionStore 和对应测试,没有修改登录 UI 或 token refresh API。

验证:
- testExpiredTokenRoutesToLogin: pass
- testMissingNavigatorDoesNotCrash: pass
- testEmptyCachedTokenClearsSession: pass
- testRefreshFailureKeepsRecoverableState: pass

未覆盖:
- 未跑完整 UI 自动化。
- 未覆盖旧客户端真实请求。

剩余风险:
- 旧缓存格式兼容只通过单元测试验证,未在真实设备回归。

这才是能被接住的交付。

八、一个可复制的任务模板

你可以直接复制下面这段给 AI:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Task:
<一句话描述任务>

Mode:
Expansion / Hold / Reduction

Goal:
本次真正要解决的问题是:

In Scope:
-

Out of Scope:
-

Research Rules:
1. 先 research,不直接改代码。
2. 区分 Facts / Assumptions / Unknowns。
3. 如果发现范围外问题,只记录到 residual risks,不顺手修。

Allowed Changes:
-

Forbidden Changes:
-

Review Rules:
按 happy / nil / empty / error 检查。

Validation:
必须记录命令、预期结果、实际结果、未覆盖风险。

它不华丽,但很实用。

九、AI 不是混乱的解药

AI 不是混乱的解药。没有 Harness,AI 会让混乱跑得更快。

但有了 Harness,AI 是非常强的执行器、检索器、测试补全器和风险扫描器。

问题不在 AI。问题在任务有没有被装进控制面。

你要做的,不是把 AI 变成一个“更听话的人”,而是把任务变成一个它能安全执行的结构。