首页
/ caveman caveman-learn skill:把 `caveman learn` 的 token 审计报告变成逐条确认的降成本编辑工作流

caveman caveman-learn skill:把 `caveman learn` 的 token 审计报告变成逐条确认的降成本编辑工作流

2026-09-06 16:17:43作者:董灵辛Dennis

本文围绕 skills/caveman-learn/SKILL.md 展开:它是 caveman 项目中 "测量—编辑" 闭环的编辑半环,负责读取 caveman learn 生成的 token 消耗审计计划,按 sink 类别逐条征求用户同意后执行修复,并用净 token 为负的门控(net-token-negative gate)保证每一处修改都真实降低了 tokens/turn。读完本文,你将掌握 Cave Score 与 ranked token sinks 的读法、四类 sink(REDUCIBLE / RECURRING_CONTEXT / SKILL_DISTILLATION / LOAD_BEARING)各自的同意循环与验证门,以及 caveman mem(cavemem)卸载上下文的定位符校验、召回成本核算和回滚路径。

caveman learn report 报告界面示意:Cave Score 与 token sinks 排名

一、定位:caveman learn 的测量端与编辑端分工

SKILL.md 开宗明义:"caveman learn" 命令负责测量 agent 的 token 花在了哪里,而 caveman-learn 这个 skill 是带同意门(consent-gated)的编辑半环,把测量结果转化为真实文件修改——且用户要逐条批准。它同时立下两条纪律:绝不宣称自己没测量过的节省("you never claim a saving you have not measured"),也绝不把 agent 变笨("you never make the agent dumber")。

这个分工在 skills/caveman-learn/CLAUDE.md 中被进一步明确为"绑定边界"(binding boundary):

  • skill 借助 agent 自身的文件工具,是唯一会修改用户配置的东西;
  • caveman learn apply 保持只读——它只是"实体化候选方案"(materializes candidates),并不真正动文件;
  • caveman mem * 系列是纯粹的机械存储操作。

skills/caveman-learn/README.md 看,安装方式也体现了它是"给 agent 加载的行为规范"而非独立程序:

caveman skills install caveman-learn            # 装入当前仓库的 .claude/skills
caveman skills install caveman-learn --user      # 装入所有仓库(~/.claude/skills)
caveman skills install caveman-learn --agent codex

CLAUDE.md 还说明了分发的工程细节:CLI(packages/cli/src/index.ts)内嵌了一份字节级相同的副本(CAVEMAN_LEARN_SKILL_MD),因为发布的 CLI 不带旁路资源文件;packages/cli/tests/skills.runtime.mjs 断言内嵌副本与规范文件一致(drift guard),因此修改 SKILL.md 必须同步修改该常量。

二、读懂新 token sinks:先弄清每类"钱坑"在说什么

SKILL.md 的前半部分是一份"新 sink 词典",教 agent 如何正确理解报告中会出现的、容易误读的新指标。这些语义细节是正确解读报告的前提:

Sink 含义 解读纪律
cache_efficiency 一百万输入 token 在缓存复用后的实际成本 它是一个"费率"(rate),不是"流量"(volume),是其他 sink 的计价基准,绝不能把它加进任何总量
tool_output_portfolio 主导上下文的工具调用形态,按权重排名 按排名查看即可
session_outcomes 扫描窗口内"没有 commit"的会话占 token 的比例 相关性数据。只能作为观察呈现并朗读其 caveat——"没有 commit 的会话不等于浪费的会话"
subagent_spend 上下文在子 agent 中消耗的比例 仅可见性(visibility only)。不得把它转化为"少开子 agent"的建议
procedure_repeat:* 蒸馏候选(distillation candidate) 走 SKILL_DISTILLATION 流程(见第五节)

其中关于行为类 sink 的表述约束值得注意:它们是"观察"(observations),数字按事实呈现,建议用弱化语气("present their numbers as fact and their suggestion softly"),绝不能把行为发现变成命令式措辞。这一点不是风格建议,而是被测试固化的:skills/caveman-learn/tests/skill-file.test.mjs 有一个测试遍历禁用词表("you don't need"、"you over-use"、"you overuse" 以及 $ 符号),断言 SKILL.md 中不存在任何命令式指责或美元符号。

