指令作为可执行约束


指令作为可执行约束

本节摘要:写成散文的指令是愿望;写成约束的指令是测试。工作台把每条规则变成 Agent 能在运行时检查、审查者能在事后核验的东西。一份典型的 AGENTS.md 读起来像入职文档——叫 Agent「小心」「彻底测试」「不确定就问」。三天后,Agent 交付一个没测试的改动、写进禁用目录、从不提问,因为它从不知道线画在哪。指令在可操作(operational)时有力量,在愿景式(aspirational)时软弱。修法是把规则写成工作台能解释、审查者能打分的东西。本节把规则从短根路由里分进 docs/agent-rules.md,给出五类覆盖大多数规则的分类(Startup 启动/Forbidden 禁用/Definition of done 完成定义/Uncertainty 不确定/Approval 审批),每规则带 slug、类别、一行描述、一个 check 字段指向 rule_checker.py 里的函数——加规则即加检查,检查器随工作台增长。规则机器可读也diff 友好(每规则一标题,改名可见,过期删除而非注释掉)。本节还讲透渐进披露(给地图而非百科全书:根路由<50 行只放指针,深度在话题文件里按需加载)与三层结构(路由/规则/话题文档),并给出可达性测试(任一规则最多两跳到)与新鲜度测试(路由短到审查者每 PR 重读)。最后给三条让规则集活过一季度的生产模式:写时打严重度标签(block/warn/info)、规则到期作为强制函数(Cloudflare 13 万次评审数据:带到期的稳定<30 条/仓,不带的长到 80+ 大多永不触发)、Markdown 为源 JSON 为缓存(同 package.json/package-lock.json)。读完本节,你能把散文指令重写成五类可执行约束。

对应原课程:Phase 14 · Lesson 33 · instructions-as-executable-constraints(原英文 phases/14-agent-engineering/33-instructions-as-executable-constraints/docs/en.md)。前置:第 32 节(最小工作台)。

学习目标

阅读完本节,你应当能够:

  1. 把路由散文与可操作规则分开。
  2. 把启动规则、禁用动作、完成定义、不确定处理、审批边界表达为机器可检查的约束。
  3. 实现一个对运行按规则集打分的规则检查器。
  4. 让规则集 diff 友好,审查能看到改了什么。
  5. 设计渐进披露的三层指令结构,并通过可达性与新鲜度测试。

一、问题与直觉

一份典型的 AGENTS.md 读起来像入职文档。它叫 Agent「小心」「彻底测试」「不确定就问」。三天后,Agent 交付一个没有测试的改动、写进禁用目录、从不提问,因为它从不知道线画在哪。

指令在可操作时有力量,在愿景式时软弱。修法是把规则写成工作台能解释、审查者能打分的东西。

五类覆盖大多数规则的分类

类别 规则回答的问题 例子
启动(Startup) 工作开始前什么必须为真? 「状态文件存在且新鲜」
禁用(Forbidden) 什么绝不能发生? 「不要编辑 scripts/release.sh」
完成定义(Definition of done) 什么证明任务完成? 「pytest 退出码 0 且验收行通过」
不确定(Uncertainty) Agent 不确定时做什么? 「开一条问题便签而非猜测」
审批(Approval) 什么需要人审批? 「任何新依赖、任何生产写」

一条塞不进这五类的规则,通常是想当两条。强制拆分。

规则机器可读

每条规则有 slug、类别、一行描述、一个 check 字段指向 rule_checker.py 里的函数。加规则即加检查;检查器随工作台增长。

规则 diff 友好

规则在一个 markdown 文件里每条一标题。改名在 diff 里可见。新规则坐在其类别顶部。过期规则被删除,而非注释掉——因为工作台是真相之源,不是团队上季度感受的聊天记录。

规则 vs 框架护栏

