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

接线与说明书

符号到语义,被点名的弱域

modesinglescorerexec_plus_judge自动化4/5趣味3/5
01

输入与证据锚点

输入 INPUT

插线板背面 / 路由器接口 / 宜家装配图某一页 / 配电箱

证据锚点 EVIDENCE ANCHOR
Vision2Code电路类图示是弱域
BlueprintSymVL密集场景退化、相似干扰项混淆、幻觉符号
02

双轴设计

轴一 · 能力 AXIS Ⅰ
连接表 F1
测「能不能把图里的节点与连线读全、读对」
AXIS Ⅱ 轴二 · 节制
unknown 使用恰当性
测「该标 unknown 时标 unknown——清晰处不推卸,遮挡处不硬猜」
两轴独立计分、独立报告,合起来画 Pareto 前沿——只报轴一的横评没有信息量。
03

Prompt

PROMPT主 PROMPT请输出这张图的结构化连接表:节点列表、每个节点的端口、连线(含方向与极性,若可判断)。
请输出这张图的结构化连接表:节点列表、每个节点的端口、连线(含方向与极性,若可判断)。

看不清或被遮挡的连线,标 "unknown",不要补全。

然后输出一段校验脚本,检查以下问题并给出定位:
环路、端口重复占用、极性或顺序违反常识、总负载超过额定值(若图中可读出额定值)。

输出 JSON:{"nodes": [...], "edges": [...], "unknown": [...], "checker": "..."}
本页补充图解 · 输出契约 ↔ RUBRIC 对应
nodes被谁打分
35连接表 F1(边集合比对)-5/条幻觉连线:图中不存在的边
edges被谁打分
35连接表 F1(边集合比对)-5/条幻觉连线:图中不存在的边
unknown被谁打分
25unknown 恰当性:遮挡处标注记分,推卸与硬猜各扣分
checker被谁打分
25校验规则覆盖:注入 4 类故障看能抓几类

蓝= 能力维度 橙= 节制维度。Prompt 要求的四个输出字段正好被四条评分维度覆盖;其中两条会倒扣,对应轴二「不补全、不编造」的节制要求。

04

Rubric 评分表

维度满分由谁打判据
连接表 F135脚本与人工标注的边集合对比。
unknown 恰当性25脚本真实遮挡处标 unknown 记分;清晰处标 unknown(推卸)与遮挡处硬猜(编造)各扣分。
校验规则覆盖25脚本用注入了 4 类故障的变体图跑它的 checker,看能抓住几类。
幻觉连线15脚本图中不存在的边,每条 -5。

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

05

跑批命令

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

数据准备:按 data/C09/manifest.jsonl 的格式放置图片与真值。score 阶段的 judge 只处理本案例 rubric 中非 deterministic 的维度。

06

实测结果 LIVE RUN

