同一块缓存被两把尺子量着,一把量费用,一把量留存时间

一、一个开关同时动了两个账

据公开报道,有厂商的 API 服务将提供较长时长的缓存保留选项,部分产品登录用户的缓存可能被更久保留。产品名、具体时长与条款细节都只作报道说法,不作为本文任何结论的依据,本文也不复述条款。值得单独写一篇的原因是结构性的:**”缓存保留时长”这个参数同时属于两本账**,一本是计费,命中率高低直接影响输入侧支出;另一本是数据留存,缓存本身是一份躺在服务端的应用侧文本副本,保留多久就是留存多久。

两本账的负责人不同。看账单的是技术或财务,判断留存责任的是合规与数据保护负责人,而绝大多数团队把这个开关当成纯性能参数,由写客户端代码的人顺手改掉。这就是问题所在:改一次配置,一边改的是钱,另一边改的是义务边界。我们要做的第一件事不是优化命中率,而是把这两件事拆到不同的人手里签字,并规定任何一档保留时长的启用都需要两边都点头。

二、命中率掉了,先分清是三种原因里的哪一种

缓存命中靠的是请求前缀与已缓存内容逐字节一致。失效原因只有三类,每类对应的代码位置不同,混在一起查会浪费很多天。

失效原因 典型表现 代码层面的成因 怎么确认
前缀变动 命中率整体塌陷,且与流量无关 前缀里混入时间戳、请求 ID、随机顺序的字段 把两次请求的完整提示做逐字节 diff
拼接方式改变 上线某次改动后命中率下一个台阶 历史消息重排、工具列表顺序变化、少样本条数调整 版本化的提示快照对比,定位到提交
保留时长到期 命中率呈周期性低谷 会话间隔超过保留窗口,缓存已失效 按”距上次同前缀请求的间隔”分桶统计命中率

第一类最普遍也最蠢。动态内容插在中间,后面全部作废,代价是整段前缀重新写入。修法是把所有每次都不同的东西一律挪到末尾——时间戳、会话变量、本次检索到的片段、用户当前问题。第二类常出现在多轮对话改造时:有人为了”上下文更完整”把历史消息压缩成一段自然语言摘要,或者把系统提示并入首条用户消息,前缀从此每次不同。修法是固定拼装函数,并把拼装结果作为快照留档,改动必须过 diff 检查。第三类不是 bug,是物理事实:会话间隔超过窗口就必然冷启动,能做的只是把窗口长度作为产品参数去考虑,而不是当作透明基础设施。

三、按”稳定前缀”分层重排,改变的是命中基线

把提示内容按变更频率从低到高排序,是让缓存真正起作用的前提,和”有没有开缓存”无关。我们固定五层,顺序不可调整:角色与输出约束等几乎不变的说明在最前;工具与函数定义其次,且要求序列化顺序稳定(同一份定义在不同运行时输出不同键顺序,就会自伤);少样本例子第三,条数与内容都固定;检索到的上下文第四,它每次都可能不同;会话历史与当前输入在最后。

重排改变的不是”能不能命中”,而是命中基线:不做分层时,命中率取决于代码写得是否碰巧稳定;做了分层后,命中率变成一个可以设计的量——你能通过控制”前缀里有多少内容真的稳定”来调节它。检索结果放进中间还是末尾,这一个决定往往就足以让整条链路从几乎不命中变成大部分命中。

顺带一条容易忽略的:命中要求前缀一致,但前缀越长,一次无意的改动波及越广。因此我们把提示模板当成有版本的构建产物管理,模板变更走与代码相同的评审,并在灰度期内同时观察命中率与答案质量,避免”为了命中而不敢改”或”改了不知道把命中改没了”两种极端。

四、缓存要单独核算,不然降本效果无法证明

