把 agent 指令拆成目录规则:减少上下文冲突的实战
很多团队给 agent 写规则时,习惯把所有东西塞进根目录:构建命令、数据库禁区、前端风格、迁移规范、截图要求,最后变成一份两三百行的“总章程”。它当然比没有好,但 agent 改一个按钮也得先吞下后端迁移约束;改一条 SQL,又得带着组件命名规则。上下文花掉了,真正和当前文件有关的规则反而不够显眼。
更稳的做法是分层。根目录只放跨仓库都成立的原则,例如安装命令、全量验证、密钥边界和提交要求;业务目录放局部约束;这次任务独有的目标、可写范围和验收证据放进任务卡。你不是在给 agent 加更多规矩,而是在让它进入哪个目录,就看到哪个目录的规矩。
GitHub Copilot 支持在仓库任意位置放置多个 AGENTS.md,处理文件时以目录树中最近的一份为准;它也支持 .github/instructions/ 下带 applyTo glob 的路径专用指令。仓库级 instructions 与路径专用 instructions 同时命中时会一起使用。[2] 这两个机制刚好能把“全局不变量”和“局部例外”分开。Claude Code 的 hooks 也有同样的边界思路:事件发生后先经 matcher 过滤,再执行对应 handler,而不是每次工具调用都跑所有检查。[1]
先决定每类信息该住在哪里#
我会把规则分成三层。第一层是根目录 AGENTS.md 或 .github/copilot-instructions.md:只写任何改动都不能绕开的内容,例如 pnpm install --frozen-lockfile、禁止提交 .env、提交前跑哪些全量检查。它应该短,且每条都能验证。
第二层是目录规则。假设 services/billing/ 只能通过 repository 层访问数据库,迁移必须附带回滚脚本;apps/web/ 则要求改交互时更新 Playwright 用例。这些规则不要放进根文件。Copilot 可以在 services/billing/AGENTS.md 放局部 agent 指令,也可以用 .github/instructions/billing.instructions.md 的 applyTo 精确匹配路径。[2] 对 Claude Code,目录里的 CLAUDE.md 或导入同一份局部说明,能避免为了一个包把全局项目说明越写越胖。
第三层是任务卡,它不入库。任务卡只解决这一次的差异:允许改哪些文件、明确不能碰什么、验收命令、需要回报的证据。比如“修 billing 重试”不该只写成一句需求,而应说明只改 services/billing/ 和其测试,不能改公共 API,最后贴出目标测试和类型检查的退出码。稳定知识入规则,临时边界留在任务里,过期内容才不会慢慢污染仓库说明。
快速上手:给一个 monorepo 分层#
先保留根规则,只写跨项目内容:
# AGENTS.md
- 安装依赖:pnpm install --frozen-lockfile
- 提交前运行:pnpm lint && pnpm typecheck
- 不得修改 .env、密钥、lockfile;依赖升级必须单独说明
- 改动公共接口时,补充兼容性测试
然后为账单服务创建局部文件:
mkdir -p services/billing
cat > services/billing/AGENTS.md <<'EOF'
# Billing rules
- 只通过 src/repositories/ 访问数据库
- 修改重试逻辑时,更新 tests/retry/ 中的用例
- 新增 migration 必须同时提供 rollback SQL
- 本目录验收:pnpm test --filter billing
EOF
如果团队主要用 Copilot,再加一个按路径命中的 instructions 文件。applyTo 使用 glob;路径专用 instructions 必须放在 .github/instructions/ 内,文件名以 .instructions.md 结尾。[2]
---
applyTo: "services/billing/**/*.ts"
---
修改持久化逻辑前先阅读同目录 AGENTS.md。
不要直接拼接 SQL;返回错误时保留原始错误码。
最后,把下面这段随任务发给 agent,而不是塞回根文件:
目标:修复 billing 的重试退避计算。
可写:services/billing/、tests/billing/。
禁止:公共类型、数据库 schema、pnpm-lock.yaml。
验收:pnpm test --filter billing && pnpm typecheck。
回报:改动文件列表、两条命令的退出码、未解决风险。
规则冲突时,别让 agent 猜#
分层会引入一个新风险:根规则说“所有 API 失败要重试三次”,账单目录却说“支付提交不得自动重试”。这不是模型理解力问题,而是规则本身矛盾。解决方式很朴素:局部文件开头直接写“本目录规则覆盖根目录关于重试的通用要求”,并说明理由。Copilot 的最近 AGENTS.md 优先级让这种覆盖有明确落点;路径专用文件与仓库级指令会一起加载,因此同一问题别在两处写相反的话。[2]
还有一条分界要守住:文件规则只是在提供上下文,不是安全闸门。碰到一次也不能错的动作,例如删除生产资源、写入密钥文件、修改付款开关,就交给 hook。Claude Code 的 PreToolUse 会在工具调用前触发,handler 可以返回拒绝决定;matcher 和条件还能让检查只针对特定工具或命令执行。[1] 指令文件负责让 agent 知道“该怎么做”,hook 负责保证“绝不能做什么”。
分层后的好处不神秘:无关规则少了,任务边界清楚了,规则过期时也知道该删哪一层。下次 agent 走进 services/billing/,它不需要从一份百科全书里翻出付款约束,约束就在门口。
Sources#
[1] https://docs.anthropic.com/en/docs/claude-code/hooks — Claude Code Hooks reference [2] https://docs.github.com/en/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-repository-instructions — GitHub Copilot repository custom instructions