ThinC:让模型用代码"思考",而不是用代码"验证"

核心摘要

Tool-integrated reasoning (TIR) 现在是数学题求解的主流范式——模型穿插着用自然语言推理 + 调用 Python 解释器做精确计算。听起来很美好,但你打开真实的 TIR trajectory 看,会发现几个让人头疼的现象:

  1. 代码经常只是事后验证:模型用 NL 把答案推完了,最后跑一段 code 确认下——code 在这里没做新计算
  2. NL 里的算术错误会污染后续 code:模型在 NL 推理时算错一个值,把这个错误值作为 hard-coded constant 塞进下一个 code block,解释器没法发现这种错误
  3. NL 和 code 在做重复的事:NL 把算法一步一步写出来,code 把这个算法 transcribe 一遍——两个 channel 在做同一件事

这篇 ThinC(Thinking in Code) 的做法是直接颠覆 TIR 的范式:代码本身就是 reasoner,不是被 NL 召唤的 tool。一个 ThinC trajectory 只有一句 NL 做战略规划,从这开始所有推理都在 code block 里展开,code 之间用 execution output 连接,NL 不再回归

实验数据:基于 Qwen3-4B-Thinking 训出来的 ThinC-4B,在 AIME24/25/26、HMMT 2025、BeyondAIME 五个 benchmark 上平均 78.1%,超过所有 TIR baseline,甚至超过 Qwen3-235B-A22B-Thinking(235B 参数的纯 NL 推理大模型)。99.2% 的最终答案直接来自解释器输出,而不是 NL 推理。

读完我的第一反应是——这篇论文证明了一件很 obvious 但被业界忽视很久的事:code 和 NL 在数学推理上的角色应该严格分工,不该混着用


论文信息

  • 标题:Teaching Language Models to Think in Code
  • 作者:Hyeon Hwang, Jiwoo Lee, Jaewoo Kang
  • 机构:高丽大学、AIGEN Sciences
  • arXiv:https://arxiv.org/abs/2605.07237

TIR 的三个结构性缺陷

我先把这三个问题讲透,因为它们是 ThinC 整个 motivation 的核心。

图1:TIR 的三个结构性缺陷

图1:(A) Post-hoc 验证——NL 已经推出答案,code 只是确认。(B) Unreliable NL 计算——NL 算错的值被 hard-code 进 code,解释器无法发现。(C) 角色错位——NL 把算法描述一遍,code 把同样的算法实现一遍。

缺陷 1:Post-hoc Verification

我用一个具体例子来讲。假设题目是"计算 \(\sum_{k=1}^{100} k^2\)"。

TIR 模型的典型行为是:

"Let me compute this. We know sum of squares formula is n(n+1)(2n+1)/6.
With n=100, we get 100*101*201/6 = 338350.

Let me verify with code:
```python
print(sum(k*k for k in range(1, 101)))
# 338350

The answer is 338350."

看到问题了吗?**模型在 NL 里把答案推出来了**——它知道公式、做了代换、得到 338350。然后跑了一段 code 只是为了"打 print 确认"。code **没做任何新计算**,纯粹是 redundant verification。

这不是个例。论文统计 TIR baseline 上有相当大比例的 trajectory 都是这种模式——code 是 NL 的鹦鹉,重复说一遍。

### 缺陷 2:Unreliable NL Computation

这个比缺陷 1 更阴险。假设题目要算 $7! \times 13$。

TIR 模型:
"7! = 5040. So 7! * 13 = 5040 * 13. Let me compute this with code:
result = 5040 * 13
print(result)  # 65520

The answer is 65520."

看起来没问题对吧?但**如果模型在 NL 里把 7! 算成 5400** 呢?code 接收的是 hard-coded `5400 * 13`,解释器无法发现 5400 是错的——它只能跑这段代码。错误就这样静默地传到 final answer。

这是 NL 推理 + code 执行混用的根本问题——**NL 不可靠的部分会污染 code 的输入**。

### 缺陷 3:Role Confusion

NL 应该做什么、code 应该做什么?TIR 没有明确划分。结果:

- NL 写:"I'll iterate from 1 to 100, for each value check if it's prime, then sum the primes"
- Code 写:`sum(p for p in range(1, 101) if is_prime(p))`

这两个在做完全相同的事。**NL 在描述算法,code 在执行同样的算法**。如果 code 才是 reasoner,那 NL 那段就是噪声;如果 NL 才是 reasoner,那 code 就是冗余。论文 argue 应该是前者——**NL 只做高层 strategy,code 做所有具体推理**。

---

## ThinC 的设计:严格的"先 plan 后 code"

![图2:ThinC trajectory 结构](https://arxiv.org/html/2605.07237v2/x2.png)

*图2:左侧是 TIR 的 trajectory——NL 和 code 交替进行,重复且容易出错。右侧是 ThinC 的 trajectory——一个 `<think>` block 做战略规划(不做任何 arithmetic),然后是一系列 `<code>` block 用执行输出连接,每一步推理都在 code 里完成。NL 不再回归。*

### Stage 1:Strategy-only Think Block

ThinC 的第一步是一个 NL `<think>` block,但有严格的约束:

1. **No arithmetic in NL**:不做任何算术或代数计算
2. **Search-space specification**:只做问题的 symbolic restructuring(如把 $a+b+ab=(a+1)(b+1)-1$ 写出来)+ 设定后续 code 要搜索的空间
3. **Single transition to code**:think block 结尾必须是"let me write code to compute this directly"——之后再也不回 NL

举个例子(论文 Appendix A 给出):

题目:找 $\leq 100$ 且能写成 $a+b+ab$($a \neq b$ 为正整数)的整数个数。

ThinC 的 think block:
I need to find the number of integers ≤ 100 that can be written as a+b+ab where a and b are distinct positive integers.

Let me think about this expression: a+b+ab = (a+1)(b+1) - 1. So I need to find how many integers n ≤ 100 satisfy n = (a+1)(b+1) - 1...

Let me just brute force this. Since a and b are distinct positive integers, let me iterate over possible values and check which sums are ≤ 100. Let me write code to compute this directly. ```

