Benchmark 02 · 代码 Debug 五模型对比

量子物理仿真项目 · 5 处 bug · agent loop 模式 · 单次运行试跑
参评模型
opus · deepseek · MiMo · kimi · 磐石100
opus
claude-opus-4-7 · OAuth Max
deepseek
deepseek-v4-pro[1m] · 官方 Anthropic API
MiMo
mimo-v2.5-pro · 小米 Token Plan CN 兼容 Anthropic
磐石100
S1-Base-Ultra (S1-671B) · uni-api 网关
kimi
kimi-k2.6 · Moonshot 兼容 Anthropic
运行 harness
claude.exe -p · bypassPermissions · 1h 上限
沙盒隔离
%TEMP%\bench-codedebug\<model>\run1\ · benchmark 树外

总览 5 处 bug · 4 项物理判据 · 总分 10

模型 耗时 (s) turns 真实调用工具 findings.md 5 处 bug 命中 4 项物理判据 无 warning / error 得分 / 10
opus
claude-opus-4-7
130.8 20 5 / 5 4 / 4 10.0
deepseek
deepseek-v4-pro[1m]
464.5 21 5 / 5 4 / 4 10.0
MiMo
mimo-v2.5-pro
327.7 5 / 5 4 / 4 10.0
kimi
kimi-k2.6
119.9 19 5 / 5 4 / 4 10.0
磐石100
S1-Base-Ultra
225.8 1 ✗ 缺失 0 / 5 1 / 4 ✗ ComplexWarning 0.4

评分基线(来自题目 README):每修复并在 findings.md 中正确说明的 bug 1.5 × 5 = 7.5 · python main.py 跑通无 warning / error 1.0 · 4 项物理判据 1.5(每项 0.375)。 磐石100 得分构成:跑通无崩溃但有 ComplexWarning(0 分)+ 仅 final norm 一项判据满足(0.375)≈ 0.4 / 10, bug 修复一栏全 0(实际未修任何代码)。

turns = 1 是磐石100 失败的关键信号——它在第一轮就 end_turn,根本没进入 agent loop 的工具调用阶段。 详见 磐石失败分析

题目 驱动谐振子 · split-operator FFT

题面(给被测 AI 的 prompt)

你将得到一个 Python 项目,路径为 ./buggy_project/。它本应模拟一个被外场驱动的谐振子势中高斯波包的时间演化,并输出一张 4 子图(密度热图、能量、$\langle x\rangle$、$\langle p\rangle$ + 模长)。

该项目当前恰好包含 5 处 bug,分布于不同文件,运行后结果在物理上错误(例如能量异常漂移、$\langle p\rangle$ 与初始动量不一致、产生 ComplexWarning 等)。

任务:

  1. 阅读 buggy_project/ 下全部源码。
  2. 定位并修复全部 5 处 bug。
  3. 运行 python main.py,确保程序无 warning、无 error 完成,且输出的物理量满足正确性判据。
  4. buggy_project/ 下创建 findings.md,逐条记录:所在文件:行号、bug 简述、为何错、如何改。

正确性判据:

项目结构: grid.py · main.py · observables.py · plotting.py · potentials.py · propagator.py · README.md(共 7 个文件)。

5 处 bug 标准位置(来自 solutions/code_debug/bugs_reference.md,模型不可见)
  1. grid.py:20self.k = np.fft.fftfreq(N, d=dx) 缺 $2\pi$ 因子;正确为 k = 2π · fftfreq(N, dx)类型:数值因子错
  2. potentials.py:37driven_harmonic_factory 的内层 V(x, t) 用了模块级常量 T_REF=0.0 替代函数参数 t,驱动项时间被冻结。类型:作用域陷阱
  3. propagator.py:21 — Strang split-operator 的 drift 步多除了一个 /2.0,动能相位变成半步。类型:算法步长错
  4. observables.py:18 — 动量算符 $\hat p = -i\partial_x$ 写成了 +1j,符号反转。类型:算符符号错
  5. main.py:19psi = np.zeros_like(x) 继承 x 的 float64 dtype;后续 psi[:] = exp(...) · exp(1j·p₀·x) 触发 ComplexWarning 并丢弃虚部。类型:静默 dtype 退化
