首页
/ caveman cavecrew 技能实战:如何基于压缩输出的子代理完成代码定位、编辑与审查

caveman cavecrew 技能实战:如何基于压缩输出的子代理完成代码定位、编辑与审查

2026-09-06 12:19:37作者:齐冠琰

cavecrew 是 caveman 项目中的一组 Claude Code 子代理预设技能,解决的核心问题是:当你需要委派任务给子代理(subagent)时,该选哪一个、何时不该委派、以及如何让子代理的返回结果不撑爆主上下文。本文基于仓库中的 skills/cavecrew/ 技能文档,结合三个子代理的 prompt 定义与模型覆盖钩子的源码实现,讲清楚 cavecrew 的决策矩阵、输出契约、链式调用模式以及 CAVECREW_*_MODEL 环境变量覆盖机制的底层原理。

定位:决策指南,而不是斜杠命令

先厘清 cavecrew 是什么、不是什么:

  • 它是一份决策指南(decision guide):告诉主线程何时应该派生一个 caveman 风格的子代理,而不是在主线程里直接干活;
  • 它不是斜杠命令:没有 /cavecrew 这样的显式调用入口。技能在对话中提到"委派"(delegation)相关意图时自动激活,触发短语包括 "delegate to subagent"、"use cavecrew"、"spawn investigator"、"save context"、"compressed agent output" 等;
  • 它不承诺任何普适的 token 压缩率:文档明确声明压缩效果取决于任务类型、所用 agent 和委派次数,不发布任何"固定压缩比例"。这一点在 skills/cavecrew/README.md 中是刻意的诚实表述。

cavecrew 与 Anthropic 默认子代理(Explore、编辑型 agent、reviewer)做的是同样的活,区别在于返回给主上下文的结果被 caveman 风格压缩,因此每次委派消耗的主上下文预算更小。完整的决策矩阵与输出契约见 skills/cavecrew/SKILL.md

三个子代理及其职责边界

cavecrew 由三个子代理组成,每个都有明确的职责、工具集与模型配置:

子代理 职责 适用场景 工具集 默认模型
cavecrew-investigator 只读代码定位 "X 在哪定义 / 谁调用了 Y / 列出 Z 的所有使用处" Read, Grep, Glob, Bash haiku
cavecrew-builder 外科手术式编辑(1-2 个文件) 范围明确、≤2 个文件的小改;3+ 文件直接拒绝 Read, Edit, Write, Grep, Glob 无(用 API 会话默认)
cavecrew-reviewer diff / 文件审查 一行一个发现(finding),带严重度标记 Read, Grep, Bash haiku

三个子代理的定义文件分别是 agents/cavecrew-investigator.mdagents/cavecrew-builder.mdagents/cavecrew-reviewer.md。它们同样随插件发布在 plugins/caveman/agents/ 目录下,这也是模型覆盖机制可以 patch 的"安装副本"所在。

investigator:只读定位器,拒绝给出修改建议

agents/cavecrew-investigator.md 的 prompt 可以看到它的硬约束:

  • 只定位、只报告、然后停("Locate. Report. Stop. Never edit, never propose fix.");
  • 输出格式是 path:line — \symbol` — 不超过 6 词的注释,3 行以上时带一行单词分组头(Defs:/Refs:/Callers:/Tests:/Imports:/Sites:),零命中输出 No match.`,最后一行给总数(0 或 1 时省略);
  • 工具策略:符号/字符串用 Grep,路径用 GlobRead 只读特定行范围,更快时才用 Bashgit log -S / git grep / find
  • 被要求修改代码时固定拒绝:Read-only. Spawn cavecrew-builder.

文档中还给出了一个真实形态的示例返回:

Defs:
- hooks/caveman-config.js:81 — `safeWriteFlag` — atomic write w/ O_NOFOLLOW
- hooks/caveman-config.js:160 — `readFlag` — paired reader
Callers:
- hooks/caveman-mode-tracker.js:33,87
- hooks/caveman-activate.js:40
Tests:
- tests/test_symlink_flag.js — 12 cases
2 defs, 3 callers, 1 test file.

注意其"路径优先、行号随行、符号加反引号"的格式约定——skills/cavecrew/SKILL.md 明确说明该输出可以用 path:\d+ 正则安全地 grep 处理。

builder:1-2 文件外科手术,3+ 文件硬性拒绝

