下一轮请求会回到上一轮留下缓存的那个副本。
智能体每一轮都会重新发送它的全部历史,因此长对话的大部分内容都是引擎已经读过的前缀。vLLM 把这部分工作保存在前缀缓存中(即它见过的提示词的注意力状态),下次同样的前缀到来时就可以跳过,但这只在做过这项工作的那个副本上有效:模型的每一份完整拷贝都有自己的缓存。vLLM 自带的负载均衡器把每一轮发给队列最短的副本,而那个副本通常从未见过这段对话,于是要把整个历史重新读一遍。LM Warden 把每个新对话放到负载最低的副本上(综合考虑进行中的请求数、缓存占用率和该副本持有的活跃对话数),并借助 Claude Code 本来就会发送的会话 ID,让对话一直留在那里。只有当该副本超过溢出阈值时,才会把请求移走:默认阈值是进行中的请求超过模型并发序列上限的四分之一,在我们的四卡主机上为 8。
副本以及这种路由属于配备 NVIDIA GPU 的 Linux 安装;Mac 应用(测试版)不支持张量并行或数据并行。
图 6一个对话的四轮请求,模型有四个副本。使用 vLLM 的负载均衡器时,每一轮都在接到它的副本上几乎从头预填充(把提示词读入缓存)。使用 LM Warden 时,对话一直留在副本 2 上,只有新的一轮需要预填充。这是机制示意图,不是测量结果。
在四卡主机上实测:把对话固定到副本后,在 4 个并发会话时,从缓存提供的提示词 token 占比从 56% 升至 86%,首字节时间中位数从 2.05 降至 0.38 s。在我们测试的每一级中,每分钟输出 token 数都更高,p95 首字节时间(最慢的 5%)也都更低。实际在工作的副本数几乎没变(4 个会话时为 2.71 对 2.83,总共四个):收益来自缓存复用,而不是更多显卡投入工作。
24 和 32 个会话这两级是对四块小显卡的刻意超载,无论是否开启亲和性,等待时间都会长达数十秒。这时取舍就显现出来了:开启亲和性时长尾延迟仍然更短,但中位数更长。数据如下。
- GPU
- 4 × NVIDIA RTX A4000,每块 16 GiB
- 模型
- qwen3-4b-dp4(Qwen/Qwen3-4B-Instruct-2507),bf16
- 切分方式
- data_parallel_size 4,tensor_parallel_size 1
- vLLM
- 0.26.0
- LM Warden
- 本版本
- 采集时间
- 2026 年 10 月 4 日,两组连续运行
- 负载
- 来自我们自己压测工具的模拟 Claude Code 风格会话,而不是 Claude Code 本身:约 3.5k token 的共享系统提示词;每个会话独有的第一条消息(标称 6k,实测约 7.2k 到 7.5k);之后再进行五轮,每轮约 400 个新 token,每轮最多输出 256 个 token。采用闭环方式:一个会话的上一轮结束后,立即开始下一轮。每一级 3 分钟。
图 7并发会话数为 4 到 32 时的首字节时间,包括中位数和 p95,采用对数刻度,以便亚秒级和长达一分钟的数值能放在一起对比。开启亲和性后,在 16 个会话以内中位数要低得多(4 个会话时为 0.38 对 2.05 s),在 24 和 32 个会话时更高;p95 在每一级都更低,不过在 16 个会话时差距(24.9 对 26.2 s)在每组只跑一次的噪声范围之内。在客户端测量,经由互联网,计到第一个流式 token。
在 16 个会话以内,开启亲和性在每一级的吞吐量、前缀缓存命中以及两列首字节时间上都领先:4 个会话时,命中率从 56% 升至 86%,首字节时间中位数从 2.05 降至 0.38 s,输出从每分钟 5,886 升至 6,744 个 token(每小时会话数从 180 升至 240)。在 24 和 32 个会话这两个超载级别,每个副本都已饱和。输出仍然更高(每分钟 11,178 对 9,048 个 token,以及 16,638 对 14,760 个 token),长尾延迟也短得多(p95 为 38 对 59 s,以及 39 对 83 s),但开启亲和性时首字节时间中位数更差:24 个会话时为 13.1 对 5.1 s,32 个会话时为 27.7 对 12.3 s。我们还没有查明原因,把溢出阈值从 8 降到 4 也没有改变这一点。有余量时优势最大;长期满负荷运行的主机应该把两种设置都测一遍,亲和性可以按模型关闭。
图 8四个副本中忙碌的副本数:每次轮询时有请求在运行的副本数,在一级内取平均。不是 GPU 利用率。亲和性几乎不改变它;收益在图 9 中。
图 9每一级的前缀缓存命中率:从缓存提供的提示词 token 数除以请求的提示词 token 数,四个副本合计,取自该级期间 vLLM 自身计数器的变化。只要还有余量,收益就会保持;到 32 个会话时对话开始溢出,收益随之消失。
亲和性开启,溢出阈值 8(自动)
每个副本的命中率,来自 vLLM 自身的计数器
图 10模型页面上的同一组计数器:每个副本一行,显示它持有的请求、有多少对话留下(sticky)或通过溢出到达、正在运行和等待的请求、使用中的 KV 缓存以及前缀缓存命中率。记录于 2026 年 10 月 4 日,亲和性开启,溢出阈值为 8(自动):sticky 100%,副本 0 到 3 上分别有 38、21、19 和 29 个 sticky 请求,前缀缓存命中率分别为 82.2%、86.0%、69.0% 和 80.0%。计数器从 warden 重启时开始累计,该时段内的所有流量都开启了亲和性:模拟的智能体会话加上真实的 Claude Code 轮次。图中是控制台里的计数卡片,并非基准测试结果。左右滚动图片可查看所有列。
最初促使我们做副本路由的那台主机,此后一直在用它。这台主机有七块 RTX 5090,以七个单卡副本运行一个 27B 模型,为一组无头(headless)Claude Code 智能体提供服务。我们最初的放置规则是对会话 ID 做哈希,这样能保持粘滞,却看不到负载。在 26 个各约 58k token 的智能体会话下,三个副本闲置,其他副本的缓存却被用到 93%,从缓存提供的提示词 token 占比从重启后的 81% 在约 35 分钟内跌到 28%。随后我们把智能体减少到 16 个会话,约每个副本两个,使工作集能放进缓存,并把新对话放到负载最低的副本上。接下来一小时里该占比为 78% 到 79%。这是观察,不是 A/B 测试:同一个工作负载,两项改动同时进行,所以收益并不全来自放置策略。由此得出的经验法则是:让并发会话数乘以其典型上下文长度,保持在主机的总缓存容量以下。
由引擎按请求测量
图 11七卡主机上每秒的提示词 token 数,分为每个副本从其前缀缓存读取的部分和必须计算的部分,并显示过去一小时的占比:78%。缓存部分是引擎对每个已完成请求的自身计数,不是估计;引擎没有测量的请求计为计算部分。记录于 2026 年 10 月 5 日。左右滚动图片可查看整个小时。