真实性声明 — 本区块展示 2026 年 8 月三次真实调用的结果(stealth/ox-alpha · z-ai/glm-5v-turbo · moonshotai/kimi-k3):同一张图(data/C09/images/wiring.png)、同一段 prompt(三个结果文件中的 prompt 字段已逐字比对一致),样本规模为演示级缩小版(每模型 1 个样本 · 1 张图 · 单轮,远小于原始题库设计,具体规模见下方 limitations)。各模型的图片、Prompt、回复与分数全部逐字取自各自的结果 JSON 与 data/C09/,未做任何润色或补写。ox-alpha 部分以 2026-08-24 21:09 写盘的最新版 results/C09.json 为准:该轮此前曾记录为「空响应」(text = null、无 error 信息),现已用同一 prompt、同一图片重新调用补齐真实回复——本页展示的回复原文与三维分数均取自这次重新调用后的最新写盘版本,分数由打分脚本对真实输出重算,score_error = null。glm-5v-turbo 与 kimi-k3 部分分别逐字取自 results/z-ai__glm-5v-turbo/C09.json 与 results/moonshotai__kimi-k3/C09.json(均 2026-08-23 写盘):两模型均有真实文本回复、finish_reason 均为 "stop"、score_error 均为 null、各维均为 0 分;ox-alpha 则在 checker可运行 一维拿到 1.0、其余两维同为 0——同样接近全零的三个分数成因并不相同,见各栏状态标注与文末解读。
模型图例 MODELSGLM-X-Preview-F (stealth/ox-alpha)GLM-5V (glm-5v-turbo)Kimi K3
modelstealth/ox-alpha run 记录results/C09.json · 2026-08-24 21:09 写盘(空响应已重新调用补齐并重算分数) itemmain · vars = {}(无变量替换)· images/wiring.png × 1 ox-alpha 结果状态有回复 · 仅 checker可运行 得分(1.0) score_errornull(打分脚本对最新输出重算无报错)
真实输入图 ACTUAL INPUT · data/C09/images/wiring.png
真实输入图 wiring.png:插座A、插座B、插座C 与右侧总开关盒的连线示意,中部有灰色「遮挡/反光」干扰块
实际喂给模型的唯一一张图 · 520×380 PNG · 6.7 KB。图中灰色块为「遮挡/反光」干扰区域;插座C 无可见连线——它正是真值里被标为遮挡(occluded)的节点。
人工标注真值 TRUTH · data/C09/manifest.jsonl
  • edges[0]:["总开关", "插座A"]
  • edges[1]:["总开关", "插座B"]
  • occluded:["插座C"]

评分脚本拿这份真值与模型的连接表做边集合比对(F1)。插座C 在真值中被标为被遮挡:其连线不可判读,正确行为是标 unknown,补全即扣分。

实发 PROMPT轮次 1 / 1vars = {} ,实发文本与模板一致,无变量替换
请输出这张图的结构化连接表:节点列表、每个节点的端口、连线(含方向与极性,若可判断)。

看不清或被遮挡的连线,标 "unknown",不要补全。

然后输出一段校验脚本,检查以下问题并给出定位:
环路、端口重复占用、极性或顺序违反常识、总负载超过额定值(若图中可读出额定值)。