agents/cavecrew-builder.md 的约束值得逐条看,因为它定义了"什么算小改":

  • 范围:1 个文件理想,2 个可以,3+ 个直接拒绝;只改已有文件(用户明确要求才建新文件);不加新抽象、不做顺手重构、不加注释;
  • 无 Bash:不能执行 shell、不能 push、不能删除——这是安全边界;
  • 工作流固定四步Read 目标(绝不盲改)→ Edit 最小可用 diff → 重新 Read 验证 → 返回回执(receipt);
  • 回执格式<path:line-range> — <≤10 词的变更说明>. 加一行 verified: re-read OK | mismatch @ path:line。"diff 是制品,回执是证明",不返回探索过程;
  • 四类终止性拒绝行(首词即终止信号,主线程可据此分派):
    • too-big. split: <n one-line tasks>.(超范围)
    • needs-confirm. op: <command>.(需要破坏性操作)
    • ambiguous. ask: <one question>.(规格含糊)
    • regressed. revert path:line. cause: <fragment>.(改后测试挂且无法在范围内修复)

reviewer:一行一个发现,只报问题不吹捧

agents/cavecrew-reviewer.md 的输出契约是最结构化的一位,四个严重度等级:

Emoji 等级 使用场景
🔴 bug 错误输出、崩溃、安全漏洞、数据丢失
🟡 risk 边界情况、竞态、泄漏、性能悬崖、缺失防护
🔵 nit 风格、命名、微性能——仅当用户要求"thorough"时输出
question 判断前需要作者意图

输出格式为 path:line: <emoji> <severity>: <问题>. <修法>.,末尾一行 totals: N🔴 N🟡 N🔵 N❓,零发现输出 No issues.,发现按"文件 → 行号升序"排列。边界约束:只审眼前之物(不做"顺便我们也改改这个")、不提大重构建议、上下文不足时追加 (see L<n> in <file>) 而不是猜、格式类小问题除非改变语义否则跳过。Bash 只允许用于 git diff / git log -p / git show,不允许任何变更型命令。

决策矩阵:cavecrew vs 原生工具 vs 主线程

这是本技能最核心的部分。完整的"任务 → 该用什么"决策表(继承自 skills/cavecrew/SKILL.md):

任务 用什么
"X 在哪定义 / 谁调用 Y / 列出 Z 的使用处" cavecrew-investigator
同上,但还想要建议/架构评论 Explore(vanilla)
外科手术式编辑,≤2 文件,范围明确 cavecrew-builder
新功能 / 3+ 文件 / 横切式重构 主线程或 feature-dev:code-architect
审查 diff、分支或文件的 bug cavecrew-reviewer
带理由和替代方案的深度代码审查 Code Reviewer(vanilla)
你心里已有答案的一句话问题 主线程,不派子代理

文档给出的经验法则是:如果你希望子代理的输出用 1/3 的 token 装下,选 cavecrew;如果你希望得到散文式的解释,选原生工具。

为什么值得做:主上下文是预算

skills/cavecrew/SKILL.md 解释了这件事的动机:子代理的工具结果会被原样注入主上下文。一个返回 2k token 散文的 vanilla Explore,每次调用都消耗主上下文预算 2k token;同样一条发现,cavecrew-investigator 约返回 700 token。文档举的算例是:一次会话里 20 次委派,这决定了上下文是提前耗尽还是能跑完任务。这是"为什么用压缩输出"的第一性原理,而不是玄学。

链式调用模式

README 与 SKILL 文档给出三种典型链路:

定位 → 修复 → 验证(最常用)

  1. cavecrew-investigator 返回位置清单(path:line、符号、注释);
  2. 主线程挑 1-2 个位置,把路径交给 cavecrew-builder
  3. cavecrew-reviewer 审查产出的 diff。

并行侦察(investigation 范围广时):在一条消息里同时派 2-3 个 cavecrew-investigator,从不同角度切入(defs / callers / tests),结果在主线程聚合。

单点编辑(位置已知时):跳过 investigator,直接把精确的 path:line 交给 cavecrew-builder

不该做的事(SKILL 文档的 "What NOT to do" 部分,值得当 checklist 用):

  • 还不知道文件在哪就用 cavecrew-builder——先派 investigator,否则主线程要在传上下文上烧 token;
  • 为 5 文件重构链 investigator → builder——builder 会返回 too-big.,白烧一个回合;
  • cavecrew-reviewer 要"总体反馈"——它只返回 findings,没有架构观点,要那种请用 Code Reviewer
  • 期待散文。cavecrew 输出是结构化的,有时简短到近乎密码,给人直接看时需要转述。

Auto-clarity(继承自 caveman 核心):三个子代理在遇到安全警告、不可逆操作确认、以及碎片化表达可能被误读的场合时,会自动切回正常英文,之后再切回 caveman 风格。