注意——没有任何计算。只是把数学结构理清楚 + 定义搜索空间。

Stage 2:Code-Centric Reasoning

从 think block 之后,所有推理在 code 里。每个 turn:

  1. 生成 code(带简短注释解释 what + why)
  2. 解释器执行,输出作为 observation
  3. 下一个 code block 基于上一个的输出继续推进

每个 code block 完成一个 reasoning step:可能是 enumerate、可能是 verify、可能是 re-derive、可能是 self-correct。Self-correction 也在 code 里做——通过对比不同 turn 的输出,模型在新一轮 code 里修正前一轮的逻辑错误。

具体看那个 \(a+b+ab\) 例子的 5 个 turn:

  • Turn 1:直接 brute force(带 early break,模型自己 flag 可能不对)
  • Turn 2:Self-correction——模型审视 Turn 1 的 break 条件,在 code comment 里写了 monotonicity argument,修正 break 位置
  • Turn 3:Structural sanity check——按奇偶性分解结果验证
  • Turn 4:Independent re-derivation——用 \((u,v)=(a+1, b+1)\) 的对偶 formulation 重新算一遍,对比是否一致
  • Turn 5:Complement audit——列出 [1,100] 中没被覆盖的 30 个值确认

整个过程没有任何 NL 在 code block 之间。所有 reasoning、verification、自我纠错都在 Python 代码里完成。

这个就是论文 emphasize 的:"code as reasoner, not tool"。


训练流程:SFT + RL

Step 1:Trajectory Distillation

用一个 strong teacher model(应该是 GPT-4o 或类似),通过 few-shot prompting 让它生成 code-centric trajectory——严格遵守 ThinC 格式:一个 strategy think block + 多个 code block。

通过 rejection sampling 过滤掉不符合 format 的 trajectory(如 think block 里有 arithmetic、code block 之间夹了 NL 等),最终构造出 12.2k 个 ThinC-SFT trajectory

Step 2:SFT

在这 12.2k trajectory 上对 base model(Qwen3-1.7B 或 Qwen3-4B-Thinking)做 SFT,让 model 学会这种 code-centric 行为。

Step 3:RL with Verifiable Rewards

数学题有 ground truth,可以用 RLVR。在 SFT 后的 model 上做 GRPO,进一步强化解题能力。


实验结果

主表

Model AIME24 AIME25 AIME26 HMMT25 BeyondAIME Avg
Qwen3-1.7B ~ ~ ~ ~ ~ 32.2
ThinC-1.7B ~ ~ ~ ~ ~ 42.8 (+10.6)
Qwen3-4B-Thinking ~ ~ ~ ~ ~ ~
Qwen3-235B-A22B-Thinking ~ ~ ~ ~ ~ ~
ThinC-4B ~ ~ ~ ~ ~ 78.1%

ThinC-1.7B 比 Qwen3-1.7B 提升 +10.6 个点,证明 paradigm shift 在小模型上也有效。

ThinC-4B 达到 78.1%,在 4 个 benchmark 上超过了 235B 参数的 Qwen3-235B-A22B-Thinking。一个 4B 模型超过 235B——这是非常 striking 的对比,说明正确的推理范式比单纯堆参数更重要

图3:ThinC vs TIR baseline 性能对比

图3:ThinC(蓝色)vs 各种 TIR baseline 和 NL reasoner 在五个 benchmark 上的对比。ThinC-4B 在每个 benchmark 上都接近或超过最强 baseline。

Code-Centric 行为验证

99.2% 的最终答案 grounded in interpreter output——这是论文最重要的 metric。

意思是:ThinC-4B 几乎从不"用 NL 算出答案再让 code 确认",而是真的让 code 来推导答案。这是行为意义上的范式 shift,不只是表面 format。

