whale — 本课题摘录
读了哪几篇: 01-turn-loop(回合循环)、02-prompt-cache-memory(提示词缓存的记忆布局)、06-provider-and-extensibility(扩展面)。
其余三篇(工具与编辑、安全与权限、子代理与工作流)本轮没读。
这一家是"缓存"这条线最硬的一份材料——它给了一个可核对的数字:约 98% 命中。
它对本课题回答了什么
决定一:先把"前缀缓存"这件事说清楚
它的解释是本课题里最清楚的一份:
你付的钱几乎和输入 token 数成正比。而编码 agent 的输 入里每一轮都在重复同一批东西: 一大段系统提示、全部工具的格式说明、以及到目前为止的所有对话。 第 20 轮请求里,前 19 轮的内容一字没变地又发了一遍。
厂商的优化规则很简单:如果这次请求的开头一段和上次逐字节完全相同,这部分按大幅折扣计费(约 1/10)。
关键词是"逐字节、从头开始"。缓存匹配的是最长公共前缀:从第 0 个字节往后比,一比到第一个不同的字节就停,后面全算未命中。 (依据:Agent 库 · whale · 招牌:提示词缓存的记忆布局(~98% 命中) —— 前缀缓存匹配的是「最长公共前缀」——从第 0 字节比到第一个不同处就停、后面全算未命中;只要在前缀中间改一个字符,它后面的所有内容哪怕原样没动也会掉出缓存按全价重算)
它的磁带比喻很好:厂商记得你上次录到哪。这次只要开头对得上就不用重录;一旦某处对不上,从那个点往后全部得重录。所以省钱的唯一办法是——别去动前面已经录好的部分,只在末尾接着录。
决定一:三段式内存布局 —— 每一段有各自的"可变性纪律"
| 段 | 内容 | 纪律 | 结果 |
|---|---|---|---|
| 不可变前缀 | 系统提示里稳定的部分 | 一经建立,字节永不重写 | 永远命中 |
| 只追加历史 | 全部对话消息 | 只在末尾追加,从不改中段 | 已发过的字节不动 → 继续命中 |
| 易变便签 | 本轮的推理、工具参数计数等 | 每轮清空 | 根本不进请求,不污染前缀 |
(依据:Agent 库 · whale · 招牌:提示词缓存的记忆布局(~98% 命中) —— 内存布局切成三段各有可变性纪律——ImmutablePrefix 字节永不重写、AppendOnlyLog 只在末尾追加从不改中段、VolatileScratch 每轮清空且根本不进请求;结果是前缀缓存命中约 98%)
招牌效果:第 N 轮相对第 N−1 轮,变的只有末尾新追加的那几条消息;前面成千上万 token 全部逐字节相同 → 命中约 98%。
第三段"易变便签根本不进请求"这一条特别值得记。 我们的循环里会产生一堆"本轮临时状态"(重试次数、耗时、界面用的进度), 一旦它们混进发给模型的内容,前缀就每轮都变。 必须从一开始就把它们和"要发出去的"分开存。
请求体的实际分段:
① 不可变前缀(合并成一条系统消息) ← 字节锁死,用指纹守护
② 运行时块(工作区路径 / 系统 / 技能 / 项目记忆)
← 标成"动态",但一个会话内通常也不变 → 也命中
③ 只追加历史 ← 头部是老消息(命中),尾部是本轮新增(未命中)
"用指纹守护前缀"是个可抄的工程做法:不是靠约定"大家别改",而是算一个指纹,一改就能发现。
决定一补充:工具太多时按需检索,不一次性塞进上下文
上千个外部工具靠一个"目录检索"的开关——不用把它们一次性通电。 (依据:Agent 库 · whale · DeepSeek Provider 与扩展面(MCP/Skills/Plugins) —— 1000+ MCP 工具靠 tool_search 按需检索而不塞进上下文,MCP 这个扩展口带一个「目录检索开关」)
这是"工具太多怎么办"的第四种做法: cherry-studio 折叠成三把元工具、qwen-code 按需塞 schema、openspace 级联筛选、whale 是一个检索开关。 四家做法不同,但共识很清楚:工具一多,全量塞进上下文就是错的。
决定四:回合循环本身
一个用户回合 = 一段 for 循环:每轮流式请求模型、执行它要的工具、把结果喂回,直到模型不再要工具或撞上某道终止闸。 (依据:Agent 库 · whale · 核心回合循环:从输入到工具执行的主线 —— 一个用户回合是一段 for 循环——每轮流式请求模型、执行工具、把结果喂回,直到模型不再要工具或撞上某道终止闸;循环本身只管控制流,记忆布局与工具执行各由别的模块负责)
关键的一句:循环本身只管控制流,记忆布局和工具执行各由别的模块负责。
这跟 kimi-code 的"循环不碰会话/传输/权限/压缩"、webwright 的"循环体只有一行"是同一主张。 本课题里已经有四家独立说了同一件事:循环要薄。
它没回答什么
- 不用原生工具调用怎么办——它对着一家厂商。
- 历史超长了怎么办——只追加不改中段的代价就是它会一直长;这三篇没讲上限之后怎么办。
- 停止条件的细节——只说"撞上某道终止闸",没展开。
坑与代价
- "只追加、不改中段"和"要压缩历史"是直接冲突的。
- whale 选了前者(省钱,但历史会一直长);
- codex / opencode 选了后者(能长跑,但每次压缩都炸缓存)。
判断(无锚): headroom 的"只压活区"是这两者的调和方案——不动前段、只压最新那条。这三家合起来就是这条线的完整谱系。 如果错,会错在: 如果模型窗口足够大、任务足够短,那根本轮不到压缩,whale 的做法就是最优;这个取舍只在"长任务 + 有限窗口"时才存在。
- 98% 这个数字是它自己的遥测。 依赖于它的使用形态(编码 agent、长会话、工具定义稳定)。我们的场景不同,数字未必可比。
但**"三段布局"这个做法是可迁移的,跟具体数字无关。**
- 它绑定一家厂商。 前缀缓存的具体规则、计价、TTL 各家不同,换厂商这套优化要重新校准。