跳到主要内容

被你的个性化层悄悄杀掉的 Prompt 缓存

· 阅读需 12 分钟
Tian Pan
Software Engineer

产品团队发布了个性化功能。智能体(Agent)现在会直呼用户姓名,根据用户的偏好调整回答长度,了解用户在医疗行业工作,并尊重用户在提及日期时所处的时区。用户满意度的提升是真实且可衡量的——A/B 测试显示点赞率提升了四个百分点,随后功能全量上线。三周后,财务部门指出推理成本大约翻了三倍,而 AI 团队中没人能立即解释原因。

解释就在系统提示词(System Prompt)构建器中一行被埋没的代码修改里。每个用户的上下文——姓名、偏好的回答长度、行业、时区——都被添加到了系统提示词的开头,以便模型在每一轮对话中都能看到。这使得从第一个 Token 开始,每个用户的 Prompt 都是独一无二的。你的供应商提供的 Prompt 缓存——原本能以标准价格的十分之一服务大约 90% 的输入 Token——失效了。延迟几乎没有波动,所以性能仪表盘(Performance Dashboard)依然显示绿色。直到月底,计费仪表盘才反映出这一情况。

这并非单纯的提示词工程 Bug、基础设施 Bug 或产品 Bug。它是三个团队从不同角度看到的同一个 Bug。解决方案不是“停止个性化”——个性化才是核心目的——但如果一个团队将个性化、系统提示词和缓存布局视为三个独立的问题,那么他们将继续为此付出高昂的代价。

为什么折扣如此容易丢失

Prompt 缓存是现代 LLM 技术栈中最大的成本杠杆。在 Anthropic 的 Claude API 上,缓存的输入 Token 成本约为标准费率的 10%。OpenAI 的自动缓存功能在 1,024 个 Token 以上生效,并为缓存的 Token 提供 50% 的折扣。Bedrock 则紧跟 Anthropic,提供 90% 的读取折扣。如果系统提示词占据了大部分输入,且缓存命中率达到 75%,你的实际输入成本将下降约三分之二。这一折扣力度之大,以至于大多数生产环境中的 AI 经济模型都在无形中依赖它,即便没人明确指出这一点。

该机制非常严苛。缓存命中要求前缀必须逐 Token 完全匹配,直到缓存控制边界。缓存键(Cache Key)是前缀的哈希值;第一个位置上的一个 Token 不同,就会使整个前缀失效。这里没有模糊匹配,没有语义等效,也没有“足够接近”。在系统提示词顶部的第一个字节的个性化内容,在功能上等同于为每个用户生成了一个唯一的缓存键。

缓存的生存时间(TTL)也很短。Anthropic 在 2026 年 3 月将默认值从一小时缩短到了五分钟,这意味着即使是理想情况下的共享前缀,也只能在极短的空闲窗口内存活。更短的 TTL 使低命中率的代价变得更高,而非更低——缓存现在成为了筛选哪些工作负载真正合格的更严苛的过滤器,而个性化的前缀根本不具备资格。

因此,失效模式是非常剧烈的。一旦将个性化内容移入前缀,缓存就会立即停止工作,不再像你的财务模型预期的那样为每个用户节省成本。这不会有逐渐退化的告警,而是一个和折扣力度一样大的断崖式下跌。

隐藏断崖的仪表盘

这一问题之所以会被发布上线,是因为工程师们实际关注的仪表盘看起来一直很正常。

延迟是第一个具有误导性的信号。缓存命中确实能显著缩短首 Token 时间(Time-to-first-token),但波动的幅度很大,且请求之间的差异也很大。当命中率从 90% 降至 0% 时,P50 延迟会增加几百毫秒——通常处于现有 P50 的噪声范围内。在一个拥有流式响应的系统中,没人会因为 P50 漂移了几百毫秒就发送告警。延迟仪表盘不会报错。

