为什么 Prompt Caching 值得单独工程化
长任务 Agent、Deep Research、代码助手、企业知识库问答和复杂客服系统都有一个共同特征:每一轮调用都会携带大量重复上下文。典型内容包括 system prompt、工具定义、输出规范、安全规则、Few-shot 示例、固定背景资料和项目约定。
这些内容很少变化,却会在每次请求里重复计费、重复 prefill、重复增加首 token 延迟。Prompt caching 的价值就是复用这些稳定前缀,减少重复计算与重复输入成本。
但 prompt caching 不是一个简单开关。生产环境真正要解决的是:哪些内容应该进入缓存前缀,哪些内容必须放在动态后缀,工具 schema 变更如何版本化,缓存命中如何监控,缓存优化是否破坏了回答质量。
一句话理解 Prompt Caching
Prompt caching 可以理解为:如果多个请求从开头开始共享相同 prompt prefix,服务端可以复用此前处理这个 prefix 产生的中间计算结果,从而减少后续请求的输入成本和 prefill 延迟。
Stable prefix -> cache lookup -> cache hit -> skip repeated prefill
Dynamic suffix -> normal processing -> final generation
适合缓存的内容:
- 稳定 system prompt
- 固定工具定义
- 稳定输出格式说明
- Few-shot examples
- 固定知识背景
- 长任务 Agent 的不变任务说明
不适合缓存的内容:
- 当前用户问题
- 当前时间戳
- session id
- 用户画像
- RAG 检索结果
- 工具调用结果
- 临时权限或上下文变量
核心知识结构
可以把 Prompt Caching Engineering 拆成 6 个核心模块:
1. Stable Prefix(稳定前缀)
稳定前缀是缓存收益的核心。只有从 prompt 开头开始完全一致的内容,才有机会命中缓存。系统指令、工具 schema、固定示例和固定背景资料应尽量前置。
2. Cache Breakpoint(缓存断点)
部分模型或平台允许开发者显式设置 cache breakpoint。它的作用是告诉服务端:从 prompt 开始到这个位置之前的内容是可复用前缀。
3. Dynamic Suffix(动态后缀)
用户输入、检索结果、工具结果、时间戳和个性化变量应该放在缓存边界之后。这样它们变化时不会破坏前面的缓存命中。
4. Tool Schema Stability(工具 Schema 稳定性)
Agent 系统经常把工具定义注入 prompt。如果每轮工具列表、工具描述或参数 schema 都变化,就会破坏缓存前缀。因此工具选择、工具压缩和工具版本管理会直接影响缓存收益。
5. Cache Metrics(缓存指标)
Prompt caching 必须可观测。至少要记录 cached tokens、cache read tokens、cache write tokens、cache hit ratio、TTFT 和输入成本。
6. Quality Regression(质量回归)
为了提高缓存命中率而改写 prompt 顺序,可能改变模型行为。Prompt caching 优化必须进入 prompt regression test,而不是只进入成本优化看板。
为什么「自动缓存」≠「稳定收益」
很多平台会自动启用 prompt caching。但自动启用只表示系统会尝试复用前缀,不代表你的 prompt 结构适合缓存。
反面案例——容易破坏缓存的 prompt 结构:
Current time: 2026-06-25 16:58:59
User id: 9182
System instructions...
Tool schemas...
Examples...
User question...
时间戳和 user id 放在最前面,会导致每个请求的 prefix 都不同。即使后面有大量稳定 system prompt 和工具定义,也很难命中缓存。
正面案例——更合理的 prompt 结构:
System instructions...
Stable tool schemas...
Stable examples...
Pinned reference material...
[cache boundary]
Current time...
User id...
Retrieved context...
User question...
核心原则:先放稳定内容,再放动态内容。
长任务 Agent 的缓存难点
长任务 Agent 比普通单轮问答更需要 prompt caching,但也更容易破坏缓存。原因有三点:
1. 工具调用会持续增长上下文
每次工具调用都会产生 tool call、tool result、模型分析和下一步计划。如果这些动态内容不断进入可缓存区域,就会产生大量不会复用的缓存写入。
2. 工具列表可能动态变化
MCP、tool retrieval、插件系统和权限系统可能让每轮可用工具不同。工具列表一变,缓存前缀也会跟着失效。
3. 记忆和摘要会改变上下文
为了控制上下文长度,Agent 往往会摘要历史、裁剪工具结果、更新 memory。这些变化如果发生在缓存边界之前,也会破坏缓存命中。
因此,长任务 Agent 的缓存策略通常不是 full context caching,而是更保守地缓存稳定 system prompt、稳定工具 schema 和固定任务说明。
推荐流程:把 Prompt 当成缓存接口设计
一个生产级 prompt caching 流程可以这样设计:
- 拆分 prompt 组件:system、tools、examples、memory、retrieval、user turn
- 标记每个组件是 stable、semi-stable 还是 dynamic
- 将 stable 组件放在 prompt 前部
- 在 stable 与 dynamic 的边界设置 cache breakpoint
- 将 user turn、RAG context、tool results 放在边界之后
- 记录 cache read tokens、cache write tokens、cached token ratio
- 对 prompt diff、工具 schema diff 做版本管理
- 用代表性评测集比较质量、成本和 TTFT
- 只在质量不下降时推广新的缓存结构
这条流程的重点是:缓存优化不是 SDK 参数,而是 prompt assembly 的架构设计。
一个可落地的 Prompt 组件分类
prompt_components:
stable_prefix:
- system_instructions
- safety_policy
- output_contract
- stable_tool_schemas
- reusable_examples
semi_stable_context:
- project_conventions
- pinned_documents
- session_summary
dynamic_suffix:
- current_user_turn
- retrieved_chunks
- tool_results
- current_time
- user_specific_permissions
- temporary_variables
cache_policy:
cache_boundary: after_stable_prefix
allow_cache_for_tool_results: false
require_prompt_version: true
require_eval_before_promotion: true
semi-stable 内容要谨慎处理。如果项目约定或 pinned documents 很少变化,可以放在缓存边界前;如果经常被更新,就应该放在边界后,或者单独版本化。
工具 Schema 是缓存命中率的隐藏变量
Agent 工具定义通常很长,包括工具名称、描述、参数 schema、枚举、使用条件和返回格式。它们很适合缓存,因为多数工具定义在多个请求之间是稳定的。
常见破坏缓存的问题:
| 问题 | 影响 |
|---|---|
| 每轮根据权限动态生成不同工具列表 | 前缀每次不同,缓存命中率为零 |
| 工具描述中包含用户专属信息 | 不同用户产生不同前缀 |
| 工具 schema 顺序不稳定 | 同样的工具集产生不同 hash |
| 工具参数说明由模型动态改写 | 同一工具产生不同描述 |
| MCP server 返回的 metadata 经常变化 | 缓存前缀频繁失效 |
更稳的做法:
- 固定工具 schema 顺序
- 固定工具描述版本
- 用 tool selection 减少注入工具数量
- 动态权限放在 cache boundary 之后
- 对工具 schema diff 做发布审查
这样可以同时降低 token 成本、提高 cache hit rate,并减少工具定义变化导致的模型行为漂移。
指标体系:不要只看 cached tokens
Prompt caching 至少要看 8 类指标:
| # | 指标 | 说明 |
|---|---|---|
| 1 | Cached Token Ratio | 缓存命中 token 占输入 token 的比例,反映稳定前缀是否足够大、是否经常命中 |
| 2 | Cache Read Tokens | 缓存读取 token 数越高,通常说明重复前缀复用越充分 |
| 3 | Cache Write Tokens | 缓存写入不是免费信号。大量 cache write 没有后续 cache read 说明在缓存不会复用的动态内容 |
| 4 | TTFT | Prompt caching 主要减少 prefill 负担,应重点观察 Time To First Token |
| 5 | Input Cost | 缓存命中会降低输入 token 成本,但要同时计算 cache write、cache read 和普通 input tokens |
| 6 | Prompt Diff Rate | 统计 system prompt、tool schema、example、pinned context 的变更频率 |
| 7 | Quality Score | 监控回答质量、结构化输出通过率和工具调用准确率 |
| 8 | Cache Miss Reason | 记录 cache miss 是由 tool schema 变化、system prompt 变化、动态变量前置、上下文摘要变化还是 provider TTL 过期造成 |
一个简化监控结构:
metrics:
cached_token_ratio: 0.72
cache_read_tokens_per_request_p50: 8200
cache_write_tokens_per_request_p50: 900
ttft_ms_p50_before: 1450
ttft_ms_p50_after: 980
input_cost_reduction: 0.43
prompt_diff_rate_daily: 0.02
tool_schema_diff_count: 3
quality_regression_detected: false
常见失败模式
1. 把时间戳放在 system prompt 开头
这是最常见的 cache breaker。时间戳、request id、session id 这类内容应放在动态后缀。
2. 每轮注入全部工具
工具越多,前缀越长,理论上更适合缓存;但如果工具列表经常变化,缓存命中反而会下降。更好的方式是稳定核心工具 + 按需动态工具后置。
3. 缓存 RAG 检索结果
RAG chunk 通常与用户问题强相关,复用概率低。把它们放进缓存区域,可能只会增加 cache write 成本。
4. 只比较成本,不比较质量
Prompt 顺序变化可能影响模型回答。缓存优化必须通过质量回归测试。
5. 忽略 TTL 和 provider 差异
不同平台的缓存触发条件、TTL、cache checkpoint、价格和指标字段不同。跨 provider 的 Agent 不能假设缓存行为一致。
生产落地 Checklist
上线前建议逐项检查:
- 是否把 prompt 拆成 stable、semi-stable、dynamic 三类组件
- 是否把 system instructions、tool schemas、examples 放在前部
- 是否把用户输入、RAG 结果、工具结果、时间戳放在后部
- 是否使用 cache breakpoint 或等价机制控制缓存边界
- 是否避免动态变量污染缓存前缀
- 是否固定工具 schema 顺序和版本
- 是否记录 cache read tokens、cache write tokens 和 cached token ratio
- 是否单独监控 TTFT,而不是只看整体延迟
- 是否把 prompt 变更纳入版本管理和 diff 审查
- 是否用代表性样本评估质量、成本和延迟
- 是否为 provider TTL、模型差异和缓存指标字段建立适配层
- 是否有关闭缓存或回滚 prompt 版本的策略
结论
Prompt caching 的本质,不是省一点输入 token 钱,而是把重复上下文变成可复用的推理资产。
- 稳定前缀决定缓存命中
- 缓存边界决定动态内容是否污染前缀
- 工具 schema 决定 Agent 缓存是否稳定
- TTFT 和成本证明优化是否有效
- 质量回归证明 prompt 结构调整是否安全
对工程团队来说,最实用的原则是:不要只问「这个模型是否支持 prompt caching」,而要问「我的 prompt 是否被设计成可缓存的接口」。
当 prompt 组件、cache boundary、工具 schema、缓存指标和质量评测形成闭环,prompt caching 才能从平台功能变成生产级 Agent 的成本与延迟优化基础设施。