框架护栏(OpenAI Agents SDK guardrails、LangGraph interrupts)在运行时层强制规则。本节的规则集是人类可读、可审查的契约,那些护栏实现的就是它。你两者都要:运行时在一轮里抓违规,规则集证明运行时在做对的事。

渐进披露:地图,而非百科全书

AGENTS.md 一直长的原因是:每个事故加一条规则,没有事故删一条。一年后,文件两千行,Agent 读第一屏、注意力预算耗尽、只按被告知的一小部分行动。巨型指令文件失败的原因和四十页入职文档一样:读者略读一次,再不回到重要的部分。

修法不是更短的文件,而是分层的。根路由保持小到每次会话都能读,只放指针。深度活在话题文件里,Agent 只在任务触及时加载。给 Agent 一张地图,而非整本百科全书,让它走到需要的那页。

AGENTS.md # 路由,<50 行:这仓是什么、去哪看、5 条硬规则 docs/ agent-rules.md # 完整规则集(本节) architecture.md # 任务触及模块边界时加载 testing.md # 任务写或跑测试时加载 deploy.md # 只为发布工作加载,门控在审批规则后 feature_list.json # backlog(第 36 节) ​
层 活在 何时读 大小预算
路由 AGENTS.md 每会话,总是 <~50 行
规则 docs/agent-rules.md 每会话,启动时 每类一屏
话题文档 docs/<topic>.md 只在任务触及该话题时 需要多深就多深

两个测试保持分层诚实。可达性测试:Agent 从路由到任一规则最多两跳,所以路由必须按路径链接每个话题文档,而非散文描述。新鲜度测试:路由短到审查者每 PR 重读,这是唯一能阻止它静默长回它取代的百科全书的东西。一个不再解析的指针,比缺失规则更糟,所以路由里的死链本身就是一条启动检查违规。

二、从零实现

原课程 code/main.py 提供:

  • agent-rules.md 解析器,把规则加载进数据类。
  • rule_checker.py 式检查函数,每个 check 引用一个。
  • 一个违反两条规则的演示 Agent 运行,加一次抓住它们的检查通过。

Step 1:规则定义(机器可读)

## RULE-FORBID-RELEASE [forbidden] block 不得编辑 scripts/release.sh。 check: no_edit_of("scripts/release.sh") ## RULE-DONE-TESTS [done] block pytest 必须退出 0。 check: shell_exits_zero("pytest") ## RULE-UNCERTAIN-NOTE [uncertainty] warn 不确定时开问题便签而非猜。 check: no_guess_without_note() ​

Step 2:解析 + 数据类

@dataclass class Rule: slug: str; category: str; severity: str desc: str; check: str def parse_rules(md_path): rules = [] for heading in parse_headings(md_path): slug, cat, sev = parse_heading_meta(heading) # RULE-X [cat] sev rules.append(Rule(slug, cat, sev, desc, check)) return rules ​

Step 3:检查器(每 check 一个函数)

CHECKS = { "no_edit_of": lambda path: path not in run.touched_files, "shell_exits_zero": lambda cmd: shell(cmd).returncode == 0, "no_guess_without_note": lambda: not run.has_guess or run.has_question_note, } def check_run(run, rules): report = [] for r in rules: fn = CHECKS[r.check_name] passed = fn(*r.check_args) report.append({"slug": r.slug, "severity": r.severity, "passed": passed}) return report # 保存为 rule_report.json ​

运行 python3 code/main.py 会输出:解析后的规则集、运行轨迹、每规则通过/失败、一份存脚本旁的 rule_report.json。

生产模式(让规则集活过一季度)

三条把规则集分开:能撑一季度的 vs 一周就腐的。

写时打严重度标签。 每条规则带 severity:block、warn、info。检查器三者都报;运行时只在 block 上拒绝。多数团队早期高估严重度,然后在截止压力下悄悄削弱;写时打标签强制前置校准。配第 38 节验证门,它把任何对 block 规则的覆盖签进 overrides.jsonl 审计日志。

