两次请求的中间段落完全相同,为什么不能直接搬用它的KV Cache?因为在常见因果Transformer里,中间Token已经读过前面的Token。前文变了,深层状态可能随之改变,即使这一段文本一字未动。
RoPE的旋转关系能够解释位置变化的一部分,不会自动抹掉前文内容对隐藏状态的影响。“内容寻址”也不是“只看当前块文本”。先把这两件事分开,才能讨论共享池。
缓存键应该表达什么
vLLM官方设计把父块哈希、当前块Token及额外身份纳入键。额外身份可以涉及适配器、多模态输入和隔离盐。下例是身份规则的教学模型,不是引擎内部结构的复刻。
import hashlib import json def block_key(parent, tokens, model_revision, tenant_salt): payload = [parent, list(tokens), model_revision, tenant_salt] encoded = json.dumps(payload, ensure_ascii=False, separators=(',', ':')).encode('utf-8') return hashlib.sha256(encoded).hexdigest() def chain(blocks, model='weights-v1', salt='tenant-A'): parent, keys = None, [] for block in blocks: parent = block_key(parent, block, model, salt) keys.append(parent) return keys first = chain([[1, 2], [3, 4], [5]]) changed_prefix = chain([[9, 2], [3, 4], [5]]) assert first[1] != changed_prefix[1] assert first[2] != changed_prefix[2] assert chain([[1, 2], [3, 4], [5]]) == first assert chain([[1, 2], [3, 4], [5]], model='weights-v2') != first assert chain([[1, 2], [3, 4], [5]], salt='tenant-B') != first print('prefix, weights revision, tenant identity: PASS')共享池解决存放与传输,不替代正确性条件
Mooncake在10月10日记录了TensorRT-LLM的连接器更新,涉及跨实例缓存池与前缀复用。这是具体的项目集成进展,不意味着任意模型、任意位置的KV都能直接交换。官方仓库
应用层可以把文档分块哈希用于检索或解析结果缓存;推理层的KV缓存还要满足模型、权重、位置、前缀和引擎布局等约束。它们可以共享元数据,但不能共享一个含糊的“命中率”。同样,租户隔离盐能限制缓存共享范围,并不代表所有时序侧信道已经被证明消除。
本地代码验证的是身份改变时键会改变,没有分配GPU页、运行重旋转Kernel或测量命中率。真正接入共享池时,应保存引擎版本和连接器配置,比较缓存命中与重新计算所得输出,并检查不同租户、适配器和多模态输入的隔离边界。