很多团队第一次给 AI 系统做缓存时,直觉都很一致:如果相同请求再次出现,就把上次回答直接返回。这个思路没错,但它只覆盖了 AI 缓存里最表层的一小部分问题。因为在真实生产环境里,AI 请求很少是“完全相同”的。用户会多打一个空格、少一句寒暄、换一种表达,甚至只是时间上下文不同,最终都会让请求在字面上不再相同。于是看起来很合理的缓存设计,上线后命中率却低得可怜。
更麻烦的是,AI 系统里的延迟和成本,并不只来自模型本身。检索、路由、权限判断、工具调用、上下文拼装、结果修复,这些步骤都在消耗时间和预算。如果缓存只盯着最终回答,就会忽略大量更值得缓存的中间结果。
所以在平台实践里,我们越来越少把 AI 缓存理解成“存一段答案”,而更把它看成一套针对不同链路环节的复用系统。缓存真正要解决的问题,并不是“用户重复问同一句话怎么办”,而是“系统里哪些代价高、稳定性高、可复用的计算结果,应该被主动保留下来”。
第一步:别急着缓存结果,先统一请求
很多低命中率问题,不是因为用户真的没有重复需求,而是因为系统没有把请求归一化。一个常见例子是客服 Copilot 场景。用户说“帮我总结这段聊天”,另一个用户说“把下面对话整理成摘要”,业务意图几乎一样,但字面上完全不同。如果缓存系统只做精确匹配,它们永远不会被视为同一类请求。
因此缓存设计的第一步通常不是建缓存表,而是做请求归一化。常见方法包括:
- 去除无关空白、标点和模板前缀。
- 把系统 Prompt 和运行时变量拆开,按结构而不是按整段文本识别请求。
- 对固定任务建立任务 ID,而不是直接把自然语言原文当 key。
- 对输入内容做稳定序列化,避免对象顺序变化导致 key 变化。
这一步的意义非常大。因为很多看似“用户输入千差万别”的场景,实际上在产品语义上高度重复,只是系统之前没有把它们识别出来。
第二步:区分字面缓存和语义缓存
做完归一化后,很多团队会进入下一层:语义缓存。所谓语义缓存,并不是简单模糊匹配,而是尝试判断“这次请求和上次请求在业务意义上是否足够接近,近到可以复用同一个结果”。
这件事听起来很吸引人,但其实很危险。因为语义相似并不总意味着结果可复用。比如“帮我总结上周客户反馈”和“帮我总结本周客户反馈”语义非常像,但答案绝对不能复用;“解释退款规则”和“解释退款规则并给出执行建议”也可能只差几个字,却对应完全不同的责任边界。
因此语义缓存真正能工作的前提,不是你有一个 embedding 相似度模型,而是你明确知道:
- 哪些任务允许“近似复用”。
- 哪些任务必须严格要求输入一致。
- 命中相似结果后,是否还需要二次验证。
- 缓存结果的可用期到底有多长。
没有这些边界,语义缓存命中率越高,反而越可能把错误答案规模化复用出去。
真正值得缓存的,经常是中间结果
AI Gateway 链路里,最常被忽略的一类缓存,是中间结果缓存。很多平台把所有注意力都放在最终模型回答上,却忘了前面很多步骤本身也很贵,而且更适合复用。
比较典型的中间缓存包括:
- 检索结果缓存。对固定知识源和高频问题,检索结果常常比最终回答更稳定。
- 工具结果缓存。像汇率、库存、规则列表、常见配置这类数据,并不需要每次都重新拉取。
- Prompt 组装缓存。复杂系统 Prompt 和工具描述的拼接,经常可以按版本复用。
- 路由决策缓存。某些短时间窗口内,主路由判断并不需要每次重算。
中间缓存的好处,在于它既能减少时延,也更容易控制风险。因为复用的是“系统内部材料”,而不是已经面向用户的最终答案。很多场景里,这种缓存比直接缓存回答更稳。
工具结果缓存尤其需要边界
工具结果缓存是 AI 系统里最容易做出收益、也最容易做错的一类缓存。因为工具调用往往比模型调用更慢、更贵、更依赖外部系统,而且用户感知非常直接。如果每次都重新查 CRM、库存、审批状态或知识库元数据,整体链路会很快变重。
但工具缓存有一个根本问题:业务数据天然会变化。某个订单状态 30 秒前还是“待处理”,30 秒后可能已经变成“已取消”;某个商品库存一分钟前还有,下一分钟可能就没了。也就是说,工具结果的缓存窗口不应该由“技术上能缓存多久”决定,而应该由“业务上能容忍多旧的数据”决定。
这也是为什么成熟平台通常不会给所有工具一个统一 TTL,而是会按工具类型、字段敏感度和业务后果来设缓存策略。查询类、低风险、变化慢的数据可以长一些;状态类、库存类、审批类结果则必须极其谨慎,甚至只允许在单次工作流范围内复用。
缓存命中不等于可以直接返回
缓存另一个经常被低估的问题,是“命中了之后到底怎么用”。在传统 Web 场景里,缓存命中往往意味着直接返回;但在 AI 系统里,这种逻辑并不总成立。因为有些缓存结果更适合作为候选材料,而不是最终输出。
例如某次缓存命中了历史摘要结果,系统可以把它当作草稿,再结合最新上下文快速生成新版本;某次命中了工具结果,系统可以先复用,再做关键字段校验;某次命中了旧的路由判断,系统也许仍需要确认当前 provider 是否处于健康状态。也就是说,缓存可以是“直接复用”,也可以是“带条件复用”。
这种设计虽然比传统缓存复杂,但它更贴近 AI 系统的现实。因为 AI 场景的很多结果,并不是单纯的静态资源,而是一种带上下文约束的阶段性产物。
失效策略比缓存本身更重要
很多缓存系统最终失控,不是因为命中率不高,而是因为失效策略太粗糙。AI 场景尤其如此。只要 Prompt 版本更新、知识源变更、工具 schema 调整、权限模型变化,过去缓存的很多内容就可能瞬间失效。问题在于,如果平台没有把这些变化和缓存键绑定起来,旧缓存仍会继续命中,看起来系统运行正常,实际结果已经悄悄偏离。
所以一个更成熟的做法,是让缓存失效和系统版本一起工作。比如:
- Prompt 版本变化时,相关回答缓存自动隔离。
- 知识库索引版本变化时,检索缓存整体换代。
- 工具 schema 变化时,工具结果缓存强制重建。
- 组织权限变化时,涉及可见性的数据缓存按租户失效。
从长期看,缓存系统是否可靠,更多取决于失效纪律,而不是取决于 Redis 配置得多快。
缓存也会反过来影响成本治理
在 AI Gateway 里,缓存从来不是单纯的性能优化功能,它还会直接改变成本结构。一个高命中的检索缓存,可能比模型单价下降更有效;一个设计良好的工具缓存,可能会同时减少外部接口成本和整体时延;一个错误的语义缓存,则可能在“降低调用量”的同时,把错误答案大规模放大。
这意味着缓存策略不应该只由工程团队单独决定,而应该和成本治理、稳定性目标、任务风险等级一起设计。某些场景宁可少命中,也要保证结果新鲜;某些场景则更适合以复用为优先。缓存因此不是简单的技术开关,而是一种产品和平台的联合策略。
缓存键设计,决定了系统后面会不会失控
很多缓存系统看起来命中率不低,但越跑越难维护,本质上是缓存键设计过于随意。AI 场景里的缓存键尤其不能只靠“把整段 Prompt 做 hash”来解决,因为一旦系统 Prompt、工具描述、知识源版本、组织权限、语言环境和模型参数都参与结果生成,简单 hash 既不利于复用,也不利于追查问题。
更成熟的缓存键通常会显式包含几类信息:
- 任务类型,而不是整段自然语言。
- 组织或租户边界,避免跨客户误命中。
- Prompt 或工作流版本,保证变更后自动隔离。
- 知识源版本和权限快照,防止引用过期资料。
- 关键参数片段,而不是全部上下文原文。
键设计越有结构,缓存系统越容易解释;键设计越随意,命中结果越像黑盒。长期看,能否解释“为什么命中了这条缓存”,往往比命中率本身更重要。
多语言和多租户场景会把缓存问题放大
单一语言、单一客户环境里,缓存已经不简单;一旦进入多语言、多租户平台,复杂度会明显上升。因为同一个业务动作在不同语言下可能需要不同 Prompt,不同租户又有不同知识源、权限和工具边界。此时如果缓存只按任务和文本做粗粒度复用,很容易出现跨语言或跨租户污染。
这也是为什么成熟平台会把缓存边界明确建立在租户和环境之上。命中率低一点并不可怕,跨边界复用才真正危险。尤其在企业场景里,缓存如果没有和租户隔离、权限过滤、知识源版本一起设计,最终可能成为数据泄露和错误引用的隐蔽通道。
缓存策略应该和观测一起演进
很多团队上缓存之后,只在乎命中率和节省了多少调用,但忽略了缓存也需要被持续观测。更有价值的观测指标通常包括:
- 不同任务类型的命中率差异。
- 命中后仍被下游判定不可用的比例。
- 因版本变更触发的大规模失效频率。
- 命中缓存后平均节省的时延和成本。
- 哪些缓存项最常引发人工回退或人工修正。
这些数据能帮助团队判断缓存到底是在创造收益,还是在偷偷制造新的复杂度。真正成熟的缓存系统,不是“一次设计好后就不再动”,而是会随着任务结构、知识治理和组织边界一起演化。
真正成熟的缓存,是一套分层体系
做得久了之后,我们反而越来越少谈“AI 系统有没有缓存”,而更多谈“缓存分层是不是合理”。因为真正有效的设计,通常至少包含几层:
- 输入归一化层,解决同类请求无法识别的问题。
- 中间结果层,优先复用检索、工具和 Prompt 组装等稳定环节。
- 回答层,只在高重复、低风险任务上使用。
- 版本失效层,确保缓存和 Prompt、知识源、权限边界同步演进。
只有这几层一起存在,缓存才不会变成一堆偶然命中的优化碎片,而会逐渐长成平台的正式能力。
结语
AI Gateway 的缓存,不只是缓存回答。它真正要解决的,是在复杂链路里识别哪些计算值得复用、哪些结果必须新鲜、哪些中间步骤可以被稳定保存。把这件事想清楚之后,缓存就不再只是“省几次调用”,而会变成稳定性、成本和体验共同受益的一层基础设施。