LLM 应用中的缓存设计
LLM 应用里的许多输入并不会频繁变化。系统指令、工具定义和部分上下文常被反复发送,相同或等价的请求也可能多次触发模型调用,带来额外的 token 消耗和响应延迟。提示词缓存(Prompt Caching)通过复用稳定前缀降低输入成本;如果完整结果可以复用,应用层结果缓存还能直接返回已有输出,避免再次调用模型。下文会围绕这两层缓存展开。
提示词缓存
本节分别说明 Anthropic 与 OpenAI 两种提示词缓存实现规范,并以 Claude Sonnet 4.5 和 GPT-4o 展示各自的使用方式与计费规则。不同模型、部署平台和 API 版本支持的缓存方式、最小长度、TTL 与价格可能不同,落地时应以当前官方文档为准。
规范概览
两种规范都复用相同提示词前缀的计算,但控制方式和计费字段不同。Anthropic 允许应用设置断点和 TTL,并分别返回缓存写入与命中 token;GPT-4o 由模型服务自动管理缓存,只返回命中的缓存 token。
- 写入:首次处理可缓存前缀时,模型服务保存处理该前缀产生的内部状态;
- 命中:后续请求匹配该前缀时,模型服务复用这些状态,只处理未命中的输入并生成输出。
Anthropic 规范
Anthropic 支持请求级自动缓存和内容块级显式断点。自动缓存只需在请求顶层添加 cache_control,模型服务会把断点放在最后一个可缓存的内容块;显式方式则把 cache_control 放在指定内容块上,缓存从请求开头到该内容块的前缀。一个请求最多使用 4 个断点,自动缓存与显式断点同时启用时,自动缓存会占用一个名额。
Claude Sonnet 4.5 要求缓存前缀至少达到 1024 token,长度不足时会正常处理请求,但不会创建缓存。默认 5 分钟缓存的写入和命中价格分别是标准输入价格的 1.25 倍和 10%;配置 ttl: '1h' 后,写入价格提高到 2 倍。响应中的 cache_creation_input_tokens 和 cache_read_input_tokens 分别表示写入量与命中量。
下面同时启用请求级自动缓存和两个显式断点。示例假设 SYSTEM_PROMPT 本身已经超过 1024 token。
这段代码会在系统提示词、参考资料和用户问题末尾设置三个断点。缓存仍在 TTL 内时,模型服务优先复用最长的匹配前缀:参考资料不变可以命中第二个显式断点;参考资料发生变化时,第一个显式断点仍可复用系统提示词。自动断点位于用户问题末尾,会缓存本次请求的完整前缀。
在追加式多轮对话中,自动断点会随新消息向后移动。为简化示意,下面按 system 和每条消息各包含一个内容块计算:
Anthropic 对每个断点最多向前检查 20 个内容块,当前断点本身算作第一个。图中的最后一种情况里,模型服务从当前断点依次检查 block20 至 block1,而上一轮自动断点位于 block1 之前,因此无法命中。模型服务随后会检查请求中的显式断点;如果也未命中,则重新处理全部提示词,并在响应开始生成时写入新的自动缓存。
工具调用可能在一次请求内产生大量内容块,使相邻两个自动断点相隔 20 个或更多内容块。此时可以提前在稳定前缀末尾设置显式断点。
OpenAI 规范
下面以 GPT-4o 为例。模型服务会自动匹配请求中的相同前缀,无需配置缓存断点。提示词达到 1024 token 后才会参与缓存,命中长度从 1024 token 起按 128 token 一档递增。例如相同前缀有 1200 token,最多按 1152 token 计入命中。
GPT-4o 的缓存写入不额外收费,命中的输入 token 按标准输入价格的 50% 计费。响应中的 usage.prompt_tokens_details.cached_tokens 表示本次命中的输入 token 数,不提供单独的缓存写入字段。GPT-5.6 及后续模型还支持显式断点,缓存写入按标准输入价格的 1.25 倍计费,并通过 cache_write_tokens 返回写入量。
下面的示例假设 SYSTEM_PROMPT 与参考资料组成的稳定前缀已经超过 1024 token。
提示词结构设计
两种规范都按请求前缀匹配缓存,因此提示词应按变化频率排列:
从左到右,内容变化越来越频繁。Anthropic 可以在需要独立复用的稳定前缀末尾设置 cache_control;GPT-4o 自动匹配前缀,无需设置断点;GPT-5.6 及后续模型也可以设置显式断点。无论采用哪种方式,前缀中的内容和顺序都必须保持一致。
应用层结果缓存
提示词缓存命中后仍会生成输出。如果多个请求可以共享结果,并且缓存的响应仍然有效,应用层结果缓存可以直接返回已有结果,无需再次调用模型。
缓存 key 设计原则
缓存 key 决定哪些请求可以共享同一结果。所有影响输出、数据范围或访问权限的因素都应参与计算,与结果无关的请求字段则应排除。常见输入包括:
- 租户或用户隔离范围,以及权限信息的哈希;
- 模板、模型、工具和输出 schema 的版本;
- 用户问题,以及上下文的哈希;
- 采样参数及其它影响输出的模型配置。
与响应无关的 traceId、requestId 和请求时间戳不参与计算。hash 需要使用确定性序列化,确保相同输入生成相同的 key。
失效与并发控制
除了设计 key,还需要处理缓存失效和并发请求:
- TTL 不应超过所有依赖中最短的有效期;
- 上下文数据、权限、模板或工具变化时,更新 key 中对应的哈希或版本字段,旧条目由 TTL 清理;
- 错误响应、未通过审核的结果和包含一次性凭证的结果不进入缓存;
- 同一个 key 失效时,多个等价请求可能同时调用模型,造成重复计算。应用可以合并这些请求,只发起一次模型调用;多实例部署时,可以使用分布式锁协调各实例。
两层缓存的协同
请求先查应用层结果缓存。命中后直接返回;未命中时调用模型,由提示词缓存尝试复用前缀;模型返回可缓存结果后,再写入应用层缓存。
成本计算与监控
成本计算示例
以 Claude Sonnet 4.5 的 5 分钟缓存为例:一次请求包含 7k token 的可缓存前缀和 0.5k token 的动态输入。连续发送两次相同前缀时,以基础输入单价为 1,成本为:
这里假设两种方案的输出 token 数相同,因此不计入差值。示例中的输入成本约节省 30%;实际收益取决于前缀的复用次数、缓存有效期和模型价格。
监控指标
应用需要记录模型服务返回的 usage:Anthropic 关注 cache_creation_input_tokens 和 cache_read_input_tokens;OpenAI 关注 prompt_tokens_details.cached_tokens,GPT-5.6 及后续模型还需记录 cache_write_tokens。按模型、提示词版本和时间窗口汇总后,重点观察:
- 提示词缓存 token 命中率:命中 token 占全部输入 token(缓存命中、缓存写入和未缓存输入之和)的比例;
- 缓存净收益:未使用缓存时的估算输入成本减去实际输入成本;
- 应用层结果缓存命中率:命中次数占查询缓存次数的比例;
- 请求成本与延迟:统计平均成本和 P95 延迟(95% 的请求不超过该耗时),观察缓存带来的整体收益。
两层缓存的边界
提示词缓存关注前缀能否复用,应用层结果缓存还要满足业务有效性和权限要求:
提示词缓存
- 可复用前缀短于最小缓存长度时,无法写入或命中缓存;
- 易变内容位于可复用前缀内时,从变化位置开始无法命中,应将易变内容放在最后;
- 对收取写入费用的模型,若相同前缀在 TTL 内很少再次出现,使用缓存反而可能增加成本。
应用层结果缓存
- 依赖实时数据、包含外部副作用或要求每次重新生成的请求,不应缓存完整结果;
- 无法通过 key 准确区分权限范围时,不应跨租户或用户共享结果;
- key 缺少内容版本或未设置 TTL 时,依赖更新后仍可能返回旧结果。
提示词缓存命中率持续下降时,优先检查提示词版本、断点位置和请求间隔;结果缓存出现旧数据或越权命中时,检查 key 的隔离范围和失效条件。