输出 JSON:{"nodes": [...], "edges": [...], "unknown": [...], "checker": "..."}
stealth/ox-alpha
GLM-X-Preview-F · 强制深度推理的 stealth 模型
有回复 · 拓扑读对但节点名误读 · checker 可运行记 1 分
run 记录:results/C09.json
finish_reason = "stop" · usage: prompt 466 tok / completion 5562 tok(usage 明细 reasoning 记 0)/ cost 0
回复以一段图面描述开场,主体为单个 ```json 围栏块(checker 以字符串内嵌于 JSON),结尾附说明
展开模型回复逐字原文(RAW RESPONSE · 约 3.6k 字符)
根据图像识别:左侧三个框为「描座A / 描座B / 描座C」(疑为“插座”),右侧为「总开关」(文字被连线部分遮挡),中部灰色标签「建指/反光」含义不明、未与任何节点相连。可见两条蓝色直线(A→总开关、B→总开关),均无箭头、无极性标记;描座C 无可见连线;所有端口均未标注。

```json
{
  "nodes": [
    {"id": "描座A", "alias_maybe": "插座A", "type": "插座/接口(推测)", "ports": [], "ports_note": "unknown: 图中未标注端口名/数量"},
    {"id": "描座B", "alias_maybe": "插座B", "type": "插座/接口(推测)", "ports": [], "ports_note": "unknown: 图中未标注端口名/数量"},
    {"id": "描座C", "alias_maybe": "插座C", "type": "插座/接口(推测)", "ports": [], "ports_note": "unknown: 未标注端口; 未见任何连线"},
    {"id": "总开关", "type": "开关(推测)", "ports": [], "ports_note": "unknown: 名称被连线部分遮挡, 端口未标注"}
  ],
  "edges": [
    {"id": "E1", "from": "描座A", "to": "总开关", "from_port": null, "to_port": null, "direction": "unknown(无箭头)", "polarity": "unknown(无L/N或+/−标记)", "geometry": "A右边框 → 总开关左边框, 斜向下直线"},
    {"id": "E2", "from": "描座B", "to": "总开关", "from_port": null, "to_port": null, "direction": "unknown(无箭头)", "polarity": "unknown(无L/N或+/−标记)", "geometry": "B右边框 → 总开关左边框, 斜向上直线"}
  ],
  "unknown": [
    "描座C: 未见连线, 是否存在被遮挡连线 unknown",
    "全部节点的端口名称与数量未标注 → from_port/to_port 均为 unknown",
    "两条连线均无箭头 → 方向 unknown",
    "无极性标记 → 极性 unknown",
    "灰色标签『建指/反光』文字含义不明, 未连接任何节点, 按注释处理而非节点",
    "『总开关』文字被连线穿过, 名称识别有不确定性",
    "图中无可读额定值/负载值 → 负载校验无法执行"
  ],
  "checker": "import sys, json\n\n# 用法: python checker.py graph.json   (graph.json 即本文件; 可选字段 ratings/loads)\n\ndef find_loops(nodes, edges):\n    adj = {n: [] for n in nodes}\n    for e in edges:\n        adj[e['from']].append(e['to'])\n        adj[e['to']].append(e['from'])\n    color = {n: 0 for n in nodes}\n    loops = []\n    def dfs(u, parent, path):\n        color[u] = 1; path.append(u)\n        for v in adj[u]:\n            if color[v] == 0:\n                dfs(v, u, path)\n            elif color[v] == 1 and v != parent:\n                loops.append('环路: ' + ' -> '.join(path + [v]))\n        path.pop(); color[u] = 2\n    for n in nodes:\n        if color[n] == 0:\n            dfs(n, None, [])\n    return loops\n\ndef find_dup_ports(edges):\n    seen, dups = {}, []\n    for i, e in enumerate(edges):\n        for side in ('from', 'to'):\n            p = e.get(side + '_port')\n            if p is None:  # 端口 unknown 时跳过, 无法判重\n                continue\n            key = (e[side], p)\n            if key in seen:\n                dups.append(f'端口重复: {key[0]}:{key[1]} 被边E{seen[key]+1} 与 边E{i+1} 同时占用')\n            else:\n                seen[key] = i\n    return dups\n\ndef check_polarity(edges):\n    bad = []\n    for i, e in enumerate(edges):\n        a, b = e.get('from_polarity'), e.get('to_polarity')\n        if a and b and a != b:\n            bad.append(f'极性违反: 边E{i+1} {e[\"from\"]}({a}) -> {e[\"to\"]}({b})')\n    return bad\n\ndef check_load(ratings, loads):\n    bad = []\n    for n, l in (loads or {}).items():\n        r = (ratings or {}).get(n)\n        if r is not None and l > r:\n            bad.append(f'超载: {n} 负载{l} > 额定{r}')\n    return bad\n\ndata = json.load(open(sys.argv[1], encoding='utf-8'))\nnodes = [n['id'] for n in data['nodes']]\nedges = data['edges']\nreport = {\n    'loops': find_loops(nodes, edges),\n    'dup_ports': find_dup_ports(edges),\n    'polarity_violations': check_polarity(edges),\n    'overload': check_load(data.get('ratings'), data.get('loads'))\n}\nprint(json.dumps(report, ensure_ascii=False, indent=2))\n# 本图预期结果: loops=[] (星型树状无环); dup_ports=[] (端口unknown无法判重);\n# polarity_violations=[] (极性unknown); overload=[] (额定值不可读, 校验空转)\n"
}
```

说明:本图拓扑为 A、B 汇入总开关的星型结构,环路检查预期通过;端口判重、极性、负载三项因图中信息缺失(端口未标、无极性记号、无额定值)只能空转,待补充 `from_port/to_port`、`polarity`、`ratings/loads` 字段后脚本即可给出定位。

页面归纳(非模型输出):把左侧三框读作「描座A/B/C」,并在每个节点自带 alias_maybe「插座A/B/C」自我纠正——「插座」被 OCR 成「描座」的单字级误读;右侧总开关文字被连线遮挡也如实说明。识别出 A、B→总开关两条连线,方向与真值拓扑一致;描座C 判定无可见连线且写入 unknown;端口名、连线方向、极性全部未硬猜、逐一标 unknown。checker 以字符串内嵌于 JSON,覆盖环路 / 端口判重 / 极性 / 负载四类故障检查。

z-ai/glm-5v-turbo
GLM-5V · 推理深度未特别配置
有回复 · 节点整体误读 · 各维 0 分
run 记录:results/z-ai__glm-5v-turbo/C09.json
finish_reason = "stop" · usage: prompt 358 tok / completion 1667 tok(其中 reasoning 943)/ cost 0.0070976
回复为单个 ```json 围栏块;checker 以字符串内嵌于 JSON
展开模型回复逐字原文(RAW RESPONSE · 约 2.2k 字符)
```json
{
  "nodes": [
    {
      "id": "gear_A",
      "label": "档屉A",
      "ports": ["port_1"]
    },
    {
      "id": "gear_B",
      "label": "档屉B",
      "ports": ["port_1"]
    },
    {
      "id": "gear_C",
      "label": "档屉C",
      "ports": []
    },
    {
      "id": "main_switch",
      "label": "总开关",
      "ports": ["port_1", "port_2"]
    }
  ],
  "edges": [
    {
      "id": "e1",
      "from": "gear_A",
      "from_port": "port_1",
      "to": "main_switch",
      "to_port": "port_1",
      "direction": "undirected",
      "polarity": "unknown"
    },
    {
      "id": "e2",
      "from": "gear_B",
      "from_port": "port_1",
      "to": "main_switch",
      "to_port": "port_2",
      "direction": "undirected",
      "polarity": "unknown"
    }
  ],
  "unknown": [],
  "checker": "def check_topology(nodes, edges):
    errors = []
    # 1. 环路检测 (DFS)
    adj = {n['id']: [] for n in nodes}
    for e in edges:
        adj[e['from']].append(e['to'])
        adj[e['to']].append(e['from'])
    
    visited = set()
    def dfs(node, parent):
        visited.add(node)
        for neighbor in adj[node]:
            if neighbor not in visited:
                if dfs(neighbor, node): return True
            elif neighbor != parent:
                return True
        return False
    
    for n in nodes:
        if n['id'] not in visited:
            if dfs(n['id'], None):
                errors.append('Error: Detected loop in topology')
    
    # 2. 端口重复占用
    port_usage = {}
    for e in edges:
        key_from = (e['from'], e['from_port'])
        key_to = (e['to'], e['to_port'])
        if key_from in port_usage: errors.append(f'Error: Port {key_from} used by multiple edges')
        if key_to in port_usage: errors.append(f'Error: Port {key_to} used by multiple edges')
        port_usage[key_from] = e['id']
        port_usage[key_to] = e['id']
    
    # 3. 极性/常识检查 (假设总开关为源)
    switch_id = 'main_switch'
    for e in edges:
        if e['to'] == switch_id and e['from'] != switch_id:
             errors.append(f'Warning: Edge {e["id"]} points into main switch, verify power flow direction')
    
    return errors

# 执行检查
print(check_topology(nodes, edges))"
}
```

