别把流程塞进 AGENTS.md:用 Skills 给 coding agent 做可复用工序

· 约 5 分钟阅读

不少项目的 AGENTS.md 最后都会变成一本操作手册:怎么查库、怎么跑截图、怎么发版、怎么审日志、遇到故障找谁。刚开始很省心,过几周就开始反噬。每次让 agent 改一行 UI,它先读完一堆和眼前任务无关的流程;规则越长,真正不能违背的几条反而越容易被淹没。

我现在把它拆成三样东西:AGENTS.md 放常驻约束,Skill 放可复用工序,子代理放一次性且噪声大的调查。不是为了追求“多 agent”,而是给上下文设预算。让主 agent 在需要时拿到正确工具,而不是开场就背完整个运维手册。

先给 AGENTS.md 减肥#

AGENTS.md 适合写每次都成立、短且可验证的规则。Codex 会先读全局规则,再从仓库根目录一路读到当前目录;同一层级若有 AGENTS.override.md,它会替代普通文件,越靠近当前工作目录的说明越靠后,因此优先级更高。[1] 这意味着根文件该像项目宪法,而不是百科全书。

我的根文件通常只留四类内容:依赖管理命令、禁止触碰的边界、必须执行的验证、提交或交付格式。比如“使用 pnpm”“不得读取 .env”“改 TypeScript 后跑类型检查”。这些话不需要按任务展开,放在会话开头正合适。

反过来,下面这些该移走:完整的排障步骤、截图脚本参数、发布前检查清单、某个服务的 SQL 诊断套路。它们只有在特定任务才有价值。Codex 的项目指令默认总容量是 32 KiB,官方也建议遇到上限时拆到嵌套目录。[1] 但比容量更现实的问题是注意力:一份四百行的规则即使没有被截断,也很难让模型在关键时刻抓住重点。

Skill 不是另一份长说明#

Skill 的价值在于“按需加载”。Codex 初始只拿到每个 Skill 的名称和描述,真正匹配任务后才读取对应 SKILL.md 的完整内容。[2] 所以描述要像路由规则,短而具体:什么时候用、产出什么、不能拿它做什么。不要写“帮助处理开发任务”,那等于没写。

一个实用的 Skill 应该是一段有起点和终点的工序。比如“排查生产 API 延迟”:输入是路由与时间窗口,步骤是读取只读指标、采样日志、对照近期发布,输出是证据和下一步;它不负责直接改生产配置。再比如“生成浏览器回归截图”:输入是页面 URL 和视口,输出是图片与失败日志。流程、脚本、参考资料都放在 Skill 目录里,主提示词只负责触发它。

官方的目录结构也支持这种做法:一个 Skill 至少有 SKILL.md,可以带 scripts/、references/、assets/;仓库内的 Skill 放在 .agents/skills,从当前目录向仓库根目录扫描。[2] 这样把技能和它依赖的脚本放在一起,不会在根目录散落一堆“仅某任务可用”的工具。

再用子代理隔离脏活#

Skill 解决“重复流程”,子代理解决“这次调查会制造很多无关上下文”。Claude Code 的子代理在独立上下文窗口运行,可以配独立系统提示、工具集和权限,最后只把结论带回主会话。[3] 查大型代码库、翻长日志、比对多个实现,这些都很适合交出去。

关键不是把任务一股脑外包,而是规定交接面。子代理收到的问题应该能在一页内说清:调查范围、允许的工具、需要带回的证据格式、什么情况下停止。主 agent 只接收“找到的文件、可复现命令、风险和建议”,不接收几千行搜索输出。Claude Code 的 Explore 本身就是只读的代码库探索代理;官方也明确把它定位成把搜索结果留在独立上下文里。[3]

这里要留一道硬边界:子代理的提示词不是权限系统。对“绝不能执行”的动作,仍然用 hook。Claude Code 的 PreToolUse 在工具调用前触发,命令 hook 能读取 stdin 的 JSON,并返回拒绝决定来阻止调用。[4] 把删生产数据、读取密钥、向外部地址上传文件这类规则放到 hook,别期待长指令永远被遵守。

快速上手:把一个发布流程拆出来#

先把根规则缩到足够短:

# AGENTS.md
- 使用 pnpm;不得手改 lockfile。
- 不读取或输出 .env、密钥、生产导出数据。
- 改动后运行 pnpm lint && pnpm typecheck。
- 交付时列出改动文件、验证命令和未解决风险。

再创建一个只负责“发布前检查”的仓库 Skill:

mkdir -p .agents/skills/release-check/scripts
cat > .agents/skills/release-check/SKILL.md <<'EOF'
---
name: release-check
description: 发布前执行构建、测试和变更摘要;只在用户明确要求发布或发布前检查时使用。
---

1. 读取 package.json,确认项目的 build 与 test 命令。
2. 执行只读检查、测试和构建,不推送、不部署。
3. 输出每条命令的退出码、失败日志摘要和变更文件列表。
4. 任一检查失败时停止,不建议绕过。
EOF

然后在任务里明确调用它,例如:“修改支付页后,使用 release-check 做发布前检查。”主 agent 平时不必携带这段流程,只有你说要发布时才展开。若检查还要翻大量 CI 日志,再让一个只读子代理负责日志归因;它的输出限定为失败阶段、首个报错、相关提交和建议,不要把原始日志整段转回来。

最后给高风险命令留一条 hook。下面的示例只拦截明显的生产删除命令;先放在测试仓库验证匹配规则,别直接复制到已有复杂配置里:

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{
        "type": "command",
        "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-prod-delete.sh"
      }]
    }]
  }
}

把流程塞回 AGENTS.md 很容易,因为它就在眼前。真正省上下文的做法是忍住:常驻规则保持短,重复工序做成可调用 Skill,噪声调查交给只读子代理,不能出错的事交给 hook。这样项目变大以后,agent 仍然知道此刻该读什么、该忽略什么。

Sources#

[1] https://developers.openai.com/codex/guides/agents-md — OpenAI Codex AGENTS.md 官方指南 [2] https://developers.openai.com/codex/skills.md — OpenAI Codex Skills 官方文档 [3] https://docs.anthropic.com/en/docs/claude-code/sub-agents — Claude Code 子代理官方文档 [4] https://docs.anthropic.com/en/docs/claude-code/hooks — Claude Code Hooks 官方参考