caveman cavecrew 技能实战:如何基于压缩输出的子代理完成代码定位、编辑与审查
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.md、agents/cavecrew-builder.md 和 agents/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,路径用Glob,Read只读特定行范围,更快时才用Bash跑git 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 文档给出三种典型链路:
定位 → 修复 → 验证(最常用)
cavecrew-investigator返回位置清单(path:line、符号、注释);- 主线程挑 1-2 个位置,把路径交给
cavecrew-builder; 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-reviewer 和 cavecrew-investigator 的 frontmatter 里默认钉着 model: haiku;cavecrew-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 里能用的模型名字符串(如 haiku、sonnet、opus)。
底层实现:只 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 正文不动":核心函数patchFrontmatterModel(src/hooks/cavecrew-model-overrides.js)只操作 frontmatter 内的model:行——有则原位替换,没有则在tools:行之后插入(无tools:行时插到收尾---之前)。正文(body)原样保留,所以上游更新 prompt 后覆盖仍然有效; - "空变量什么都不做":空串、纯空白直接跳过;含换行或控制字符(
\x00-\x1f\x7f)的值整体被拒绝——这是对 YAML 注入的防御; - "仅插件安装才有可 patch 的本地文件":
resolvePluginRoot(src/hooks/cavecrew-model-overrides.js)优先读CLAUDE_PLUGIN_ROOT,否则探测hooks/目录的上两级或上一级哪个含agents/目录;找不到时静默 no-op; - 一个源码注释里的重要细节:
insideGitWorkTree(src/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 内不改动被跟踪源码"的守卫测试。
适用前提与限制小结
- 前提:cavecrew 是 Claude Code 生态下的技能与子代理预设,三个 agent 定义依赖 Claude Code 的 subagent 机制与 frontmatter(
tools:/model:)约定;模型覆盖仅对插件安装生效,对源码仓库 checkout 自动失效; - 压缩是"每次委派省预算",不是"每次省固定比例":SKILL 文档中的 2k → ~700 token 是一个量级示例,实际收益随任务与委派次数变化;
- builder 的能力边界由工具集决定:它拿不到
Bash,所以不能跑测试、不能提交、不能删文件——需要这类操作的场景要么走needs-confirm.终止行,要么回到主线程; - 输出面向机器聚合:cavecrew 的设计假设结果由主线程消费(可 grep、可按终止首词分派),人类读者需要转述。
相关文档:skills/cavecrew/README.md、skills/cavecrew/SKILL.md 及仓库总览 README.md。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0625
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00