资讯动态

测试时扩展实操:推理范式、评测与可复现性指南

发布时间:2026/8/27 4:55:00 来源:尧图企业网站定制
Test-Time Scaling测试时扩展这几年在推理型 LLM 里几乎成了绕不开的话题。它的核心思想很直接与其继续堆训练算力不如在模型回答问题时额外分配更多计算资源让模型多采样、多想几步、多验证几轮从而提升推理质量。随着 DeepSeek-R1 这类开源推理模型出现普通开发者也终于能在本地环境里跑通“更长思考”的推理流程。这篇文章围绕推理范式Inference Regimes、评测Evaluation和可复现性Reproducibility三个维度展开先讲清楚概念再给出可落地的实验流程、参数取舍和坑点排查。适合正在复现相关论文、想把推理模型接入业务、或者在做技术选型和评测方案的人。很多文章一上来就讲“测试时扩展有多强”但实际跑过之后你会发现真正难的不是理解思想而是选哪种推理策略、评测怎么设计、跑完结果换台机器还能不能复现。下面按我的实际落地顺序拆一遍。1. 先搞清楚 Test-Time Scaling 到底在解决什么问题1.1 从“训练时堆算力”到“推理时堆算力”传统提升 LLM 能力的方式主要在训练阶段发力模型规模更大、训练数据更多、训练时间更长。这个路线有效但成本越来越高。训练一次大模型需要大量 GPU而且很多时候你已经有了一个可用的模型不可能为了某个具体任务重新训练。Test-Time Scaling 换了一个思路模型权重不变把额外计算放到推理阶段。具体表现为让模型生成长一点的思考过程再给出答案同一个问题生成多个候选答案最后投票或筛选让模型基于已有回答继续检查、修正引入验证器对多个候选答案排序。这个思路在数学推理、代码生成、逻辑问答这类任务上尤其明显。原因也很简单这类任务往往有明确的正确答案多尝试几次或者让模型自我检查确实能减少低级错误。但这里有一个很容易误判的地方Test-Time Scaling 不是“想得越久越好”。更准确的说法是在推理阶段通过分配不同的计算预算和搜索策略换取更高的任务准确率。不同模型、不同任务、不同预算下收益差异非常大。有的任务采样 4 次就能涨 5 个点有的任务采样 64 次也只涨 1 个点。1.2 推理规模不是一个变量而是一组变量很多人刚接触这个概念时会把测试时扩展理解为“让模型多输出一些 token”。这只是其中一部分。真正决定推理扩展效果的是一组变量采样次数同一个问题生成多少条候选答案采样参数温度、top_p、频率惩罚等输出长度限制允许模型思考多少 token候选筛选方式直接投票、验证器重排、还是搜索式探索验证器有没有一个能判断答案质量的函数或外部模型计算预算总推理时长、总 token 数、GPU 显存占用任务类型数学题、代码题、开放问答适用的扩展方式完全不同。这些变量组合在一起就是论文里常说的 Inference Regimes推理范式。同一个模型用并行采样和用顺序迭代结果会有明显差异同样的并行采样用投票和用验证器重排结果也会有差异。所以看论文时一定要先确认它实验用的是哪种推理范式。1.3 哪些人最需要关注这个方向如果你属于下面几类这篇文章的实操部分会更有参考价值正在复现相关论文发现论文里的分数自己怎么跑都跑不出来在做推理模型的评测发现同样的题、同样的模型反复测分数忽高忽低想把推理模型接入业务但不确定该用多少次采样、要不要额外加验证器在做技术方案对比需要量化评估“多花一倍推理时间能换多少准确率”。这类问题的共同点不是模型本身不够好而是推理策略、评测方法、实验记录这三件事没有做到位。2. 推理范式Inference Regimes怎么选不同策略的决定性差异2.1 单次解码一切实验的基线我建议任何实验都从单次解码开始。这不仅仅是为了省算力更是为了建立基线。所谓单次解码就是输入一个问题模型自己决定思考多少步最后输出一个答案。这时候需要记录四样东西准确率平均输出 token 数最大输出长度单条耗时。这些数据是你后面所有扩展策略的比较基准。后续无论做多次采样、投票、还是引入验证器都要拿结果和这个基线比才能判断“额外花掉的推理时间到底值不值”。有些人喜欢直接上 best-of-n 或者搜索式扩展跳过基线。这个习惯不太好。因为后面跑出来的结果如果看起来不错你根本不知道是推理策略的功劳还是模型本身在那个任务上已经很强了。2.2 并行扩展多次采样与自一致性最直观的扩展方式是让模型对同一个问题生成 N 个答案然后做投票。常见做法是 Self-Consistency多次采样后取出现次数最多的答案字符串作为最终结果。这里有两个关键细节投票对象是最终答案字符串不是整段推理过程必须先把推理过程中夹带的“最终答案”抽取出来再做字符串归一化。字符串归一化指的是去掉多余空格、统一标点、把“100 个”和“100个”视为同一个答案。否则投票会被同一答案的不同写法拆散影响效果。并行扩展的优势是实现简单、耗时可控。代价是总 token 数会线性增长。生成 8 个候选答案输出 token 大概是单次解码的 8 倍。如果你的推理接口按 token 计费这个成本要提前算清楚。2.3 顺序扩展迭代优化与自我检查另一种常见推理范式是顺序扩展。模型先生成一个答案然后基于这个答案继续反思、检查、修正循环多次。这种方式更接近人做题时的“做完检查一遍”行为。对某些任务尤其是需要长链条推理的数学题顺序扩展比单纯多次采样更省 token因为它是在已有答案基础上做局部修正而不是每次都从头重新生成。但顺序扩展有两个难点迭代次数不确定运行时间波动很大模型可能出现“自我强化误区”坚持原本的错误答案越修正越自信。如果要做顺序扩展实验必须设定最大迭代次数和停止条件。比如“修正后的答案和上一轮答案一致时停止”或者“达到第 5 轮强制结束”。否则批量任务可能被个别长样本拖死。2.4 交给验证器Best-of-N 和重排序如果有额外的验证器可以生成 N 个答案再用验证器打分取最高分的答案输出。这就是 best-of-n。这里的核心是验证器质量。验证器不准排序就是乱的。最典型的问题是验证器偏好长答案。只要答案写得长、看起来完整就给高分而不管正确答案是什么。自己做验证器时优先选那些已经在结果级数据上训练过的打分器或者用 LLM-as-a-judge 的方案。用 LLM 做 judge 时要固定评分 prompt、固定温度、固定模型版本否则同一个候选答案在不同次打分中可能分数浮动很大。2.5 搜索式扩展Beam Search 与树搜索更复杂的方式是搜索式扩展。模型同时探索多个推理路径保留得分最高的若干候选逐步扩展直到找到满意答案。这类方法适合研究级探索比如论文中验证“更多搜索是否能带来更多收益”。工程落地时要谨慎评估。因为搜索式扩展的代码复杂度、调试成本、运行时长都比并行和顺序扩展高一个数量级。2.6 不同推理范式的资源对比为了让你在选型时有个粗略判断这里给一张基于常见开源模型的对比表。具体的绝对值取决于模型和任务但相对关系基本稳定。推理范式实现复杂度总 token 消耗耗时波动适合场景单次解码低1 倍小基线对比、快速验证并行采样 投票低N 倍小题库类任务、准确率优先顺序迭代中不稳定大长链条推理、模型具备反思能力Best-of-N 验证器中高N 倍 验证开销中有可靠验证器的场景搜索式扩展高高大研究探索、特定强推理任务实际选择时先按这个顺序试单次解码 - 并行采样投票 - 加验证器。如果收益不明显再考虑顺序迭代和搜索式方法。3. 实操在真实环境里跑通一次推理扩展实验3.1 环境准备先确认硬件和依赖在本地复现测试时扩展实验不一定要顶配 GPU。中端显卡也能跑但要把模型规模和采样次数降下来。以开源推理模型为例常见的部署方式有两种用 transformers 直接加载模型适合小模型、单条测试用 vLLM 部署推理服务适合多次采样、批量任务。vLLM 的好处是支持并行采样一次请求可以返回多个候选答案不用自己重复调用。这对测试时扩展非常关键因为多次采样如果逐条调用网络和调度开销会非常大。依赖方面至少要准备Python 3.10 或更高版本PyTorch版本要和模型要求匹配vLLM 或 transformers显存足够的 GPU磁盘空间用于存放模型权重和推理日志。如果你的机器只有一块 16GB 显存的显卡建议先用 7B 级别的蒸馏推理模型。如果显存只有 8GB可以降低 max_model_len或者用 4bit 量化方式加载模型。注意低显存环境能跑通不代表适合跑批量任务。同一时间占用的候选答案越多显存峰值就越高。先把单条任务跑通再逐步增加采样次数不要一上来就跑 64 次采样。3.2 最小可运行流程一次生成多个候选答案下面给出一段基于 vLLM 的示例代码。这个流程包含加载模型、设置采样参数、生成多个候选答案、抽取最终答案、多数投票。from vllm import LLM, SamplingParams llm LLM( modeldeepseek-ai/DeepSeek-R1-Distill-Qwen-7B, dtypebfloat16, max_model_len8192, ) params SamplingParams( temperature0.6, top_p0.95, max_tokens2048, n8, # 一次生成 8 条候选答案 ) question 一个班级有 28 名学生其中 1/4 的学生戴眼镜。请问戴眼镜的学生有多少人 prompt f请一步一步思考最后用“答案是xxx”的形式给出答案。\n{question} outputs llm.generate([prompt], params) candidates [] for output in outputs: for item in output.outputs: candidates.append(item.text) print(f生成候选答案数量: {len(candidates)})这段代码的核心在n8。它让 vLLM 一次返回 8 条采样结果而不是你手动循环调用 8 次。省时省力。3.3 答案抽取与多数投票候选答案生成后先不要直接数出现次数先做答案抽取和归一化。import re from collections import Counter def extract_answer(text: str) - str: # 优先找“答案是”后面的内容 match re.search(r答案是[:]\s*(.), text) if match: return match.group(1).strip() # 找不到就取最后一行 lines [line.strip() for line in text.strip().splitlines() if line.strip()] return lines[-1] if lines else text.strip() def normalize_answer(answer: str) - str: # 去掉空格、统一数字和单位之间的连接方式 answer re.sub(r\s, , answer) answer answer.replace(, ,).replace(。, .) return answer extracted [normalize_answer(extract_answer(c)) for c in candidates] counter Counter(extracted) final_answer counter.most_common(1)[0][0] print(多数投票结果:, final_answer) print(各答案分布:, counter)这个环节最容易出错。模型输出里可能出现多种格式比如“答案是 7 人”“答案7人”“7”。如果直接对原始文本做字符串统计同一个答案会被当成三个不同答案投票结果就会偏离。3.4 关键参数说明下面这些参数决定了测试时扩展的效果边界逐个说明。参数含义建议temperature采样随机性推理模型通常用 0.6 左右不要太高top_p核采样范围0.9 到 0.95 是常见区间n采样候选数入门先用 8验证收益后再增加max_tokens单条答案最大长度按任务复杂度设置过长浪费资源max_model_len模型上下文窗口决定能否容纳完整思考过程温度这个参数需要单独强调。很多人用默认的 1.0 做多次采样结果投票效果不稳定。温度太高模型容易胡言乱语温度太低多次采样的答案几乎相同投票就失去意义。建议在 0.5 到 0.8 之间做一个小范围扫描找到生成答案多样性收益最大的点。3.5 成功标准怎样才算跑对了判断实验是否成功不是看有没有报错而是看三个指标单条候选答案是否完整有没有出现截断、重复循环、突然中止投票结果是否合理跟人工判断是否一致耗时和 token 消耗是否符合预期8 次采样的 token 消耗是否接近单次解码的 8 倍。如果候选答案大量截断先看 max_tokens 是否设置得太小。如果投票结果不稳定先看答案抽取和归一化是否靠谱。如果耗时异常高先看是不是并发设置和显存不足导致排队。4. 评测Evaluation怎么做才靠谱不能只看答案对不对4.1 为什么推理模型的评测比普通模型更麻烦普通模型的评测很多时候只要比对输出和标准答案。但推理模型引入了“思考过程”和“多次采样”评测难度直接上升。第一推理过程可能很长答案隐藏在最后一段需要做答案抽取第二同一个问题多次采样的答案可能不完全一致需要决定用“首次答案”还是“投票答案”第三评测结果高度依赖采样参数温度变了、采样次数变了分数就变了。所以评测报告里必须写清楚用的是什么推理范式、多少候选、怎么抽取答案、怎么处理多样本。否则任何分数都不可复现。4.2 三方评测框架省力但要注意边界关于很多人关心的“有没有好的第三方评测工具能调用自己写的 API、按自己定义的规则评测”——答案是有的而且这一类工具很容易踩坑。比较常见的选择包括EleutherAI 的 lm-evaluation-harness支持很多标准 benchmark适合做公开榜单分数对比OpenAI Evals灵活性高支持自定义评测逻辑可以接入自己的模型 APIOpenCompass中文社区比较活跃覆盖的 benchmark 数量多也支持自定义数据集和评测函数。使用这些工具时先确认三件事是否支持你需要的模型接入方式OpenAI 兼容 API、vLLM 接口、transformers 本地加载是否支持自定义评测指标和评分函数答案抽取和解析逻辑能不能替换。很多评测框架默认只做“整段字符串匹配”对推理模型的评测结果非常不友好。因为模型可能用不同格式输出正确答案字符串匹配会误判为错误。建议在正式跑榜单之前先用 50 道题做小范围校验检查评测框架的答案抽取逻辑是否符合预期。4.3 接入自己的 API自定义评测函数的思路如果你的场景比较特殊比如要评测的答案不是选择题而是根据自定义规则判断第三方框架不一定够用。这时候可以自己写评测脚本调用自己部署的模型 API。这里给一个思路示例import requests def call_my_model(prompt: str, n: int 1) - list[str]: resp requests.post( http://127.0.0.1:8000/v1/chat/completions, json{ model: my-reasoning-model, messages: [{role: user, content: prompt}], temperature: 0.6, max_tokens: 1024, n: n, }, timeout180, ) resp.raise_for_status() return [choice[message][content] for choice in resp.json()[choices]] def my_judge(question: str, gold_answer: str, model_answer: str) - float: # 这里写你自己的评分逻辑可以返回 0 到 1 之间的分数 # 也可以调用另一个模型做 judge return 1.0 if model_answer.strip() gold_answer.strip() else 0.0这种方式的优点是完全可控评测规则由你定义模型输出由你解析评测过程透明。缺点是工作量更大你需要自己维护数据集、并发调用、失败重试、结果汇总这些工程细节。如果题量不大比如几百道题直接写脚本最灵活。如果要跑几千道题甚至更多建议用现成评测框架作为底座只替换其中的答案抽取和评分函数。4.4 评测指标不要只盯准确率推理模型的评测指标至少要覆盖四个维度答案正确率基础指标但必须说明是 pass1 还是 majk答案稳定性同一问题多次采样答案分布是否集中集中的稳定性更好推理过程质量步骤是否完整、有没有跳步、有没有关键推导错误计算效率达到某个准确率需要多少推理 token、多少时间。这里特别说一下 passk 和 majk 的区别passk生成 k 个答案只要有 1 个正确就算通过适合“找最优答案”场景majk生成 k 个答案投票取最多数答案适合“最终只输出一个答案”场景。同一个评测集pass8 的分数通常会明显高于 maj8。因为 pass8 只看有没有一个正确答案而 maj8 需要多数答案都指向正确。汇报结果时如果只写“采样 8 次准确率 xx%”不区分 pass 和 maj非常容易误导。4.5 评测里的常见陷阱评测结果不可信很多时候不是模型问题而是评测流程问题。数据污染评测题目可能出现在训练语料里。检测方式是看模型能不能直接背出答案而不是推理出来。提示偏差不同的 prompt 模板对同一模型准确率影响很大。评测时 prompt 格式要固定单独修改某个题目的提示也会破坏可比性。答案提取误差模型输出了正确推理过程但因为你只比对“最后一行”或某个固定格式导致判断为错误。建议建立答案提取的校验集。评分模型抖动用 LLM 做 judge 时评分 prompt 和采样参数不一致会给同一答案打出不同分数。注意评测脚本要比模型本身更先稳定下来。如果评测逻辑一直改那前期的实验结果全部作废后面对比时很难判断分数变化到底来自模型还是来自评测改动。5. 可复现性Reproducibility最容易翻车的地方5.1 随机性从哪里来测试时扩展实验的随机性来源很多比普通推理实验多得多采样时的随机种子温度、top_p、top_k 的取值多卡并行时的数据分片顺序后处理时字典遍历顺序LLM-as-judge 评分时的随机性。很多实验只记录“最终准确率”不记录这些随机来源。下一次换个环境跑分数不一样就到处怀疑模型。实际上对推理模型来说同一条 prompt 在不同随机种子下生成 8 个候选答案投票结果都会可能有差异。尤其是候选答案之间票数接近的时候随机性对最终结果影响更大。5.2 每次实验必须记录的配置清单为了能让实验结果可复现每次跑实验至少应该记录下面这些内容基础模型名称和版本号包括蒸馏底座模型量化方式比如 BF16、INT8、INT4推理框架版本vLLM 版本不同采样行为可能不同采样参数温度、top_p、n、max_tokens、seed推理范式并行、顺序、best-of-n、搜索式prompt 模板完整记录不只用一句话概括答案抽取逻辑正则表达式或函数代码评分逻辑字符串匹配、规则判断、还是 LLM judge数据集版本题目列表、标准答案文件哈希值运行环境GPU 型号、显存、CUDA 版本、Python 版本。这些信息可以用一个实验配置表来管理。建议每次实验开始前先填完配置再启动任务。不要跑完再补记录因为很容易漏掉关键细节。5.3 为什么换了环境结果就不一样同一个脚本在 A 机器和 B 机器上跑出不同分数原因通常不是“B 机器有问题”而是依赖版本不一致尤其是 vLLM、transformers、PyTorch 的版本模型权重加载精度不同FP16 和 BF16 在某些显卡上行为会有差异采样算法实现细节不同同样的 seed 在不同版本框架里产生的随机序列可能不一样批处理顺序不同导致显存分配和推理批处理策略不同。这里要区分“确定性问题”和“随机性问题”。在单次解码、temperature 设为 0 的情况下大多数推理框架能保证确定性输出。但一旦开了多次采样、温度大于 0就不存在绝对的“完全一致”。所以可复现的目标不是让两次实验分数一模一样而是让分数在合理波动范围内并且你能解释波动来源。5.4 实用复现清单把可复现性落实到日常实验中我一般按这个顺序做固定数据集数据集文件固定后用哈希值记录固定模型加载参数记录模型路径、量化方式、显存设置固定推理框架版本锁在 requirements.txt 里固定采样参数和 seed每次实验记录完整参数固定评测脚本答案抽取和评分函数用 git 管理固定计算环境记录 GPU 型号和 CUDA 版本结果落盘每条候选答案、投票结果、中间抽取结果都要保存。只要做到这七步即使换一台机器跑也能快速定位结果差异来自环境还是代码。6. 实战建议从最小实验到规模化跑批6.1 推荐实验顺序不管你是复现论文还是做业务验证我建议按下面的顺序推进。第一步用小数据集快速验证。选 30 到 50 道题覆盖不同难度。先跑单次解码记录基线和耗时。第二步做并行采样。从 n4 开始逐步增加到 n8、n16。画一条“准确率随采样次数变化”的曲线。如果 n8 到 n16 准确率基本不涨说明这个模型在该任务上的并行扩展收益已经到顶了。第三步尝试顺序迭代。让模型在已有答案基础上检查、修正看同样 token 预算下准确率能否超过并行采样。第四步如果并行和顺序都到瓶颈再考虑引入验证器。验证器可以先从简单的“答案一致性”开始再逐步换成模型打分。第五步确定最终方案后跑完整评测集并多次重复实验记录准确率的均值和波动范围。6.2 常见报错和排查顺序测试时扩展相关报错大部分不是模型问题而是下面几类。显存不足生成多个候选答案时vLLM 内部会把多个样本放进同一个 batch显存需求会成倍增加。先降 n再降 max_tokens最后考虑量化。输出截断答案是“半截的”。检查 max_tokens 是否太小或者模型思考过长后没有剩余空间输出最终答案。投票结果为空答案抽取函数没有匹配到任何内容。先打印几条原始输出观察格式再调整正则。评分不稳定同一个候选答案重复评分分数不一致。检查 judge 模型的 temperature建议设为 0并固定 prompt。复现不了分数先对比实验配置再对比评测代码版本。大部分所谓“复现不了”都出在这两处。排查顺序建议先看输出样例再看采样参数再看依赖版本最后看评测逻辑。6.3 低配置环境下的取舍如果你的机器只有一张中端显卡仍然可以做有价值的测试时扩展实验但要注意取舍。模型优先选 7B 左右或更小的推理模型不要硬上 32B 或更大尺寸采样次数先控制在 4 到 8 次数据集用小样本比如每个任务 100 道题以内输出长度限制缩小到刚好够用的范围比如 1024 token一次只跑一个实验不要同时跑多个任务抢占显存。低配置环境适合做“趋势判断”比如采样次数从 1 增加到 8准确率有没有明显上升。这个趋势在更大模型上通常仍然成立但幅度会不一样。你要清楚自己是在验证方法不是在复现论文的全部数据。6.4 不要盲目堆推理算力最后说一个见过很多次的误区看到测试时扩展能涨点就把采样次数从 1 加到 64希望分数一直涨。现实是并行采样的收益是递减的。n1 到 n8 可能涨 5 个点n8 到 n32 可能只涨 1 个点n32 到 n64 可能完全不涨甚至因为投票平局而下降。比较合理的做法是先找到收益拐点。在你的数据集上把 n 从 1 到 4 到 8 到 16 逐一测试记录准确率和总 token 消耗画出收益曲线。在收益拐点附近选一个性价比最高的 n。这样既不会浪费大量推理算力也避免了“选了一个看起来很高但实际不稳定的配置”。落地上还有一个细节批量任务要提前考虑失败重试、输出目录、任务队列。如果你要跑几百道题每道题都做 16 次采样中间一个请求超时就会打断整个流程。建议先把单条任务跑稳再写批量脚本并给每个任务单独保存结果文件方便断点续跑。踩过几次之后我发现Test-Time Scaling 相关的很多问题不是工具能力不够而是前置环境、评测逻辑和实验记录没有处理干净。先把这三件事做好再去追求更复杂的推理策略会顺很多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价