为什么 Claude + OpenCode 完全没有缓存、费用暴增?
为什么 Claude + OpenCode 完全没有缓存、费用暴增?
很多用户在把 OpenCode 接入 Claude 模型后,会发现一个很反直觉的问题:
同样是写代码、读项目、跑 Agent,Claude Code 的缓存命中率很高,但 OpenCode + Claude 可能几乎没有缓存,账单突然暴涨。
这不是玄学,核心原因是:Claude 的缓存机制、OpenCode 的提示词组织方式、以及 OpenAI 兼容网关的协议转换之间发生了错配。
一句话结论
OpenCode + Claude 费用暴增,通常不是 Claude 模型本身“突然变贵”,而是缓存没有真正生效。
常见原因有三个:
- Claude 需要请求里明确启用
cache_control。 - OpenCode 可能没有正确插入或维护 Claude 缓存断点。
- 如果通过
/v1/chat/completions这类 OpenAI 兼容接口中转 Claude,网关通常无法自动猜出应该在哪里加 Claude 缓存标记。
结果就是:每次请求都把系统提示词、项目上下文、工具说明、历史对话重新按完整输入 Token 计费。
社区观察
Linux.do 相关讨论中,有用户提到:
- OpenCode 的 cache 写入量很低,不足总输入的十分之一。
- Claude Code 的 cache 写入量可以长期保持在较高水平。
- 也有人反馈,即使用 Codex 接入 OpenCode,缓存率也很低,说明问题不只在模型,也可能在工具的上下文组织和缓存适配上。
参考讨论:
- https://linux.do/t/topic/1548049/8
OpenAI 为什么更容易有缓存?
OpenAI 的 Prompt Caching 是自动机制。
只要提示词足够长,并且前缀保持一致,OpenAI 后端会自动尝试复用缓存。开发者通常不需要额外写缓存标记。
你可以在响应日志里看这个字段:
{
"usage": {
"prompt_tokens_details": {
"cached_tokens": 1920
}
}
}
如果 cached_tokens 很高,说明大量输入前缀被缓存复用了。
这也是 GPT-5.5 + Codex 这类组合容易省钱的原因。Codex 通常会把稳定内容放在前面,例如:
- 系统指令
- 工具说明
- 项目规则
- 不变的仓库上下文
然后把动态内容放在后面,例如:
- 用户当前问题
- 本轮工具结果
- 临时文件片段
这正好符合 OpenAI 的缓存规则:稳定前缀越一致,缓存越容易命中。
OpenAI 官方文档也建议把静态内容放在提示词开头,把动态内容放在末尾,并通过 cached_tokens 观察缓存命中情况。
参考:
- https://developers.openai.com/api/docs/guides/prompt-caching
Claude 为什么不一样?
Claude 的 Prompt Caching 不是简单的“什么都不用管”。
当前 Claude 文档支持通过 cache_control 启用缓存。常见写法是:
{
"cache_control": {
"type": "ephemeral"
}
}
或者在特定内容块上设置缓存断点:
{
"type": "text",
"text": "这里是稳定的系统提示词、项目背景或工具说明",
"cache_control": {
"type": "ephemeral"
}
}
Claude 的响应里通常看这些字段:
{
"usage": {
"input_tokens": 50,
"cache_creation_input_tokens": 12000,
"cache_read_input_tokens": 0
}
}
含义大致是:
cache_creation_input_tokens:本次写入缓存的 Token。cache_read_input_tokens:本次从缓存读取的 Token。input_tokens:未走缓存的普通输入 Token。
如果你多次请求后仍然看到:
{
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 0
}
那就基本说明:缓存没有生效。
Anthropic 官方文档也明确说明,缓存有最小长度要求,并且需要检查 cache_creation_input_tokens 和 cache_read_input_tokens 来验证缓存是否真的生效。
参考:
- https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching
OpenCode + Claude 为什么容易出问题?
原因一:OpenCode 可能没有为 Claude 写入 cache_control
如果工具底层只是把上下文拼成普通对话,然后发给 Claude,但没有加:
"cache_control": {
"type": "ephemeral"
}
Claude 就不会按你预期缓存那段长上下文。
这和 OpenAI 不同。OpenAI 是自动缓存,Claude 需要工具或网关明确表达缓存意图。
原因二:OpenAI 兼容接口不天然支持 Claude 缓存语义
很多用户为了方便,会让 OpenCode 走 OpenAI 兼容接口:
/v1/chat/completions
这类请求体通常长这样:
{
"model": "claude-opus-...",
"messages": [
{
"role": "system",
"content": "..."
},
{
"role": "user",
"content": "..."
}
]
}
问题是,标准 OpenAI 请求体里没有 Anthropic 的 cache_control 语义。
如果中转网关只是把 OpenAI 格式转换成 Claude 格式,它也很难凭空知道:
- 哪一段是稳定系统提示词?
- 哪一段是项目上下文?
- 哪一段应该作为缓存断点?
- 哪些动态工具结果不能放进缓存前缀?
所以,除非网关专门支持 Claude 缓存字段透传或自动插入,否则缓存很容易丢失。
原因三:提示词前缀被动态内容污染
即使工具加了缓存控制,缓存也要求前缀稳定。
下面这些内容如果被放在前缀里,会破坏缓存:
- 当前时间戳
- 每轮变化的工具调用结果
- 临时文件列表
- 随机排序的 JSON 字段
- 动态生成的系统说明
- 每轮都变化的项目扫描结果
结果就是:看起来你每次都在发“同一个项目上下文”,但模型看到的前缀其实每次都不同,缓存自然命不中。
为什么费用会暴增?
代码 Agent 的输入通常很大。
一次请求可能包含:
- 长系统提示词
- 工具定义
- 项目目录结构
- 相关文件内容
- 历史对话
- 最近的工具执行结果
如果有缓存,后续请求可能只需要为少量新增内容付普通输入 Token 费用。
如果没有缓存,每次都相当于重新发送几万甚至几十万 Token。
所以费用差距不是 10% 或 20%,而可能是数倍甚至一个数量级。
Claude 官方缓存价格机制里,缓存读取 Token 通常远低于普通输入 Token。也就是说,缓存命中率一旦从 90% 掉到接近 0%,账单会非常明显地上升。
怎么确认自己有没有中招?
看日志,不要只看感觉。
OpenAI / GPT 系列
重点看:
usage.prompt_tokens_details.cached_tokens
如果多轮请求后 cached_tokens 长期为 0,说明没有命中缓存。
Claude 系列
重点看:
usage.cache_creation_input_tokens
usage.cache_read_input_tokens
usage.input_tokens
可以粗略计算缓存读取占比:
缓存读取占比 =
cache_read_input_tokens /
(cache_read_input_tokens + cache_creation_input_tokens + input_tokens)
如果 cache_read_input_tokens 长期接近 0,说明后续请求没有有效复用缓存。
用户应该怎么做?
1. 不要默认认为 OpenCode 已经支持 Claude 缓存
只改 base_url 和 api_key,不代表 Claude 缓存已经启用。
你需要确认:
- OpenCode 当前版本是否支持 Claude prompt caching。
- 请求体里是否真的带了
cache_control。 - 中转网关是否会保留或生成 Claude 缓存字段。
- 控制台日志里是否出现
cache_read_input_tokens。
2. 优先使用支持 Claude 缓存的工具链
如果你主要使用 Claude 做代码 Agent,建议优先选择明确支持 Claude 缓存机制的工具。
比如:
- Claude Code
- 支持 Claude cache breakpoint 的客户端
- 能透传 Anthropic 原生
/v1/messages请求的网关 - 明确支持
cache_control的中转配置
3. 尽量走 Claude 原生协议
如果条件允许,Claude 模型优先使用 Anthropic 原生格式,而不是强行伪装成 OpenAI 格式。
OpenAI 兼容接口很方便,但它不一定能表达 Claude 的所有能力。缓存就是典型例子。
4. 把稳定内容放前面,动态内容放后面
无论 OpenAI 还是 Claude,都建议这样组织上下文:
稳定内容放前面:
- 系统提示词
- 项目规范
- 编码规范
- 工具说明
- 固定仓库摘要
- 长期不变的文档
动态内容放后面:
- 当前用户问题
- 本轮工具结果
- 临时错误日志
- 当前 diff
- 刚读取的文件片段
5. 给编程工具单独创建 API Key
建议为 OpenCode、Claude Code、Codex、Cursor、Windsurf 等工具分别创建 API Key。
这样你可以单独观察:
- 哪个工具消耗最高
- 哪个模型缓存命中最低
- 哪个 Token 组更适合当前任务
- 是否某个工具在重复发送超大上下文
6. 在控制台核对 Token 组和缓存策略
不同 Token 组的模型来源、缓存策略、价格费率和可用线路可能不同。
如果你使用 AIOAGI,请在控制台确认:
- 当前 API Key 属于哪个 Token 组
- Token 组是否支持目标 Claude 模型
- 是否有缓存优惠说明
- 日志里是否能看到缓存读写字段
- 实际扣费是否符合预期
推荐排查顺序
如果你已经遇到 Claude + OpenCode 费用异常,可以按这个顺序查:
- 查看控制台请求日志。
- 确认
cache_read_input_tokens是否长期为 0。 - 确认请求是否经过
/v1/chat/completions这类 OpenAI 兼容路径。 - 检查网关是否支持 Anthropic
cache_control。 - 检查 OpenCode 是否有 Claude 缓存相关配置。
- 对比同一项目在 Claude Code 中的缓存命中情况。
- 如果 OpenCode 无法改善,换用支持缓存的客户端或切换模型/分组。
- 为 OpenCode 单独设置额度上限,避免继续烧余额。
常见误区
误区一:只要模型支持缓存,就一定会自动省钱
不一定。
OpenAI 的缓存更偏自动,Claude 需要请求正确表达缓存意图。工具没有适配,缓存就可能完全不生效。
误区二:第一次请求很贵,说明缓存没用
第一次请求通常是写入缓存,费用可能不会低。真正省钱的是后续多次读取缓存。
要看第二次、第三次之后的 cache_read_input_tokens。
误区三:用了中转站就一定能自动处理缓存
不一定。
中转站能做协议转换,但不一定能理解你的提示词结构。它不知道哪一段应该缓存,哪一段不应该缓存。
误区四:缓存会影响模型回答质量
Prompt caching 缓存的是输入前缀的计算结果,不是缓存答案。命中缓存后,模型仍会根据当前完整请求生成新回答。
总结
Claude + OpenCode 完全没有缓存、费用暴增,本质上是工具链没有把 Claude 的缓存机制用起来。
OpenAI 系列通常更容易自动命中缓存;Claude 则需要客户端、网关和提示词结构一起配合。
如果你是普通用户,最实用的建议是:
- 用日志确认缓存,不要凭感觉。
- Claude 编程任务优先使用支持缓存的工具。
- 不要盲目把 Claude 塞进 OpenAI 兼容接口就直接长时间跑。
- 给编程 Agent 单独建 API Key,并设置额度上限。
- 发现
cache_read_input_tokens长期为 0,就立刻停下来排查。
缓存命中率不是小优化。对长上下文代码 Agent 来说,它直接决定你是在正常使用,还是在按全量上下文反复付费。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)