会,但只在两个 LoRA 配置的 lora_name 相同、权重不同时发生。vLLM 0.11.1 同时开启 enable_lora=True 与 enable_prefix_caching=True 后,计算 KV 块哈希时把 lora_name 当作 LoRA 额外键拼进哈希,而 vLLM 文档要求对给定适配器全局唯一的是 lora_int_id。结果两个同名但权重不同的适配器得到相同的缓存哈希,命中同一批 KV 块,第二个请求会读到按第一份权重算出的缓存激活,输出错误并随缓存命中状态波动。报告给出的临时规避办法是:在修复前给每个不同权重的 LoRA 配置分配唯一的 lora_name;这个问题只在前缀缓存开启时出现。
前缀缓存的键里,LoRA 身份用的是名字
前缀缓存要回答一个很具体的问题:这段 prompt 对应位置的 KV,能不能直接拿之前算好的来用。判断依据是一个哈希键。据一篇技术文章的描述,vLLM 用每个 KV 块内容的 rolling block hash 标识该块,并在申请到 block 时就把哈希登记进全局哈希表,后续请求拿同样的哈希去查表,命中就复用。这段描述来自二手技术文章,不是官方文档,但它足以说明哈希键的构成决定了谁能和谁共享块。
只有 token 内容不够。同一段文字在不同的 LoRA 权重下前向计算出来的 key/value 不同,所以 LoRA 身份必须作为额外键拼进哈希,把不同适配器的块区分开。
0.11.1 的实现里,这个额外键是 vllm/v1/core/kv_cache_utils.py 中返回的 request.lora_request.lora_name。代码注释和报告者都指出,这里应该用 lora_int_id。vLLM 文档写明 lora_int_id must be globally unique for a given adapter,报告者据此认为它才应该是主缓存键;实际参与相等判断、哈希和缓存键的是名字。于是哈希函数看到的 LoRA 身份是字符串,而非文档承诺唯一的整数。
这把“唯一性”从 ID 转移到了名字上:只要两个配置的 lora_name 相同,哈希就不区分它们。
同名不同权重,怎么落到同一批块上
因果链可以顺着一次请求走完:
- 服务里注册了两个适配器,
lora_name都叫my-lora,lora_int_id不同,权重也不同。多租户服务里不同用户各自上传一个重名适配器,就会出现这种配置,报告把这种场景列为受影响场景。 - 第一个请求带适配器 A 进来,prompt 前若干块算完,块哈希用
lora_name="my-lora"拼出来,登记进全局哈希表;这些块里存的是按 A 权重算出的 key/value。 - 第二个请求带适配器 B 进来,前缀相同。块哈希依然只用
my-lora,算出来的键和 A 完全一致,查表命中。 - 命中后这些块直接参与 B 请求的注意力计算,不会用 B 的权重重新算 key/value。B 的注意力读到的是 A 的激活,输出因此错误。
| 两个配置的关系 | 哈希里的 LoRA 键 | 是否命中同一批块 |
|---|---|---|
lora_name 相同、权重不同 | 相同字符串 | 是,出问题 |
lora_name 不同 | 不同字符串 | 否 |
| 同一个适配器的重复请求 | 相同 | 是,预期复用 |
报告指出输出会随缓存状态显得不确定:同一段 prompt 在 B 上跑两次,结果可能不一样,差别来自第一次请求有没有先把 A 的块写进缓存、以及这次 prompt 有多少部分命中了缓存。命中比例越高,被污染的上下文越多。这只说明方向,报告没有给出污染程度或命中率的量化数据。
边界也要说清楚:资料证明的是“同一 lora_name、不同 lora_int_id”这一种配置下的冲突,不能扩写成不同 LoRA 适配器之间普遍共享缓存。名字不同时哈希不同,块不会被复用。
规避与自查
最直接的做法是让每个不同权重的配置拿到唯一的 lora_name,这也是报告在修复前给出的建议。落到多租户服务里,注册适配器时不要直接拿用户填的名字当 lora_name,而是在名字里拼上能区分权重来源的标识,例如内部 ID,保证“同名”在哈希层面不会发生。
风险范围同样要认清:问题只在前缀缓存开启时出现。关闭 enable_prefix_caching 就不会走这条按块哈希复用 KV 的路径,代价是失去前缀复用的收益。这个取舍是否值得,取决于你的负载里公共前缀占多大比例,资料没有给出可套用的阈值。
要确认自己是否踩中,可以做一个小对照:准备两份权重不同、lora_name 相同的适配器,用同一段 prompt 请求第二份适配器,分别在开启和关闭前缀缓存时各跑一次;再在开启缓存的情况下,改变“之前是否请求过第一份适配器”,看输出是否跟着变。如果只有开启缓存、且先跑过第一份适配器时输出才异常,就符合报告描述的模式。
版本上要留一分余地。报告在 vLLM v0.11.1、enable_lora=True、enable_prefix_caching=True 下复现了问题,并引用了修复提交与 #31489;但资料没有证实这些改动合并进了哪个发布版本,issue 本身也仍处于 open/stale 状态。因此既不能断言你手上的版本已修复,也不能断言仍未修复。升级前后都用上面的对照实验验证一遍,比依赖版本号更可靠。