CachedMicrocompact机制解析
CachedMicrocompact机制解析
1. 要回答的问题
这份文档只回答一个问题:
为什么 cachedMicrocompact 不改本地消息内容,也能让发给模型的有效上下文变短。
2. 核心结论
cachedMicrocompact 不是在本地 transcript 上删内容,而是在发 API 请求时:
- 给旧
tool_result标上cache_reference - 再插入一段
cache_edits - 告诉服务端缓存层“把这些旧工具结果从有效上下文里删除”
所以:
- 本地
messages可以保持完整 - API 侧真正用于推理的缓存上下文却已经被裁短
3. 它发生在两层
3.1 第一层:Microcompact 层只“登记要删谁”
在 src/services/compact/microCompact.ts 里,cachedMicrocompactPath() 做的事情主要是:
- 识别哪些旧工具结果可以删
- 生成
cache_editsblock - 放进
pendingCacheEdits - 返回时保持
messages原样不动
这一步的重点是:
只登记删除计划,不直接改本地消息。
3.2 第二层:API 层把删除计划真正塞进请求
在 src/services/api/claude.ts 里,请求构造阶段会:
consumePendingCacheEdits()getPinnedCacheEdits()- 调用
addCacheBreakpoints(...)
真正的“缓存编辑版消息”是在这里才被拼出来的。
4. addCacheBreakpoints 做了什么
addCacheBreakpoints(...) 是理解这套机制的关键函数。
它先把本地 messages 转成 API 侧 MessageParam[],然后在这个 API 专用视图上做三件事:
4.1 重新插入历史上已经 pin 住的 cache_edits
这些 edits 不是发一次就算了,而是后续请求也要在原位置重发。
原因是:
- 服务端缓存前缀是按位置和结构理解的
- 如果某个删除指令之后不再重发,缓存语义就会发生漂移
4.2 把新的 cache_edits 插进最后一个 user message
cache_edits 的形态大概是:
{
type: 'cache_edits',
edits: [
{ type: 'delete', cache_reference: 'some_tool_use_id' }
]
}它不是单独的请求顶层字段,而是被插进消息内容数组里的一个 block。
4.3 给缓存前缀里的旧 tool_result 补上 cache_reference
只有当旧工具结果先有了 cache_reference,后面的 cache_edits 才能指向它们并要求删除。
所以这两步是配套的:
- 先命名
- 再删除
5. 为什么这样就等于“删上下文”
因为启用 cache editing 后,服务端不再只是把 prompt 当成纯文本重新算一遍。
它会理解:
- 哪些块是缓存前缀里可引用的内容
- 哪些
cache_reference这次请求要求删除
于是本次 API 请求的语义就变成:
- 前面的大段缓存前缀仍然沿用
- 但其中某些旧
tool_result已经被显式标记为删除
所以模型真正看到的有效上下文,就比本地 messages 更短。
6. 为什么不直接改本地 transcript
这套设计的优势很明显:
6.1 UI 和恢复更稳定
本地 transcript 还保留完整工具输出,便于:
- UI 展示
- 会话恢复
- 调试与回放
6.2 更好地保留 prompt cache
如果直接改本地消息内容,就可能导致:
- 缓存前缀断裂
- 后续整段重写
- 缓存命中下降
而 cache_edits 的目标正是:
尽量在保留缓存前缀的前提下删掉无用旧内容。
6.3 本地视图和 API 视图可以分离
这其实是一个很典型的设计:
- 本地层保留“完整历史”
- API 层构造“最优发送视图”
cachedMicrocompact 走的就是这条路线。
7. 为什么还要 pin
新生成的 cache_edits 插进请求之后,还会被 pin 到某个 user message 位置。
后续每次请求时:
- 历史 pinned edits 会先被重新插回
- 新 edits 再继续追加
这意味着 cache_edits 不是一次性临时补丁,而是:
缓存语义的一部分,需要在后续请求里维持位置稳定。
8. 它和 time-based microcompact 的根本差异
两者最本质的区别是:
8.1 Time-Based Microcompact
- 直接改本地消息内容
- 把旧
tool_result.content替换成占位文本 - 是“内容级改写”
8.2 Cached Microcompact
- 不改本地消息内容
- 只改 API 请求里的缓存编辑语义
- 是“发送视图级改写”
9. 一句话总结
cachedMicrocompact 的关键不在于“本地删了什么”,而在于:
它把本地完整 transcript 转成了一份带 cache_reference + cache_edits 的 API 请求视图,让服务端缓存层替你删掉旧工具结果。