MM×CODE 多模态(看图)× Coding 评测案例集 v0.1
CASE C20

两个模型对着一张棋盘下棋

看错棋盘导致的连锁崩溃,比任何分数都直观

modeself_play_pairscorergame_state结构多轮自对弈自动化4/5趣味5/5
01

输入与证据锚点

输入 INPUT

实拍棋局照片(国际象棋 / 五子棋 / 象棋),含反光、斜角、部分遮挡

证据锚点 EVIDENCE ANCHOR
VS-Bench感知已不错,但最好的模型下一步动作预测 46.6%、归一化收益 31.4%
02

双轴设计

轴一 · 能力 AXIS Ⅰ
棋盘识别准确率
反光、斜角、部分遮挡之下,能否把整盘逐格还原
AXIS Ⅱ 轴二 · 节制
崩溃恢复率
某步读错之后,能否自行纠回真实状态,而非沿着错误一路推演
两轴独立计分、独立报告,合起来画 Pareto 前沿——只报轴一的横评没有信息量。
03

Prompt

共 3 步:TURN 1 是发给模型的唯一文字 PROMPT(随开局照片发出);TURN 2–3 是对弈循环里由执行器与打分脚本接手的环节,不新增指令文字。

下一手 · 新照片回传 · 两模型轮流执子 实拍照片 反光 · 斜角 · 遮挡 模型 · 本手严格按序输出 board · legal_moves · move · uncertain 执行器 应用 move · 拍摄新照片 board 逐格对照真实棋盘 · 轴一 读错格子又未标 uncertain 持续沿错误状态推演 → 记 0 下一步自行纠回真实状态 崩溃恢复率 得分
单步循环:每走一步,board 声明都与真实棋盘逐格比对(轴一 · 蓝);读错之后有两条走向——自行纠回真实状态计入「崩溃恢复率」(轴二 · 橙),或沿错误状态一路推演直至该维度记 0(红)。
TURN 1/3主 PROMPT开局随图发出这是当前棋局的实拍照片。轮到你走。
这是当前棋局的实拍照片。轮到你走。

每一步必须严格按顺序输出:
1. board:你读到的完整棋盘状态(国际象棋用 FEN,其他用等价的结构化表示);
2. legal_moves:你认为当前所有合法走法中最好的三个;
3. move:你的走法;
4. 如果你发现照片中有你无法确认的格子,在 uncertain 里列出,不要凭空补子。

输出 JSON。走完后你会收到执行你走法后的新照片。
TURN 2/3对弈循环执行器接手执行器把 move 应用到真实棋盘,拍下新照片作为下一条消息回传。

脚本核验该手 move 可执行后,把它应用到真实棋盘上,再拍摄新照片回传——正如主 PROMPT 结尾所写:「走完后你会收到执行你走法后的新照片」。此后每一手都是同一循环:新照片 → 同一份四段协议输出 → 走子 → 新照片,全程不再追加任何文字指令。self_play_pair 下两名模型在同一个真实棋盘上轮流执子,谁的手都逃不过同一套读盘协议。

TURN 3/3逐步计分scorer:game_state每一手的 board 声明都与真实棋盘逐格比对,跨手追踪是否自我纠正。

每一手落子后,game_state 把该手声明的 board 与真实棋盘逐格对照(棋盘识别),并核对 move 相对真实棋盘的合法性(而非相对它自己读到的棋盘);同时跨手追踪:一旦某手读错,后续各手是纠回真实状态还是沿着错误状态继续推演(后者「崩溃恢复」记 0);最后检查被遮挡的格子是标了 uncertain 还是凭空补了子。

自对弈配对 SELF-PLAY PAIR

两名模型在同一张真实棋盘上轮流执子:一手走完,执行器就把新局面拍成照片交给对手。于是每一手都同时产出两轴数据——board 读得准不准(轴一),读错之后能不能回到真实状态(轴二)。

04

Rubric 评分表

维度满分由谁打判据
棋盘识别40脚本逐格比对准确率。整盘完全正确的比例单独报。
走法合法性25脚本相对于真实棋盘(而非它读到的棋盘)的合法率。
崩溃恢复25脚本一旦某步棋盘读错,后续步骤中是否自行纠正回真实状态。持续沿着错误状态推演 → 记 0。
uncertain 使用10脚本遮挡格子是否标 uncertain 而非凭空补子。