三、第一步:读取计划(read the plan)

编辑循环的起点固定为一条命令:

caveman learn report --json

要求解析 caveman.learn.v1 JSON,展示三样东西:Cave Score 及其四个分量排名后的 token sinks,以及每个 sink 的类别(class)与依据(basis)。

3.1 spend 块的呈现规则

如果计划里携带 spend 块,必须把它放在最前面讲:扫描窗口花了多少,以及缓存复用后的有效输入费率(effective_input_multiplier)。原文档给出了五条"讲钱时不可违背"的规则:

  1. Spend 是窗口花掉的成本,绝不是"某个修复能收回的钱"
  2. 必须说明它覆盖的窗口;永远不要把窗口金额乘算成月、年或 run rate
  3. unpriced 非空,要说明总额只是下限(floor),并点名被排除在外的模型;
  4. 必须加上订阅说明:在 Max/Plus/Advanced 计划上边际成本为零,这个数字是 token 的 API 等价价值,不是花掉的钱;
  5. 任何一项都不得称为 verified(已验证)

3.2 提案前的模拟:caveman learn simulate

在提出修复提案之前,可以运行:

caveman learn simulate <sink_id>

原文档对其定位非常克制:它只能作为"扫描历史之上的规模感"(scale over scanned history)展示——对扫描历史求和,从不向前投影tests/skill-file.test.mjs 同样用 sums over scanned history and never projects forward 的正则固化了这一承诺。

四、REDUCIBLE:对"可缩减"内容执行带门控的裁剪

适用于重载的 CLAUDE.md、从未被调用的 skill 等"减掉就赚"的场景。原文档给出的完整操作流程是:

# 1. 实体化候选(不编辑任何东西)
caveman learn apply <sink_id> --dry-run

随后依次:

  1. 提出具体 diff,并展示修改前后的 tokens/turn(before -> after);
  2. 询问用户 yes 或 no。用户确认后,由 agent 用自己的文件工具执行编辑;
  3. 重跑 caveman learn report --json(或对触碰的文件重新计数)以确认缩减。这就是净 token 为负的门(net-token-negative gate):如果 after 没有低于 before,回滚并报告。任何不降低 tokens/turn 的编辑都不得保留。

README 还补充了这条路径的闭环:一次编辑在"应用 + 复测门通过"之后,skill 会调用 caveman learn applied <sink_id>,把 sink、修复类别、应用时间与 before 值记入 caveman 自己的结果存储(outcome store);后续扫描会对比修复后会话,报告 improvedunchangedregressedinsufficient_data 四种纵向判决。这份账本本身不编辑用户或仓库配置。

五、RECURRING_CONTEXT 与 cavemem_offload:把反复重建的上下文卸载到 cavemem

针对"每个会话都重新建立一遍"的重块(fix kind 为 cavemem_offload),目标是把它移入 cavemem,使其按需紧凑召回而不是每轮重贴。这是原文档中最长、约束最密的一段,核心是"定位符"(locator)机制:候选只携带定位符,绝不携带块本体

完整流程(每条都有对应命令):

1. 生成候选并只取定位符

caveman learn apply <sink_id>

命令把候选 JSON 写到 ~/.caveman/candidates/。agent 只取三样东西:定位符(locator)、数字、建议的指针文本(proposed pointer text)。原文档明确警告:"Do not trust any body from the candidate; there is none."

2. 本地自行重读真实块并校验哈希

打开定位符中的 rel_path,跳到 jsonl_line,用同样的方式对该 turn 重新分段(按空行切分、保持顺序),取 block_index,然后验证原始块的 sha256 等于定位符中的 content_sha256。若不匹配,说明文件自扫描以来已变化——放弃这一项(abort this item)。

3. 存入 cavemem

caveman mem remember -- "<the real block>"

注意 -- 的作用:它终止选项解析,因此以 --- 规则开头的块会被逐字存储而不是被当作 flag 解析。记下返回的 id。

从源码侧印证,cavemem CLI 的子命令面与 skill 使用的完全对应。mem/cmd/cavemem/main.go 中的用法字符串为:

