Kimi 上下文缓存怎么用:自动命中的条件与失效场景

2026-08-25

数据截至 2026-08,价格与限额以各官网为准。本文只讲计费与接入机制,不列具体价格数字。

如果你是带着”先创建一个缓存对象,拿到 cache ID,再在请求里引用它”的思路来找 Kimi 的上下文缓存文档的,可以省下这份力气:官方文档明确写了 Context Caching 对所有模型请求自动启用,无需手动创建、无需引用缓存 ID、无需管理 TTL。你唯一能控制的变量只有一个——请求前缀稳不稳定。它按前缀匹配工作,只有与之前请求完全一致的前缀部分才能命中,前缀中任何一个位置发生变化,该位置之后的缓存都会失效。所以这件事的操作层面不在”怎么用缓存 API”,而在”怎么组织 messages 才不会天天把自己的缓存打碎”。

先纠正预期:这里没有”创建缓存”这一步

Kimi 官方文档对 Context Caching 的定义是:预先存储可能被频繁请求的大量数据,再次请求相同信息时直接从缓存提供,无需重新计算或从原始数据源检索。关键在后半句——在 Kimi API 里,这个能力对所有模型请求自动启用,当系统检测到重复的初始上下文(例如 system prompt、知识文档、工具定义等)时,会自动复用已缓存的内容。

文档把”无需配置”拆成了三条,值得逐条对照自己的代码看一遍:

  • 无需手动创建:系统会自动识别并缓存高频使用的初始上下文,你不需要主动声明哪一段该被缓存;
  • 无需引用缓存 ID:调用 /v1/chat/completions 时按正常方式传入 messages 即可,系统在后台自动匹配缓存;
  • 无需管理 TTL:缓存的生命周期由系统自动管理,官方的表述是系统会在合适的时机自动触发缓存优化。

常见问题页里也重复确认了同一件事:Context Caching 不需要手动配置,Kimi API 会对重复的初始上下文自动尝试缓存,无需手动创建 cache ID、设置 TTL 或添加额外请求参数。

这个设计的代价是控制权的让渡。你没法强制某段内容常驻缓存,也没法主动让缓存失效重建。能做的只有让前缀稳定。跨厂商的缓存计费口径差异,可以先看缓存计费的通用机制那篇打底,本文只讲 Kimi 这一家的具体形态。

命中的唯一规则:前缀必须完全一致

“自动”两个字容易让人以为系统会智能地找出相似片段。它不会。官方在动态加载工具那篇里把规则写得很直白:上下文缓存按前缀匹配,只有当前请求与之前请求完全一致的前缀部分才能命中缓存,前缀中任何位置发生变化,该位置之后的缓存都会失效。

把这句话翻译成日常写代码时的判断标准,就是三件事:

第一,改动的位置比改动的大小重要得多。在 system prompt 开头插一个当前时间戳,改动只有十几个字符,但它位于前缀最前端,后面所有内容的缓存全部作废。反过来,在 messages 末尾追加一整段几千字的用户提问,前面的前缀纹丝不动,已建立的缓存照常命中。

第二,任何”每次请求都不一样”的内容都不该出现在前缀里。时间、随机 ID、请求序号、A/B 实验分组标记,这类东西一旦混进 system prompt 或工具定义,缓存命中率就会长期趴在低位,而且账单上看不出原因,只能看到输入 token 里缓存命中的那部分始终起不来。

第三,工具定义也是前缀的一部分。文档在描述被缓存的初始上下文时,明确把工具定义和 system prompt、知识文档并列。也就是说,如果你的工具列表是按业务动态拼装的、顺序还不固定,那它和一个变动的 system prompt 是一回事。

官方注意事项里给的建议也是同一个方向:请确保你的知识内容、system prompt 和工具定义相对稳定,以获得更好的缓存命中率;修改前缀内容可能降低缓存命中率。

太短的请求根本进不了缓存

这一条是很多人试了半天没效果的原因。官方文档给了一个 prompt tokens 的下限:当前一个请求的 prompt tokens 大于该下限时,新的请求才能命中前缀缓存;当前一个请求的 prompt tokens 小于该下限时,请求不会被缓存,而是被丢弃。具体数值请以官方《上下文缓存》文档当前版本为准。