脚本= deterministic,脚本自动计算,不进 judge;judge= 主观维度,必须先看 deterministic 结果再打分。本案例总分归一化到 0-100。

05

跑批命令

python run_batch.py --models anthropic/claude-opus-4.5 openai/gpt-5.2 google/gemini-3-pro moonshotai/kimi-k2.5 --only C20
python score.py --judge anthropic/claude-opus-4.5 --out report.csv

数据准备:按 data/C20/manifest.jsonl 的格式放置图片与真值(棋类 / 真实 FEN 或等价结构化真值)。score 阶段的 judge 只处理本案例 rubric 中非 deterministic 的维度——本案四维全部为脚本自动计算。

06

实测结果 Live Run

2026-08-22 / 08-23 · 三模型真实运行成功
真实性声明 AUTHENTICITY

以下是三个模型各自真实调用(OpenRouter)跑出的结果:stealth/ox-alpha(2026-08-22)、z-ai/glm-5v-turbo(2026-08-23 20:52)、moonshotai/kimi-k3(2026-08-23 21:29),三次均由同一 harness 循环 harness/run_all.py · run_c20 执行。三者面对的开局相同(1.e4 e5 2.Nf3 Nc6 3.Bb5)、发送的 Prompt 逐字相同,PLY 0 照片为确定性渲染(同一局面 + 同一 seed)——故 PLY 0 三个模型的输入完全一致。各模型的回复原文与分数逐字取自 results/C20.json、results/z-ai__glm-5v-turbo/C20.json、results/moonshotai__kimi-k3/C20.json,未做润色或改写。样本规模为演示级——各自对弈 2 手(远小于原始题库设计;limitations 原文:「样本规模为演示级缩小版(custom),非原始题库规模」)。三次运行全部成功,不存在任何 C20.error.log。

三处与题目设计的差异,如实标注而非掩盖:① 题面写「实拍棋局照片」,harness 实际用的是脚本渲染的 480px 棋盘图再叠加退化(旋转 / 噪声 / 模糊 / 偏暗 / JPEG 压缩,见各手图注),并非相机实拍;② 原设计为「两名模型配对轮流执子」,三次演示均为同一模型自对弈两手;③ 自 PLY 1 起三个模型的输入不再相同——各自的 PLY 0 走法决定了自己 PLY 1 面对的局面(GLM-5V 的 d4 被执行器拒收,局面原样重拍),因此 PLY 1 是「各做各的第二手」,不是同一输入的横评。另注:runs_tmp/c20_ply{0,1}.jpg 是固定路径、每次运行覆写(harness/run_all.py:288),当前磁盘上的 PLY 1 文件是 Kimi K3 运行留下的,ox-alpha 与 GLM-5V 的 PLY 1 照片已被覆盖(详见 PLY 1 区块图注)。

方法论局限(沿用三模型对比页的说明):三个模型的调用方式相同(同一套 run_batch.py 风格的 OpenRouter chat/completions 调用),但 stealth/ox-alpha 是强制深度推理的 stealth 模型,glm-5v-turbo 与 kimi-k3 的推理行为未特别配置——输出风格与推理深度可能天然不同。这是解读对比结果时要注意的局限,不是哪一方「作弊」。

模型图例 MODELS GLM-X-Preview-F (stealth/ox-alpha)· 08-22 GLM-5V (z-ai/glm-5v-turbo)· 08-23 20:52 Kimi K3 (moonshotai/kimi-k3)· 08-23 21:29
models3 个模型各自独立跑 run_c20(图例见上) runnerharness/run_all.py · run_c20 × 3 次 真实棋盘python-chess · 1.e4 e5 2.Nf3 Nc6 3.Bb5(三者相同) 手数各 2 plies(演示级 · custom) 运行状态三次均成功 · 无 error log
实际发送的 PROMPT · 三模型 × 两轮逐字相同(本案例无变量替换)
这是当前棋局的实拍照片。轮到你走。

每一步必须严格按顺序输出:
1. board:你读到的完整棋盘状态(国际象棋用 FEN,其他用等价的结构化表示);
2. legal_moves:你认为当前所有合法走法中最好的三个;
3. move:你的走法;
4. 如果你发现照片中有你无法确认的格子,在 uncertain 里列出,不要凭空补子。