页面归纳(非模型输出):输出了结构完整的连接表,但四个节点被读成「档屉A/B/C(gear_*)」而非插座A/B/C,与图中真实物件完全错位;顶层 unknown 列表为空(仅在两条边的 polarity 字段标 unknown),被遮挡的插座C 未按题目要求标注。

moonshotai/kimi-k3
Kimi K3 · 推理深度未特别配置
有回复 · 读图与真值语义一致 · 因输出格式不合记 0 分
run 记录:results/moonshotai__kimi-k3/C09.json
finish_reason = "stop" · usage: prompt 466 tok / completion 8834 tok(其中 reasoning 6904)/ cost 0.1272126
回复为裸 JSON、无代码围栏;edges 用嵌套 endpoints 结构
展开模型回复逐字原文(RAW RESPONSE · 约 8k 字符)
{
  "nodes": [
    {
      "id": "SOCKET_A",
      "label": "插座A",
      "type": "socket",
      "bbox": [50, 61, 110, 101],
      "ports": [
        {
          "id": "right",
          "side": "right",
          "role": "terminal",
          "connected_by": "E_A_MAIN"
        }
      ],
      "attributes": {}
    },
    {
      "id": "SOCKET_B",
      "label": "插座B",
      "type": "socket",
      "bbox": [50, 201, 110, 241],
      "ports": [
        {
          "id": "right",
          "side": "right",
          "role": "terminal",
          "connected_by": "E_B_MAIN"
        }
      ],
      "attributes": {}
    },
    {
      "id": "SOCKET_C",
      "label": "插座C",
      "type": "socket",
      "bbox": [50, 302, 110, 342],
      "ports": [
        {
          "id": "right",
          "side": "right",
          "role": "terminal",
          "connected_by": null,
          "basis": "same symbol as SOCKET_A/SOCKET_B; no visible wire"
        }
      ],
      "attributes": {}
    },
    {
      "id": "MAIN_SWITCH",
      "label": "总开关",
      "type": "main_switch",
      "bbox": [350, 171, 410, 211],
      "ports": [
        {
          "id": "left_upper",
          "side": "left",
          "role": "terminal",
          "connected_by": "E_A_MAIN"
        },
        {
          "id": "left_lower",
          "side": "left",
          "role": "terminal",
          "connected_by": "E_B_MAIN"
        }
      ],
      "attributes": {}
    }
  ],
  "edges": [
    {
      "id": "E_A_MAIN",
      "endpoints": [
        {
          "node": "SOCKET_A",
          "port": "right"
        },
        {
          "node": "MAIN_SWITCH",
          "port": "left_upper"
        }
      ],
      "direction": "unknown",
      "polarity": "unknown",
      "basis": "visible blue conductor; no arrowhead; no L/N/PE label"
    },
    {
      "id": "E_B_MAIN",
      "endpoints": [
        {
          "node": "SOCKET_B",
          "port": "right"
        },
        {
          "node": "MAIN_SWITCH",
          "port": "left_lower"
        }
      ],
      "direction": "unknown",
      "polarity": "unknown",
      "basis": "visible blue conductor; no arrowhead; no L/N/PE label"
    }
  ],
  "unknown": [
    {
      "subject": "edge direction and polarity",
      "location": [
        "E_A_MAIN",
        "E_B_MAIN"
      ],
      "reason": "no arrowheads and no L/N/PE labels are visible"
    },
    {
      "subject": "rating or secondary text inside 总开关",
      "location": "MAIN_SWITCH",
      "reason": "small text is not legible; no rated current or power value is used"
    },
    {
      "subject": "遮挡/反光 annotation",
      "location": "approx bbox [179, 261, 261, 304]",
      "reason": "treated as an annotation only; no visible conductor passes through it, so no hidden wire is inferred"
    }
  ],
  "checker": "import json\nfrom collections import defaultdict\n\ndef run(data):\n    nodes = {n.get('id'): n for n in data.get('nodes', [])}\n    edges = data.get('edges', [])\n    findings = []\n\n    # 1) duplicate port occupancy\n    use = defaultdict(list)\n    for e in edges:\n        for ep in e.get('endpoints', []):\n            key = (ep.get('node'), ep.get('port'))\n            if all(key):\n                use[key].append(e.get('id'))\n    for (node, port), ids in sorted(use.items(), key=lambda x: (str(x[0][0]), str(x[0][1]))):\n        if len(ids) > 1:\n            findings.append({'type': 'port_duplicate_occupied', 'severity': 'error', 'location': {'node': node, 'port': port, 'edges': ids}, 'message': '同一端口被多条连线占用'})\n\n    # 2) possible loops: undirected component rule; a tree has edges == nodes - 1\n    node_ids = [n.get('id') for n in data.get('nodes', []) if n.get('id')]\n    parent = {n: n for n in node_ids}\n    def find(x):\n        while parent[x] != x:\n            parent[x] = parent[parent[x]]\n            x = parent[x]\n        return x\n    def union(a, b):\n        ra, rb = find(a), find(b)\n        if ra != rb:\n            parent[rb] = ra\n    valid_edges = []\n    for e in edges:\n        eps = e.get('endpoints', [])\n        ns = [ep.get('node') for ep in eps if ep.get('node') in nodes]\n        if len(ns) >= 2:\n            valid_edges.append(e)\n            union(ns[0], ns[1])\n    comp_nodes = defaultdict(set)\n    comp_edges = defaultdict(set)\n    for n in node_ids:\n        comp_nodes[find(n)].add(n)\n    for e in valid_edges:\n        eps = e.get('endpoints', [])\n        ns = [ep.get('node') for ep in eps if ep.get('node') in nodes]\n        if len(ns) >= 2:\n            comp_edges[find(ns[0])].add(e.get('id'))\n    for root, ns in sorted(comp_nodes.items(), key=lambda x: str(x[0])):\n        es = comp_edges.get(root, set())\n        if ns and len(es) >= len(ns):\n            findings.append({'type': 'loop_possible', 'severity': 'error', 'location': {'nodes': sorted(ns), 'edges': sorted(es)}, 'message': '连通分量边数不少于节点数,可能存在环路;方向未知时按无向图判断'})\n\n    # 3) polarity / order common sense for main-switch to socket edges\n    for e in edges:\n        eps = e.get('endpoints', [])\n        if len(eps) != 2:\n            continue\n        a, b = eps[0], eps[1]\n        na = nodes.get(a.get('node'), {})\n        nb = nodes.get(b.get('node'), {})\n        la = str(na.get('label', '')) + ' ' + str(na.get('type', ''))\n        lb = str(nb.get('label', '')) + ' ' + str(nb.get('type', ''))\n        pair = (('总开关' in la and '插座' in lb) or ('插座' in la and '总开关' in lb))\n        if pair:\n            d = e.get('direction')\n            p = e.get('polarity')\n            if d in (None, 'unknown'):\n                findings.append({'type': 'direction_unknown', 'severity': 'info', 'location': {'edge': e.get('id')}, 'message': '总开关-插座连线无箭头;按常识应复核是否为 总开关 -> 插座'})\n            elif d in ('socket->main_switch', 'load->source', 'downstream->upstream'):\n                findings.append({'type': 'direction_common_sense', 'severity': 'warning', 'location': {'edge': e.get('id')}, 'message': '方向疑似反向;通常供电方向应为 总开关 -> 插座'})\n            allowed = {'L', 'N', 'PE', 'L+N', 'L+N+PE', 'AC', 'DC+', 'DC-'}\n            if p in (None, 'unknown'):\n                findings.append({'type': 'polarity_unknown', 'severity': 'info', 'location': {'edge': e.get('id')}, 'message': '极性未标注或不可读;常见插座回路应为 L/N/PE 之一的组合'})\n            elif p not in allowed:\n                findings.append({'type': 'polarity_common_sense', 'severity': 'warning', 'location': {'edge': e.get('id')}, 'message': '极性标注不在常见 L/N/PE 集合内,需要核实'})\n\n    # 4) rating/load check only when a readable rating exists\n    rated = []\n    for n in data.get('nodes', []):\n        attrs = n.get('attributes', {})\n        r = attrs.get('rated_current_A')\n        if r is None:\n            r = attrs.get('rated_power_W')\n        if r is None:\n            r = attrs.get('rating')\n        if r is not None:\n            rated.append((n.get('id'), r))\n    if not rated:\n        findings.append({'type': 'rating_not_readable', 'severity': 'info', 'location': {'nodes': node_ids}, 'message': '图中无可信额定值或负载,无法计算总负载是否超限'})\n    else:\n        for sw_id, rating in rated:\n            lim = rating.get('A') if isinstance(rating, dict) else rating\n            if not isinstance(lim, (int, float)):\n                continue\n            total = 0.0\n            used = []\n            for e in edges:\n                eps = e.get('endpoints', [])\n                touches = any(ep.get('node') == sw_id for ep in eps)\n                if not touches:\n                    continue\n                load = e.get('load_A')\n                if load is None:\n                    load = e.get('attributes', {}).get('load_A')\n                if isinstance(load, (int, float)):\n                    total += load\n                    used.append(e.get('id'))\n            if total and total > lim:\n                findings.append({'type': 'overloaded', 'severity': 'error', 'location': {'node': sw_id, 'edges': used}, 'message': '合计负载 ' + str(total) + 'A 超过额定 ' + str(lim) + 'A'})\n    return findings\n"
}