cavemem [mcp] | remember <text>|--stdin | recall <query> [limit] [token_budget] | supersede <id> <text> | history <id> | forget <id> | recover <handle>

其中 recover <handle> 正是 skill 里指针文本所承诺的"字节级精确原文"恢复路径;MCP 侧对应工具为 cavemem_remember / cavemem_recall / cavemem_forget / cavemem_recover 等(见同文件的工具定义与描述:"Remember 幂等:相同文本记两次只存一份"、"recall 命中附带 recovery_handle")。

4. 诚实测量门

  • before = 该块的 tokens/turn(它每轮都加载);
  • after = 指针的 tokens/turn + 召回成本;
  • 召回成本必须实测:运行 caveman mem recall "<topic>",读命中结果上的 tokens_added
  • 若 after 不低于 before:运行 caveman mem forget <id>源文件保持原样,停止。

5. 修剪源文件、写入指针

把块从它的 CLAUDE.md / AGENTS.md 章节中移除(若是用户手动粘贴的内容,则告诉用户别再粘贴什么),在原位置写入候选建议的指针文本。指针必须命名召回路径:caveman mem recall "<topic>" 取紧凑形式,caveman mem recover <handle> 取字节级精确原文。

6. 绝不让 agent 变笨的守护(the dumber-guard)

收尾前必须确认两件事都成立:caveman mem recall "<topic>" 返回命中,且指针已就位。若召回无果或指针未写,回滚——caveman mem forget <id> 并恢复源文件。原文档把这条守护抬到了原则高度:"移除上下文却没有可用的召回路径,是这条守护要阻断的那一种失败。"随后重新测量,报告确认的缩减量与召回路径。

六、SKILL_DISTILLATION:为 procedure_repeat 写 skill,但必须用 holdout 实验结算

procedure_repeat sink 指向"用户在多个会话中重复的同一串工具步骤"。把它写成 skill 可能阻止 agent 反复重新推导它——但 skill 会每个会话都加载进前缀,而只有命中该模式的会话才产生回报。原文档指出这与报告所惩罚的 dead_load sink 同构,因此用不同的方式结算,不允许走捷径:

  • 绝不把它过净 token 为负门。那个门只重数文件,看不见"成本与收益落在不同地方"这件事;
  • 先展示候选:那些步骤、它在多少个会话中复现、这些 span 消耗了多少 token,并直言"回报未获证明"(payback is unproven);
  • 若用户想要,写 skill 的同口气就启动 holdout 实验
caveman learn experiment start <label> --sink <sink_id> --fix-kind skill_distillation

并向用户说明机制:开着它跑一段,然后执行 caveman learn experiment arm <label> off,在无它的情况下跑一段可比的时长。每个 arm 至少需要 5 个会话,在此之前不存在任何判决;

  • caveman learn experiment report <label> 读结果:
    • insufficient_data 判决意味着"继续跑"——绝不能包装成小胜;
    • regressed 判决意味着删掉 skill,并且直接说出来;
  • 实验框架比较的是每会话中位数 token。若它标记 on-arm 每轮工具错误更多,必须把这个放在最前面讲:"一个更便宜但更容易失败的会话不是节省。"

七、LOAD_BEARING 与 savings 账本:证据分级

LOAD_BEARING 类别只有一条规则:永不触碰。它出现在报告中只是为了让分数保持诚实。

当需要呈现已实现修复的回报时(caveman learn savings),账本按"如何测量"分组。原文档强调:分组不是装饰,它是论断的强度——

证据层级 含义
deterministic_remeasure 被编辑的文件被重新计数。本地最强档
controlled_holdout 在同一台机器上开着 vs 关着测得
counterfactual_replay 真实历史在应用变更后重跑
interrupted_time_series 修复前会话 vs 修复后会话,无对照臂

