3、推理结果一致性定义
在 vLLM 生产环境排障中,“推理结果不一致”是最常被提及却又最容易被误判的问题。要准确排查,首先必须把“一致性”这个词从模糊的直觉提升为可度量、可复现的工程定义。本章节将明确一致性的边界,区分确定性推理与随机性推理的本质差异,并给出可操作的评估指标。
3.1 什么是一致性:从“看起来像”到“可量化”
推理结果一致性,指的是在输入完全相同的条件下,模型多次推理输出结果之间的稳定程度。这里的关键是“输入完全相同”——不仅包括 prompt 文本,还包括采样参数(temperature、top_p、max_tokens 等)、随机种子、模型权重版本、推理引擎配置(如 vLLM 的 block size、dtype)以及硬件环境(GPU 型号、驱动版本)。
一致性可以拆解为三个递进层次:
- 逐字一致(Exact Match):两次输出字符串完全相同。这是最严格的标准,通常只在 temperature=0 且关闭随机采样时才有可能达到。
- 语义一致(Semantic Match):输出文本不同,但核心含义、事实、数值、结论相同。例如“北京是中国的首都”与“中国的首都是北京”。
- 分布一致(Distribution Match):多次输出的整体概率分布稳定。例如在 100 次采样中,“正面回答”出现 82 次,“拒绝回答”出现 18 次,这个比例在多次实验中保持稳定。
在 vLLM 场景中,我们通常关注的是逐字一致与分布一致。前者用于回归测试和 CI 验证,后者用于评估生成质量与业务稳定性。
3.2 确定性推理与随机性推理:本质区别
vLLM 推理引擎本身是确定性的——给定相同的输入张量、权重和计算图,前向传播的数学运算是完全可复现的。但采样过程引入了随机性,导致最终输出文本可能不同。理解这一区别是排查一致性问题的基础。
下表对比了两种推理模式的关键差异:
| 维度 | 确定性推理(temperature=0) | 随机性推理(temperature>0) |
|---|---|---|
| 采样策略 | 贪心解码(greedy decoding),每步选概率最高的 token | 概率采样(如 top-k、top-p、temperature 缩放后随机抽样) |
| 输出可复现性 | 同一权重+同一输入,输出完全一致(理论上) | 即使 seed 相同,不同 batch 或并行度下也可能不同 |
| 随机种子影响 | 不影响结果(因为不采样) | 影响结果;但 vLLM 的 seed 控制粒度需验证 |
| 适用场景 | 代码生成、数学计算、结构化输出、回归测试 | 对话、创意写作、数据增强、多样性要求高的场景 |
| vLLM 配置 | --temperature 0 或 sampling_params.temperature=0 |
--temperature 0.7 --top-p 0.9 等 |
一个常见的误区是:“只要设置了 seed,输出就一定一致”。实际上,vLLM 的 seed 控制的是 Python 随机数生成器(用于采样),但以下因素仍可能导致不一致:
- 多进程/多卡推理时,每个 worker 的随机状态独立,seed 只作用于主进程。
- batch 内多条请求共享采样状态时,请求顺序变化会影响后续采样结果。
- vLLM 的 continuous batching 机制导致 token 生成顺序动态变化,影响随机数消费顺序。
temperature=0 并不完全等价于“确定性输出”。如果模型使用了 dropout(训练时)或某些算子(如 flash attention 的数值近似),前向传播本身可能引入微小浮点差异。但在推理阶段,vLLM 默认关闭 dropout,因此 temperature=0 时输出通常是逐字一致的。
3.3 评估指标:如何量化一致性
为了客观评估一致性,我们需要量化指标。以下三个指标覆盖了从文本到分布的多个维度:
3.3.1 重复率(Repetition Rate)
重复率衡量的是同一输入多次输出中,完全相同结果所占的比例。计算公式为:
重复率 = (完全相同的输出对数) / (总输出对数) × 100%
例如,对同一 prompt 执行 5 次推理,得到 5 条输出。两两比较,若 5 条全部相同,则重复率为 100%;若 3 条相同、2 条不同,则相同对数为 C(3,2)=3,总对数为 C(5,2)=10,重复率为 30%。
重复率适用于:
- 验证 temperature=0 时是否真正确定性(期望 100%)。
- 评估随机采样时输出多样性是否合理(过高或过低都需关注)。
3.3.2 方差(Variance)
方差衡量的是输出在某个可量化维度上的离散程度。由于文本本身不可直接计算方差,通常需要映射到数值特征:
- 输出长度方差:每次生成 token 数量的波动。
- 数值输出方差:如模型返回“置信度分数”“金额”“概率”等数值时,多次输出的标准差。
- 嵌入向量方差:对输出文本做 embedding,计算向量间的欧氏距离或余弦相似度方差。
方差的计算公式(以输出长度为例):
设 n 次输出长度分别为 L1, L2, ..., Ln
均值 μ = (L1 + L2 + ... + Ln) / n
方差 σ² = Σ(Li - μ)² / n
方差越小,说明输出越稳定。但需要注意:方差为 0 并不一定是好事——如果业务需要多样性(如推荐文案),过小的方差反而说明模型退化。
3.3.3 语义相似度(Semantic Similarity)
当输出文本不同但语义相近时,重复率和方差都无法反映。此时使用语义相似度指标:
- BLEU / ROUGE:基于 n-gram 重叠,适合翻译、摘要等任务。
- BERTScore / Sentence-BERT 余弦相似度:基于语义向量,适合开放域生成。
- LLM-as-a-Judge:用另一个 LLM 判断两次输出是否语义等价。
在实际排障中,建议组合使用:先用重复率快速判断是否“完全一致”,再用方差判断数值稳定性,最后用语义相似度确认“看起来不同但实际等价”的情况。
3.4 案例:一次典型的一致性排查流程
假设你收到反馈:“vLLM 部署的模型,同一个问题每次回答都不一样,是不是 bug?”按照以下流程排查:
- 确认采样参数:检查请求中的 temperature、top_p、seed 是否设置。如果 temperature=0.7,那么“每次不一样”是正常现象。
- 固定 seed 测试:将 temperature 设为 0,seed 设为固定值(如 42),连续请求 10 次,计算重复率。
- 检查 vLLM 配置:确认是否启用了
--seed参数,以及是否在多卡环境下使用--tensor-parallel-size。 - 对比单卡 vs 多卡:在单卡上重复步骤 2,若单卡重复率为 100% 而多卡不为 100%,则问题出在并行采样状态同步。
- 记录日志:使用 vLLM 的
--log-requests记录每次请求的采样参数和输出,便于复现。
以下是一个典型的 vLLM 请求配置示例:
from vllm import SamplingParams
# 确定性推理配置
deterministic_params = SamplingParams(
temperature=0.0,
top_p=1.0,
max_tokens=256,
seed=42
)
# 随机性推理配置
random_params = SamplingParams(
temperature=0.8,
top_p=0.9,
max_tokens=256,
seed=None # 不固定种子
)
3.5 误区与复盘:一致性排查中的常见陷阱
用户说“两次回答不一样”,但仔细对比后发现只是措辞不同,核心结论相同。此时应使用语义相似度指标,而不是逐字对比。
误区二:忽略 batch 影响
在 vLLM 中,同一 batch 内的多条请求共享采样状态。如果 batch 大小或请求顺序变化,即使 seed 相同,输出也可能不同。排查时务必固定 batch 配置。
误区三:认为 temperature=0 绝对一致
虽然理论上贪心解码是确定性的,但 vLLM 的某些优化(如 speculative decoding、chunked prefill)可能引入非确定性。如果业务要求严格一致,建议在 CI 中做重复率测试,而不是假设。
误区四:只测一次就下结论
一致性是统计概念,至少需要 5~10 次重复实验才能得出可靠结论。单次输出不同可能是偶发随机性,不代表系统不稳定。
最后,将一致性评估纳入日常运维流程:在模型更新、vLLM 版本升级、硬件变更后,运行一组标准测试 prompt,记录重复率、方差和语义相似度基线。一旦指标异常波动,即可快速定位是模型、引擎还是环境变化导致。
上图总结了本章节的核心框架:先明确输入条件,再区分推理模式,然后选择合适的评估指标,最后依据判定逻辑得出结论。在实际排障中,按照这个流程可以避免大多数误判。