页面归纳(非模型输出):识别出插座A/B/C 与总开关、两条 总开关—插座 可见连线,插座C 判定「无可见连线」,灰色遮挡块只当作标注处理而不推断暗线,方向/极性如实标 unknown——与人工真值语义一致;但其 edges 采用嵌套 endpoints 结构、unknown 条目不含字面「插座C」,打分脚本按平铺 from/to 键与子串匹配取值双双落空。

results/C09.json → score 键(原样)得分参考满分对应 rubric 维度
连接表F1_近似0.035连接表 F1 —— 模型两条边的端点写作「描座A / 描座B」(它自己已用 alias_maybe 纠正为「插座A/B」),与真值节点名「插座A / 插座B」逐字比对不匹配,无边命中记 0。键名自带「近似」,为启发式判定而非严格基准。
checker可运行1.025校验规则覆盖 —— 内嵌于 JSON 字符串的 checker 被沙箱试运行通过,本案例唯一非零维度、记满分;其脚本覆盖环路 / 端口判重 / 极性 / 负载四类检查。该维度为启发式多签名调用(见 limitations),非严格基准。
unknown恰当性0.025unknown 使用恰当性 —— 模型的 unknown 列表写了「描座C: 未见连线…」等 7 条、克制判断本身与真值一致,但打分按是否包含字面「插座C」匹配,「描座C」≠「插座C」,落空记 0。
flags[](空数组)—幻觉连线等倒扣标记:score.flags 键存在且为空数组——模型输出的两条边均对应真值拓扑(仅端点名误读),没有可判定为「幻觉连线」的边,无扣分项触发。
score_error(顶层字段)null—打分脚本对空响应补齐后的最新输出(2026-08-24 写盘版本)重算未报错,分数即按真实回复算得。