规则到期作为强制函数。 每条规则带 expires_at 日期(默认成文后 90 天)。检查器在一条未过期规则连续 60 天零违规时发警告;下次季度评审要么论证保留、要么削弱成 info、要么删除。Cloudflare 的生产 AI 代码评审数据(2026-04,30 天跨 5169 仓 131246 次评审运行)显示:带显式到期的规则集稳定在每仓 <30 条;不带的涨到 80+,大多永不触发。

Markdown 为源,JSON 为缓存。 agent-rules.md 是成文文件;agent-rules.lock.json 是检查器热路径读的缓存。锁由 pre-commit 钩子重生。Markdown diff 可审查;JSON 解析不进每一轮。同 package.json/package-lock.json、Cargo.toml/Cargo.lock 的形状。

💡 设计要点:把指令从散文变成约束,本质是把「应该」变成「必须,否则验证门拦住」。这与第 26 节「每步验证门」、第 38 节验证门一脉相承——规则集是人类可读的契约,验证门是它的运行时强制。没有运行时强制的规则,只是更精致的愿望。

三、框架对比

运行时 规则如何被用
Claude Code、Codex、Cursor 会话开始读规则,拒动作时引用;CI 重跑抓静默漂移
OpenAI Agents SDK 同样检查注册为输入/输出护栏;markdown 是文档面,SDK 是运行时面
LangGraph 在飞节点违规时触发 interrupt;处理器读规则、问人、续跑

规则集跨三者可移植,因为它只是 markdown 加函数名。

四、可复用产物

原课程 outputs/skill-rule-set-builder.md:采访项目主,把现有散文指令分进五类,产出带版本的 agent-rules.md 加检查器桩。

五、练习

  1. (Easy) 若你产品真需要,加第六类。论证它为何不塌进现有五类。
  2. (Medium) 扩展检查器,让规则带严重度(block/warn/info),报告按此聚合。
  3. (Medium) 把检查器接进 CI:最新 Agent 运行上 block 严重度规则失败即 fail build。
  4. (Hard) 每规则加「到期」字段。90 天无检查失败,规则上评审。
  5. (Hard) 找一份真实 AGENTS.md,重写成五类规则。它有多少行是可操作的?多少是愿景式的?

本节要点回顾

  1. 散文指令是愿望,约束指令是测试:工作台把每规则变成运行时可查、事后可核验的东西。
  2. 五类分类:启动、禁用、完成定义、不确定、审批;塞不进的通常想当两条,强制拆分。
  3. 规则机器可读:slug+类别+描述+check 函数;加规则即加检查。
  4. diff 友好:每规则一标题,改名可见,过期删除而非注释掉。
  5. 规则 vs 框架护栏:护栏是运行时强制,规则集是人类可读契约;两者都要。
  6. 渐进披露:给地图非百科;根路由<50 行只放指针,深度在话题文件按需加载。
  7. 三层结构:路由(每会话)/规则(启动)/话题文档(按需);每层大小预算不同。
  8. 两个测试:可达性(任一规则最多两跳)、新鲜度(路由短到每 PR 重读);死链即启动检查违规。
  9. 三条生产模式:写时打严重度(block/warn/info)、规则到期(Cloudflare 数据:带到期<30 条,不带 80+ 大多不触发)、MD 源+JSON 缓存。
  10. 把「应该」变「必须」:规则集是契约,验证门是运行时强制;无强制的规则只是更精致的愿望。

下一节,我们做实「状态」这一面——仓库记忆与持久状态:状态文件该承载哪些键、如何演化、如何在多会话与多 Agent 间保持一致,让仓库本身成为 Agent 的长期记忆。


作者与出处
原作者: Rohit Gupta
来源:rohitg00
许可证:MIT
整理: 灏天文库整理
由灏天文库结构化整理,提供目录导航、全文检索与在线阅读,便于系统化学习
发布者: 作者: Rohit Gupta 转发
评论区 (0)
U