大模型推理的账单里,输入侧有一块经常被忽略的开销:预填充(prefill)。模型每次请求都要把整段上下文从头算一遍,这段计算按输入计价。对于智能体这类"每一步都驮着同一份长上下文"的负载,重复计算的比例会很高。前缀缓存(Prompt Caching)就是把这个重复项消掉的一层优化。这篇按架构分层,讲清它省在哪、代价在哪、边界在哪。
计费架构:输入与输出的定价是分离的
先建立成本模型。一次请求的成本由输入和输出两部分构成,二者定价独立。预填充属于输入侧。在一个 20 多步、几十次工具调用的智能体流程里,每一步都携带同一份系统提示词(可能有两万多 Token),同一段内容会被重复计入输入成本二十多次。
关键结论是:前缀缓存的折扣只作用于输入。因此它天然适合"长输入、短输出"的负载;反过来,短输入长输出的任务,无论怎么配都省不下来。
缓存机制架构:复用的是状态,不是文本
前缀缓存的原理,是把模型读完一段稳定前缀之后得到的中间状态(KV 缓存)保存下来,后续请求若前缀完全一致,直接接续,跳过重算。
这里有一条必须写进设计文档的约束:缓存以逐字一致的前缀为键。 它不认"意思相近的一段话"。前缀中任何一个字符变化,从变化点之后的缓存全部失效。这条约束直接决定了后面所有的排布规范。
排布架构:提示词结构即缓存命中率
命中率不是引擎参数,而是提示词结构的产物。两个变量决定它:前缀的排布顺序,以及两次请求的间隔。
一个公开案例很有代表性:某安全智能体的缓存一直开着,实测命中率却只有 7%。根因是系统提示词里混入了一块每步都在改写的工作记忆,且它位于前缀中段。修正方式是把它移到对话末尾的用户消息,命中率随即升到 74%,稳定后为 84%,整体调用成本下降 59%。
从结构上看,两万 Token 的提示词,若把会变的那一块放在第 3 位,前缀只有约 2 格可复用;把它移到第 20 位,则可复用约 19 格。静态内容量、动态内容量都没变,差的只是位置。
还有一条常被低估的规则:失效是分层的。 前缀通常按"工具定义 → 系统提示词 → 消息"的顺序拼接,上层变动会使下层全部失效。这意味着修改一个工具的字段或描述,也会导致整段缓存清零——提示词模板的每一次改动都要考虑这层连带影响。
自建推理架构:块匹配与基数树是两条路线
把模型换成自建部署后,前缀缓存省的是算力时间,但匹配粒度会带来不同口径的损耗,选型时要区分:
- vLLM:按块匹配,默认块大小为 16 个 Token。前缀长度不是块整数倍时,最后一个不满的块要重算。17 Token 的前缀命中 16 个。
- SGLang:采用基数树(radix tree),粒度细到单个 Token,没有块边界的截断损耗。对前缀长度不规则、复用片段零碎的负载更友好。
- vLLM 的 V1 引擎已将前缀缓存的开销降到接近零,命中率为 0 时也几乎不损失吞吐,因此默认开启。
选型上可以这样权衡:负载前缀规整、追求工程成熟度,vLLM 是稳妥选择;前缀碎片化、命中片段短而多变,SGLang 的细粒度更占优势。在托管平台上,这一步通常由推理服务内部完成,但验收口径不变——看计数,不看开关。
可观测架构:把命中计数纳入监控
前缀缓存的成本风险在于它静默失效:失手时不报错、不打警告,返回内容与正常一致,只有账单变化。因此不能依赖"开关是否打开",必须把缓存计数纳入监控。
- 云上:读取返回中的用量字段。写入计数与读取计数均为 0,即未命中。这两个数须与普通 Token 计数一并落库。
- 自建:以同一段前缀做冷、热两轮压测,对比两轮命中计数。
- 口径一致性:控制台的命中率是时间聚合值,单次响应的计数只描述单个请求,二者不可直接比较。
选型边界:什么时候该用,什么时候别用
前缀缓存的收益需要三个条件同时成立:前缀足够稳定、请求间隔在缓存寿命内、内容长度达到最小门槛。缺任何一条,收益都会归零甚至为负。
几个具体的判断点:
- 短输入长输出的任务,命中折扣作用有限,优先级应让给其他优化。
- 稀疏调用(两次间隔超出寿命)的负载,缓存基本用不上。
- 寿命语义要注意:默认寿命从请求发出起算,且生成本身耗时也计入其中;命中读取会重置计时。因此高并发密集调用的负载反而更容易维持缓存常驻。
- 全量无差别开启有时会拖慢整体,需按负载特征区分。
在平台上落地时,可以把提示词模板与数据集放在对象存储(如 OSS)统一管理,训练/推理任务跑在 PAI 等托管平台,命中计数接入监控看板。提示词模板的变更要像代码一样走评审——因为一次不经意的改动可能让整段缓存失效,成本会立刻体现出来。
小结
前缀缓存是一层"用前缀稳定性换输入成本"的架构优化。它的价值不来自开关,而来自提示词结构:静态内容前置,动态内容后置。设计得当,输入成本能显著下降;设计不当,它会安静地失效,只在账单上留下痕迹。