以上数值逐字取自 results/C09.json(2026-08-24 21:09 随空响应补齐后最新写盘)的 score 字段,由评分脚本对模型的真实回复计算得出,不是估计值。checker可运行 拿到 1.0;其余两维为 0 的原因是端点名「描座 ↔ 插座」一字之差导致逐字比对落空,而不再是空输出。其中「连接表F1_近似」「checker可运行」两项受本机环境限制属近似判定(见下方 limitations),不应视为严格基准结果。

三模型分数对比 · SCORES SIDE BY SIDE(数值逐字取自各自 results JSON 的 score 字段 · 色条视觉沿用 compare.html)
连接表F1_近似轴 0 – 1(参考满分 35 归一前)
0.0
0.0
0.0
checker可运行轴 0 – 1
1.0
0.0
0.0
unknown恰当性轴 0 – 1
0.0
0.0
0.0

三个模型的 flags 均为空数组;分数不再齐刷刷全零:ox-alpha 在 checker可运行 一维拿到全场唯一的非零分 1.0,其余两维仍与两家同为 0——同样是 0,成因各不相同:一个是端点名单字误读导致逐字比对落空(克制判断本身与真值一致),一个是内容级误读,一个是读图正确而输出格式不合解析契约。逐条归因见下方「解读」卡片。

