08 为什么 Agent 框架天然容易缓存命中率不高
上一节讲 Claude Code,是因为它有文档、有 changelog,也能看到它怎么处理缓存、MCP、compaction 和 subagent。
把视角换到 OpenCode、OpenClaw、Hermes 这类框架,问题会更普遍。它们不一定有 Claude Code 那么明确的缓存优化记录,但它们面对的工程约束差不多。
Agent 框架要做的事情太多了。
它要接模型,要接工具,要读文件,要跑命令,要处理 MCP,还要把项目规则、任务状态、历史消息塞进上下文。对用户来说,只是让 Agent 继续干活;对模型来说,每一轮请求都可能带着一大包上下文。
缓存问题就出在这里。
前面讲过,prompt caching 依赖稳定前缀。可 Agent 框架里,很多内容天生不稳定。当前目录会变,权限状态会变,工具列表会变,任务进度也会变。它们对 Agent 有用,但放得太靠前,就会影响后面的缓存复用。
MCP 会进一步放大这个问题。
一个 MCP server 接进来,可能带来一批工具。模型要调用工具,通常得先看到 tool schema。工具名、参数结构、说明文案,只要有变化,请求前缀就跟着变。
很多时候,用户根本没意识到这些变化。用户只看到 Agent 在读文件、跑测试、查资料,实际请求里已经多了不少工具说明和运行状态。
工具结果也很麻烦。
文件内容、测试日志、网页正文、搜索结果,这些东西都可能很长,而且每次不同。框架如果把它们长期留在历史里,后续请求就会一直带着这些动态内容走。缓存仍然可能命中,但命中条件会更苛刻。
compaction 和 subagent 也会改变成本结构。
compaction 可以把历史压短,省 token;代价是原来的历史被摘要替换,缓存前缀也会变。subagent 可以并行推进任务;代价是每个 subagent 都要有自己的上下文,工具、规则、任务说明都可能重新进入请求。
所以复杂 Agent 工具里的缓存表现,通常没有直连 API 测试那么稳定。
直连 API 做缓存测试,只要保持前缀一致,结果就容易解释。Agent 框架多了一层上下文组织逻辑,工具、状态、历史压缩、多模型兼容都会掺进来。最后账单变贵,不一定是模型没缓存,也可能是框架每轮都在改请求前缀。
这也是 provider-agnostic 框架的取舍。
Claude 有 cache_control 和 breakpoint,OpenAI 有自动前缀匹配和 prompt_cache_key,DeepSeek 有 hit/miss 字段。框架如果要同时兼容它们,就很难为某一家模型做得特别极致。
比较合理的做法,是把稳定内容固定住,把动态内容往后放。项目规则、常用工具说明、任务目标尽量稳定;当前状态、工具结果、临时摘要尽量后置;用不到的工具不要提前塞进上下文。
到这一层,缓存问题已经从模型文档进入框架工程。再往后看中转站,问题会更直接:上游到底有没有命中,usage 字段有没有透传,缓存省下来的成本最后算给了谁。