# QwenJev — 用 Qwen3.5-9B 多模态改造 NanoJev 的 ARC-AGI-3 双系统智能体 > 本文档是整个项目的构造蓝图:背景 → 架构 → 数据 → 训练 → 智能体接入 → Kaggle 部署 → 评测 → 路线图。 > 按顺序读完即可独立复现整个系统。README 按要求留空,所有内容都在本文档中。 > **v0.2.0 架构决策:视觉塔必保留在 System-1 每步推理路径上**——隐藏关全是陌生机制, > 只看 hex 文本串没法玩游戏;本仓库的 System-1 骨干直接是多模态模型,每步都"看"当前帧。 --- ## 1. 项目定位 ### 1.1 要解决的问题 ARC Prize 2026(ARC-AGI-3)要求智能体在**从未见过的交互式游戏环境**中探索、获取目标、构建世界模型。评分采用 RHAE(Relative Human Action Efficiency):完成度 × 效率(步数取平方惩罚),意味着**瞎探索的代价极高**。 原始 NanoJev(TianyuCodings/NanoJev,0.6B)是一个极合适的 System-1 决策内核:**states + questions 进,完整概率分布出,零输出 token 解码**。但它有两个与本赛不匹配的短板: 1. **没有视觉塔**——骨干是纯文本的 Qwen3-0.6B,只能吃文本化的网格; 2. **没有游戏级的探索/反思机制**——它是一个"打分器",不是完整智能体。 ### 1.2 QwenJev 的改造思路 | 短板 | 改造手段 | 落点 | |------|----------|------| | 无视觉塔 | **视觉塔直接保留在 System-1 推理路径上**:骨干改为多模态模型(hf 后端 = Qwen3-VL 系列,预训练视觉塔原样保留;tiny 后端 = 自带微型视觉塔),叶子升级为 `[帧图像, state, instruction, candidate]`,每步都看当前帧 | `qwenjev/vision.py` + `qwenjev/system1.py` | | 小模型感知不如 9B | Qwen3.5-9B 做**冻结教师**,吃同一帧、过自己的视觉塔,把逐层隐状态蒸馏对齐给学生(stage A) | `train/distill_alignment.py` | | 缺少探索机制 | 9B 作为 **System-2 主控**:感知局面、提出候选动作假设、失败后写记忆笔记;由调度器**稀有地**唤醒 | `qwenjev/system2.py` | | 单步决策慢/贵 | NanoJev 式 **System-1**:单次前向输出候选动作分布,每步都跑(含视觉前向) | `qwenjev/system1.py` | | 接口封闭 | 完整对接官方 **ARC-AGI-3-Agents** 开源框架,实现 `Agent` 两个方法即可提交比赛 | `agent/qwenjev_agent.py` | | 本地无 GPU/无游戏 | 内置 **mock 推箱游戏**(多关卡、种子确定)+ **tiny 微型 VLM**(~1M 参数,纯 CPU),全管线零下载跑通 | `data/mock_env.py` | 一句话:**视觉塔每步都在环上(System-1 骨干原生多模态);9B 出眼光(教师蒸馏 + System-2 稀有唤醒);tiny 后端让全链路在笔记本 CPU 上跑通。** ### 1.3 与 NanoJev 原作的关系 - 忠实保留其输入契约:每个问题 = 一个 state + 一组候选;每个候选编码为 `[帧图像, state, instruction, candidate]` 的多模态叶子(原作为纯文本 `[state, instruction, candidate]`);候选路径重复 state;问题之间独立(前向中无跨问题注意力)。 - 忠实保留三种原语:`Choice`(2–255 候选,set-attention + softmax)、`Boolean`(sigmoid p_true)、`Score`(2–10 有序等级,期望值读出)。 - 沿用其训练配方:complete-question 交叉熵,backbone lr `1e-5`、decision-head lr `1e-4`。 - 差异点:① state 序列化改为**版本化规范串**(原作审计文档承认 `str()` 序列化非规范,属遗留问题);② **叶子多模态化——视觉塔每步在环**;③ 增加 ACTION6(x,y) 的候选离散化;④ 外层接 ARC-AGI-3 环境与双系统调度。 --- ## 2. 总体架构 ``` ┌────────────────────────────────────────────┐ │ ARC-AGI-3-Agents 官方框架循环 │ │ main.py → Swarm → Agent.choose_action() │ └───────────────┬────────────────────────────┘ │ frames / FrameData ▼ ┌────────────────────────────────────────────┐ │ agent/qwenjev_agent.py │ │ is_done(): state is WIN │ │ choose_action(): 严格解析 + 安全回退 │ └───────────────┬────────────────────────────┘ ▼ ┌────────────────────────────────────────────┐ │ qwenjev/hybrid.py │ │ 调度器: novelty / reward / stall 触发 │ │ 动作-效果记忆 + 时间预算管理 │ └──────┬───────────────────────┬─────────────┘ 唤醒(稀有) │ │ 每步(便宜) ▼ ▼ ┌────────────────────────┐ ┌────────────────────────────────┐ │ System-2 主控 (慢) │ │ System-1 决策模型 (快) │ │ Qwen3.5-9B 多模态 │ │ 多模态骨干 + 决策头 │ │ · 感知局面 summarize │ │ · 视觉塔: 每步编码当前帧 ★必保留 │ │ · 假设机制 hypothesize │ │ · Choice 头: 候选动作打分 │ │ · 提议候选 propose │ │ (set-attn + softmax) │ │ · 失败反思 reflect │──▶ · Boolean 头: 动作-效果判真 │ └────────────────────────┘ │ · Score 头: 局面价值分级 │ ▲ 训练期教师 └────────────────────────────────┘ │ 同一帧过双方视觉塔 叶子 = [帧图像, state, instruction, └── 蒸馏对齐 (stage A) ── candidate],同题共享帧 qwenjev/vision.py 负责网格→图像/张量、多模态叶子、TinyVLM ``` 数据流要点: 1. `state_codec.encode_observation()` 把每步的帧数组编码为:规范 state 串 + 差分网格(`*` 标记变化格,供"上一步干了什么"这一最廉价的学习信号)+ 帧哈希(新颖性检测)。 2. `candidates.build_candidates()` 生成候选:简单动作(ACTION1–5、ACTION7=undo)+ ACTION6 的锚点离散化(变化格 > 稀有格 > 8×8 粗格网,上限 255)。 3. **当前帧随每步决策进入 System-1 视觉塔**(`hybrid.decide()` 把 `grids[0]` 传给 `s1.choose()`)——这是 v0.2.0 的硬性架构约束,不许回退到纯文本。 4. System-2 提议的候选被**稳定置顶**(不删除其他候选),最终仍由 System-1 打分决定——9B 可以错,打分器说了算。 5. RESET 永远不进候选列表,只由生命周期守卫(NOT_PLAYED / GAME_OVER / 超时)触发,防止自杀式重启。 --- ## 3. 核心模块详解 ### 3.1 视觉塔 `qwenjev/vision.py`(v0.2.0 新增,架构核心) **为什么必须保留视觉塔**:ARC-AGI-3 的智能体只能通过帧观察世界;隐藏评测关的机制全部陌生,实体形状、邻接、运动这些线索在 hex 文本串里大量丢失。System-2 每局最多唤醒 40 次,**不能指望 9B 替 System-1 看路**——所以视觉塔必须长在每步都跑的 System-1 上。 两种可互换后端(同一接口): | 后端 | 骨干 | 用途 | |------|------|------| | `"hf"` | `AutoModelForImageTextToText` 加载的 Qwen3-VL 系列多模态权重(默认 `Qwen/Qwen3-VL-2B-Instruct`)| 正式训练/提交;预训练视觉塔**原样保留**,可选 `freeze_vision_tower` | | `"tiny"` | `TinyVLM`:patch-embed 微型 ViT 塔(64 视觉 token)+ byte 级微型因果 LM(~1.1M 参数)| 本地跑通/CI/单测;零下载、纯 CPU、毫秒级 | 多模态叶子 `MultiModalLeaf = [图像, state 文本, instruction, candidate]`:同题候选**共享同一帧**,`encode_question()` 一次构造全部叶子。关键实现细节:注意力掩码用 **additive float mask(-1e9)而不是 bool 掩码**——bool 掩码与 causal 组合会在 padding 行产生全 -inf → softmax NaN(开发中实际踩过并修复,单测 `test_tinyvlm_all_finite_with_padding` 永久看守)。 ### 3.2 状态编码 `qwenjev/state_codec.py` - **网格 → 文本**:每格一个字符,0–15 → hex(`0123456789abcdef`),64×64 最多 4KB,远比视觉 token 便宜且无损。 - **差分网格**:与上一帧逐格比较,变化格写 `*`。注意实现教训:hex 字母可以大写标记,但 `0-9` 是数字无法大写——所以用专用标记符(单测覆盖了这个坑)。 - **规范 state 串**:`qwenjev-state-v1|h=.. w=.. l=.. s=..\n<网格>`。版本号置顶 + meta 键排序,保证同一局面永远产出同一字符串(checkpoint 可复现的前提)。 - **网格 → 图像**:`grid_to_image()` 用 16 色稳定调色板渲染。**v0.2.0 起不只是 System-2 用**:System-1 视觉塔每步也吃这张图(`vision.py` 转张量/PIL)。 ### 3.3 候选生成 `qwenjev/candidates.py` ACTION6(x,y) 是唯一带坐标的动作,必须离散化才能进 Choice 头。锚点优先级: 1. **变化格**(上一帧的 `*` 位置)——游戏机制大概率藏在这里; 2. **稀有格**(非零值按局部稀有度排序 top-24)——目标物/关键机关往往颜色稀缺; 3. **8×8 粗格网**兜底(保证全图覆盖)。 上限 255 候选(TypeSafe Choice 契约上限),顺序稳定,避免候选索引漂移悄悄改变叶子输入。 ### 3.4 System-1 `qwenjev/system1.py` - `encode_question(state, candidates, instruction, grid)` → N 个多模态叶子(每候选一个,state 重复,**当前帧图像共享**); - `forward_choice(leaves)` → **一次 backbone 前向(含视觉塔)**:叶子向量 → 投影 → set-attention(同题候选间)→ softmax → 概率列表; - `choose(..., grid)` → 贪心或按分布采样,返回 `Decision(probs, candidates, chosen, index)`; - `forward_boolean` / `forward_score` 及其**可训练孪生** `forward_boolean_logits` / `forward_score_logits`(v0.2.0 修复:旧实现返回 detach 张量,梯度根本流不进模型); - `save()` / `load_heads()`:tiny 后端打包 backbone + 全部头;hf 后端只存头(权重留在 HF 权重目录); - `eval()` / `train_mode()`:决策头 dropout=0,保证加载后推理确定。 ### 3.5 System-2 `qwenjev/system2.py` - 两种后端:`mode="openai"`(vLLM 的 OpenAI 兼容端点,**首选**)或 `mode="transformers"`(进程内加载,重); - `perceive(obs, grids, memory)` → 结构化 `PerceptionReport`:局面摘要、实体清单、≤3 条机制假设、3–8 个建议动作;输入含 hex 网格文本 + 渲染 PNG(双通道喂视觉塔)+ 记忆笔记; - `reflect(history)` → GAME_OVER/停滞后的持久记忆 `{learned, avoid, next_try}`,跨 episode 保留; - `bias_candidates()` 把 9B 的建议动作稳定置顶(保留全部候选)。 ### 3.6 调度器 `qwenjev/hybrid.py` System-2 唤醒条件(满足其一,且调用数 < `system2_max_calls_per_game`): | 条件 | 含义 | |------|------| | 新帧哈希 | 局面没见过,需要 9B 看一眼 | | `levels_completed` 增加 | 进新关卡,机制可能变 | | 连续 12 步无变化 | System-1 卡死,需要外部视角 | 同时管理:每局时间预算(默认 900s,官方文档明确超时会直接 fail 该次运行)、动作数上限、动作-效果记忆(哪个动作改变多少格)、每局反思笔记。 **任何一层失败都不能杀死运行**:9B 端点挂了 → 跳过;System-1 权重缺失 → 启发式策略;输出不合法 → 正则清洗 + 安全回退(官方文档警告:一个畸形输出就会以 `ValueError` 终结当前游戏)。 --- ## 4. 数据管线 ### 4.1 来源:25 个公开游戏自采(已确认可用,2026-09-23 实测) - 游戏源码从 arcade API 自动获取:`arc-agi` 包 NORMAL 模式 `make()` 会把游戏源码(单游戏约 120KB)缓存到 `environment_files///`,之后永久离线(OFFLINE 模式约 2000 FPS、无限实例);**匿名 key 自动下发,无需 Kaggle 账号、无需接受比赛规则**。一键预缓存:`python ops/fetch_games.py`(25 游戏约 65 秒); - kagglehub 比赛下载(`kagglehub.competition_download('arc-prize-2026-arc-agi-3')`)需要 KGAT token + 官网接受规则,且与本地游戏引擎是同一套(`arc-agi` 包本地托管同引擎)——本仓评测链路已不依赖它; - 游戏清单(与 arcprize.org/tasks 一致,`ops/run_eval.py --list-games` 可从 API 拉实时列表):`ar25 bp35 cd82 cn04 dc22 ft09 g50t ka59 lf52 lp85 ls20 m0r0 r11l re86 s5i5 sb26 sc25 sk48 sp80 su15 tn36 tr87 tu93 vc33 wa30`; - **评测是另外 110 个从未公开的隐藏游戏**(55 个 Public LB + 55 个 Private LB),所以数据管线的一切设计都服务于"可泛化的探索先验",而非背题。 ### 4.2 采集 `data/collect_selfplay.py` - ε-greedy(默认 ε=0.25)包住当前 HybridAgent 策略; - 每步记录:动作、坐标、前后帧、`levels_completed` 变化、可用动作集、帧哈希、规范 state; - 输出 JSONL 分片 `data/traces//ep*.jsonl` + `summary.json`; - **游戏源双轨**:`game_id` 以 `mock` 开头 → 内置推箱游戏(零依赖);否则走 `arc-agi` 离线引擎(需安装包 + 游戏文件); - 批量采集时 System-2 默认关闭(吞吐优先),可选开启给少量轨迹加 9B 注释。 ### 4.3 内置 mock 游戏 `data/mock_env.py`(v0.2.0 新增) 多关卡推箱游戏("sokoban-lite"),实现官方环境契约的子集:`reset()/step()/observe()`、FrameData 兼容字段、`RESET/ACTION1-7` 全动作、≤64×64 网格值 0–15、种子确定(crc32)可复现。机制刻意稀疏:推箱进目标才涨关卡、超预算 GAME_OVER——正好复刻隐藏关的稀疏奖励探索难度。`step_env()` 适配器统一 mock(按名调用)与官方引擎(GameAction 枚举)。 ### 4.4 构造训练样本 `data/build_dataset.py` | 问题族 | 问题模板 | 标签来源 | |--------|----------|----------| | **Choice**(主任务) | "哪个候选动作最可能取得进展?" + 全部候选 | 即时结果分级:`levels_completed` 增加=+2;帧变化未丢关卡=+1;无变化=0,取最优动作为 one-hot | | **Boolean**(效果预训练) | "ACTION k 会改变画面吗?" | 前后帧哈希差 | | **Score**(价值塑形) | "当前局面希望多大?" 2–10 级 | 关卡进度 + 探索覆盖率的启发式 | **每个样本都携带 `grid` 字段(v0.2.0 起)**:System-1 的视觉塔训练/推理都要吃图像,样本不带帧就没法训。划分逻辑:≥5 个游戏时按游戏切分 train/val(防同游戏泄漏);单游戏冒烟时退化为按行 crc32 哈希切分(保证 train 非空——单游戏场景下按游戏切会把全部样本切进 val,开发中踩过)。 ### 4.5 增广 `data/augment.py` ARC 传统增广全部可用:转置/镜像/旋转/重着色(固定 0=背景)。**ACTION6 坐标必须与网格同步变换**(`coord_transform()`),否则标签说谎。 --- ## 5. 训练方案 ### 5.1 两阶段配方 **Stage A:视觉蒸馏对齐**(`train/distill_alignment.py`) - 教师:冻结的多模态模型,**同一帧真实过其视觉塔**(hf 后端:processor 构造 `pixel_values` 进模型前向;tiny 后端:教师 TinyVLM 同样吃图像张量)——绝不允许出现"蒸馏时没看图"的假对齐(v0.1 的占位符实现已废弃); - 学生:System-1 多模态骨干,同样图像+文本前向,取逐层隐状态池化; - 对齐层集隐状态(默认最后 2 层),`1 − cosine` 损失,逐层独立投影头; - 产物:`checkpoints/qwenjev-s1/stage_a.pt`(投影头 + tiny 学生权重),Stage B 自动加载。 **Stage B:决策头 SFT**(`train/train_system1.py`) | 超参 | 值 | 出处 | |------|-----|------| | 目标函数 | complete-question CE(整题 softmax,非逐叶子二分类) | NanoJev `hard_lr1e5` | | backbone lr | 1e-5 | 同上 | | decision-head lr | 1e-4 | 同上 | | epochs | 4(三族问题混合,真实网格随样本进视觉塔) | 可调 | | LoRA | 默认关闭;hf 大骨干时建议开 `r=32, α=64` | 可选 | **v0.2.0 训练修复清单**(旧代码静默失效的三处):① Boolean/Score 头改用可训练 logits 孪生方法,BCE/CE 梯度真正流进模型;② Choice 批训练改用带图前向(旧行为在 `torch.no_grad()` 里算概率再包装,同样训不动);③ Stage A checkpoint 自动加载,蒸馏成果不白费。 ### 5.2 显存预算(RTX Pro 6000 96GB 实测口径) | 场景 | 占用估算 | |------|----------| | Stage A:9B 教师 4bit + Qwen3-VL-2B 学生(含双方视觉塔前向)| ~12–16 GB | | Stage A:9B 教师 BF16(`teacher_4bit: false`) | ~28–32 GB | | Stage B:Qwen3-VL-2B 全参数训练 | ~20–26 GB;LoRA 减半以下 | | 推理:System-1(2B)+ System-2(9B BF16)常驻 | ~26 GB,96GB 富余 | 消费级 24GB 卡(4090/3090)建议:教师 4bit + 学生 LoRA;tiny 后端则任意机器(含无 GPU 笔记本,~1.1M 参数 fp32 ≈ 5MB)都能跑。 ### 5.3 下载权重 ```bash python scripts/download_weights.py # Qwen3-0.6B + Qwen3.5-9B + NanoJev 参考 ``` --- ## 6. 智能体接入(官方开源框架) ### 6.1 安装到 ARC-AGI-3-Agents ```bash git clone https://github.com/arcprize/ARC-AGI-3-Agents.git cd ARC-AGI-3-Agents # 1) 拷贝本仓库的 agent/qwenjev_agent.py 到 agents/ # 2) 保证 qwenjev 包可导入(repo 根目录放本仓库,或 pip install -e) # 3) 注册: # agents/__init__.py 中加入 # from .qwenjev_agent import QwenJevAgent # AVAILABLE_AGENTS["qwenjevagent"] = QwenJevAgent uv run main.py --agent=qwenjevagent --game=ls20 # 单游戏试跑 uv run main.py --agent=qwenjevagent # 全部游戏 ``` ### 6.2 框架接口速查(v0.9.3) - 基类 `Agent`,必须实现 `is_done(frames, latest_frame)` 与 `choose_action(frames, latest_frame) -> GameAction`; - `FrameData` 关键字段:`levels_completed` / `win_levels`(v0.9.3 由 `score`/`win_score` 改名)、`available_actions`(v0.9.2+)、`state`; - `GameAction`:`RESET`、`ACTION1–7`;`action.is_simple()` / `action.is_complex()`;复杂动作 `action.set_data({"x":..,"y":..})`; - 网格 ≤64×64,值 0–15,(0,0) 左上,(x,y) 顺序; - 游戏状态:`NOT_PLAYED / NOT_FINISHED / WIN / GAME_OVER`。 --- ## 7. Kaggle 部署(比赛提交) ### 7.1 硬件与限制 | 项 | 值 | |----|-----| | 专属加速器 | RTX Pro 6000(`g4-standard-48`:1×96GB 显存、48 vCPU、180GB 内存) | | 运行上限 | CPU/GPU Notebook 均 ≤ **9 小时** | | 网络 | **禁网**(权重/依赖全部走 Kaggle Dataset) | | 配额 | RTX 并发 1/人,高峰排队可达数小时——**只在完整方案上烧 Commit** | ### 7.2 打包步骤(`scripts/package_kaggle.py`) ```bash python scripts/package_kaggle.py --username <你的Kaggle用户名> --accelerator rtx6000 cd kaggle_kernel && kaggle kernels push -p . ``` 生成的 notebook 三个关键单元格: 1. 从比赛 Data 包的 `arc_agi_3_wheels/` **离线安装** arc-agi(禁网解法一); 2. 挂载权重 Dataset(`/kaggle/input/qwenjev-weights/...`,公开预训练权重合规); 3. 实例化 `QwenJevAgent`,接入官方 sample-submission 驱动循环,工具包自动产出 `submission.parquet`。 ### 7.3 九小时时间预算(务必先算再跑) - 隐藏集 110 局;平均每局预算 ≈ **4.9 分钟**; - System-1 每步毫秒级,主导耗时的是 System-2:单次调用按 3–5s 计,每局 `system2_max_calls_per_game=40` → 9B 总开销 ≈ 2–3.3 分钟/局,留有余量但**不富裕**; - 调参顺序:先压 `system2_max_calls_per_game`,再压 `stall_patience`;`game_time_limit_s` 宁低勿高(超时=整局报废)。 --- ## 8. 评测与迭代 ### 8.1 一键评测(v0.4.2 起:`ops/run_eval.py`) ```bash pip install arc-agi # 官方本地引擎(PyPI,纯 Python) pip install -U "torchao>0.16" # v0.4.3 实测坑:旧版 torchao 会令 hf 加载失败(见下) python ops/run_eval.py --download-only # 一次性缓存 25 公开游戏(约 3MB,匿名 key) python ops/run_eval.py --games all25 # 全量评测:GPU→hf 后端自动拉 HF 检查点并 merge LoRA;无 GPU→tiny python ops/run_eval.py --games ls20 --max-actions 60 # 指定游戏 + 预算 python ops/run_eval.py --backend tiny --no-checkpoint --games mock --max-actions 60 # 纯 harness 冒烟 python ops/run_eval.py --checkpoint /path/to/dir --games ... # 本地检查点目录(qwenjev_s1.pt [+ hf_lora/]) ``` - 检查点解析(默认 `hf:tchbcb/qwenjev@t4_assets_v2/checkpoints`):自动下载 qwenjev_s1.pt + hf_lora 分片 → `parts/reassemble` 重组 → sha256 校验 → 后端 auto 决定 hf(fp16 基座 + LoRA merge,与训练同构)或 tiny; - 生命周期:WIN 结束本局;GAME_OVER 触发 `brain.on_game_over` + 自动重置续玩(同一动作预算内公平比较,`resets` 入报告); - 报告字段:`win / final_state / best_level / resets / actions / seconds / steps_per_s`,默认写 `eval_report.json`(`--out` 改路径); - **增量落盘(v0.4.3)**:每完成一个游戏即原子重写报告(`.tmp` → `replace`),Colab/隧道中途断连也保留已完成游戏的结果,报告 `meta` + `summary.played` 恒反映已落盘部分; - **torchao 坑(v0.4.3 实测)**:transformers 5.16.1 加载 Qwen3-VL 时校验 torchao 版本,`torchao==0.10.0` 会令 `build_s1` 抛 "only versions above 0.16.0 are supported",run_eval **静默回退启发式策略**继续跑完(不中断)——健康检查判据:`steps_per_s > 100` 必是启发式,真模型推理约 1 步/秒量级(T4 实测 1.15 步/秒 @ 150 步预算);`pip install -U torchao`(0.18.0 验证通过)后重跑即可; - `--list-games` 从 arcade API 拉实时游戏列表(静态清单兜底)。 ### 8.2 本地 CPU 能不能跑?(2026-09-23,2 核 / 3GB 容器实测) | 配置 | 可行性 | 实测/推算依据 | |---|---|---| | tiny 后端 + v0.2.0 训练头(128 维) | ✅ 完整评测 | 25 游戏全部跑通(40 步/游戏),0.5–4 步/秒(快慢取决于 ACTION6 候选数) | | tiny 后端 + v2 检查点 | ❌ 维度不匹配 | v2 头是 2048 维(hf 隐藏维),tiny 骨干是 128 维 | | hf 后端(Qwen3-VL-2B fp16) | ⚠️ 需 ≥8GB 内存 | 基座权重 ~4.4GB + 三头 254MB(fp32, 63.5M 参数)+ 激活;本 3GB 容器物理不可行;bitsandbytes 4bit 仅限 CUDA,CPU 无替代 | | hf 后端(GPU:T4 16GB) | ✅ 已验证 | fp16 基座 + merge 后 300 步 601.6s(§11.2 v2 eval) | - CPU 评测的检查点是 `checkpoints/qwenjev-s1/`(v0.2.0 时代 128 维 tiny 头 + backbone,`load_heads` 向后兼容:escalate/温度表缺省跳过);其结论只用于 harness 验证与横向对比,不代表 v2 模型水平; - 4bit 量化在 CPU 上不可用(bitsandbytes 依赖 CUDA),若要在 CPU 跑真 2B 建议在 ≥16GB 内存机器用 fp16(`--backend hf` 会自动走 `resume_adapters(merge=True)`); - 提速方向:调小候选池(`build_candidates` 的 ACTION6 锚点数)或调大 `eval_leaf_batch`。 - 官方正式指标 RHAE = 按关卡 `min(人类步数/智能体步数, 1.0)²` 加权平均,人类基线本地拿不到——所以 `evaluate_local.py` 的绝对分数**只用于横向比较不同版本的智能体**,不代表排行榜; - 迭代循环:改 `agent/my_agent.py`(或 hybrid 配置)→ 本地秒级验证 → 满意后再花 Kaggle Commit; - 关注三条曲线:完成率(WIN 数)、平均步数、System-2 调用次数。好方向的标志是**完成率升、System-2 调用降**。 ### 8.3 v3 真游戏训练轮(2026-09-23,进行中) **背景**:v2 只见过 mock 推箱,zero-shot 25 公开游戏 2 局实测 0 胜 0 关(§3 基线)→ 转真游戏训练。 **采集**(真数据比预想廉价得多): - 工具:`scripts/collect_chunk.py`(分块断点续采,本地沙盒前台 <9 分钟/调用友好; 非空 ep 文件即视为完成——多数游戏 ε=0.35 随机探索几十步就 GAME_OVER,早死也是有效信号); - 配置:`configs/collect_real25.yaml`(25 游戏 × 8 集 × 400 步,ε=0.35,seed 13); - 实测吞吐:本地 2 核 ~9 步/秒(ar25 64×64 大网格),小网格 60+ 步/秒;远端 2 核 nohup 全量 24 游戏 × 10 集约 90 分钟; - 本地 3GB 内存注意:`build_dataset.py` 已瘦身(只保留 `grids_before[0]`,丢 grids_after 与多帧, 内存降 ~70%;顺带跳过截断行)——全量 2.8GB 轨迹可在 3GB 容器构建成功。 **数据**:远端 37,890 步 + 本地 36,918 步 → 合并 **167,635 样本** (choice 18,389 / boolean 74,338 / score 74,808 量级,train 158,290 + val 9,245),约为 v2 mock 语料 6 倍。 **训练**(`ops/t4_real25.py`,远端 `nohup python3 -u -B t4_real25.py`): - 阶段 stamp 幂等(`/content/qwenjev_work_v3/done_v3/*.stamp`),失败重跑自动跳过已完成阶段; - prep:HF 匿名拉 v2 hf_lora 分片重组(sha256 校验)→ `stage_a_lora/` 起点(与 zero-shot 基线同起点,对照干净); - real_b:SFT 180 步(~38s/步,T4 ~2 小时;峰值 12.6GB/15GB); - real_c:RLCD + 校准 → 产物自动推 HF `t4_assets_v3/checkpoints/`; - 评对照:`python ops/run_eval.py --games ar25 bp35 --max-actions 150 --checkpoint hf:tchbcb/qwenjev@t4_assets_v3/checkpoints --backend hf`。 **判据**:`best_level_sum` > 0(v2 基线=0)即真数据生效;仍 0 → ε 提 0.45 + System-2 教师蒸馏 + 25×16×600 重采。 --- ## 9. 路线图 | 里程碑 | 内容 | 验收标准 | 状态 | |--------|------|----------|------| | M0 | 仓库骨架 + 单测 + 文档 | `make test` 全绿 | ✅ | | M1 | **本地全链路跑通**:mock 游戏 → 采集 → 建库 → Stage A 蒸馏 → Stage B 训练 → 评测(视觉塔全程在环) | `make smoke` 五环节全绿,蒸馏 loss 收敛,36 个单测通过 | ✅ | | M2 | 换 hf 后端:Qwen3-VL-2B 学生 + 9B 教师,25 公开游戏真实采集 | Choice 标签集 ≥ 5 万题,公开关 eval 完成率显著高于随机基线 | | | M3 | System-2 接入 + 调度调参 | 完成率升 & 9B 调用数下降 | | | M4 | Kaggle 打包提交 | 官方 LB 出分,进入迭代循环 | | 后续方向:RLCD 后训练(NanoJev 官方 roadmap 同款)、共享前缀推理提速、把 Score 头升级为学习型局面价值模型。 --- ## 10. 风险与合规清单 1. **泛化陷阱**:隐藏 110 关机制全部陌生,过拟合 25 公开关 = 白给。每轮训练都要看"未见过游戏"上的表现(val 按游戏切分就是为此)。 2. **畸形输出即死刑**:官方文档明确模型回包必须严格解析为合法动作名,否则 `ValueError` 终结当前游戏——`qwenjev_agent.py` 已内置正则提取 + 随机合法动作回退。 3. **RESET 滥用**:RESET 不在候选池,仅由生命周期守卫触发。 4. **Testing Policy**:官方对评测环境禁止逆向/探测/暴力破解(详见 arcprize.org 的 Testing Policy),提交前务必通读并遵守。 5. **开源义务**:获奖者不开源方案会被取消资格——本仓库 MIT 协议即为此准备。 6. **Token 安全**:HF/Kaggle token 只放 `.env`(已 gitignore)或环境变量;任何在聊天/截图中明文出现过的 token,用完后建议立刻轮换。 7. **成本纪律**:RTX 排队以小时计且配额独占,本地 `make play-local`/`make eval` 先行,Kaggle Commit 只留给接近最终的版本。 --- ## 11. 命令速查 ```bash make setup # 环境安装(Python 3.12+) make test # 单测 36 个(纯 CPU,零下载) make smoke # 一键本地跑通:mock采集→建库→蒸馏→训练→评测(无GPU可用) make collect # 自博弈采轨迹(mock 游戏 / 25 公开游戏) make build-data # 轨迹 → Choice/Boolean/Score 训练样本(含 grid 帧字段) make distill # Stage A:9B 教师 → System-1 学生 视觉蒸馏对齐 make train-s1 # Stage B:决策头 SFT(NanoJev 配方,自动加载 stage A) make eval # 本地评测(mock 游戏默认) make push-hf # 推送本仓库到 HuggingFace(HF_TOKEN 从环境读) python scripts/download_weights.py # 拉权重 python scripts/serve_system2.py --port 8000 # 9B 端点(transformers 兜底) # vllm serve Qwen/Qwen3.5-9B --port 8000 # 9B 端点(首选) python scripts/package_kaggle.py --username XXX --accelerator rtx6000 ``` ### 11.1 本地跑通记录(v0.2.0,2026-09) 无 GPU(4GB RAM / CPU)环境实测:`make smoke` 全链路通过——mock 游戏 2400 步轨迹、5267 样本(train 4927 / val 340)、Stage A 蒸馏 56 步 align_loss 0.0062→0.0012 收敛、Stage B 三头联训完成、评测 agent 完整跑 600 步决策(每步含视觉塔前向,~210ms/步)。 切换真实模型的路径:`configs/train.yaml` 里 `system1.backend: "hf"`(学生 `Qwen/Qwen3-VL-2B-Instruct`)+ `stage_a_distill.teacher_model: "Qwen/Qwen3.5-9B"`,代码路径已就绪;建议先在单卡 GPU 机器上冒烟 hf 路径,再上 Kaggle。