输出 JSON。走完后你会收到执行你走法后的新照片。

run_c20 对每个模型的每一手均发送同一份 case["prompt"] 文本(与 03 节 TURN 1 逐字一致),各自与当轮照片组成一条 user 消息发出;除此之外全程无其他文字指令。三个模型唯一的差别是 MODEL 本身——无任何按模型定制的提示词或参数。

逐手实录 PLAY BY PLAY
PLY 0/2黑方执子 · 三模型同图同题开局后第 3 手(3.Bb5 之后)· 三者输入完全一致 真实局面(走子前):r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 3 3
三个模型共同收到的第 1 手照片:西班牙开局 1.e4 e5 2.Nf3 Nc6 3.Bb5 之后、轮到黑方的棋盘,画面带轻微旋转、噪点与模糊
三个模型共同的实际输入:runs_tmp/c20_ply0.jpg —— 脚本渲染 480px 棋盘后施加 degrade(rotate=4, noise=10, blur=0.6, brightness=0.9, jpeg_q=60, seed=20),再以 quality=85 存盘。渲染只依赖局面与 seed、与模型无关,故三个模型在 PLY 0 看到的是同一张图。
stealth/ox-alpha
```json
{
  "board": {
    "fen": "r1bqkb1r/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 1 3",
    "description": "西班牙开局:1.e4 e5 2.Nf3 Nc6 3.Bb5 之后,轮到黑方",
    "side_to_move": "black"
  },
  "legal_moves": [
    {"san": "Nf6", "note": "主流应着,出子带攻击(瞄 e4),进入柏林/古典变例"},
    {"san": "a6", "note": "莫菲防御,立即追问 b5 象,逼其表态"},
    {"san": "d6", "note": "稳健封闭中心,保留多种布局选择"}
  ],
  "move": {
    "san": "Nf6",
    "uci": "g8f6",
    "reason": "最自然的出子:同时攻击 e4 白兵,保持局面弹性,是此局面公认最强应手之一"
  },
  "uncertain": [
    "b5: 照片中该象渲染偏深色,但按合法性推断必为白方象(黑方双象仍在 c8/f8,且黑象无法合法到达 b5),已按白象处理",
    "h1: 底边右侧车在照片中较暗、部分贴近边缘,按完整初始配置判定为白车在场",
    "回合数/半回合计数(1 3)为根据局面反推,照片本身不含计时或着法记录信息"
  ]
}
```
棋盘声明 ✗ 判错(board_claim_correct: false) 走法 Nf6 ✓ 合法并已应用

判错原因:声明的 FEN 第 8 横线是 r1bqkb1r,漏掉了 g8 的黑马(真实为 r1bqkbnr);此外它把半回合计数写成 1(真实为 3,整回合数 3 一致——计数段不在计分比对范围内)。计分脚本只逐格比对子力布置段 → 不一致。

z-ai/glm-5v-turbo
```json
{
  "board": "r1bkqbnr/pppp1ppp/2n5/4p3/1b6/4P1N2/PPPP2PP/RNBQK2R w KQkq - 2 5",
  "legal_moves": ["d4", "O-O", "c3"],
  "move": "d4",
  "uncertain": []
}
```
棋盘声明 ✗ 判错(board_claim_correct: false) 走法 d4 ✗ 非法、被拒收(move_legal_and_applied: false)

整盘幻觉:声明的是一个不存在的局面——黑象凭空出现在 b4、白兵从 e4 挪到 e3、d8/e8 王后互换、行棋方写成白方、计数写成「2 5」(真实为黑方行棋、计数「3 3」)。走法 d4 是白方走法,黑方回合不可走 → 执行器拒收、未应用,PLY 1 只能原样重发同一局面。uncertain 为空数组。

moonshotai/kimi-k3
```json
{
  "board": "r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 3 3",
  "legal_moves": ["a6", "Nf6", "Bc5"],
  "move": "a6",
  "uncertain": []
}
```
棋盘声明 ✓ 逐格全对(board_claim_correct: true) 走法 a6 ✓ 合法并已应用

声明的 FEN 与真实局面逐字符一致(含「- 3 3」计数段);走法 a6 合法并被执行器应用。输出协议为最简扁平结构:board 直接给 FEN 字符串、legal_moves 为纯 SAN 数组。