命中收益在账单上的形态是”一部分输入 Token 按不同单价计费”。要能核算,就得在网关侧把四类量分开记录并各自命名:缓存写入的输入量、命中并复用的输入量、未参与缓存的普通输入量、输出量。这四列齐了,才能回答两个真正会被问到的问题。

  • 这一档缓存到底省下多少:拿命中量与写入量各自乘适用单价,与”全无缓存”的反事实基线对比。反事实基线要用同期同流量的输入量算,不能拿历史月份直接比,否则季节性会被算进收益。
  • 命中率该报多少:分母必须写清是”全部输入量”还是”可缓存输入量”。后者会显著高于前者,两种口径混用必然引发争论。我们固定用全部输入量作分母,同时单独报”可缓存前缀占比”——后者上不去说明是拼装结构问题,前者上不去才需要怀疑保留窗口或流量间隔。

命中率要做成一个可观测指标而不是抽查:按场景、按模型版本、按会话长度分桶,配一条阈值告警。它同时是质量指标:命中率突然升高有时意味着本该变动的内容不变了,比如检索层失效退化成固定前缀,这时缓存当然命中,答案却在用过期的东西。把命中率与”检索是否真的执行””答案是否带新出处”放在同一张面板上,才不会只看见好数字。所有具体价格数字以供应商合同与账单为准,本文不给倍数也不给金额。

五、保留时长拉长之后,合规侧要补的动作

技术侧收益越大,越要确认留存侧能不能承接。保留时长变长意味着这些文本在服务商侧存在的时间变长,而它们的内容往往包含系统提示、业务规则、客户数据片段与内部工具定义。要补的动作有四组。

留存清单新增一项。把”接口侧缓存”作为一类衍生数据登记:数据类别、来源字段、保留时长、可否主动关闭、销毁方式。没登记的副本类型会在删除请求到来时凭空消失于流程之外。

导出与删除要覆盖缓存。删除请求的验收不能只看业务库。我们要求一条可执行的检查:删除后重新构造同前缀请求,确认不再返回与旧内容强相关的结果,并记录验证方式与时间。做不到就要求在合同或工单里给出缓存失效的技术手段与生效时限。

把”永久保留”这类说法问成条件。需要书面回答的问题清单不长,但每一个都得问:保留的是原始文本还是派生表示;是否在账号或合同终止后继续存在;终止条件是什么、由谁触发;是否用于任何后续产品改进,若要需单独同意;有没有可关闭的开关。问不出现实语义,就按最保守情况处理——不把敏感内容放进会被长保留的前缀里。

确认项 为什么必须问 拿不到答复时的默认处理
多租户是否共享缓存 决定跨客户泄露的可能性 视为共享,敏感内容不进前缀
命中判定是否可被观测 时延与命中长度可能泄露内容存在性 关键请求加随机化前缀或直接关闭
保留时长是否可配置 决定能否按数据分级差异化 按最长档估算留存,写入清单
缓存内容能否主动清除 决定删除请求能否兑现 视为不可清除,限制写入内容范围

其中”多租户是否共享”最值得单列。企业客户最怕的不是自己数据被多存了一会儿,而是隔离边界含糊。隔离机制是否按账号维度、是否包含密钥归属、审计证据由谁提供,这三问要有明确答复。

六、两本账拆开之后怎么跑

落地成一份职责表,洹拓在项目里就按这张表分配签字人:

事项 负责人 输出物 复核频率
缓存档位与保留时长选择 平台工程 配置变更记录与命中率影响评估 每次变更
命中与成本核算口径 财务分析加平台工程 四列计量字段与分桶面板 每月
留存登记与删除覆盖验证 合规负责人 衍生数据清单、删除验证记录 每季
供应商条款确认 采购 书面问答与合同附件 续约前
提示前缀分层评审 应用负责人 模板版本与快照 diff 每次模板改动

顺序上有一条纪律值得单独强调:先定留存边界,再优化命中率。反过来做的结果,是一整套依赖长保留的链路建好之后,才发现某类内容根本不该被长存,届时改造成本比当初多写一层拼装要高得多。缓存是加速器,不是存储;把它当存储用,就要按存储的规则尽义务。