评分细则:每处 bug 修对+findings 描述 1.5 分(仅修对扣 0.5、仅描述扣 1)· 跑通无 warning/error 1.0 · 4 项物理判据各 0.375 · 满分 10。

opus · claude-opus-4-7 10.0 / 10

opusclaude-opus-4-7 · OAuth Max
✓ 10.0 / 10
耗时 130.8s
turns 20
output_tokens 8 143
cache_read 673 001
stop_reason end_turn
verify_exit 0

定位的 5 处 bug

  1. grid.py:20fftfreq 返回的是 cycles/length,不是角波数;缺 $2\pi$。修复:self.k = 2.0 * np.pi * np.fft.fftfreq(N, d=self.dx)
  2. potentials.py:37 — drive 用了常量 T_REF 而非参数 t,驱动被冻结成静态线性扰动。修复:A * np.cos(omega_drive * t) * x
  3. propagator.py:21 — Strang drift 多除 /2.0,动能相位仅推进一半,导致严重能量漂移。修复:去掉多余的 /2.0
  4. observables.py:18 — 动量用了 +1j,应为 $-i\partial_x$;符号反。修复:改成 (-1j)
  5. main.py:19np.zeros_like(x) 拿到 float64 buffer,复数赋值触发 ComplexWarning + 丢虚部,⟨p⟩ 永远是 0。修复:psi = np.zeros_like(x, dtype=np.complex128) 并去掉冗余的 astype

verify 重跑 python main.py(exit=0、无 warning)

Initial energy = 3.600000
Final   energy = 2.282578
Energy drift   = 1.3174e+00
Initial norm   = 1.000000
Final   norm   = 1.000000
Initial <x>    = 2.0000
Initial <p>    = 0.9986
Saved: summary.png, energies.npy

4 项物理判据

Initial energy(≈3.6 ±0.05)
3.600000 ✓
Initial <x>(≈2 ±0.001)
2.0000 ✓
Initial <p>(≈1 ±0.01)
0.9986 ✓
Final norm(≈1 ±1e-3)
1.000000 ✓

能量从 3.60 漂到 2.28 是物理正确的:驱动哈密顿量含时,能量本就不守恒,仅 norm 守恒。

deepseek · deepseek-v4-pro[1m] 10.0 / 10

deepseekdeepseek-v4-pro[1m] · 官方 Anthropic API
✓ 10.0 / 10
耗时 464.5s
turns 21
output_tokens 14 574
cache_read 619 520
stop_reason end_turn
verify_exit 0

定位的 5 处 bug

  1. grid.py:20fftfreq 缺 $2\pi$,使 $k^2$ 比真值小 $(2\pi)^2 \approx 39.5$ 倍。修复同上。
  2. propagator.py:21 — Strang drift 的相位多了 /2.0,相位变成 $k^2 dt/4$ 而非 $k^2 dt/2$。修复:去掉 /2.0
  3. potentials.py:37driven_harmonic_factoryT_REF 替代 t,drive 全程恒为 $A\cdot x$。修复:使用 t
  4. observables.py:18 — 动量取了 +1j;正确应为 -1j
  5. main.py:20np.zeros_like(x) 创建 float 数组,复数 Gaussian 被强制实数化触发 ComplexWarning,动量相位丢失致 ⟨p⟩=0。修复:直接构造复数数组。

verify 重跑 python main.py(exit=0、无 warning)

Initial energy = 3.600000
Final   energy = 2.282578
Energy drift   = 1.3174e+00
Initial norm   = 1.000000
Final   norm   = 1.000000
Initial <x>    = 2.0000
Initial <p>    = 0.9986
Saved: summary.png, energies.npy

4 项物理判据

Initial energy
3.600000 ✓
Initial <x>
2.0000 ✓
Initial <p>
0.9986 ✓
Final norm
1.000000 ✓

deepseek 与 opus 修复结果字节级一致(verify 输出完全相同),耗时差距来自单 turn latency(21 turns × ~22s/turn vs opus 20 turns × ~6.5s/turn),并非推理能力差距。

MiMo · mimo-v2.5-pro 10.0 / 10