错误率是第二个具有误导性的信号。这里没有错误。供应商成功处理了每一个请求;只是按全价计费。SLO 仪表盘对这种变化是视而不见的。

成本仪表盘虽然存在,但通常以天或周为单位进行汇总,而在许多组织中,财务部门的月度结算才是精度最高的数据来源。从周二发布开始的缓存命中率暴跌,会在当月 25 号左右产生账单惊喜——在拥有正确仪表盘的人发现之前,成本已经持续复增了三周。到那时,发布已被宣布在满意度指标上取得成功,团队已经转向其他工作,而成本回退必须从 Token 日志中进行逆向分析。

缓存命中率本身才是能发现这一问题的指标,而大多数团队并未在自己的遥测系统中体现这一指标。供应商的账单门户会在事后显示它。一些观测工具——如 Helicone、Datadog 的 LLM 产品、LangFuse——会捕获 cache_read_input_tokens 并将其与延迟并列显示。如果你的仪表盘在延迟和错误面板旁边没有一个“缓存 Token / 总输入 Token”面板,那么你在飞行时就缺少了那个能在跌入断崖前发出警告的仪器。

个性化究竟应该放在哪里

修复方案是结构性的。个性化本身不是问题;问题在于个性化的位置。

缓存是通过前缀来识别的,因此提示词的设计也必须遵循同样的逻辑。所有稳定的内容都放在顶部:行为指令、工具定义、响应格式规则、政策区块、参考术语表、长期上下文。所有针对每个请求、每个用户或每个会话的内容都放在缓存边界之下:用户的显示名称、陈述的偏好、会话历史、刚检索到的文档、当前时间戳。

这在理论上听起来显而易见,但在实践中却经常被违反。常见的违规行为是:个性化是由代码库中一个完全不了解缓存边界的层注入的。“系统提示词生成器”是一个具有简洁 API 的函数 —— buildSystemPrompt(user) —— 它将用户字段填充到单个字符串中。缓存断点由另一层(通常是 SDK 调用处)根据生成的字符串设置。这两个层都无法单独发现该函数的参数化实际上破坏了设置断点的目的。

三种模式可以可靠地弥补这一差距。

第一种是将系统提示词视为由两个片段组成的产物,而不是单个字符串。稳定片段在进程启动时构建一次并标记为可缓存。个性化片段根据每个请求构建,要么附加在缓存边界之后,要么移动到第一个用户消息中。边界在类型上是明确的,而不是在调用处推断出来的。

第二种是通过工具调用加载每个用户的上下文,而不是将其硬编码到系统提示词中。模型拥有一个 get_user_profile 工具。系统提示词告诉它何时调用。缓存前缀保持通用,因为工具定义是通用的;用户特定的数据仅作为工具结果进入对话,而工具结果在构建上就是附加在缓存区域之后的。在需要配置文件数据的轮次中,这会增加一次额外的往返(round trip),但一旦计算了缓存账目,这通常仍然是更便宜的架构。

第三种是将个性化保留在用户消息轮次中。“用户偏好的响应长度是简短的。他们在医疗保健行业工作。他们的时区是亚洲/新加坡”可以作为用户实际问题的前奏,而完全不触及系统提示词。模型的行为是一样的;缓存前缀保持不变。

选一个吧。错误的答案是把个性化留在系统提示词的顶部,因为提示词工程团队优化了提示词质量,而缓存布局却成了别人的问题。

组织失灵模式

这种反模式反复出现的原因是,必须协同设计的这三件事通常由不同的团队负责。

产品团队负责个性化。他们有一份要注入的每用户信号路线图 —— 偏好、历史摘要、个人资料字段 —— 以及积压的 A/B 测试,将每个信号与满意度指标配对。他们编写模型应该拥有哪些上下文的规范。

AI 团队负责系统提示词。他们调整措辞、结构、指令顺序和示例选择。他们将系统提示词视为具有自己变更日志的版本化产物。他们不一定知道产品团队计划下一步注入哪些字段。