注意这句话的主语——是前一个请求的 prompt tokens 决定了后续请求能不能命中,而不是当前这个请求。这意味着缓存是被前一次调用”种下”的:如果你的第一次调用本身就很短,它压根没有留下缓存,第二次调用无论多长都无从命中。

实践含义有两个。一是拿一句”你好”做冒烟测试来验证缓存生效,方法本身就不成立。二是像 QA Bot 这种系统里挂着大段知识文档的场景天然满足条件,而那种 system prompt 只有一两句话、全靠用户输入撑长度的应用,缓存能带来的空间要小得多。

想在发请求前就估算前缀长度,官方提供了计算 Token 的接口 https://api.moonshot.cn/v1/tokenizers/estimate-token-count,请求体传 modelmessages,结构与 chat 接口一致。把你的固定前缀单独发过去估一次,就知道它离门槛有多远。

messages 怎么摆:官方给的摆法有一处反直觉

官方注意事项里关于多轮对话的原话是:将固定的大段上下文(如知识文档)放在 messages 数组的最前面(system 消息之前),然后将用户问题和模型回复追加其后,系统会自动识别并缓存这些固定内容。

括号里那句”system 消息之前”是反直觉的——多数人的习惯是 system 永远排第一,知识文档塞进 system 的 content 里。这里照录官方表述,不做引申解释,具体以官方文档当前版本为准。真正要记住的是那个不变量:固定内容在前,可变内容在后,追加而不是插入

对多轮对话还要补一句结构上的前提:Kimi API 是无状态的,本身不具有记忆功能,要实现多轮对话,需在每次请求时把前一轮的 assistant 回复(以及工具执行结果,如适用)原样追加到 messages 数组中再发送。“原样追加”这四个字和缓存直接相关——如果你在回填历史时做了裁剪、摘要或格式重排,改动的是中间位置,那么改动点之后的缓存就命中不了了。想省上下文长度和想命中缓存,这两个目标在这里是打架的。

怎么确认真的命中了:cached_tokens

Kimi 的 chat 接口在响应的 usage 对象里除了 prompt_tokenscompletion_tokenstotal_tokens,还有一个 cached_tokens 字段。这是你唯一的客观依据——不要凭响应快慢去猜有没有命中,那种判断在文档里没有任何依据。

流式调用有个容易踩的坑:默认情况下流式响应的分片里是没有 usage 的。官方给的办法是传 stream_options: {"include_usage": true},这样可以在最后一个 chunk(data: [DONE] 之前)额外获取 usage 字段,显示本次请求的 Token 消耗。示例里那个末尾 chunk 的 usage 中同样带着 cached_tokens

所以做缓存优化的第一步不是改 prompt,而是先把 cached_tokens 记进你自己的日志。改一版前缀结构,看这个数字的变化,这是唯一能闭环的做法。落到长期监控上,可以配合成本监控的做法一起搭,把命中比例和账单曲线放在一起看。

prompt_cache_key:官方给的一个提高命中率的字段

chat 接口的请求参数里有一个 prompt_cache_key,字符串类型,官方说明是:用于缓存相似请求的响应以优化缓存命中率。对于 Coding Agent,通常是代表单个会话的 session id 或 task id,退出并恢复会话时应保持不变;对于 Kimi Code Plan,此字段为必填以提高缓存命中率;对于其他多轮对话 Agent,也建议使用此字段。

三个限定条件都不能丢:必填只对 Kimi Code Plan 成立,对普通 API 调用是建议而非强制;“退出并恢复会话时应保持不变”说明它的粒度是会话而不是单次请求;对 Coding Agent 之外的场景,官方的措辞是”建议使用”。文档里没有说明这个字段与前缀匹配规则之间的具体关系,也没有说明取值格式有什么约束,这部分不做推断。

动态加载工具时,别把前缀打碎

