普通 LLM 像一次 O(1) 查表——不管问题多难,都是一次前向传播立刻吐答案,计算量固定。推理模型(o1 / DeepSeek-R1)则像数据库的查询优化器:简单查询走 fast path,复杂查询愿意在运行时多花 CPU 做规划、试错、回溯,再返回结果。本质是把"算力预算"从训练时一次性投入,挪一部分到每次请求的运行时按需投入。
痛点:再大的模型,单次前向的计算深度是固定的——这对"想一眼就答"的题没问题,但对需要多步推演的数学题、代码题,等于逼一个人在 0.5 秒内脱口而出答案,必然出错。2024 年 OpenAI o1 给出的答案是:让模型在回答前先生成一长串内部思考(chain of thought),把"想"这个动作变成可以花更多 token、更多时间的过程。
机制核心不是 prompt 技巧,而是训练方式:o1 用强化学习(RL)训练模型自己"学会怎么想"——奖励信号来自最终答案对不对(数学、代码这类可自动验证的领域),模型在试错中学会拆解步骤、识别并纠正自己的错误、此路不通就换条路。2025 年 DeepSeek-R1 进一步证明:纯 RL(不靠人工标注的推理过程)就能自发涌现出反思、验证、回溯这些行为。
关键反直觉:在推理模型里,"更聪明"可以靠"想更久"换——这是"做大模型"之外的第二条 scaling 路径。代价是延迟和 token 成本陡增。
from openai import OpenAI client = OpenAI() # 需要 OPENAI_API_KEY # 推理模型的关键参数:reasoning_effort 控制"想多久" resp = client.chat.completions.create( model="o1", reasoning_effort="high", # low/medium/high:高=更多测试时算力 messages=[{"role": "user", "content": "一个三位数,各位数字之和为 12," "百位是个位的两倍,十位比个位大 1,求这个数。"}] ) print(resp.choices[0].message.content) # 注意:内部 reasoning tokens 你看不到(OpenAI 隐藏),但要付费 print(resp.usage.completion_tokens_details.reasoning_tokens) # 监控思考成本
CoT 就是给黑盒函数加 print 调试——把模型本来藏在权重里、一步算完的隐藏计算,外化成一串可见的中间 token。这些 token 又被喂回模型当下一步的输入,等于模型用自己的输出当暂存盘(scratchpad)。没有 scratchpad,复杂运算只能在一次前向里硬挤;有了它,串行计算被展开成更多步。
痛点的根源在架构:Transformer 单次前向的计算深度是固定的(层数决定)。一道需要 20 步推演的题,硬塞进固定深度等于让算力不够用。CoT 的机制巧妙:自回归生成是串行的——模型每吐一个 token,都能把已生成的全部 token 重新读一遍再算下一个。所以让它先写出推理步骤,相当于把"计算"摊到 token 序列长度上,用序列长度换有效计算深度。
2022 年 Wei et al. 发现:只要在 few-shot 例子里展示推理过程(而非只给答案),大模型在数学、常识推理上的准确率大幅跃升——而且这种能力只在足够大的模型上涌现。即 "Let's think step by step"。
注意区分两层:CoT prompting(Day 3 讲过的提示技巧,靠 prompt 诱导)和推理模型内建的 CoT(o1/R1 通过 RL 训练,自发生成且远比人写的长、会自我纠错)。后者是把前者从"技巧"升级成了"模型的原生能力"。
from anthropic import Anthropic client = Anthropic() # 用 <thinking> 标签给普通模型显式开辟 scratchpad(CoT 的手动版) resp = client.messages.create( model="claude-opus-4-8", max_tokens=1024, messages=[{"role": "user", "content": "先在 <thinking> 里逐步推演,再在 <answer> 里给最终答案。\n" "问题:仓库每天进货 50 件、出货 80 件,初始 600 件,第几天清空?"}] ) # 模型会先写推理过程(净减 30/天 → 600/30=20),再给答案 print(resp.content[0].text) # 工程上:<thinking> 段可在展示给用户前剥离,只留 <answer>
生成答案是 writer,验证答案是 reviewer——就像写代码 vs code review,写单测 vs 跑单测。关键洞察:验证往往比生成容易(看懂一个证明比自己想出来简单,复现 bug 比发现 fix 简单)。推理模型利用这个不对称——用一个验证器(verifier / reward model)来检查生成器的输出,把"难的生成"问题部分转化成"易的验证"问题。
痛点:模型推理链很长时,一步错则步步错——一个早期的小算错会被后续步骤"理所当然"地继承,最后给出自信而错误的答案。怎么知道哪步错了?两类验证器:
2023 年 OpenAI 的 "Let's Verify Step by Step" 给出关键实证:在高难度数学(MATH 数据集)上,过程监督(PRM)显著优于结果监督(ORM)。直觉:告诉模型"第 3 步错了"比只说"最终答案错了"信息量大得多——前者把信用分配(credit assignment)问题精确到了步骤级。
自我验证还有更轻量的形态:让模型自己检查自己("重新审视上面的推理,有没有算错?")。但要警惕——验证器本身也是模型,会有盲区,模型对自己错误的"自纠"能力有限,独立训练的验证器通常比"自己查自己"更可靠。
def verify_steps(problem, solution_steps): # 用一个独立调用当"验证器",逐步检查(PRM 的轻量实现) prompt = f"""问题:{problem} 解题步骤: {chr(10).join(f'{i+1}. {s}' for i, s in enumerate(solution_steps))} 逐步检查每一步是否正确。只输出第一个出错的步骤编号; 全部正确则输出 OK。""" r = client.messages.create( model="claude-opus-4-8", max_tokens=256, messages=[{"role": "user", "content": prompt}]) return r.content[0].text # "OK" 或 "第 3 步错误:..." # 用法:生成 → 验证 → 若有错,带着"第N步错"的信号重试 verdict = verify_steps("求 17×23", ["17×20=340", "17×3=51", "340+51=391"])
Best-of-N 就是分布式系统的 scatter-gather + ranking:同一个问题并行采样 N 个候选答案(scatter),再用验证器选出最好的一个(gather + rank)。它和 hedged requests(对冲请求)同源——多发几个请求,取最优那个,用冗余换质量。而 self-consistency(自洽)是它的特例:N 个答案做多数投票,类似 Raft 的 quorum 表决。
痛点:模型采样有随机性(temperature > 0),一次生成可能恰好走错路。但"偶尔能答对"≠"答不对"——如果正确答案在 100 次采样里出现过哪怕几次,我们只要有办法把它挑出来,准确率就能大幅提升。两种"挑"的策略:
这是测试时计算最直接的体现:N 越大,花的算力越多,准确率越高(log 关系,边际递减)。o1 这类模型则更进一步——把"采样 + 验证 + 回溯"内化进单条长推理链,而不是外部跑 N 次。
from collections import Counter def self_consistency(problem, n=10): answers = [] for _ in range(n): r = client.messages.create( model="claude-opus-4-8", max_tokens=1024, temperature=0.8, # 必须 >0 才有多样性 messages=[{"role": "user", "content": f"逐步推理后,最后一行写 '答案: X'。\n{problem}"}]) ans = extract_final_answer(r.content[0].text) # 解析末行 answers.append(ans) # 对最终答案做多数投票(边际化掉不同推理路径) return Counter(answers).most_common(1)[0][0] # N 个独立推理路径殊途同归 → 答对的概率比单次高得多 best = self_consistency("一支笔 3 元,买 7 支再打 9 折,共多少钱?", n=10)