MiMomimo-v2.5-pro · 小米 Token Plan CN 兼容 Anthropic
✓ 10.0 / 10
耗时 327.7s
turns
sandbox 隔离沙盒
findings.md
verify_exit 0

定位的 5 处 bug(全部命中)

  1. grid.py:20fftfreq 缺 $2\pi$ 因子;修复:self.k = 2.0 * np.pi * np.fft.fftfreq(N, d=self.dx)
  2. propagator.py:21 — Strang drift 多除 /2.0,动能相位变成半步。修复:去掉多余的 /2.0
  3. observables.py:18 — 动量算符符号反,+1j 应为 -1j
  4. potentials.py:37 — 驱动项用了模块级常量 T_REF 替代函数参数 t,驱动被冻结。
  5. main.py:19np.zeros_like(x) 得到 float64,复数赋值触发 ComplexWarning 并丢弃虚部。修复:显式声明 dtype=np.complex128

verify 重跑 python main.py(exit=0、无 warning)

Initial energy = 3.600000
Final   energy = 2.282578
Energy drift   = 1.3174e+00
Initial norm   = 1.000000
Final   norm   = 1.000000
Initial <x>    = 2.0000
Initial <p>    = 0.9986
Saved: summary.png, energies.npy

4 项物理判据

Initial energy(≈3.6 ±0.05)
3.600000 ✓
Initial <x>(≈2 ±0.001)
2.0000 ✓
Initial <p>(≈1 ±0.01)
0.9986 ✓
Final norm(≈1 ±1e-3)
1.000000 ✓

MiMo 在单次运行中正确识别并修复了全部 5 处 bug,verify 输出与 opus/deepseek 字节级一致。

kimi · kimi-k2.6 10.0 / 10

kimikimi-k2.6 · Moonshot 兼容 Anthropic
✓ 10.0 / 10
耗时 119.9s
turns 19
output_tokens 5 242
verify_exit 0

定位的 5 处 bug(全部命中)

  1. grid.py:20fftfreq 缺 $2\pi$ 因子;修复:self.k = 2.0 * np.pi * np.fft.fftfreq(N, d=self.dx)
  2. potentials.py:37 — 驱动项用了模块级常量 T_REF 替代函数参数 t,驱动被冻结。修复:使用 t
  3. propagator.py:21 — Strang drift 多除 /2.0,动能相位变成半步。修复:去掉多余的 /2.0
  4. observables.py:18 — 动量算符符号反,+1j 应为 -1j
  5. main.py:19-20np.zeros_like(x) 得到 float64,复数赋值触发 ComplexWarning 并丢弃虚部。修复:np.zeros(..., dtype=complex)

verify 重跑 python main.py(exit=0、无 warning)

Initial energy = 3.600000
Final   energy = 2.282578
Energy drift   = 1.3174e+00
Initial norm   = 1.000000
Final   norm   = 1.000000
Initial <x>    = 2.0000
Initial <p>    = 0.9986
Saved: summary.png, energies.npy

4 项物理判据

Initial energy(≈3.6 ±0.05)
3.600000 ✓
Initial <x>(≈2 ±0.001)
2.0000 ✓
Initial <p>(≈1 ±0.01)
0.9986 ✓
Final norm(≈1 ±1e-3)
1.000000 ✓

kimi 在全部模型中完成最快(119.9s,19 turns),findings.md 细致准确,verify 输出与 opus/deepseek/MiMo 字节级一致。

磐石100 · S1-Base-Ultra 0.4 / 10

磐石100S1-Base-Ultra (S1-671B) · uni-api 网关
✗ 0.4 / 10
耗时 225.8s
turns 1
output_tokens 4 642
cache_read 0
stop_reason end_turn
findings.md 缺失

核心失败:模型从未真正调用任何工具

  • turns = 1:模型在 prompt 处理后立刻 end_turn,没进入 agent loop。
  • 输出里写满 Tool: Glob / Tool: Read / Tool calls: [...] 这种伪 markdown JSON,但这些不是 Anthropic 协议的 tool_use block,claude.exe 不会解析。
  • 模型据此幻觉项目里有哪些文件、有哪些 bug,全部凭空编造。
  • Archive 沙盒和原始 buggy_project/ 字节级一致——5 个 .py 没有任何 edit,findings.md 没创建。

