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( model="deepseek-ai/DeepSeek-R1-Distill-Qwen-7B", dtype="bfloat16", max_model_len=8192, ) params = SamplingParams( temperature=0.6, top_p=0.95, max_tokens=2048, n=8, # 一次生成 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)}")这段代码的核心在n=8。它让 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:灵活性高,支持自定义评测逻辑,可以接入自己的模型 API;
- OpenCompass:中文社区比较活跃,覆盖的 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, }, timeout=180, ) 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 评测指标:不要只盯准确率
推理模型的评测指标至少要覆盖四个维度:
- 答案正确率:基础指标,但必须说明是 pass@1 还是 maj@k;
- 答案稳定性:同一问题多次采样,答案分布是否集中,集中的稳定性更好;
- 推理过程质量:步骤是否完整、有没有跳步、有没有关键推导错误;
- 计算效率:达到某个准确率需要多少推理 token、多少时间。
这里特别说一下 pass@k 和 maj@k 的区别:
- pass@k:生成 k 个答案,只要有 1 个正确就算通过,适合“找最优答案”场景;
- maj@k:生成 k 个答案投票,取最多数答案,适合“最终只输出一个答案”场景。
同一个评测集,pass@8 的分数通常会明显高于 maj@8。因为 pass@8 只看有没有一个正确答案,而 maj@8 需要多数答案都指向正确。汇报结果时如果只写“采样 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 道题,覆盖不同难度。先跑单次解码,记录基线和耗时。
第二步,做并行采样。从 n=4 开始,逐步增加到 n=8、n=16。画一条“准确率随采样次数变化”的曲线。如果 n=8 到 n=16 准确率基本不涨,说明这个模型在该任务上的并行扩展收益已经到顶了。
第三步,尝试顺序迭代。让模型在已有答案基础上检查、修正,看同样 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,希望分数一直涨。
现实是,并行采样的收益是递减的。n=1 到 n=8 可能涨 5 个点,n=8 到 n=32 可能只涨 1 个点,n=32 到 n=64 可能完全不涨,甚至因为投票平局而下降。
比较合理的做法是:先找到收益拐点。在你的数据集上把 n 从 1 到 4 到 8 到 16 逐一测试,记录准确率和总 token 消耗,画出收益曲线。在收益拐点附近选一个性价比最高的 n。这样既不会浪费大量推理算力,也避免了“选了一个看起来很高但实际不稳定的配置”。
落地上还有一个细节:批量任务要提前考虑失败重试、输出目录、任务队列。如果你要跑几百道题,每道题都做 16 次采样,中间一个请求超时就会打断整个流程。建议先把单条任务跑稳,再写批量脚本,并给每个任务单独保存结果文件,方便断点续跑。
踩过几次之后我发现,Test-Time Scaling 相关的很多问题不是工具能力不够,而是前置环境、评测逻辑和实验记录没有处理干净。先把这三件事做好,再去追求更复杂的推理策略,会顺很多。