尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

测试时扩展(Test-Time Scaling):让推理模型在部署后继续提升能力

测试时扩展(Test-Time Scaling):让推理模型在部署后继续提升能力 最近在一个技术群里看到一个很有意思的问题有人问“模型是不是部署之后能力就固定了推理阶段还能不能继续提升”。这个问题放在两年前答案几乎是确定的模型参数训练完能力就冻结了之后只能靠提示词、RAG、微调这些外部手段补救。但这一批以推理能力见长的 LLM 出现后局面已经变了——模型可以在回答之前“多想一会儿”甚至生成多份答案再挑一个更好的。这种在推理阶段额外消耗算力来换取答案可靠性的做法就是本文要展开的 Test-Time Scaling测试时扩展。这篇文章想围绕“Test-Time Scaling in Reasoning LLMs”讲透三件事Inference Regimes推理范式、Evaluation评测、Reproducibility可复现性。这三件事也是当前实践中最容易出现认知偏差的地方。很多人以为测试时扩展就是“多采样几次然后投票”实际上不同任务适合不同的推理范式很多人以为评测就是跑两个开源 benchmark实际上不严谨的评测协议会掩盖真实改进还有不少人在复现别人结论时发现“分数对不上”这不一定是模型跑错了更可能是推理参数、模型版本、采样种子这些条件没被记录。读完这篇文章你可以得到四样东西理解测试时扩展的核心原理和适用边界在 API 或本地推理框架上跑通一个最小采样验证实验知道如何用第三方评测工具自定义评测自己的模型 API拿到一份可复现实验的检查清单。1. 为什么“推理阶段多算力”突然成为焦点1.1 训练时扩展的边际收益开始变小过去几年大模型的能力提升主要靠的是训练时扩展Training-Time Scaling把模型参数做得更大把训练数据堆得更多把训练算力拉得更高。这套范式在预训练阶段效果显著但代价也越来越明显。训练一次超大模型需要数月时间和极高成本而且不是每个团队都有能力承担。于是业界开始寻找另一种提升能力的方向既然训练阶段把模型“调教”好成本太高能不能在推理阶段通过更多计算让模型表现更好答案是可以。最典型的例子就是带思维链的推理模型。这类模型在生成最终答案之前会先产生一段内部推理过程。从公开资料看以 OpenAI o1、DeepSeek-R1、Qwen 的 QwQ 等为代表的一系列模型核心变化之一就是在推理时投入更多计算资源让模型能够自我纠错、分步推理、探索多种可能性。1.2 测试时扩展的本质把推理当成一个搜索过程如果只从表面理解测试时扩展常常被误读成“让模型生成更长的文本”。这是一个很大的误区。测试时扩展的本质是把推理过程从“一次前向传播直接输出答案”变成“在解空间中搜索更好的答案”。生成更长文本只是搜索的一种表现形式更重要的手段包括多次采样、验证器筛选、树搜索等。从这个角度看测试时扩展更像是在推理阶段引入了一个控制系统生成器负责产生候选解验证器负责评估候选解搜索策略负责决定下一步往哪个方向走。这个框架统一了很多看似不同的技术比如自一致性Self-Consistency、Best-of-N 采样、过程奖励模型、AlphaZero 风格的树搜索它们都只是不同配置下的搜索策略而已。1.3 这意味着开发者的工作方式要变如果推理阶段还能继续“提升能力”那开发者的职责就不只是部署模型和写提示词了。你需要考虑推理预算怎么分配、验证器怎么设计、评测协议怎么建立。这也是为什么本文要把 Inference Regimes、Evaluation、Reproducibility 放在一起讨论——它们决定了你在推理阶段投入的每一分算力到底有没有换来真实的可靠性和可用性。2. 基础概念Inference Regimes 到底指什么2.1 什么是推理范式Inference Regimes可以理解为“一组可复现的推理策略和资源分配方式”。它描述的是模型在推理阶段以什么样的方式使用计算资源来生成最终答案。同一个模型使用不同的推理范式最终效果可以相差很大。本节先梳理四种常见的推理范式从最简单到最复杂。这是理解测试时扩展的基础。2.2 四种常见推理范式第一种是静态单次生成Greedy / Single-Pass。模型只做一次前向传播以贪心解码或低温度采样直接输出结果。这种范式速度快、成本低但遇到复杂推理任务时一旦第一次生成出错没有机会修正。第二种是多路采样加自一致性Sampling Self-Consistency。模型生成多个候选答案然后通过投票或聚类选出最一致的答案。这个范式的假设是多次采样中频繁出现的答案更可能是正确答案。它不需要额外的验证器但对生成类任务效果有限。第三种是 Best-of-N 加验证器重排Validator Reranking。先生成 N 个候选答案再用一个验证器对候选答案打分最后选择得分最高者。验证器可以是规则、另一个模型、代码执行结果等。这个范式适合“答案可以被评估”的任务比如数学题、代码题。第四种是搜索式推理Search-Based Reasoning。把推理建模为多步搜索过程每一步可能对应一个中间状态搜索算法在状态空间中探索比如树搜索、Beam Search甚至结合强化学习风格的过程奖励模型。这个范式最强大但设计和计算开销也最高。下面是四种范式的对比推理范式是否需要验证器计算开销适合任务典型实现单次生成否低通用问答、摘要贪心解码多路采样自一致性否中选择题、数学答案多次采样投票Best-of-N验证器重排是中高代码、数学、结构化输出生成N个候选打分排序搜索式推理是高复杂推理、竞赛题树搜索、过程奖励模型小结论推理范式的选择不是越复杂越好而是取决于你是否有可靠的验证器。如果没有验证器多路采样和自一致性是简单有效的选择如果有强验证器Best-of-N 通常能带来更稳定的收益。3. 测试时扩展的收益与成本边界3.1 哪些任务受益最明显从观察到的行业实践来看测试时扩展在“可验证任务”上收益最大。这类任务有一个共同特点存在明确的对错标准或者至少存在可比较的评估函数。典型例子包括数学题、代码题、逻辑推理题、结构化信息抽取。在这类任务上你让模型多生成几个候选再用验证器去筛选通常能稳定提升准确率。为什么因为这类任务的错误模式往往是“局部思路对最终结论错”。多采样相当于给模型多几次尝试机会验证器负责把错误答案过滤掉。两者一配合准确率自然提升。3.2 哪些任务收益不明显相反在开放式生成任务上比如写文案、做翻译、头脑风暴测试时扩展的收益往往不明显甚至可能变差。原因很简单这些任务没有唯一正确答案投票和验证器都无法发挥应有的作用。更关键的是这类任务对生成质量的主观评价和偏好有强相关性多采样之后再“投票”反而可能让风格趋向平庸。所以如果你正在做一个纯生成类应用先别急着上多路采样。你应该先问自己一个问题我的任务有没有办法定义一个自动化的评估函数如果没有测试时扩展可能不是最优解。3.3 成本与延迟的隐性代价测试时扩展带来最直接的代价是延迟和成本。生成 N 个候选推理延迟基本线性增长。对实时性要求高的产品比如在线客服、语音助手这种延迟可能是不可接受的。另一个隐性代价是评测方差变大。采样温度大于 0 时模型输出本身有随机性测试时扩展的效果在不同运行批次之间可能有明显波动。如果你在开发阶段不把这种方差纳入考虑就可能出现“今天提升 3 个点明天又降回去”的诡异现象。这里给出一个务实建议在决定采用哪种推理范式之前先抽一个小规模代表性子集分别用单次生成和多路采样跑一遍看收益是否值得额外算力和延迟。不要一开始就在全量数据上做实验。4. 环境准备接入推理模型的两种常见方式4.1 使用 OpenAI 兼容 API大多数推理类模型都提供了 OpenAI 兼容的 API 接口这种方式是最快的接入路径。你只需要准备好 API Key 和接口地址就能通过 OpenAI SDK 完成调用。一个典型的环境变量配置如下export OPENAI_API_KEYyour-api-key export OPENAI_BASE_URLhttps://api.example.com/v1不同模型提供商的地址和模型名不同请以实际申请到的服务为准。本文演示的代码只需要替换base_url和model字段即可适配到你的目标模型。4.2 使用本地推理框架如果你的场景对数据安全要求高或者你希望更精细地控制推理参数可以考虑本地部署。当前社区里使用较多的推理框架包括 vLLM、SGLang 等它们都提供 OpenAI 兼容的服务接口。启动一个本地服务后客户端代码与远程 API 几乎完全一致只是base_url需要指向本地地址。需要注意本地部署还需要考虑 GPU 显存、并发控制、量化精度等因素。本文不展开具体部署细节只强调一点无论远程 API 还是本地框架你最终得到的都是一个标准的 chat completions 接口这就是后续实操的基础。4.3 Python 环境准备建议使用 Python 3.10 及以上版本并安装openai库pip install openai如果你是在 Jupyter Notebook 或普通 Python 脚本中运行请确保 API Key 和 Base URL 已正确写入环境变量或者直接在代码中显式传入配置。5. 最小示例用多采样自一致性提升选择题准确率5.1 场景定义假设我们有一个小规模选择题集每个题目有 A、B、C、D 四个选项。我们想让模型给出一个相对可靠的答案并验证多采样是否比单次生成更准确。先准备一个 OpenAI 兼容客户端# 文件路径llm_client.py import os from openai import OpenAI client OpenAI( api_keyos.environ.get(OPENAI_API_KEY), base_urlos.environ.get(OPENAI_BASE_URL), ) def generate_answer(question: str, choices: dict, temperature: float 0.0) - str: choices_text \n.join([f{k}. {v} for k, v in choices.items()]) prompt f请从下列选项中选择正确答案只输出选项字母。\n题目{question}\n{choices_text} response client.chat.completions.create( modelos.environ.get(OPENAI_MODEL, your-model-name), messages[{role: user, content: prompt}], temperaturetemperature, max_tokens16, ) return response.choices[0].message.content.strip()这段代码的核心是把题目和选项拼成 prompt要求模型只输出选项字母。temperature0时输出相对稳定多路采样时则调高温度。5.2 实现自一致性采样自一致性的逻辑很简单生成 N 个候选答案统计每个选项字母出现的次数返回出现次数最多的选项。当多个选项并列时可以任选一个或取第一次出现的候选。# 文件路径self_consistency.py import random from collections import Counter from llm_client import generate_answer def self_consistency_answer(question: str, choices: dict, n_samples: int 5) - str: candidates [] for _ in range(n_samples): # 采样温度可以设置在一个适中范围比如 0.7 ans generate_answer(question, choices, temperature0.7) # 简单清洗只保留 A/B/C/D 这类答案 if ans and ans[0] in choices.keys(): candidates.append(ans[0]) if not candidates: return 无法确定 counter Counter(candidates) return counter.most_common(1)[0][0]5.3 对比单次生成与多路采样现在我们可以写一个简单的评测脚本对比单次生成和自一致性在同样题目上的准确率。# 文件路径compare.py from llm_client import generate_answer from self_consistency import self_consistency_answer questions [ { question: 如果一个三角形的两边长分别是 3 和 4夹角为 90 度那么第三边长度是, choices: {A: 5, B: 6, C: 7, D: 8}, answer: A, }, { question: 下列哪个数不是质数, choices: {A: 2, B: 3, C: 4, D: 5}, answer: C, }, ] def main(): single_correct 0 sc_correct 0 for item in questions: single generate_answer(item[question], item[choices], temperature0.0) sc self_consistency_answer(item[question], item[choices], n_samples5) print(f题目{item[question]}) print(f单次生成答案{single}, 正确答案{item[answer]}) print(f自一致性答案{sc}, 正确答案{item[answer]}) if single item[answer]: single_correct 1 if sc item[answer]: sc_correct 1 print(f单次生成准确率{single_correct / len(questions):.2%}) print(f自一致性准确率{sc_correct / len(questions):.2%}) if __name__ __main__: main()运行这个脚本你会看到每个题目的对比结果。如果你的数据集足够大并且题目属于可验证类型自一致性通常能带来几个百分点的准确率提升。这里有一个容易踩的坑不要在小数据集上反复调整采样次数和温度去“刷高”评测集分数。这样做的本质是对评测集过拟合换一批新题效果可能立刻下降。正确做法是先定好评测集再选择参数。6. 进阶推理范式用验证器做 Best-of-N6.1 什么是验证器多路采样自一致性没有使用额外信息来评估“哪个答案更好”只是依赖候选答案之间的频率。但很多任务其实存在评估函数比如代码题可以看编译是否通过、测试用例是否跑过数学题可以看推导过程是否合理。这时候我们可以引入验证器Validator接受一个候选答案输出一个质量分数。Best-of-N 的流程是先生成 N 个候选答案然后用验证器给每个候选打分最后返回得分最高的候选。这个范式比简单投票更能利用任务本身的反馈信号。6.2 一个安全的代码题验证示例以代码题为例假设我们需要模型生成一个 Python 函数。这里的安全问题是绝对不能直接在本地执行模型生成的代码尤其当代码来自不可信模型时可能包含恶意操作。因此在演示验证器时我们使用一个“弱验证器”——只检查代码语法是否合法不真正执行代码。更强的验证器应该在隔离沙箱中运行测试用例。# 文件路径best_of_n.py import ast from llm_client import generate_answer def syntax_validator(code: str) - float: 弱验证器只检查 Python 语法是否合法。 返回 1.0 表示语法合法0.0 表示存在语法错误。 try: ast.parse(code) return 1.0 except SyntaxError: return 0.0 def generate_code_candidates(prompt: str, n_candidates: int 5) - list[str]: candidates [] for _ in range(n_candidates): response generate_answer(prompt, temperature0.8, max_tokens512) candidates.append(response) return candidates def best_of_n(prompt: str, n_candidates: int 5) - str: candidates generate_code_candidates(prompt, n_candidates) best_code candidates[0] best_score -1.0 for code in candidates: score syntax_validator(code) if score best_score: best_score score best_code code return best_code这段代码演示了一个最小可用的 Best-of-N 流程。syntax_validator只是语法级验证生产环境如果要评估代码正确性建议使用沙箱、容器或者在线代码执行平台并且在隔离环境中运行测试用例。6.3 更强的验证器测试用例执行如果有测试用例你就可以构造一个更强的验证器代码通过测试用例的数量越多得分越高。这里的执行环境必须隔离并且对超时、内存、网络访问都做严格限制。从工程角度最稳妥的方式是使用容器或云函数来运行测试而不是在评测脚本的同一个进程里直接执行。验证器设计的质量直接决定了 Best-of-N 的上限。一个错误的验证器会给出错误反馈反而把候选答案越筛越差。这也是测试时扩展实践中最容易被低估的部分。7. 评测难题为什么“准确率涨了3个点”不一定可信7.1 评测是测试时扩展的最大盲区测试时扩展的核心目标是提升答案可靠性但如果评测本身不可靠你根本无法判断优化是否有效。这里存在三个层面的陷阱。第一层是评测集问题。如果评测集与模型训练数据高度重叠或者题目在网上有公开答案模型可能在“背答案”而不是“推理”。这会导致测试时扩展的收益被高估。第二层是推理参数不一致。同一个模型temperature 设为 0.0 和 0.7 的结果可能差异很大max_tokens 如果限制过小模型还没来得及推理完就被截断。不同团队在报告结果时如果不注明这些参数数字之间根本没有可比性。第三层是指标与任务不匹配。比如对开放式生成任务使用字符串精确匹配或者对多步推理任务只检查最终答案不看过程。这些指标无法反映真实能力变化。7.2 第三方评测工具能解决什么问题最近经常有人问有没有好的第三方评测工具可以调用自己写的 API根据自己定义的评测标准来评估模型这类诉求很实际。自研评测脚本很容易因为数据集管理混乱、评分标准不一致、参数记录不完整而失去可信度第三方评测工具的价值在于把“模型接入、数据集管理、评分函数、结果聚合”固化下来。社区里常用的评测工具包括 OpenAI Evals、DeepEval、promptfoo 等。它们都支持自定义模型 API 和自定义评测逻辑。不同工具的侧重点不同OpenAI Evals 偏研究实验DeepEval 偏自动化测试和 CI 集成promptfoo 更适合提示词与模型对比。选择哪一个取决于你的目标是做研究评测还是做工程回归。7.3 一个自定义评测脚本的最小示例下面用一个不依赖特定框架的最小示例演示如何构建“调用自己的 API 自定义评分”的评测脚本。假设我们要评测模型对数学题的答案正确率评分函数就是判断最终答案是否等于标准答案。# 文件路径custom_eval.py import json from llm_client import generate_answer class CustomEvaluator: def __init__(self, eval_file: str): with open(eval_file, r, encodingutf-8) as f: self.cases json.load(f) def score_single(self, case: dict) - bool: model_answer generate_answer(case[question], case[choices], temperature0.0) return model_answer case[answer] def run(self) - dict: total len(self.cases) correct 0 details [] for case in self.cases: is_correct self.score_single(case) if is_correct: correct 1 details.append({ question: case[question], expected: case[answer], correct: is_correct, }) return { total: total, correct: correct, accuracy: correct / total, details: details, } if __name__ __main__: evaluator CustomEvaluator(eval_set.json) result evaluator.run() print(json.dumps(result, ensure_asciiFalse, indent2))这个脚本看起来简单但它已经具备了评测系统的基础能力数据集从外部文件加载评分函数可以替换结果可导出。接入 DeepEval 或 promptfoo 时核心逻辑只是把score_single和run转换成工具对应的格式。如果你使用 promptfoo可以用 YAML 配置文件声明提示词、模型提供方和测试用例把模型 API 地址指向你自己的服务断言规则里写自定义的评分条件。具体字段以官方文档为准但整体思路是把评测配置代码化而不是散落在临时脚本里。7.4 评测协议要先于优化在实际项目中更推荐的做法是先把评测集和评测脚本固化到仓库里作为基准再开始做任何测试时扩展实验。每次改动推理参数或推理范式只允许通过评测脚本的输出来判断是否有效。这样做才能避免“感觉上变好了”的假象。8. 可复现性记录哪些信息才能被别人复现8.1 模型和推理参数测试时扩展实验的可复现性首先取决于你是否完整记录了模型和推理参数。这里包括模型名称或权重文件版本、推理框架版本、temperature、top_p、max_tokens、采样次数 n、验证器和评分逻辑等。一个常见的问题是模型名称没写全或者写了“deepseek-chat”但没有说明调用日期因为 API 端模型可能随时间迭代。对于本地模型则需要记录权重文件的 commit ID 或版本哈希。8.2 评测集版本评测集也是一个变量。如果你在实验中不断往评测集里加题目或者把人工校验过的样本混进测试集前后结果就不可比。建议给评测集文件增加版本号比如eval_set_v1.json并在结果报告中注明使用的版本。8.3 随机性与重复实验当 temperature 大于 0 时采样结果天然有随机性。此时单次运行评测得到的结果只是一个随机变量样本不能代表真实水平。更稳妥的做法是同一组实验参数跑多轮取平均值和标准差。如果标准差过大说明当前推理范式的稳定性不足需要排查是模型问题、评测集问题还是采样参数问题。8.4 一个实验记录模板以下是建议保存到评测结果文件中的最小字段{ experiment_id: exp_001, model: your-model-name, model_version: 2025-06-01, inference_framework: openai-sdk, inference_regime: self_consistency, temperature: 0.7, top_p: 1.0, max_tokens: 1024, n_samples: 5, eval_set_version: eval_set_v1, eval_metric: exact_match, seed: 42, run_count: 3, results: { accuracy_mean: 0.82, accuracy_std: 0.01 } }把这些信息保存下来你才能在几周后复盘“为什么当时效果好”也才能让别人真正复现你的实验。9. 常见问题与排查思路以下是在测试时扩展实践中比较常见的问题和对应的排查方案。问题现象可能原因排查方式解决方案多路采样后准确率没有提升任务不可验证或评测集太小检查任务是否有明确对错扩大评测样本引入验证器或换用可评估任务结果在不同运行之间波动很大采样温度过高评测集样本量不足固定 seed重复运行多次取均值降低温度增加评测样本数量API 调用超时或返回空内容max_tokens 设置过小查看 API 返回日志和错误信息增大 max_tokens检查提示词格式相同配置在不同框架上结果不一致采样算法或量化精度不同对比各框架的推理参数默认值统一框架版本记录推理参数验证器总是选不出高分答案验证器与任务目标不匹配抽样检查验证器的打分结果重新设计验证器加入更多反馈信号每一类问题优先从日志和数据入手而不是凭感觉调整参数。比如 API 超时查看返回的错误码结果波动先重复运行三次准确率不提升先确认评测集是否有足够的区分度。10. 最佳实践与工程建议10.1 先定评测集再做推理优化这是测试时扩展最重要的一条工程原则。评测集是你在推理优化这条路上的“仪表盘”如果没有仪表盘你根本不知道自己在往哪个方向开。评测集需要包含足够多样化的题目并且与训练数据尽量隔离。10.2 做小规模敏感性分析在投入大量算力之前先做一个敏感度分析temperature 从 0.0 到 1.0 各跑一遍n_samples 从 1 到 10 各跑一遍记录准确率和成本。这样你会得到一张“算力投入-准确率收益”的曲线从中找到性价比最高的配置。10.3 把评测脚本纳入 CI如果你在开发一个面向生产的 LLM 应用建议把评测脚本接入 CI/CD 流程。每次修改推理代码、提示词或模型版本时自动跑一遍评测集防止回归。这个实践的成本不高但能避免很多线上事故。10.4 设计成本上限和降级方案测试时扩展会显著增加推理成本。建议为每个请求设置采样次数上限并且在高并发场景提供降级方案比如流量高峰时自动切换到单次生成模式流量平稳时再使用多路采样。成本和质量之间需要可配置的平衡机制。10.5 安全边界不能省使用模型生成的代码必须在隔离环境中执行涉及敏感数据的评测必须在私有化环境完成涉及第三方 API 的调用要控制并发和频率避免对上游服务造成压力。10.6 日志和追踪每次推理请求都应该记录prompt、采样参数、候选数量、验证器得分、最终答案、耗时时长。这些日志不仅用于调试也是后续优化推理范式的数据基础。11. 总结与进一步方向测试时扩展为 LLM 应用打开了一个新的优化维度模型部署之后推理阶段的算力投入可以继续换取答案可靠性。但它的收益高度依赖任务类型、验证器质量和评测协议。可验证任务可以优先尝试多路采样和 Best-of-N开放式任务则要谨慎使用。如果你准备在真实项目中实践可以从三件事开始第一定义一个小而精的评测集并固化评测脚本第二用单次生成和多路采样做对比看收益是否值得成本第三把实验参数、评测集版本和模型版本记录下来形成可复现的实验基线。下一步值得继续深入的方向包括树搜索与过程奖励模型、更强验证器的设计比如基于测试用例、基于规则、基于模型反馈、以及评测集的自动构建与去重。这些方向并不独立它们最终都会汇聚到同一个问题上如何用最合理的推理算力得到最可靠的答案。
返回列表