Robustness to Early Code Failures

图4:早期 code 执行失败的 robustness

图4:当第一个 code block 出错时,ThinC 能稳定从 code-level 错误中恢复(用下一个 code 修),TIR baseline 表现急剧下降——因为 TIR 习惯回到 NL 试图绕过 code,但 NL 没法做精确推理。

这是 ThinC 范式的一个 unexpected benefit——因为模型从训练就被 forced 用 code 思考,它对 code 失败的处理也更稳健。它知道唯一的出路是写另一段 code,而不是退回 NL。

OOD Generalization

在 GPQA-Diamond(graduate-level science)上做 OOD 测试:ThinC-4B 在 avg@16 上超过 ASTER-4B 3.1 个点,在 best@16 上比 base model 高 7.6 个点。说明 code-centric 范式不仅限于数学,能 transfer 到其他 reasoning domain

图5:GPQA OOD 表现

图5:ThinC-4B 在 GPQA-Diamond 上的表现领先 baseline。这是一个让人 surprised 的 transfer——training data 是 math,但 evaluation 是 science,code-centric 行为能跨域。


我的判断:值不值得读?

强推,特别是如果你在做 reasoning model 或 tool use。

亮点

  1. Paradigm clarity:把 TIR 三个隐藏的结构性问题摆出来——这本身就是非常 valuable 的诊断。之前社区都在比"哪个 TIR 系统更强",没人系统讨论"TIR 这个范式本身有什么问题"
  2. 设计 elegant:一个 think block + 多个 code block,简单清晰,可复现性极高
  3. 效果 striking:4B 超过 235B——这种数量级的差距很难单纯用 trick 解释,应该是范式本身的胜利
  4. 99.2% interpreter-grounded 这个 metric 设计得很巧——直接 measure 了"是否真的 think in code",而不是表面 format
  5. Robustness 和 OOD transfer——两个 unexpected benefit,说明这个范式有 generalization power

问题

  1. 依赖强 teacher:12.2k SFT data 都是从 teacher 蒸馏的。如果没有 strong teacher 怎么 bootstrap?
  2. Think block 的设计有点 rigid:所有 reasoning 在 code 里这个 constraint 太硬。某些问题确实需要先做一些 NL 层面的概念辨析(如证明题)。论文没讨论 ThinC 在证明类问题上的表现
  3. 代码运行的 latency:ThinC trajectory 比 NL reasoner 多了很多 code execution turn。inference latency 应该比纯 NL reasoner 高不少。论文 Appendix C 报告了 tool call 数量但没明确报告 wallclock time
  4. 没有 thorough error analysis:剩下的 ~22% 错题里,是 code 写错了?还是 think block 的策略错了?还是 code 反复跑不出来?这块分类分析很有价值,论文没做
  5. 跟 PAL/PoT 的关系:本质上 ThinC 像是 PAL/PoT 的强化版(PAL 是 single-pass code generation,ThinC 是 multi-turn)。论文里有提及但没充分对比

对工程实践的启发

  • NL 推理 + code 计算的混用是 anti-pattern。要么走纯 NL(速度快但精度差),要么走纯 code(精度高但 latency 大),不要混
  • Think block 应该极度克制——只写 strategy,不写 calculation。这是个很 actionable 的 prompting tip,即使不重训 model 也能用
  • Self-correction 应该在 code 里做,不在 NL 里。"让 code 来 verify code"比"让 NL 来 verify code"更可靠
  • Interpreter-grounding ratio 是个值得 track 的 evaluation metric——比单纯看 accuracy 更能反映 model 是否真的在 think in code

收尾

回头看 LLM math reasoning 的演化:

  • CoT:纯 NL,思路对但容易算错
  • PAL/PoT:纯 code,但 single-pass
  • TIR (ReTool/ASTER/Tool-Star):NL + code 交替,但混乱
  • ThinC:code as reasoner,NL only for strategy

这是一个很清晰的趋势——让 reasoning 落到一个 verified、deterministic 的 channel 上。NL 太 fuzzy,混合范式太 noisy,纯 code 又太 rigid——ThinC 找到的"strategy NL + execution code"是个 sweet spot。

下一个值得追的问题:

  1. 能不能把 ThinC 扩展到非数学领域?比如 software engineering agent、scientific reasoning?OOD 实验给了正面信号但还不够
  2. Think block 能不能完全去掉?给个 prompt 之后直接进 code reasoning?还是 strategy NL 是必须的?
  3. 当问题需要 symbolic reasoning(如证明题)而非 numerical computation 时,ThinC 怎么办?SymPy 能做一部分,但抽象代数级别的证明可能超出 SymPy 能力

如果你在做 reasoning model,这篇文章值得仔细读,特别是 Appendix A 的完整 trajectory 示例——它对"code-centric"长什么样有非常具体的演示。


觉得有启发的话,欢迎点赞、在看、转发。跟进最新 AI 前沿,关注我