第 9 天讨论模型路由时,缓存会直接影响模型调用的延迟和账单。但“命中缓存”可能指完全不同的事:供应商复用相同 Prompt 前缀的计算、应用复用上次检索列表,或者把旧答案直接返回给用户。三者的收益、风险和失效方式不能混在一起。
今天的目标是给缓存划清责任边界,并做一套可回放的本地实验:缓存每次命中都能说明“复用了什么、为何仍可用、节省了多少、是否跨越了权限边界”。
一、先分清五类缓存
| 层次 | 复用对象 | 典型键 | 收益 | 最大风险 |
|---|---|---|---|---|
| 供应商 Prompt 缓存 | 相同前缀的模型计算状态 | 模型、前缀及供应商缓存配置 | 降低输入处理延迟和相应费用 | 前缀变动导致未命中;把它误认为旧答案 |
| Embedding 缓存 | 文本对应的向量 | 文本哈希、Embedding 模型与维度 | 减少重复向量化 | 模型升级后仍读旧向量 |
| 检索缓存 | 一次查询的候选 ID、排序及过滤结果 | Query、索引版本、租户与权限、检索配置 | 减少向量库和重排请求 | 版本或权限变化后返回旧证据 |
| 工具结果缓存 | 只读工具的业务结果 | 资源 ID、租户、权限、业务版本、TTL | 降低数据库或外部 API 压力 | 状态更新后返回过期数据 |
| 答案缓存 | 完整的生成结果及引用 | 请求语义、模型/Prompt/知识版本、权限范围 | 跳过整个生成链路 | 跨用户泄露、错用旧政策、重复副作用 |
供应商 Prompt 缓存只复用处理前缀的计算状态,仍然生成一次新输出。它也不会缩短模型逻辑上看到的上下文,缓存命中的输入 Token 依然可能计入速率限制。OpenAI 的 Prompt caching 文档明确说明了前缀复用、重新生成和速率限制;Anthropic 的 Prompt caching 文档给出了缓存写入与读取用量字段。(检索日期:2026-11-05)
应用层答案缓存则是直接返回保存的结果,不再走当次生成。这一步必须由后端决定能否复用,不能因为两个问题的向量很接近就自动复用答案。
二、供应商 Prompt 缓存:让稳定内容先出现
一个模型请求可能包含系统规则、工具 Schema、用户消息、检索片段、会话历史。前缀缓存要求前面的内容保持一致;如果把每次都变的时间戳、检索结果或随机请求 ID 放到最前面,后面即使是同一套规则,也很难形成可复用前缀。
可以按这样的顺序组织请求,前提是符合所用 API 的角色和安全约束:
1 | 稳定的系统/开发者指令与输出契约 |
这里的“公共”必须经过数据边界审查。租户私有材料即使可缓存,也只能在供应商提供的隔离机制和本应用的租户策略允许时使用;不能把其他租户的私有文本拼进共享前缀。权限与审批条件仍要在本次请求中由后端校验,缓存不能充当授权。
不要把“同一会话”当成命中保证。提供商的缓存有长度、保留时间、机器路由和模型差异;需要从实际用量字段计算命中情况,不能只凭输入看起来相同就报“已省钱”。
一个容易算错的账本
一次调用可能包含普通输入、缓存读取、缓存写入和输出。不同供应商的字段语义并不一致:有的总输入字段已包含缓存子项,有的要将普通输入与缓存读写相加。先把原始 usage 连同供应商、模型和价格版本保存,再在适配层统一成互斥计费桶:
1 | { |
output_tokens 可能包含不可见推理 Token,不能用最终显示的文字估算精确账单。成本按每个互斥桶乘对应费率,再加重排、工具、失败重试等任务成本。费率需要保存快照,历史账单不能随着今日价格变化而重算。
三、应用缓存:键里要放能改变答案的条件
对于企业知识问答,答案是否可复用至少受以下条件影响:
1 | tenant_id |
这不是要求把所有明文拼进 Redis Key。可以将结构化字段序列化后做稳定哈希,同时保留可审计的元数据。ACL 指纹应由后端当前权限集合计算;缓存命中后仍应检查当前身份和资源授权。权限撤销时,版本号或策略纪元要变化,避免 TTL 未到期继续命中。
一个 Java 风格的键构造例子:
1 | record AnswerCacheScope( |
缓存键只是第一道隔离。读缓存前后要在服务端执行授权,缓存值也要保存来源 chunk_id、生成时间、过期时间、策略版本和答案状态。对于订单余额、审批状态、库存、航班时刻等强时效数据,宁可只缓存短时间的只读工具结果,并在生成答案前重新取最新状态。
语义缓存的误命中
两个 Query 相似,不代表可以共享答案:
- “我能申请报销吗?”与“我不能申请报销吗?”只差一个否定词。
- “2025 年政策”与“2026 年政策”只差年份。
- “我的订单 O-17”与“同事的订单 O-17”文字相同,权限主体不同。
- “解释退款原因”与“执行退款”语义相关,但副作用完全不同。
所以语义缓存只适合经过任务分类的低风险、事实稳定、可共享答案场景。先做租户和 ACL 的精确过滤,再在允许复用的候选集合中计算语义相似度;命中后还要做实体、数字、否定、时间和动作类型校验。涉及写操作、审批、支付或当前账户数据时,禁止用相似问题的旧结果替代本次执行。
四、失效与并发:版本优先,TTL 兜底
缓存过期时间是最后一道保险,不能代替数据变更事件。
- 文档更新:发布新
knowledge_snapshot或index_version;新请求只读新版本命名空间,旧缓存等待清理。 - 权限变化:变更
policy_epoch或 ACL 指纹,立即让旧命中失效。 - 模型与 Prompt 变化:新版本写新键;用固定 Golden Set 复测后再扩大流量。
- 工具结果变化:以业务事件删除或切换资源版本,TTL 控制异常情况下的最长陈旧时间。
- 缓存回源高并发:用 single flight 合并同一个键的回源请求,设置等待截止时间;缓存服务不可用时限流回源,不让模型或数据库被并发冲垮。
对公开 FAQ 可以用适度随机 TTL 缓解集中失效;对权限和政策这种有版本的知识,应让版本切换承担主要失效责任。空结果可以短时缓存,但必须区分“确实无结果”和“下游超时”;后者不能写成长期空答案。
五、用同一套样本评估收益和错误
不要只报告“缓存命中率 60%”。命中率高可能是跨租户误命中或旧答案复用。对一组脱敏样本,至少比较:
| 指标 | 解释 |
|---|---|
| 正确命中率 | 命中结果经当前权限、版本和事实检查后仍可用的比例 |
| 错误命中数 | 否定、金额、日期、订单、租户或动作类型被混淆的次数 |
| 缓存读取/写入 Token | 供应商 usage 的实际字段,不靠估算 |
| 每成功任务成本 | 所有调用、重试和缓存费用之和 ÷ 成功任务数 |
| P95 与首 Token 延迟 | 比较用户实际等待,而不是只看平均值 |
| 失效传播时间 | 政策或权限变化后,旧结果停止服务的时间 |
实验矩阵可以这样设计:
1 | A. 无应用缓存,保留供应商默认 Prompt 缓存 |
每组固定模型、Prompt、工具回执和知识版本;遇到政策更新、权限撤销、跨租户同问、否定词与年份变化时重新跑。没有运行的 Case 标记 NOT_RUN。缓存节省和质量变化必须由实验记录证明,不能拿社区帖中的“降本百分比”当自己项目的结果。
六、90 分钟动手任务:给缓存加一个准入器
用本地 FakeModelClient、内存 Map 和假计费字段即可,不接真实付费 API。
1 | sealed interface CacheDecision { |
至少写六个固定夹具:公开 FAQ 重复请求、跨租户同问、权限撤销、政策版本更新、否定词改写、写工具请求。期待结果是第一类可命中,其余不能错误复用。再模拟同一热点 Key 的 20 个并发请求,验证 single flight 只回源一次、等待超时有明确状态。保存每个 Case 的键摘要、准入原因、命中状态和版本字段。
七、面试题:缓存设计要能说明错误边界
以下题目来自牛客公开用户面经和题库整理,检索日期均为 2026-11-05。公司与面试经历由发帖者自述,未获得企业官方核验;参考答案是本系列基于官方资料与工程原则整理的答法,不代表来源帖作者的原回答。
题 1:Prompt Cache 是什么,能直接返回旧答案吗?
- 方向: 模型工程 / Prompt 缓存;难度: 中。
- 来源: 牛客《聊一聊最近碰到的一些 Agent 面试题(五)》,公开题目含 Prompt 缓存与成本性能影响。
- 参考答案: 它复用相同前缀的模型计算,通常降低输入处理的延迟和相应费用,当前请求仍会生成新输出;答案缓存才直接返回旧结果。把稳定系统指令和工具定义放在变化内容之前,并以供应商实际 cache-read/write 用量验证收益。缓存输入仍可能计入 TPM。
- 追问: 同一会话为什么仍可能没有缓存命中?前缀变化后如何从 usage 中定位?
题 2:模型结果、向量和检索结果分别如何缓存?
- 方向: AI 平台 / 缓存隔离;难度: 中高。
- 来源: 牛客公开项目面试问答,其中列出三类缓存及键设计。
- 参考答案: 向量键绑定文本哈希、Embedding 模型和维度;检索键绑定 Query、索引/知识版本、租户、权限和检索策略;答案键再加模型、Prompt、工具 Schema、输出参数和适用时间。命中后仍校验当前授权和来源版本。写操作与强时效个人数据不复用旧答案。
- 追问: 权限撤销后如何立即阻止旧答案命中?哪种缓存可以拥有较长 TTL?
题 3:一个 5~6 步的 Agent 任务又慢又贵,缓存应该放在哪里?
- 方向: Agent 成本 / 任务评测;难度: 高。
- 来源: 牛客《Agent 应用工程师·详细面试题库》,场景题涉及模型分级、缓存、并行和成本监控。
- 参考答案: 先按 trace 拆出每步模型、检索、工具、排队和重试成本。稳定前缀争取供应商 Prompt 缓存;重复向量化、只读工具和检索可以按版本缓存;最终答案只在安全且事实稳定的场景缓存。比较所有计划任务的完成率、P95、错误命中和每成功任务成本,避免缓存提高命中率却降低质量。
- 追问: 如果缓存命中率上升、任务成功率下降,先查看哪些 Case?失败重试成本算在哪个任务上?
题 4:缓存击穿、穿透、雪崩在 AI 服务中分别会造成什么?
- 方向: Java 后端 / AI 网关可靠性;难度: 中高。
- 来源: 牛客用户整理的阿里云 AI Agent 算法一面,题面包含三类缓存故障;公司标签为发帖者自报。
- 参考答案: 不存在的 Key 反复回源是穿透,热点 Key 过期后大量并发回源是击穿,多 Key 同时失效或缓存集群故障是雪崩。在 AI 服务中分别可能打满向量库、模型并发和租户额度。用参数校验与短时空值、single flight、TTL 抖动、限流、熔断和后端容量保护处理;权限和版本校验不能为提高命中率而省略。
- 追问: Redis 故障时允许多少请求直接回源?回源限流与租户配额冲突时如何排序?
八、今天留下的交付物
提交一份缓存矩阵、一个 CacheDecision 准入器、六个安全夹具和一张实际用量/质量对照表。明天继续把成本账本落到请求、任务和租户三个层级,并讨论预算预检与运行中硬上限。