三条绑定规则:

  1. 永远不跨档求和,永远不呈现单一混合的节省头条——重数过的文件和前后中位数不是同一种证据;
  2. 呈现某行为"赢"时,必须朗读该行的 confounders——它们是常设告诫而非小字注释,恰恰是为好消息场景而设;
  3. 朗读 attribution.provenanceintext 表示文件仍带着我们提议的编辑;changed_since 表示有人在它之上改过,delta 的一部分不属于我们——必须说明;target_missing 表示 delta 根本无法挂到该修复上。changed_sincetarget_missing 的行绝不能作为 caveman 成果呈现

还有一条设计性约束:回归(regression)按设计不携带美元数字。呈现它时带着判决并给出回滚路径;不软化,也不省略。

八、绑定规则(Binding rules)与测试固化

SKILL.md 末尾的绑定规则是整个 skill 的宪法,逐条对应测试断言:

  • 逐编辑同意(Consent per edit)。不存在隐藏单条 diff 的 "apply all";
  • 编辑应用复测门通过之后,运行 caveman learn applied <sink_id>;后续 learn 运行据此报告纵向判决(improved / unchanged / regressed / insufficient_data);regressed 要如实呈现并给出该编辑的精确回滚路径;
  • 每个编辑都可逆:准确报告改了什么。卸载(offload)的回滚 = caveman mem forget <id> + 恢复被修剪的源;
  • inferred only:绝不把本地数字称为 verified;货币(currency)只在报告自身携带它的位置(spend 块、已定价的 savings 行)允许出现,且必须完整保留该块自身的框定——窗口限定、绝不投影、绝不称 verified;
  • 分析器(caveman learn)是只读的。skill 是唯一的写入者,而且只在 yes 之后。

这些规则不是空话:skills/caveman-learn/tests/skill-file.test.mjs 对规范文件本身做了五组断言——frontmatter 合法(name: caveman-learn + description);四条关键措辞(net-token-negative gate、never make the agent dumber、consent per edit、reversible、inferred only)全部在场;cavemem_offload 机制三要素(content_sha256 校验、caveman mem recover 恢复路径)齐备;纵向闭环(caveman learn applied <sink_id>、四种判决名、"Present regressed honestly and offer the exact revert path"、simulate 的历史求和承诺)逐一核对;外加禁用命令式措辞与占位符(TODO/XXX 等)扫描。可以说,这份测试就是 skill 的"诚实性 lint"。

九、CLI 侧实现印证

从源码结构看,caveman learn 的本地命令面由 TypeScript CLI 转发给 Go 分析器(proxy)执行。packages/cli/src/index.tshelp()learn 子命令有专门的 usage 分发;在 learn 命令的 porcelain 实现处(同文件约 L13787–L13884 区域)可以看到 learn scan --write-reportlearn report --jsonproxyExecLearn 代理执行、scan / reportproxyPassthrough 的模式,印证了 SKILL.md 中 caveman learn report --json 返回结构化 JSON、apply 只产出候选文件这两条陈述。分析器本体的 Go 实现位于 proxy/internal/store/learn.golearn_digest.golearn_types.golearn_simulate.go 等),对应报告、摘要、类型定义与模拟求和;cavemem 存储端则在 mem/(BM25 召回、store.go),与 caveman mem recall 命中上读 tokens_added 的用法相衔接。

十、小结

caveman-learn skill 的价值不在"省了多少",而在一套可审计的方法论:

  1. 测量与编辑严格分离——分析器只读,skill 是唯一写入者,且每写一处都要先拿到 yes;
  2. 每类 sink 有各自的门——REDUCIBLE 过净 token 为负的重数门,RECURRING_CONTEXT 过 sha256 定位符校验 + 实测召回成本 + 召回可用守护,SKILL_DISTILLATION 过 holdout 对照而非文件重数;
  3. 证据分级呈现——savings 按测量方式分四档,不跨档求和,provenance 与 confounders 必须随结论一起朗读;
  4. 一切可逆——每个编辑都携带精确的回滚路径,卸载失败则 forget + 恢复源。

配合 skills/caveman-learn/README.md 的安装命令与 docs/technical/cli-reference.md 中的 CLI 参考,开发者可以先跑 caveman learn report --json 看懂自己的 token 流向,再安装本 skill,让 agent 在逐条同意下把报告里最贵的 sink 变成可验证的缩减。

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