AI 推理缓存:命中率好看,不代表结果可以随便复用
AI 推理缓存命中率好看不代表结果可以随便复用一、推理缓存先解决边界再追求命中率AI 后端为了降低成本经常会加入推理缓存。相同请求直接返回历史结果看起来能节省 Token 和延迟。但模型调用不是普通查询。Prompt、模型版本、系统指令、温度参数、工具版本、用户权限都会影响结果。只用用户输入做缓存 key很快会把错误结果复用出去。推理缓存要先定义可复用边界。适合缓存的是稳定、无副作用、对实时性要求低的请求。比如文案改写候选、分类结果、嵌入向量。涉及权限、实时状态、个人资料或外部工具调用的结果要么不缓存要么只缓存中间层。二、缓存 key 必须包含模型和上下文版本缓存命中是否安全取决于 key 是否表达了所有影响结果的因素。至少要包含模型版本、prompt 模板版本、参数摘要、输入哈希和租户边界。不要把原始输入直接当 key既不安全也不利于脱敏。flowchart TD A[用户请求] -- B[输入规范化] B -- C[计算输入哈希] D[模型版本] -- G[缓存 Key] E[Prompt 版本] -- G F[参数摘要] -- G C -- G G -- H{缓存命中} H --|是| I[返回缓存结果] H --|否| J[调用模型] J -- K[写入缓存]这里的 prompt 版本常被忽略。模板改了一句话结果语义可能变化。旧缓存继续命中会让灰度发布看起来没有生效。三、Go 实现要把过期和租户隔离写清楚下面示例展示一个缓存 key 构造函数。它不追求复杂但把影响结果的字段显式列出来。type CacheKeyInput struct { TenantID string ModelVersion string PromptVersion string ParamDigest string InputHash string } func BuildInferenceCacheKey(in CacheKeyInput) (string, error) { if in.TenantID || in.ModelVersion || in.PromptVersion || in.InputHash { return , fmt.Errorf(missing cache key field) } raw : strings.Join([]string{in.TenantID, in.ModelVersion, in.PromptVersion, in.ParamDigest, in.InputHash}, :) sum : sha256.Sum256([]byte(raw)) return infer: hex.EncodeToString(sum[:]), nil }租户 ID 必须进入 key。多租户平台里即使输入相同也不能默认共享结果。除非系统有明确的跨租户公共缓存设计并且缓存内容不含任何用户上下文。四、缓存失效要服务发布而不是靠自然过期碰运气推理缓存要支持按模型版本、prompt 版本和租户失效。模型升级、模板修复、安全策略变化时不能等 TTL 慢慢过期。平台需要有主动清理入口并记录谁在什么时候触发了失效。缓存指标也要分层看。命中率高不等于系统健康。还要看缓存结果复核失败率、不同模型版本的命中分布、缓存写入失败率和平均节省延迟。如果命中率来自过度泛化的 key那是风险不是收益。另一个边界是流式响应。完整结果可以缓存但流式过程中的中间 token 不适合直接复用。可以在模型完成后写入最终结果下次请求再模拟流式返回但要标记这是缓存结果。五、总结AI 推理缓存要先保证结果复用安全再谈成本优化。缓存 key 应包含租户、模型版本、prompt 版本、参数摘要和输入哈希并支持主动失效。命中率只是一个指标不能掩盖权限、版本和实时性边界。基础设施要托底就要把这些边界写进代码和运维流程。