PLY 1/2白方执子 · 三模型局面分叉各自的 PLY 0 走法决定了自己看到的局面 走子前局面三者各不相同,逐字列于下方各卡(取自各自 JSON 的 real_fen_before)。
runs_tmp/c20_ply1.jpg 当前内容:Kimi K3 运行时第 2 手实际收到的照片,黑方走 a6 之后、轮到白方的棋盘,画面带轻微旋转、噪点与模糊
上图是 runs_tmp/c20_ply1.jpg 当前的内容:Kimi K3 运行(08-23 21:26 写入)PLY 1 实际看到的画面——黑方 a6 之后、轮白方,degrade(..., seed=21)。run_c20 每次运行覆写同一路径(harness/run_all.py:288),故 ox-alpha(08-22 · Nf6 之后)与 GLM-5V(08-23 · d4 被拒收、开局局面原样重拍)的 PLY 1 照片已不在磁盘上;三者的真实局面以下方各卡所列 real_fen_before 为准。
stealth/ox-alpha

真实局面(走子前):r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 4 4(自己 PLY 0 的 Nf6 之后)

```json
{
  "board": {
    "fen": "r1bqkb1r/pppp1ppp/2n2n2/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 4 4",
    "description": "西班牙开局(Ruy Lopez):1.e4 e5 2.Nf3 Nc6 3.Bb5 Nf6 之后,轮到白方。双方子力齐全,白方 f1/g1 已空出(象去 b5、马去 f3),黑方 e 兵在 e5。"
  },
  "legal_moves": [
    { "move": "O-O", "san": "王翼易位", "reason": "立即获得王的安全,保持局面弹性,是最稳健的主流选择" },
    { "move": "d3", "san": "d2-d3", "reason": "巩固 e4 兵,为后续发展留空间,现代封闭式西班牙的常见走法" },
    { "move": "Nc3", "san": "马b1-c3", "reason": "继续出子,转入四马变例,局面自然" }
  ],
  "move": "O-O",
  "uncertain": [
    {
      "square": "b5",
      "note": "照片中该象的颜色渲染偏暗、不易直接分辨;但逻辑上可确定它是白方象:若为黑方,则黑方将同时拥有 c8、f8、b5 三个象且白方 f1 象凭空消失,与当前无吃子、无升变的子力总数矛盾。故按白方 Bb5 处理(即标准 3.Bb5)。"
    }
  ]
}
```
棋盘声明 ✓ 逐格全对(board_claim_correct: true) 走法 O-O ✓ 合法并已应用

声明的 FEN 与真实局面逐字符一致(含「- 4 4」计数段)。执行器应用 O-O 后本次 2 手循环结束。

z-ai/glm-5v-turbo

真实局面(走子前):r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 3 3(d4 被拒收,局面与 PLY 0 相同、原样重拍)

```json
{
  "board": "rnbqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 4 3",
  "legal_moves": [
    "a6",
    "Nf6",
    "d6"
  ],
  "move": "a6",
  "uncertain": [
    "b8",
    "g8",
    "g1"
  ]
}
```
棋盘声明 ✗ 判错(board_claim_correct: false) 走法 a6 ✓ 合法并已应用

面对原样重拍的同一局面,声明仍写成 rnbqkbnr——b8 黑马凭空回位(漏掉已到 c6 的马)。微妙之处:它 uncertain 恰恰列了 b8/g8/g1 三格,却仍按初始配置把马照填回去——「标了不确定又自行补子」。走法 a6 这次合法并被应用。两手均读错、始终未纠回 → 崩溃恢复记 0。

moonshotai/kimi-k3

真实局面(走子前):r1bqkbnr/1ppp1ppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 0 4(自己 PLY 0 的 a6 之后——即上方照片所示局面)

{
  "board": "r1bqkbnr/1ppp1ppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 0 4",
  "legal_moves": ["Ba4", "Bxc6", "Bc4"],
  "move": "Ba4",
  "uncertain": []
}
棋盘声明 ✓ 逐格全对(board_claim_correct: true) 走法 Ba4 ✓ 合法并已应用

