6 条行为约束------让 Agent 不再"我以为"
Agent 写代码最常见的翻车模式是什么?不是你给的指令不够详细,而是它在你不注意的地方默默做了假设------"这个字段应该是必填的吧""这个方法应该是同步的吧""这个接口应该返回 200 吧"------然后一路基于错误假设写下去,直到出 bug。
agent-skills 项目里有一套 6 条 Core Operating Behaviors,就是在每一个"容易默默假设"的节点上强制 agent 停下来、把话说清楚。这篇文章把它们拆开,每条配一个不加约束会翻车的场景和加上约束后的效果。文末附可直接复制到项目里的完整配置。
6 条行为约束总览
markdown
1. Surface Assumptions → 开工前把你默认为真的东西说出来
2. Manage Confusion → 撞见矛盾时停下来,不要猜
3. Push Back → 需求有明显问题时敢说"不建议"
4. Enforce Simplicity → 写完检查:能更简单吗?
5. Scope Discipline → 别碰和任务无关的代码
6. Verify, Don't Assume → 说"做完了"之前贴证据
这 6 条不是 24 个 skill 里的某一个------它们是所有 skill 之上的全局规则,任何时候生效。下面逐条展开。
1. Surface Assumptions------把默认假设摆到台面上
不加约束时:
bash
你:帮我加一个 POST /api/checkout 接口,请求体有 orderId。
Agent:好的。(默默假设 orderId 是必填、用户已登录、支付方式从订单里取...)
你一周后发现:未登录也能调、orderId 传空字符串也返回 200、支付方式字段根本没传------每一个都是 agent 默认真、你没说的假设。
加了约束后:
markdown
# 在你的 CLAUDE.md 里加:
## Surface Assumptions
在写任何有点复杂度的代码之前------不是重命名变量、改配置那种------先列出你的假设:
ASSUMPTIONS I'M MAKING:
-
关于需求的假设
-
关于架构的假设
- 关于范围的假设 → 不对现在纠正,我就按这些假设继续。
效果:
markdown
Agent:在写 POST /checkout 之前,我做了这些假设:
1. orderId 必填且非空,不存在时返回 404
2. 用户已通过 authMiddleware 登录,userId 从 req.userId 取
3. 支付方式从该订单已有的 paymentMethod 字段取
→ 不对现在纠正。
你:第 3 条不对,支付方式应该由请求传入,用户可以选不同方式。
你看------开工前一句对话就纠正了。不加约束,这个错误假设要等到 review 甚至上线才发现。
2. Manage Confusion------撞见矛盾停下来,不要猜
不加约束时:
agent 在写代码时发现 spec 说"所有接口走 REST",但代码库里已经有一批 GraphQL mutation。它选了一个觉得靠谱的------默默走了 REST,又多了一套并行实现,维护成本加倍。
加了约束后:
markdown
## Manage Confusion
遇到 spec 和代码矛盾、需求不完整、或任何不确定的情况:
1. STOP。不要猜。
2. 说清矛盾点。
3. 列出选项和 trade-off。
4. 等待回答后继续。
效果:
css
Agent:STOP。spec 说"所有接口走 REST",但现有代码 src/graphql/ 里
已经有 4 个 GraphQL mutation。我该:
A) 按 spec 加 REST 接口(会多一套并行实现)
B) 按代码惯例加 GraphQL mutation(需要你更新 spec)
→ 选哪个?
3. Push Back------需求有问题时敢说"不建议"
这是 6 条里最容易踩中的坑
不加约束时:
bash
你:POST /checkout 里顺便把用户所有历史订单也查出来返回吧,前端刚好能刷新列表。
Agent:当然可以!(它没说"这样不合适"------谄媚是 LLM 的默认行为)
一个"创建"接口返回了全量列表,语义污染、性能隐患、耦合------全是这句"当然可以"的代价。
加了约束后:
markdown
## Push Back When Warranted
你不是点头机器。当方案有明显问题时:
- 直接指出问题,量化后果("这会让 P95 延迟上升 ~200ms")
- 提出替代方案
- 用户了解代价后仍坚持,照做
效果:
markdown
Agent:不建议这么做。具体代价:
1. 语义污染:"创建"接口返回全量列表,后人难懂
2. 性能:历史订单一多,每次创建都拉全量,响应体越来越大
3. 替代方案:创建只返回新订单;列表走已有的 GET /api/orders(已有分页)
如果你了解这些后仍坚持,我照做。
4. Enforce Simplicity------写完自查:能更简单吗?
不加约束时:
agent 给一个"创建任务"的接口写了 3 层 service + Builder 模式 + 工厂类------总共 180 行,但实际逻辑只是"校验 2 个字段 + insert 一条记录"。
加了约束后:
markdown
## Enforce Simplicity
写完后问自己:
- 能更少行吗?
- 这些抽象值得它们的复杂度吗?(不到第三个使用场景不要抽象)
- 一个 Staff Engineer 看了会说"你为什么不直接..."吗?
如果写了 1000 行而 100 行就够,你失败了。
效果:
arduino
Agent:初稿引了 TaskFactory + TaskBuilder + 三层 service,180 行。
自查:两个字段不需要 Builder/Factory,Staff Engineer 一定会说"为什么不直接 handler + validator?"。
已精简为 1 个 handler + 1 个校验函数,32 行。
5. Scope Discipline------别碰和任务无关的代码
这是 agent 最容易"手痒"的坑------写着写着看到旁边有个旧注释看不懂、有个变量好像没用到、有个 import 顺序不顺眼,顺手就改了。
加了约束后:
markdown
## Scope Discipline
只碰本次任务范围内的代码。禁止:
- 删除你看不懂的注释
- "顺便"重构相邻模块
- 删除看似没用但你没确认的代码
- 加 spec 里没有的"顺便"功能
如果看到范围外的问题想改------记下来问用户要不要另开 task,不要顺手改。
效果:
sql
Agent:改 auth.ts 时看到旁边 getOrders 里有个不理解的老注释、deleteOrder 里有个好像没用的变量。
按 Scope Discipline,不碰。
记下来了------你看要另开 task 处理吗?
这种"不请自来的装修"是最容易引入隐蔽 bug 的行为,限制它价值很大。
6. Verify, Don't Assume------说"做完了"时贴证据
不加约束时:
你:写完了吗?
Agent:应该没问题了,代码看起来是对的。
加了约束后:
markdown
## Verify, Don't Assume
任务在验证通过前不算完成。"看起来对"永远不够。必须有证据:
- 测试输出(命令 + 结果)
- 构建输出
- 运行时数据(curl 结果、截图等)
效果:
bash
Agent:完成,证据如下。
$ npm test -- checkout
✓ POST /checkout 创建成功返回 201
✓ orderId 缺失返回 422
✓ 未登录返回 401
Tests: 3 passed
$ curl -s -XPOST .../api/checkout -d '{"orderId":"o_1"}' -H "Authorization:..."
201 {"data":{"id":"ch_01","orderId":"o_1","status":"pending"}}
实战落地:你能直接拿走的东西
方案 A:加到 CLAUDE.md(Claude Code 用户)
把下面内容粘贴到项目根目录的 CLAUDE.md:
markdown
# 行为约束
## Surface Assumptions
在写任何有点复杂度的代码前------改个变量名不算------先列出假设:
ASSUMPTIONS I'M MAKING:
- 需求假设 2. 架构假设 3. 范围假设 → 不对就纠正,否则我按这些继续。
shell
## Manage Confusion
遇到 spec 和代码矛盾、需求不完整时:STOP → 说清矛盾 → 列选项和 trade-off → 等回答。
## Push Back
方案有明显问题时直接指出,量化后果,给替代方案。不是点头机器。
## Enforce Simplicity
写完自查:能更少行吗?抽象值得吗?Staff Engineer 看了会说"为什么不直接..."吗?
## Scope Discipline
只碰任务范围内的代码。不删看不懂的注释,不顺手重构,不加 spec 外的功能。
## Verify, Don't Assume
说"做完了"必须贴证据:测试输出、构建结果、curl 结果或截图。
方案 B:加到 .cursor/rules(Cursor 用户)
把上面内容保存为 .cursor/rules/behaviors.md。
方案 C:加到 .github/copilot-instructions.md(Copilot 用户)
同样的内容,放到 .github/copilot-instructions.md。
方案 D:新 session 时贴到对话里(任何工具通用)
开新 session 时把下面这段贴进去:
markdown
本次 session 全程遵守 6 条规则:
1. 写代码前先暴露你的假设,等我确认
2. 遇到需求矛盾停下来问我,不要猜
3. 我的方案有问题直接说,量化后果 + 给替代方案
4. 写完自查能否更简单------能砍行数就砍
5. 别碰和本次任务无关的代码
6. 说"做完了"时贴测试结果或 curl 输出作为证据
注意事项
⚠️ 这 6 条规则不是装了就一劳永逸。Agent 仍然会尝试跳步------它会在第 3 次任务时说"这个太简单了不用列假设了吧"。规则的价值不是让它 100% 遵守,而是当它想跳步时,你有明确的条款把它拉回来。把它理解成"驾驶辅助",不是"自动驾驶"。
这篇文章的核心和这篇文章没讲的东西
agent-skills 项目的完整设计包括 24 个结构化 skill(spec-driven-development、test-driven-development、code-review 等),这 6 条行为约束是跨所有 skill 的底层规则。
这篇文章取了最通用、最不依赖工具的 6 条------不管你是 Claude Code、Cursor、Copilot 还是手动贴 prompt,都能用。下一篇讲 Doubt-Driven Development:怎么在关键决策点上派一个对抗性 reviewer 来"找茬"。