基础架构或平台团队负责 SDK 调用、缓存配置、速率限制和成本仪表板。他们是唯一以 cache_read_input_tokens / total_input_tokens 为指标进行思考的团队,而且他们通常对产品路线图的了解最少。

当个性化进入系统提示词时,三个团队都只看自己负责的部分,觉得没问题。产品看到了满意度的提升。AI 看到了清晰的提示词。基础架构看到成本仪表板尚未汇总变更。而它们之间的鸿沟正是退化发生的地方。

弥合差距并不需要重组。它需要一个三个团队都同意查阅的单一产物:在对提示词构建路径进行任何更改时,都要进行缓存布局审查。审查回答一个问题:更改后,代表性请求中的输入 token 有多少比例仍可缓存?如果该比例下降,除非能说明成本影响的负责人明确签字,否则该更改不能发布。

让防御机制化

审查可以捕捉明显的情况,而机械闸门(mechanical gates)则能捕捉其余的情况。

构建缓存感知的 CI 检查非常简单,它是组织宁愿拥有也不愿缺失的安全网。通过新的提示词构建路径快速连续运行一组固定的 50 到 100 个最近的生产环境提示词。测量第二次运行时的已缓存输入 token 比例。将其与生产版本的基准比例进行比较。如果比例下降超过几个百分点或低于绝对底线 —— 对于稳定的工作负载,60% 是一个合理的起跑线 —— 则构建失败。这不只是质量关卡,它是单位经济效益关卡。构建失败是因为提议的更改在生产环境中的成本将高于其替换的版本。

另一种补充防御存在于提示词构建层本身。将可缓存区域设为类型化对象 —— 一个带有单个字符串字段的 CacheableSystemPrompt —— 并要求所有针对每个请求的数据完全存在于不同的类型中。编译器强制执行边界。审查者的工作变成了验证流入可缓存类型的数据是否不依赖于每个请求的输入。大多数个性化导致的退化在进入缓存之前就被类型系统拦截了。

第三种防御是观测性的。在你自己的遥测中,将缓存命中率作为一等公民生产指标,而不是账单门户的一项功能。通过读取响应的 cache_read_input_tokens 字段,计算每次调用的命中率。按路由、按提示词版本、按部署进行聚合。对 24 小时内滚动下降超过 10 个百分点的情况发出告警;这几乎总是对应于使前缀失效的提示词更改。告警在数小时(而不是数周)内闭环了代码更改与单位经济效益退化之间的关系。

这对生产环境中的 AI 意味着什么

“个性化杀死了缓存”的故事只是一个更普遍模式中的一个实例。LLM 应用的经济模型并非模型的属性;它们是 Prompt 布局、缓存边界、重试策略、流式传输配置以及 SDK 调用形式的属性。所有这些都存在于 AI 团队编写而产品团队并不阅读的代码中。

技术栈中任何一处的改动都可能使单位成本产生一个数量级的变化。这种变化看起来并不像基础设施的变更。它看起来像是一个 Prompt 的改动、一个功能变更或是一次满意度实验。成本影响在代码对比(diff)时是不可见的,只有在账单结算时才清晰可见。

交付可持续 AI 产品的团队学会了将 Prompt 布局视为一种基础设施,任何面向产品的改动都可能破坏它。他们像审查 Schema 一样审查它。他们像运行测试一样在 CI 中对其进行拦截。他们像监控 SLO 一样在生产环境中监控它。他们在延迟和错误仪表板旁边发布缓存命中率仪表板,并每周进行查看。

那些没有这样做的团队将继续发布提升满意度的功能,却在无形中倒置了利润。他们会和财务部门同时发现这种倒置——这通常已经太迟了三周,不仅需要回滚发布,还要解释账单上的支出项。

References:Let's stay in touch and Follow me for more thoughts and updates