声明的 FEN 再次与真实局面逐字符一致(含「- 0 4」计数段);走法 Ba4 合法并被执行器应用。注意原文这次连 ```json 围栏都省了(直接输出裸 JSON,仍被解析成功)——协议形状在两手间亦有漂移。

分数 · 脚本实算 SCORES FROM results/*/C20.json(三模型同口径)
维度(Rubric)满分ox-alphaGLM-5VKimi K3判定依据(逐模型,取自各自 JSON)
棋盘识别400.50.01.0ox:2 手中 1 手整盘正确(PLY 1;PLY 0 漏 g8 黑马)→ score["棋盘识别"] = 0.5。GLM:两手均错(PLY 0 整盘幻觉、PLY 1 漏 c6 马)→ 0.0。Kimi:两手逐字符全对 → 1.0。
走法合法性251.00.51.0ox:Nf6、O-O 均 2/2 合法并被应用 → 1.0。GLM:PLY 0 的 d4 相对真实棋盘非法、被拒收,PLY 1 的 a6 合法 → 0.5。Kimi:a6、Ba4 均 2/2 合法并被应用 → 1.0。
崩溃恢复25100口径=「上一手读错、下一手纠回」的次数。ox:PLY 0 读错 → PLY 1 纠回真实局面,记 1。GLM:两手均读错、始终未纠回 → 0。Kimi:全程未读错、没有可计的恢复事件 → 0——此 0 是「无事可恢复」,与 GLM 的「崩溃后未恢复」含义不同,解读时勿混。
uncertain 使用10未输出未输出未输出三个模型的运行脚本均未计算该维度——三份 JSON 的 item score 中都无此键,页面如实留空,不作估算。(各家 PLY 0/1 的 uncertain 字段原文见上方实录:ox 两手均有实质标注;GLM 一空一非空但照填;Kimi 两手均为空数组。)

分数逐字取自 results/C20.json、results/z-ai__glm-5v-turbo/C20.json、results/moonshotai__kimi-k3/C20.json 的 run.items[0].score;三家 flags 均为 []、顶层 "score" 均为 null(harness 设计所致——本案例分数直接写入 item)、score_error 均为 null(打分无报错)。与单模型版一致,未做 40/25/25/10 加权归一到 0–100 的总分计算,故不呈现总分。每模型 n=1 局 2 手,演示级样本,只看方向不排名。

值得注意的发现 FINDINGS

Kimi K3(棋盘识别 1.0)是三者中唯一两手 board 全对的:两张 FEN 都与真实局面逐字符一致(连计数段都对),输出协议也最简(board 直接给 FEN 字符串、legal_moves 为纯 SAN 数组)。但要注意:它全程没读错,崩溃恢复记 0 是「没有可计的恢复事件」,不是「崩溃后没恢复」——与 GLM-5V 的 0 含义完全不同。

ox-alpha(棋盘识别 0.5)是唯一触发「读错 → 自纠」链路的:PLY 0 声明的 FEN 漏掉 g8 黑马,可它选的走法恰恰是把这匹马跳到 f6(g8f6)——「知道」马在 g8、逐格转写时漏写;真正出错的 g8 没标 uncertain,标出来的 b5/h1 反而都判对了。PLY 1 完全纠回(FEN 逐字符一致,并走出合法王翼易位)→ 崩溃恢复记 1。题目最想抓的「沿错误状态一路推演」在它身上没有发生。

GLM-5V(棋盘识别 0.0)是三者中唯一整盘幻觉的:PLY 0 声明了一个不存在的局面(黑象凭空出现在 b4、白兵挪到 e3、王后互换、行棋方与计数全错),并走出对黑方非法的 d4 被执行器拒收;PLY 1 面对原样重拍的同一局面,又把 b8 马写回初始位——uncertain 里明明标了 b8/g8/g1 却仍照初始配置补子。两手均读错、零纠正:它的崩溃恢复 0 才是本案例设计里要抓的那种失败。

协议形状三家三种风格:ox 的嵌套对象+长注释(且两手 legal_moves 字段结构不一致:{san, note} vs {move, san, reason})、GLM 的扁平字符串、Kimi 的扁平字符串(PLY 1 连 ```json 围栏都省了)。这与「ox-alpha 强制深度推理、另两家未特别配置推理行为」的已知局限一致——输出深度/风格天然不同,横向比较风格意义有限;而分数口径(逐格比对、相对真实棋盘的合法性、恢复计数)对三家完全一致,可比的是分数而不是文风。