score 内外字段(原样)stealth/ox-alphaz-ai/glm-5v-turbomoonshotai/kimi-k3
run 记录文件results/C09.jsonresults/z-ai__glm-5v-turbo/C09.jsonresults/moonshotai__kimi-k3/C09.json
flags[](空数组)[](空数组)[](空数组)
score_error(顶层字段)nullnullnull
回复状态(页面归纳)有回复 · 拓扑正确 · 节点名误读(描座↔插座)有回复 · 节点整体误读有回复 · 读图与真值语义一致
LIMITATIONS · results/C09.json 原文

① 模型生成代码的函数签名不受约束,沙箱用启发式多签名尝试调用,非严格基准;
② 样本规模为演示级缩小版(1),非原始题库规模。

解读 · 页面撰写,非模型输出

值得注意的变化:C09 上 stealth/ox-alpha 本轮留下了完整回复,「空响应」已成历史——同一 prompt、同一图片重新调用后有真实文本(约 3.6k 字符)、usage(prompt 466 / completion 5562 tok)、finish_reason = stop。内容层面它其实读得不差:A、B 汇入总开关的星型拓扑与真值一致,被遮挡的插座C 判定无可见连线并如实写入 unknown,端口 / 方向 / 极性一律不硬猜;坏在一处单字 OCR 级误读——「插座」被识成「描座」(模型自己在 alias_maybe 里纠正了过来),而打分按节点名字面比对,「描座A」与真值「插座A」错开,F1 与 unknown 两维双双落空记 0。唯一得分项是 checker可运行 1.0:其脚本覆盖环路 / 端口判重 / 极性 / 负载四类检查并被沙箱跑通。另一件如实记录的事:此前页面曾按空响应存档如实披露过该轮无输出,如今分数随真实回复补齐后重算,才第一次反映真实输出的表现。单样本不构成对该模型接线读图能力的任何结论性判断。