如果你的 Agent 挂了大量工具、走的是按需注入的路子,官方在动态加载工具那篇里专门写了对上下文缓存的影响,三条原则可以直接抄:

  • 追加,不要插入:新的工具声明一律追加到 messages 末尾,已有前缀保持不变,不影响已建立的缓存;向对话中间插入或修改任何消息(包括已注入的工具声明),都会使变更位置之后的缓存无法命中。
  • 保留已注入的声明:动态工具声明按请求生效,不会被服务端记住。建议在后续请求中原样保留已加载的工具声明,这样工具保持可用、前缀保持稳定,有利于持续命中缓存;若不再携带,该工具声明即失效,如果该工具未在其他位置声明,模型将无法调用它,同时由于 messages 发生变化,变更位置之后的前缀缓存也可能无法命中。
  • 核心工具固定在顶层声明,之后不再改动:把每轮都要用的核心工具放在请求顶层 tools 字段做全局声明,声明之后保持内容不变。官方明确说顶层全局工具声明不影响缓存命中,保持稳定即可让前缀缓存持续有效,只有按需使用的工具才做动态注入。

还有一条容易被忽略的好消息:官方在 K3 工具调用最佳实践里写了 tool_choice 不会破坏前缀缓存,可以按请求粒度调整。也就是说”这一轮强制调工具、下一轮让模型自己决定”这种切换是安全的,不必为了保命中率而把 tool_choice 锁死。

计费上它到底意味着什么

Kimi 对 Chat Completion 接口的 Input 和 Output 均实行按量计费。上下文缓存在计费上的体现是:输入 token 区分缓存命中与未命中,两者分别计价。以 Kimi K3 为例,官方说明是计费不按上下文长度分段,所有用量均按量付费,输入(区分缓存命中与未命中)与输出分别按统一单价计费。批量推理那条线同样有缓存命中 token 的价格项。具体单价一律以官方定价页当前版本为准,本文不列数字。

有一个结构性的点值得单独说:如果你上传并抽取文档内容,再把抽取出的文档内容作为 Input 传给模型,那么文档内容也是要按量计费的(文件内容抽取与文件存储接口本身的收费政策见官方定价页当前版本)。这正是文档问答类应用最该上缓存的原因——同一份文档被问一百次,它就作为固定前缀重复进入了一百次输入计费。

想进一步压命中率,可以再看缓存命中率优化的通用套路,Kimi 侧的计费口径细节则见 Kimi API 计费

和 RAG 怎么选:官方给了一张对比

官方文档专门比较了 Context Caching 和 RAG 两条降本路线,结论不是”缓存更好”,而是适用面不同:

  • 业务成本:Context Caching 在特定场景下成本压缩程度极高,但降本幅度与业务特性高度相关;RAG 任何业务均可降本,与业务特性无关,但召回精度问题可能导致回答准确率下降。
  • 研发成本:Context Caching 相对较低,系统自动处理缓存,无需额外接入或调优;RAG 相对较高,需 RAG 与 Embedding 结合,并持续进行业务定制化调优。
  • 额外优势:RAG 的原始文本长度可扩展到非常长,适合一次性数百万字上下文的场景。

官方给的建议是:频繁查询固定内容(如 FAQ、文档问答)时优先使用 Context Caching;内容极长且查询方向不固定时,可考虑 RAG 方案。

至于什么算”频繁请求固定长上下文”,文档列了几类典型场景:提供大量预设内容的 QA Bot(如产品文档问答助手)、针对固定文档集合的频繁查询(如上市公司信息披露问答工具)、对静态代码库或知识库的周期性分析(如各类 Copilot Agent)、瞬时流量巨大的爆款 AI 应用、交互规则复杂的 Agent 类应用。

最容易栽的三个坑

第一个坑是拿短请求验证缓存。 前一个请求的 prompt tokens 没过门槛,这次调用压根没被缓存下来,你后面怎么试都不会有命中,很容易误判成”这功能没生效”。验证要用真实长度的前缀。

第二个坑是在前缀里塞了变量而不自知。 时间戳、会话 ID、动态拼接顺序不固定的工具列表,都属于这一类。它不会报错,只会让 cached_tokens 长期偏低。排查方法很朴素:把连续两次请求的 messages 完整序列化后做逐字节 diff,第一个不同的位置就是你的缓存断点。

第三个坑是为了省上下文而改写历史。 多轮对话里做摘要压缩、裁剪旧消息、重排格式,改的都是中间位置,等于每一轮都在重建缓存。要压上下文可以,但尽量在末尾做,别动已经稳定下来的前缀。

下一步能立刻做的事只有一件:在你的调用封装里把 usage.cached_tokens 打进日志,流式调用记得加上 stream_options。没有这个数字,后面所有关于缓存的优化都是盲调。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。