模型覆盖机制:CAVECREW_*_MODEL 环境变量

README 的"Model overrides"一节说明:cavecrew-reviewercavecrew-investigator 的 frontmatter 里默认钉着 model: haikucavecrew-builder 没有 model: 行,跟随 API 会话默认。启动 Claude Code 之前在 shell 里设置环境变量即可逐代理覆盖:

环境变量 作用于
CAVECREW_REVIEWER_MODEL cavecrew-reviewer
CAVECREW_BUILDER_MODEL cavecrew-builder
CAVECREW_INVESTIGATOR_MODEL cavecrew-investigator

示例——只把 reviewer 升到 sonnet,其余保持默认:

export CAVECREW_REVIEWER_MODEL=sonnet

取值就是 Claude Code agent frontmatter 里能用的模型名字符串(如 haikusonnetopus)。

底层实现:只 patch model: 一行

这套覆盖机制由 src/hooks/cavecrew-model-overrides.js 实现,并在 src/hooks/caveman-activate.js 的 SessionStart 钩子早期被以 best-effort 方式调用(任何异常都被吞掉,绝不阻塞会话启动):

// Apply per-agent model overrides from env vars before emitting rules.
// Best-effort: any error is swallowed so SessionStart is never blocked.
try {
  const { applyOverrides, resolvePluginRoot } = require('./cavecrew-model-overrides');
  applyOverrides(resolvePluginRoot(__dirname));
} catch (e) {}

从源码可以确认 README 中每一条行为声明的具体落点:

  • "只 patch model: 行,prompt 正文不动":核心函数 patchFrontmatterModelsrc/hooks/cavecrew-model-overrides.js)只操作 frontmatter 内的 model: 行——有则原位替换,没有则在 tools: 行之后插入(无 tools: 行时插到收尾 --- 之前)。正文(body)原样保留,所以上游更新 prompt 后覆盖仍然有效;
  • "空变量什么都不做":空串、纯空白直接跳过;含换行或控制字符(\x00-\x1f\x7f)的值整体被拒绝——这是对 YAML 注入的防御;
  • "仅插件安装才有可 patch 的本地文件"resolvePluginRootsrc/hooks/cavecrew-model-overrides.js)优先读 CLAUDE_PLUGIN_ROOT,否则探测 hooks/ 目录的上两级或上一级哪个含 agents/ 目录;找不到时静默 no-op;
  • 一个源码注释里的重要细节insideGitWorkTreesrc/hooks/cavecrew-model-overrides.js)会向上最多走 64 层查找 .git。这是因为当钩子从源码 checkout(git 仓库克隆)里运行时,plugin root 解析到的是仓库根目录,若不拦截,每次 SessionStart 都会重写被 git 跟踪的 agents/*.md、弄脏工作树。因此:在 git 仓库内运行时覆盖机制自动禁用,只在已安装的插件目录($CLAUDE_CONFIG_DIR 下,上方无 .git)中生效。这也解释了 README 中"patch 持久到插件更新或重装为止"——它改的是安装副本的文件内容;
  • CRLF 处理:patch 时保留原 frontmatter 的换行符风格(检测 \r\n 则用 CRLF 插入),避免在 Windows 上产生混合换行。

这套机制的完整测试在 tests/test_cavecrew_model_overrides.js,覆盖约 25 个用例,包括:替换/插入 model: 行、正文保留、空值与控制字符拒绝、CRLF 一致性、缺失文件静默、以及"git work tree 内不改动被跟踪源码"的守卫测试。

适用前提与限制小结

  1. 前提:cavecrew 是 Claude Code 生态下的技能与子代理预设,三个 agent 定义依赖 Claude Code 的 subagent 机制与 frontmatter(tools: / model:)约定;模型覆盖仅对插件安装生效,对源码仓库 checkout 自动失效;
  2. 压缩是"每次委派省预算",不是"每次省固定比例":SKILL 文档中的 2k → ~700 token 是一个量级示例,实际收益随任务与委派次数变化;
  3. builder 的能力边界由工具集决定:它拿不到 Bash,所以不能跑测试、不能提交、不能删文件——需要这类操作的场景要么走 needs-confirm. 终止行,要么回到主线程;
  4. 输出面向机器聚合:cavecrew 的设计假设结果由主线程消费(可 grep、可按终止首词分派),人类读者需要转述。

相关文档:skills/cavecrew/README.mdskills/cavecrew/SKILL.md 及仓库总览 README.md

登录后查看全文
热门项目推荐
相关项目推荐