方法论局限 · 化用自 compare.html 全站对比页说明

三个模型的调用方式相同(同一套 run_batch.py 风格的 OpenRouter chat/completions 调用),但 stealth/ox-alpha 是强制深度推理的 stealth 模型,glm-5v-turbo 与 kimi-k3 未特别配置推理行为——输出风格与推理深度可能天然不同。这是解读对比结果时要注意的已知局限,不是哪一方「作弊」。本案例另有一层打分侧局限:exec_plus_judge 脚本按固定输出契约解析回复(edges 取平铺 from/to 键与真值边做集合比对、unknown 按是否包含字面「插座C」判定、checker 取独立的 ```python 围栏块进沙箱试运行)——输出形状不合契约即记 0,因此这里的分数衡量的是「符合契约的可评分产出」,与读图对错并不同义。三家的 usage 也相差悬殊(completion tokens:GLM-5V 1667 / Kimi K3 8834 / ox-alpha 5562——其中 ox-alpha 的 usage 明细里 reasoning tokens 记为 0),与上述推理深度差异一致。

解读(三模型) · 页面撰写,非模型输出

三个模型在本案例的总分面貌仍然接近全零,但构成已经不同:① stealth/ox-alpha 是「读对了图、输错了名字」——拓扑方向(A/B 汇入总开关)、被遮挡节点的克制判断都与真值语义一致,checker 还拿到全场唯一非零分(可运行 1.0);但把「插座」OCR 成「描座」(自标 alias_maybe 纠正),F1 与 unknown 两维按节点名/字面的比对双双落空,属「一字之差」级失败;② glm-5v-turbo 是「答非所问」——输出了结构完整、checker 写得像样的连接表,但节点整体误读成「档屉A/B/C(gear_*)」而非插座,与真值边(总开关—插座A/B)按节点名比对全部错开,且顶层 unknown 列表为空、被遮挡的插座C 未按要求标注,属内容级失败;③ kimi-k3 则是「答对了但不合答题卡」——其读图结果与人工真值语义一致(两条 总开关—插座 可见连线、插座C 判定无可见连线、灰色遮挡块只当标注而不推断暗线、方向极性如实标 unknown),但 edges 用嵌套 endpoints 结构而非平铺 from/to、unknown 条目不含字面「插座C」、checker 内嵌于 JSON 字符串而无独立 python 围栏块,三项判定双双落空记 0,属格式级失败。换言之:同样接近全零的表象背后是三种不同的情形,且 ox-alpha 与 kimi-k3 在读图层面其实都对——直接拿这个分数当横评名次会产生误导,这也正是全站对比页把 C09 三家画成近似全零时需要回到详情页看原文的原因。n=1 单样本,不构成对任何一方接线读图能力的结论性判断。