真实面经题目 · 原创解析
长上下文推理中 KV Cache 为什么可能被污染,如何做缓存隔离、清理和复用边界控制?
这题考的是大模型推理缓存的正确性与安全边界:KV Cache 本身是某个模型、某段 token、某套位置编码和注意力 mask 下的中间状态;一旦跨请求、跨会话、跨租户、跨模板版本或跨可变上下文错误复用,就可能产生答案串扰、隐私泄漏、事实陈旧或位置错乱。
真实面经题目 · 原创解析
这题考的是大模型推理缓存的正确性与安全边界:KV Cache 本身是某个模型、某段 token、某套位置编码和注意力 mask 下的中间状态;一旦跨请求、跨会话、跨租户、跨模板版本或跨可变上下文错误复用,就可能产生答案串扰、隐私泄漏、事实陈旧或位置错乱。
我会先区分两类 KV Cache:一类是单次请求 decode 过程中的历史 K/V,生命周期应该严格绑定 request 或 session;另一类是 prefix cache,把相同前缀的 K/V 复用给多个请求以节省 prefill 成本。所谓污染,通常不是 K/V 数值自己变脏,而是缓存被错误复用或没有及时失效:例如把 A 用户的长上下文前缀复用到 B 用户,系统 prompt 模板变了但 key 没变,LoRA adapter 或模型版本不同却共享缓存,滑动窗口丢弃 token 后位置没有对齐,工具结果或检索证据更新但旧前缀仍被命中。解决思路是把缓存边界显式化。缓存 key 至少要包含模型权重版本、tokenizer、token id 序列或其 hash、position scheme、attention mask、系统模板版本、adapter、租户或权限域等会影响 K/V 语义的因素;decode KV 默认 request 私有,prefix cache 只能复用不可变、可共享、权限一致的前缀。对可变上下文要做版本化和失效,对跨租户和隐私内容要禁用共享或按安全域隔离。清理上要有 TTL、LRU、引用计数、请求结束释放、取消释放、内存水位淘汰和异常回收。观测上要记录 cache hit 来源、key mismatch、跨域命中拦截、污染回归测试和 canary prompt。核心原则是:能复用的只能是语义完全相同且安全域一致的前缀,不能为了命中率牺牲正确性和隔离性。
KV Cache 污染不是指缓存里的浮点数随机坏掉,而是缓存状态与当前请求不匹配。常见表现包括回答带入别的会话内容、引用旧上下文、忽略新工具结果、跨用户泄漏、位置编码错位、adapter 不一致导致输出异常,或 prefix cache 命中后答案稳定偏错。
自回归 decode 阶段的 K/V 是当前请求已经生成或输入过的 token 的注意力记忆,默认应绑定一个请求或一个明确的会话分支。并发 batch 可以共享调度和内存池,但不能共享语义状态。请求结束、取消、超时或分支回滚时,对应 block 要释放或引用计数递减。
Prefix cache 能复用相同前缀的 prefill 结果,但相同不能只看文本字符串。K/V 依赖 token id、模型权重、tokenizer、位置编码配置、attention mask、系统模板、adapter、视觉或工具特殊 token 等因素。任何一个会改变前缀表示的因素变化,都应导致 cache key 不同或缓存失效。
企业知识、用户隐私、租户数据、付费权限和会话记忆不能随便进入全局共享 prefix cache。可以把 cache 分成 public prefix、tenant prefix、user/session prefix 等安全域;含隐私或检索证据的前缀默认只在同一权限域内复用,必要时完全不共享。
系统 prompt、工具结果、RAG 证据、用户画像、会话摘要和模板字段都可能更新。如果缓存 key 只记录模板名称而不记录版本或内容 hash,就会复用旧 K/V。更稳妥的做法是对可变前缀做内容 hash、版本号或构建批次标记,更新后自动失效旧缓存。
滑动窗口、attention sink、chunked prefill、分页 KV 和上下文压缩都会改变当前序列能看到的历史范围。清理旧 block 时必须同步更新 position、mask、block table 和可见窗口,不能让模型以为某些历史 token 仍可见,也不能把旧位置的 K/V 接到新位置上继续用。
推理服务通常会把 KV 放在分页 block 或内存池里。多个序列复用 prefix 时需要引用计数;生成分支、投机解码、取消请求或失败重试时需要释放未提交 block。否则轻则显存泄漏,重则 block 被错误复用到其他序列,形成难排查的串扰。
清理机制包括请求结束释放、TTL、LRU/LFU、内存水位淘汰、低优先级 prefix 淘汰、异常任务回收和周期性一致性扫描。淘汰时要保证没有活跃引用,不能在序列仍依赖某段 K/V 时回收;保留时也要限制生命周期,避免陈旧上下文长期命中。
需要记录 cache hit/miss、hit 的安全域、key 组成版本、跨域命中拦截、block 引用计数异常、释放延迟和 cache 相关错误。测试上可以设计两组带互斥秘密词的会话、模板版本切换、adapter 切换、租户切换和滑动窗口边界用例,验证不会串答案。
不够。K/V 还依赖 tokenizer 后的 token id、模型权重、位置编码配置、attention mask、系统模板版本、adapter 和特殊 token 等因素。文本一样但 tokenizer 或模型版本不同,缓存也不能复用。
通常只有完全公开、不可变、与用户权限无关的公共系统前缀或模板片段适合全局共享。只要前缀包含用户输入、租户知识、会话摘要、RAG 证据或隐私字段,就应按安全域隔离,甚至禁用共享。
如果实现正确,不会。调度层应通过引用计数或序列状态判断 block 是否仍被活跃序列使用。只有无引用或过期的缓存才能被回收,不能因为内存压力直接清掉仍在用的 K/V。
滑动窗口删除旧 token 后,要同步维护可见 token 范围、position id、attention mask 和 block table。新 token 只能 attend 到窗口内允许的 K/V,不能把旧位置的 K/V 当成新上下文继续拼接。
可以构造两个会话,分别注入互斥的秘密词或事实,然后交替并发请求、启用 prefix cache、切换模板和取消请求,检查任何一方答案都不能包含另一方事实。同时检查 cache hit 日志是否跨安全域。
不应把正确性和隐私边界让位于命中率。可以优化公共前缀、模板稳定性和调度复用,但含权限或用户内容的缓存必须保持隔离。命中率指标要和污染拦截、泄漏测试、答案一致性一起看。