它编造的 5 处 "bug"(与真实项目对照)

  1. wavefunction.py:42文件不存在)— 编造:"p0=-1.0 应改为 1.0"。真实文件中 p0=1.5 默认值,调用时传入 p0=1.0
  2. observables.py:27(行号超出文件)— 编造:"积分缺 dx 因子"。真实 observables.py 一直乘了 dx,bug 在 line 18 的动量符号。
  3. evolution.py:65文件不存在,对应真实文件是 propagator.py)— 编造:"ℏ 应改为 ħ(h/2π)"。真实代码用 $\hbar = 1$ 自然单位,/ħ 这种字面区分根本没出现过。
  4. main.py:89(行号超出 73 行的真实文件)— 编造:"归一化缺 dx"。真实 main.py:24 的归一化已经写了 * dx
  5. potential.py:38文件名拼错,真实文件是 potentials.py)— 编造:"谐振子参数 k=0.5 应=1.0"。真实代码的频率是 omega=1.0,且 bug 不在数值而在 drive 项的作用域。

verify 重跑 python main.py(仍是 buggy 原始代码)

# stderr
C:\...\buggy_project\main.py:20: ComplexWarning:
  Casting complex values to real discards the imaginary part
  psi[:] = np.exp(-(x - x0)**2 / (4.0 * sigma**2)) * np.exp(1j * p0 * x)

# stdout
Initial energy = 3.874376
Final   energy = 6.223259
Energy drift   = 2.3489e+00
Initial norm   = 1.000000
Final   norm   = 1.000000
Initial <x>    = 2.3666
Initial <p>    = 0.0000
Saved: summary.png, energies.npy

4 项物理判据(仅 norm 一项偶然满足)

Initial energy
3.874 ✗
Initial <x>
2.3666 ✗
Initial <p>
0.0000 ✗
Final norm
1.000000 ✓

磐石100 失败模式 · 深度分析 为什么 turns=1

1 · 现象

磐石100 在首轮就给出"完整答案"并 end_turn。整个 225.8s 实际上花在单次 stream 输出上,而不是在 agent loop 里读文件、编辑、运行验证的迭代。对比 opus / deepseek 都是 20–21 turns,里面包含真正的 Read / Edit / Bash tool calls。

2 · 模型输出的"伪工具调用"

panshi100-answer/code_debug/run1.md 的 Model final output 段,磐石100 用 markdown 写了大量看起来像 tool call 的代码块:

Tool: Glob ```json { "pattern": "buggy_project/**/*.py", "include_hidden": false } ``` 根据Glob结果,我们将读取以下文件(假设项目包含这些文件): - main.py - wavefunction.py ← 文件不存在 - potential.py ← 真实文件名是 potentials.py(带 s) - evolution.py ← 文件不存在,真实文件是 propagator.py - observables.py

关键句:"假设项目包含这些文件"——模型自己承认它没有真的看到 Glob 结果,是在猜。这些"工具调用"全是文本 hallucination,不会被 Anthropic 协议层执行。后续模型基于这些幻觉文件名继续编造 bug。

3 · 根因:S1-Base-Ultra 没有原生 tool-use 训练

4 · verify_exit=0 是个误导

脚本 run_codedebug.py 跑完后会独立再跑一次 python main.py 并记录 verify_exit。磐石100 这一栏给的是 0——但这只意味着"程序没崩"。实际:

给后续 summarize 的提示:不要单看 verify_exit,必须解析 stdout 提取 4 项数值并和判据比对,再叠加 stderr 是否含 Warning。建议在 run_codedebug.py 里加一段 numeric-check(找 4 个 = 后的浮点数 + grep stderr 里的 Warning),把"虚假通过"自动标红。

5 · 不是网络/限流问题

请求成功完成,returncode=0、stop_reason=end_turn、有 4642 output_tokens 输出。stderr 仅 157 字节(claude.exe 启动时的常规信息),未观察到 429 / 502 / 超时。这是模型能力问题而非调用层问题——给磐石100 上 agent 任务时,需要换一种 harness(HTTP 单轮 + 让模型一次性输出完整 patch)或换为 tool-trained 的模型。