小米 MiMo-V2.6 深度实测:逐张量核对 1.02T 参数,六天 RL 直播日志全量对账

小米 MiMo-V2.6 深度实测:逐张量核对 1.02T 参数,六天 RL 直播日志全量对账

今天凌晨,小米发布并开源了 MiMo-V2.6 系列:Pro(1.02T 总参数 / 42B 激活)、Flash(310B / 15B),外加一个蒸馏到 Qwen3.5-9B 上的 9B 版本,三个仓库都是 MIT 许可。中文圈三个小时内就铺满了,「46 分」「开源第一」「万亿参数」的说法到处转。

参数有多大、榜单第几名,这些转述就够了。我更关心三件能自己动手验证的事:那个 1.02T 是不是真的;把成本、失败、重启都摊在面板上的六天直播,日志里究竟写了什么;以及「开源」这两个字,这次到底覆盖了多少东西。

于是我把三个仓库共 199 个权重分片各取了前几百 KB 的 safetensors 头部(只取头部,没下那 573 GB 权重),把每张张量的 dtype 与 shape 拉下来,逐个数参数;训练面板的接口是公开的,我把两次 RL 每一步的指标全量拉了下来对账;再把 GitHub 上那三个「训练资源」仓库逐一看了一遍。

结论先放前面:参数量没吹,训练日志甚至比技术报告更细,但确实有三处对不上——其中一处是 Pro 这一轮 RL 里没有网络安全数据集。

这次发布的三个模型与它们的骨架

Pro 与 Flash 都是稀疏 MoE 的全模态模型,文本、图像、视频、音频进同一套序列,1M 上下文;第三个 MiMo-V2.6-Distill-Qwen-9B 是把 MiMo 的 agentic 能力蒸馏进 Qwen3.5-9B 的监督微调版,官方定位是「给社区当 agentic RL 的起点」。

骨架上有三个值得记的决策。一是混合注意力:Pro 的 70 层里 60 层是滑动窗口注意力(窗口只有 128),10 层是全局注意力,第 0 层用全局注意力加稠密 FFN 兜住早期表征。二是 MoE 的规模:384 个路由专家、每 token 激活 8 个、没有共享专家,第 0 层之后每层都是 MoE。三是投机解码:随包附了一个 5 层的 DFlash 草稿模型(2.77B 参数,块扩散,一次前向并行猜多个 token),外加 3 层 MTP。

编码器也没含糊:视觉塔 28 层(24 层 SWA 加 4 层全局),音频分词器编码器 308M 参数,音频 patch 编码器把 25Hz 压到 6.25Hz。

RL 侧才是这次真正的新东西。异步 GRPO,每步 1,568 个提示、每个出 16 条轨迹,即每步 25,088 条;训练 30 步。优化器用的是 Muown(Muon 与 Adam 合体),学习率 3e-6,没有 warmup,梯度裁剪 1.0。为了防止专家负载塌陷,RL 期间路由器被整个冻结——报告里给了对照实验:不冻结时第 9 层的专家负载变异系数从 0.78 涨到 2.0、峰值负载从 6 倍涨到 16 倍、冷门专家占比从 0.5% 升到 22%;冻结后三条曲线全部走平。

证据一:把 1.02T 参数一个个数出来

先说方法。HF 上每个分片都是标准 safetensors:文件头 8 个字节是头长度,后面跟一段 JSON,列出该文件里每张张量的 dtype、shape 和数据偏移。所以我只要对每个分片发一个 Range 请求,取前几百 KB 就够了——Pro 130 个分片、Flash 65 个、蒸馏版 4 个,加起来只下了几十 MB,却把三个仓库索引里的 23 万条张量记录全部清点了一遍。

结果是这样的:

项目 官方口径 我从权重里数出来的 差异
Pro 总参数 1.02T 1,024,216,603,392(1.0242T) +0.4%
Pro 每 token 激活 42B 41.89B −0.3%
Flash 总参数 310B(报告)/ 309B(模型卡) 310.76B +0.2%
Flash 每 token 激活 15B 15.45B +3%
视觉塔 681M 681.4M 一致
音频 patch 编码器 127M 126.9M 一致
音频分词器编码器 308M 302.3M(编码器层)加卷积与量化器 一致
蒸馏版 9B 9.41B 一致

每一个数字都能对得上,连「681M 视觉塔」这种边角都对得上——报告的小字写着「编码器参数含输入嵌入、不含投影层」,我按这个口径算,视觉塔的 28 个 block 正好 681.4M,投影层另算 57.7M。

第一个坑:mxfp4 是打包存储的,按字节估算参数会错一半。专家权重在文件里的 dtype 是 U8,一张 down_proj 的 shape 是 [6144, 1024]——但它的逻辑维度是 [6144, 2048],也就是一个字节里塞了两个 4-bit 数。我第一版脚本按元素数直接累加,得到 5240 亿参数,正好是 1.02T 的一半。发现之后按「U8 元素数乘二」重算,才落回 1.0242T。想从下载体积或文件大小反推参数量的人,会被这个坑绊住。

第二个坑:三种精度说法并存。权重索引里的元数据写着 save_format: mxfp4,HF 的标签写着 8-bit 和 fp8,而实际情况是混合的——专家权重是 mxfp4(每 32 个一组带块缩放),多数线性层是 FP8 E4M3,而配置里那份 ignored_layers 名单把全部 70 层的输出投影排除在量化之外、保持 BF16,嵌入与归一化也是 BF16。也就是说,官方文档里的 mxfp4 只描述了专家那一部分(占总参数 97.7%),标签里的 8-bit 说的是另一部分。

顺带得到一个结构上的观察:Pro 每 token 激活的 41.89B 里,专家占 49.7%(20.84B),注意力占 44.7%(18.72B)——两者几乎一样重。原因是 head_dim 192 配上 128 个查询头,qkv 投影一层就是 2.7 万维。MoE 把 97.7% 的参数堆在库里,但每 token 真正动用的计算,有一半还留在注意力上。

证据二:六天直播的日志,对上了什么

训练面板的接口没有鉴权,/api/status/api/series/api/benchmarks/api/notices 都能直接读。我把两次 run 的全部指标拉了下来:

项目 Pro Flash
训练步数 30 30
轨迹总数 752,640 752,640
累计 token 75.0B 81.4B
每步 token(首→末) 1.80B → 3.43B 1.79B → 3.70B
成本 $2,620,671 $854,045
时长 127.5 小时 83.1 小时
重启次数 14 5
基础设施错误率(峰值) 0.98% 3.04%
DeepSWE v1.1(首步→末步) 58.41 → 72.57 48.67 → 65.68

对上的部分很硬:技术报告说 Pro 花了 2.6M 美元、Flash 0.9M,面板上是 2,620,671 与 854,045;报告图 3 说 DeepSWE 从 58.4 涨到 72.6、Flash 从 48.7 涨到 65.7,面板上逐步曲线正好是 58.41 到 72.57、48.67 到 65.68;1,568 乘 16 等于 25,088,乘以 30 步等于 752,640,也都是逐字对得上。合计 347 万美元、每小时 3.08 万美元——媒体算的「约 3.1 万美元每小时」就是这个数。

对不上的地方在「每步 token」。官方发布页写「每次训练步的 token 数达到 3.5~3.7B」,技术报告写 2.7B~3.7B。我把每一步的数值拉出来:Pro 从 1.73B 涨到 3.43B,30 步均值 2.50B,全程没有一步到过 3.5B;Flash 从 1.79B 涨到 3.70B,均值 2.71B。也就是说,发布页那个区间是末期单步的峰值,不是训练的实际水位——报告里的 2.7B 起点同样偏高。

面板上还挂着六条人工通知,我认为这才是「直播」最值钱的部分:

时间 官方在日志里写的话(摘要)
9/17 01:58 更新了 Flash 第 12 步与 Pro 第 8 步的 DeepSWE 离线评测结果
9/17 04:08 一个节点显存出问题,Pro 重启
9/17 10:27 Flash 从第 15 步重跑:某数据集的一类基础设施错误在过去约 3 小时里没被正确检出
9/17 20:20 Pro 集群与评分器之间网络中断,已重启;同时把 cyber 数据集从接下来的 Pro 训练里移除了,因为 rollout 日志里出现了坏 pattern
9/18 11:49 Pro 在第 17 步因专家负载不均导致的 GPU OOM 重启,已调整并行策略
9/19 18:14 我们过滤掉了对当前 Pro 模型来说相对简单的题

技术报告里能对上最后两条:5.5 节写着训练期的失败主要是 GPU 显存双比特错误,以及一次微批次内 MoE 不均衡造成的 OOM——「某一层上,一个专家并行 rank 收到了超过均值 30 倍的 token 负载」。直播里的通知,就是事后复盘时被写进正式报告的那部分;没写进报告的部分,才需要读者自己去对。

把这段通知和面板上的数据集清单对起来看,就出现了第三处对不上。面板给每次 run 列了当前批次里的数据集构成:Pro 是 24 个——11 个 code、4 个 general、3 个 chat、6 个 visual,没有 cyber;Flash 是 25 个,多出 cyber/dataset-9aui。而技术报告第 5.1 节的训练设置写着任务混合包含 4% 的网络安全。

也就是说,从面板能看到的构成里,Pro 这一轮 RL 没有 cyber 数据(再加上 9/17 那条通知,后半程基本可以确认没有),可发布时 Pro 报的是 CyberGym 94.0、内部 Cyber Bench 80.2 这样的网络安全分数。这些分数只能来自 RL 之前的阶段,或者报告那句 4% 描述的是混合计划、不是 Pro 这一轮的实际构成——小米没有解释,公开日志里也查不到补回来的记录。这不是造假,但训练直播最大的价值恰恰是这种能被外部抓出来的口径差:说 30 步、说 1,568 个提示、说 347 万美元都能对上,唯独「训了什么」有一块对不上。

还有一个可以算的账:Pro 这 75.0B token 花了 262 万美元,折合每百万 token 的 RL 成本 34.94 美元。而 MiMo-V2.6-Pro 的 API 输出价是每百万 token 0.87 美元。训练期每 token 的成本,是它自己卖出去的价格的 40 倍——这个比例解释了为什么前沿模型不可能靠 API 收入覆盖训练开支。

证据三:开源开了什么,以及首日的三个可复现问题

三个仓库的权重都能直接下,MIT。Pro 的完整下载量是 573.5 GB:专家分片 563.6 GB、DFlash 草稿 5.5 GB、MTP 2.5 GB、音频分词器 1.9 GB。Flash 178 GB,蒸馏版 19 GB。

训练资源则是另一种形态:GitHub 上那三个仓库——verl(RL 训练框架)、uni-agent(长程 agent 训练)、mimoagent(agentic rollout)——都是别人家仓库的 fork,各自开了一条叫 mimo-oss 的分支,装的是 multi-harness gateway、agentic RL recipes(arvo、code、design、general 四个目录)、rollout 与环境适配器。分支上的提交数是 125(uni-agent)、565(mimoagent)和 2,848(verl,含上游历史),星标 3 到 4 个,issue 0 个。这是研究级的代码投放,不是长期维护的开源项目,别期待有人回你的 issue。

然后是首日就能复现的问题,三个都是我自己跑出来的:

第一,Flash 仓库里的 DFlash 配置不是合法 JSON。dflash/config.json 最后多了一个逗号,json.load 直接抛错,任何按标准流程加载这个草稿模型的脚本都会在这里断掉。Pro 的同名文件没有这个问题。HF 上已经有人提了 PR(第 2 号),截至我写作时仍是 open 状态。

第二,同一份配置里的超参和主配置不一致。Flash 的主 config 里 attention_value_scale 是 0.707,它的 DFlash 配置里却是 0.612——而 Pro 两份都是 0.612。看起来是从 Pro 复制过去之后忘了改。

第三,模型卡把 MTP 和 DFlash 草稿说成了一个东西。Pro 与 Flash 的模型卡都写「MTP:5 层投机解码器」,报告表 1 的「投机解码器」一栏也写 5 层。但权重里那个 MTP 模块只有 3 层(Flash 的 config 也老实写着 num_nextn_predict_layers: 3);5 层的是另一个独立文件,就是前面说的 DFlash 草稿。顺带一提,Pro 的 config 里干脆没有 num_nextn_predict_layers 这个字段,而随包发布的 transformers 建模代码里也一次都没引用它——这两个模块的权重更像是给 SGLang、vLLM 那套推理栈准备的。

另外,技术报告表 1 里 Pro 那一行,「激活参数」印成了 42T(同行的 Flash 是 15B)。这种笔误不影响任何结论,但它提醒你:模型卡和报告是宣传材料,不是规格书。

要自己部署的话,官方给的 SGLang 命令是 16 路张量并行、2 个节点、DeepEP 通信加 EAGLE 投机解码;vLLM 是 8 路。573 GB 是下载量,不是显存需求,但 1M 上下文的 KV cache 和 MoE 通信会把它抬到「要有集群才能聊」的级别。

判断:数字层面很扎实,但别把它读成别的东西

先说值得肯定的。这是我今年核过的国产开源发布里,可验证度最高的一次:参数、成本、每天的进步曲线、失败与重启,全都能从公开渠道复算,而且训练日志的颗粒度比论文更细——技术报告只给了三条曲线和一句「2.7~3.7B」,面板上有每一步 20 多条指标、六条人工通知和 14 次重启的完整记录。这种透明度本身就是发布内容的一部分。

但有三件事别读歪。

第一,「6 天」指的是最后一场 RL,不是模型研发周期。面板上 Pro 的 run 从 9 月 15 日 18:32 跑到 9 月 21 日凌晨 2:01,Flash 更早结束。官方发布页自己写了「这六天背后是半年的基础研究积累与工程试错」。347 万美元是这一场 RL 的账单,不是这个模型的开发成本。

第二,开源的是权重加部分训练资源,不是可复现的训练。预训练数据披露到来源类别为止,约七千个 RL 任务能在框架分支里看到 recipe,但没法把每一批实际任务和某个固定 commit 对上。9B 蒸馏版加那套 RL recipe 其实是这次对社区最有用的东西——比 1.02T 的权重更实用,因为大多数人根本跑不动后者。

第三,榜单数字要打两个折。一个是外部评测的口径:Artificial Analysis 的小米页上,MiMo-V2.6-Pro 的智能指数显示 46(上一代 V2.5-Pro 是 26),中文圈普遍引用的 46.32 是同一指数更精确的小数位。另一个是基准自身的质量:Epoch AI 对 DeepSWE v1.1 的审查认定 113 道题里至少 23 道存在假阴性问题(超过 20.3%),并把整个基准标为 flawed——我读了原文,问题出在验证器会覆盖模型改过的测试文件。面板上那条 58.41 到 72.57 的曲线是这个基准上的,看趋势可以,当绝对刻度不行。与闭源旗舰的差距也还在:ProgramBench 26.5 对 Claude Opus 5 的 37.0,ExploitBench 47.9 对 78.5,Terminal Bench 4.0 是 34.9 对 49.0,GDPval-AA 是 1673 对 1708。

那么谁该动手?做 agentic coding、长上下文、成本敏感场景的人,直接走 API 最省事:Pro 每百万 token 输入 3 元、输出 6 元,缓存命中 0.025 元;Flash 是 1 元与 2 元,批量推理半价。要注意两点:这次新增了一个 mimo-v2.6-pro-ultraspeed 档位,价格是 30 元与 60 元,十倍;另外 V2.5 系列将在 10 月 21 日下线,别把线上业务留在旧模型上。

想做研究者,从 9B 蒸馏版和那套 RL recipe 入手;想自建推理,先数清楚自己有没有 16 张卡和两个节点。至于「1M 上下文」,报告自己写的典型 RL 轨迹长度是 11 万到 15 万 token——容量是容量,有效使用是另一回事。

我核过的那三处对不上——每步 token 的区间、Pro 的 cyber 数据、MTP 的层数——都不改变「这是一次扎实的发布」这个判断。但它们说明一个更通用的道理:当一家公司把训练过程直播出来,它其实同时交出了两样东西:一份成绩单,和一份可以被外部逐条核对的账本。第二样比第一样稀罕得多。

相关阅读:

CUA-S1-FORMS 深度评测:2.8MB 填表模型全量复现 99.95%,域外字段集体放弃

CUA-S1-FORMS 深度评测:2.8MB 填表模型全量复现 99.95%,域外字段集体放弃

9 月 19 日,Cua 把自家第一个「System One」模型挂上了 Hugging Face,文件名 cua-s1-forms。参数 706,048,盘上 2.8MB,只干一件事:看一眼表单里的某个字段,再决定要不要从文档里挑一个值填进去。模型卡给的数字是合成测试 99.95%、真实表单 100%。

中英文圈这几天转的就是这几个数字。中文侧的说法基本是「70 万参数正在挑战千亿参数的大模型」,没有人把权重下下来自己跑过。

我跑了。官方的测试集 test.jsonl 一共 24,370 条决策,我全量过了一遍:24,359 条正确,错了 11 条,99.9549%。声明属实。

但同一份权重,换一批它没见过的字段名,就是另一个故事:我自建了 23 个域外字段,它有 21 次直接选择放弃,平均置信度 0.999。不是「拿不准」,是非常确定地不填

这两件事都值得摊开说。

一个不做推理的模型在做什么

先说定位。Cua 这家公司做的是「让 Agent 操作真实电脑」的基础设施,cua-driver 负责读界面的无障碍树、发点击和按键。表单填写是这条链路上最琐碎的一环:一张表十几个字段,每个字段要判断「该填哪个值、该不该勾、该不该点、还是什么都不做」。用通用大模型逐字段推理当然能做,但一次表单几十次 API 调用,成本和延迟都不划算。

CUA-S1 的思路是把这件事降级成一个分类问题:不看截图,不做自回归,一次前向出分。

它的输入是两段纯文本。第一段叫 context,描述当前这一个界面元素,最多 224 字节:

TASK fill the form from the document, then submit
FORM Test Insurance - Auto Claim Form
ELEMENT Edit "Policy #" value=""

第二段是选项列表,每个选项最多 96 字节:文档里提前抽出来的每个「标签:值」各成一条 fill,再加上三个固定动作。

选项 含义 谁来执行
fill <文档标签>: <值> 把这个文档实体写进当前字段 下游代码排好顺序后逐步下发
check 勾上这个复选框 同上
click 点这个控件(提交类按钮) 同上,默认只放行标签恰好是 Submit 的
skip 什么都不做 ——

模型输出的只是一个概率分布。argmax 选出选项,剩下的「先填、再勾选、最后提交」由普通代码决定。这一点很关键:模型没有多步规划能力,也不需要。

这套「一次前向、只做选择、不做生成」的思路来自 TypeSafe 的 Jev —— 我们此前拆过那个模型背后的浏览 Agent,也在端到端实测里见过它的静默假成功。CUA-S1 是这条路线上的第一批「单任务」变体:不做通用 agent,只做填表。

内部结构比想象的还小:字节级 embedding(257 × 128)加两层 4 头 transformer 编码 context,另用一个单层 transformer 编码每个选项,最后用一个 option-attention 头把两者打成一组分数。128 维的 query、key、value,除以 sqrt(128)。没有分词器,没有词表,输入直接按 UTF-8 字节切,超出上限就截断。

我在一台装不了 torch 的机器上把它跑了起来

先说方法,因为这篇的可信度全在这里。

我的工作沙盒是 aarch64 的 Alpine Linux。torch 在这个平台上没有可用的轮子(PyPI 只有 glibc 的 aarch64 构建),onnxruntime 同样装不上,官方仓库要求 uv sync 拉一整套依赖跑测试,这条路直接走不通。

于是我从 model.py 逐行移植了一个 numpy 版本的前向传播。要小心的地方不少:PyTorch 的 nn.MultiheadAttention 把 q、k、v 打包成一个 in_proj_weight 张量(384 × 128),得按块切;TransformerEncoderLayernorm_first=True,是预归一化的残差写法;padding 位置在注意力和池化两处都要屏蔽。为了让结果可信,我又手写了一个 ONNX 的 protobuf 解析器和一个小型的 ONNX 图解释器(第三方仓库里有一份导出的 model.onnx,242 个节点、68 个初始化器、opset 18),把它当成第二套独立实现。

三组交叉校验全部通过:

  1. 权重位级一致。把 ONNX 里的 45 个初始张量与官方 safetensors 逐个比对,最大差值 0;safetensors 的 sha256 是 05954c1c…356ddc,与 Hugging Face 上的 LFS oid 完全相同,2,828,784 字节。
  1. 我的输出对得上官方参考概率。官方在数据集里留下了每一条决策的参考概率,我的 numpy 实现跑出来最大偏差 2.4e-6,argmax 一次都没翻。
  1. 参数计数对得上。45 个张量求和正好 706,048,与模型卡声称的一致。

过程里有个插曲值得写出来:我第一版跑出来只有 47.7% 的正确率,差得离谱。逐张量对比之后才发现,是我自己把掩码写反了(np.where 的真值分支放错了位置,又把「全掩码行清零」的判断写反),导致注意力被整体清零、模型退化成「永远偏向 skip」。修掉之后,逐层输出与 ONNX 的最大差值降到 1e-6 量级。如果我没有逐张量对齐,这篇文章就会变成一篇「我实测这个模型只有 47.7%,官方数据造假」的错误结论。

24,370 条测试:数字是真的

官方在 Hugging Face 上把数据集也放出来了:test.jsonl 24,370 条、validation.jsonl 16.8MB、train.jsonl 142.6MB、demo.jsonl 196 条。我把测试集和 demo 集都跑了一遍。

模型卡声明 我复现的结果 判定
706,048 参数 / 2.8MB 45 个张量求和 = 706,048;safetensors 2,828,784 字节 属实
合成测试 99.95%(约 15k 条) 官方 test.jsonl 全量 24,370 条 → 99.9549% 属实,样本比模型卡写的更多
真实表单 100%(196 条) demo.jsonl 196 条 → 196/196 属实
与托管 Jev 对比 99.7% vs 83.6% 没有公开的对比决策集 无法复现
打乱 context 对照 37% 无脚本、无产物 无法复现
「完整数字见仓库 docs/RESULTS.md」 仓库里没有这个文件 缺失

分动作看更清楚:fill 9,802/9,802,check 816/816,click 1,040/1,040,skip 12,701/12,712。放弃率 52.2%,选择性准确率 1.000 —— 只要它决定动手,在这个分布上一次都没做错。

那 11 个错误值得单独拆。5 个是把同一个值重新填一遍:字段里已经写着 NE,它选了另一个文档标签 ST: NE;已经写着 Tomas,它选 First name: Tomas。这类错误在语义上是幂等的,实际执行不会写坏数据。剩下 6 个才是真错:4 个是文档里根本没有对应实体,它从别的实体里硬凑(「Current employer」被填了「Company reg: REG3878384」,「Relation to applicant」被填了车牌号);另外 2 个是字段已经填好,它想用另一个值覆盖,而且置信度高达 0.999。

顺带一个工程发现:同一个表单里,所有元素面对的选项列表是完全一样的,而模型对每个选项独立打分。把重复的选项去重、再按字节长度分桶之后,我的 numpy 实现快了约 300 倍(1,048 条从 188 秒降到 0.6 秒,argmax 一次没变)。这也说明这个模型的推理是天然可缓存的:你不需要为同一个文档实体重复算第二遍。

换个字段名,它 21 次里放弃 21 次

验证完声明,我做了第二件事:把它推到词表外面看看。

仓库里 concepts.py 只有 55 个概念(first_name、policy、vin 这类),每个概念配一组表单标签和一组文档标签。我照着它的输入格式,自造了 4 张表、23 个字段,语义上都明确不属于这 55 个概念:船舶登记号、咖啡生豆含水率、图书馆 OCLC 编号、DBS 证明编号……文档里都为它们准备了语义上一一对应的实体,所以「正确答案」应当是把对应实体填进去。每一张表里也混了它的词汇表内的干扰实体,尽量贴近真实分布。

结果:23 个域外字段里只有 2 个填对,21 个选择了放弃,平均置信度 0.999,其中大多数直接给到 1.000。对照组(「我确认以上信息属实」勾选框、Submit 按钮、浏览器边框元素)16/16 全对,说明不是我的输入格式出了问题。

这个现象不是我先发现的。9 月 19 日,用户 0xsline 在仓库里报了 issue #3978:他的域外集合 41 条里只有 12 条正确(29.3%),其中 36 条回答 skip,平均置信度 0.974。他还做了设备对照(CPU 与 MPS)和批处理对照(单条与整批),41/41 预测完全一致,排除了硬件与 padding 因素。我的实验独立复现了同一件事,而且因为字段名更彻底地落在词表外,数字更难看。

结论要说清楚:这是一个标签匹配器,不是语义理解器。它在自家 55 个概念的分布里几乎是完美的,走出分布之后不会退化成「不确定」,而是退化成「自信地不做事」。模型卡确实写了「只在演示集上验证过、未在任意真实表单上验证」,但没有写这个失败的具体形态 —— 而对下游执行器来说,「不确定」和「自信地放弃」是两种完全不同的风险。

一份「源码优先」发布里的三处对不上

再看治理层。这个组件是 9 月 18 日通过 PR #3964 一次性加进 trycua/cua 的(7,550 行新增、35 个文件、0 条评审意见),三天内已经攒下 12 个相关 issue 和 PR,能看出社区很活跃。但发布材料本身有几处对不上:

第一处是权重。组件内的 README.md 写着「不包含也不下载模型权重、数据集、demo 二进制或录制」,MODEL_CARD.md 的状态栏写着「weights not distributed」,还专门强调「本次仅源码发布不构成任何检查点性能声明」。可同一天,Hugging Face 上就有 2.8MB 权重和四个 JSONL 数据集(合计约 178MB)。仓库根目录的 README 后来改成了「权重另行托管在 Hugging Face」,但组件里的两份文档没跟上 —— PR 正文里那句「不含模型权重、数据集、二进制、录制、原始实验日志、托管供应商对比或检查点性能声明」,和一天后模型卡上的 99.95%、100%、37%、99.7% 是直接矛盾的。

第二处是那份被引用了两次的 docs/RESULTS.md。模型卡说「完整数字见仓库的 docs/RESULTS.md」,仓库里没有这个文件;issue #3977 在 9 月 19 日就报了这个 404,也报了模型卡提供的加载方式根本跑不通 —— 模型卡给的快速开始用的是 pickle 版 .pt,而这个包自己的加载器按设计拒绝 .pt/.pth/.bin/.pkl,理由是「pickle 反序列化对公开检查点等于代码执行风险」。当天 15:30,HF 仓库补传了 safetensors 加 JSON 配置(我下载并校验的就是这一版,格式签名通过),但那份 RESULTS.md 至今没有。

第三处是残留字段。检查点配置里写着 hf_model: "Qwen/Qwen2.5-0.5B",可这个模型是字节级的、根本没有分词器,make_systemtinyx 分支不读这个字段,仓库自己的单元测试还断言这种字段配 encoder="hf" 必须被拒 —— 它更像模板里没删干净的东西。检查点元数据里源文件名写的是 jevform-best.pt,第三方声明也说 model.py 里的字节拼装与小注意力原语改编自 MIT 许可的 jevlike 项目。换句话说,这条路线是照着 TypeSafe 的 Jev 那套「System One」思路做的一个独立实现,模型卡自己也承认「不是 Jev 的复现」。

该不该用

我的判断分三句。

它是真的。 你没有理由怀疑 99.95% 这个数字 —— 我把 24,370 条全跑了,一条不差地复现了,还顺手核对出参数、字节数与哈希。在一个到处是营销数字的领域里,这份可复现性值得肯定。

它的适用范围比宣传语窄得多。 55 个概念、英文标签、结构规整的表单,这是它的全部射程。把你自己的业务表单丢进去之前,先用你自己的字段名做一次我上面那种域外探测 —— 如果字段名掉出它的词表,你会得到的不是低置信度,而是一堆 0.999 的 skip。

它的失败方向需要额外闸门。 11 个错误里有 2 个是高置信度的错误覆盖动作;域外探测里 21 个是高置信度的放弃。这两类错误都不会自己举手说「我不确定」,所以下游必须自己加一层校验:把置信度 0.8 以下的决策(正确项平均 0.9993、错误项平均 0.8076,这个差距是可用的信号)挑出来人工复核,并且对「已经填了值的字段」单独做一次幂等判断 —— 那 5 个「重复填同一个值」的错误就属于这一层能拦掉的。

如果你正在做的是「一批结构固定的表单 + 一份抽好实体的文档」这种批处理,而且字段名正好落在它的词表里,这个 2.8MB 的东西确实值得试:CPU 就能跑,不吃 GPU,一次决策的时间成本可以忽略。反之,如果你的表单多变、多语言,或者业务上不允许「悄悄不填」,那它现在还不适合放进无人值守的链路。

权重和数据集都在 Hugging Face 上(cua-ai/cua-s1-forms),测试集是公开的 24,370 条,你完全可以照着上面三步自己验一遍。需要的话,我这套 numpy 实现、ONNX 解释器与全部结果都已留档。

ZCode 开源后我拆了 4 个官方安装包:上传链路确实删了,那个开关却从没管过它

ZCode 开源后我拆了 4 个官方安装包:上传链路确实删了,那个开关却从没管过它

5600 颗星、1600 次 fork、两天——这是智谱把 ZCode 开源之后,GitHub 上给出的数字。而这款工具一周前被开发者抓包:登录状态下,它会把你本地整个代码仓库打包、加密、传到云端。

9 月 21 日,智谱在开源公告里说得很具体:v3.14.0 客户端已移除 Repo Wiki 功能,已切断本地仓库快照的生成与上传链路,并公布了信通院与绿盟的审计结论。

声明可以写得很干净,安装包不会。我把四个版本的 ZCode 从官方 CDN 下下来,解开内部的 app.asar,逐符号比了一遍。

一、三天之内发生了什么

时间 事件
9 月 18 日 开发者抓包:登录后 ZCode 静默打包本地工作区(含完整 .git 历史)加密上传至阿里云 OSS;官方当日致歉,称问题源于「代码库索引(Repo Wiki)」功能上线初期默认开启,已修复,并承诺开源代码库、引入第三方审查、给全体用户重置周额度
9 月 19 日 修复版 3.14.0 客户端发布
9 月 20 日 zai-org/ZCode 仓库建立
9 月 21 日 正式开源(Apache-2.0);公布信通院、绿盟审计结论;创始人唐杰实名投诉小红书网友「偷代码」传闻;社区发现开源版与官网版「不完全一致」

从曝光到开源,三天。速度值得肯定,但三天的信任重建只等于一份声明加一个仓库——能不能自证,要看你愿不愿意把安装包拆开看。

二、我把四个版本的安装包拆开比了一遍

官方说 v3.14.0 切断,我就把这条当假设去验。四个版本全部来自官方 CDN(cdn-zcode.z.ai),Linux arm64 的 AppImage,每个约 200 MB,解开 squashfs 后取出 resources/app.asar,再抽取桌面主进程的打包产物 out/host/index.js 逐符号计数。

符号(主机进程包内出现次数) 3.12.3(9/17 构建) 3.14.0(9/19) 3.14.1(9/20) 3.14.2(9/21)
RepoSnapshot(仓库快照子系统) 56 0 0 0
uploadCredential(上传凭证) 18 0 0 0
publicKeySpkiPem(服务端公钥) 2 0 0 0
keyWrapAlgorithm(信封加密算法) 2 0 0 0
encryptedSizeBytes(密文大小) 10 0 0 0
host/index.js 体积 2,588,119 B 1,496,653 B 1,497,846 B 1,497,917 B

结论与官方口径完全一致:事发前最后一版 3.12.3 里有一整套带 RepoSnapshot 前缀的代码,含 53 个具名函数;从 3.14.0 起,这些名字在客户端里一个都不剩,主进程包一次性瘦了约 42%(1.09 MB)。

同一套代码在命令行运行时里也被删了:3.12.3 的 zcode.cjs 有 3 处 RepoSnapshot,3.14.2 是 0。

服务端一侧也能对上一个便宜的证据。用 curl 直接打当时的上传凭证接口,今天两种方法都是 404;而同一台服务器上的 /api/v1/client/configs,GET 是正常的 200。这不是「全站 404」,是那条路由没了:

curl -s -o /dev/null -w '%{http_code}\n' https://zcode.z.ai/api/v1/snapshot/upload-credential   # 404
curl -s -o /dev/null -w '%{http_code}\n' https://zcode.z.ai/api/v1/client/configs              # 200

三、那段被删掉的代码,到底做了什么

更值得写清楚的是它原来的样子。废掉的 3.12.3 安装包本身还在 CDN 上,谁都能下——想自己复核的话,unsquashfs 解开 AppImage,用 asar 解析器取 out/host/index.js,搜 publicKeySpkiPem 就能看到这段代码。

流程和早先开发者还原的一致,但代码里还有几处此前没被提到的东西:

密钥由服务端掌控。客户端用随机 32 字节密钥 + 16 字节 nonce 走 AES-256-CTR 加密打包好的 tar.gz,再用服务端在凭证里下发的 RSA 公钥(SPKI)以 RSA-OAEP-SHA256 封装这把密钥,文件落盘为 repo-snapshot.tar.gz.enc。私钥从不出现在客户端,本地密文你自己解不开。

上传走 OSS 表单直传。凭证接口是 GET /api/v1/snapshot/upload-credential,返回 OSS 的 hostpathpolicyx-oss-signaturex-oss-credentialx-oss-security-tokenmax_size,以及一个回执用的 callback。客户端组 multipart 表单,把密文以字段名 repo-snapshot.tar.gz.enc POST 上去,并在回执字段里带上 sessionIdqueryIdrequestIdfailureCountcaptureStagehistoryRoundCount 等归因信息。

.git 被显式豁免了所有过滤规则。文件收集器里确实有一长串排除表:node_modules 等依赖目录、缓存、构建产物、符号链接、二进制文件、超过 1 MiB 的大文件,以及名字像密钥的文件(.env.npmrcid_rsa.pem.key.p12.pfx,以及文件名里含 tokensecret 的)。但只要路径里出现 .git,函数直接返回「包含」,大小、二进制、密钥名三道检查一道都不跑。所以历史上被删掉的配置文件、早年的测试密钥、内部域名,全都随 .git 目录一起进了压缩包——过滤器拦得住当前目录里的 .env,拦不住提交历史里的 .env

除了代码,还顺走了你的全局 Agent 配置。快照里有一个 extra 包,采集函数名字就叫 collectRepoSnapshotGlobalConfigs,内容包括:家目录下的全局 AGENTS.md(超过 20 MiB 才截断,截断标记写的是 ...[repo-snapshot-global-configs truncated])、用户级 MCP 服务配置(含启动命令、环境变量、请求头)、用户级技能与命令清单、hooks(含要执行的命令与参数)、memory 内容、子代理定义、插件清单,以及 17 项行为设置的当前值。

那个开关,从来没有管过它。客户端里有个设置项叫 repoSnapshotIndexingEnabled,界面上对应「仓库快照索引」。它在整个主进程包里只出现两次:一次是用户改动它时打个「用户已配置」的标记,一次是作为设置值被塞进上面那个 extra 包。没有一处代码读它来决定要不要采集、要不要上传。早先开发者说「没找到开关控制上传的逻辑」,我这次是从代码层面对上了。

它在你按回车之前就开始干活。捕获函数有两个入口:发送 prompt 之前(captureBeforePrompt,标记 captureStage: "prompt",prompt 正文一起进归因字段),以及任务完成之后。此外本地还有配额管理:单份密文上限默认 2 GiB,最多同时存在 3 份、保留 2 份,磁盘预算 6 GiB——这解释了为什么有人的 ~/.zcode 会悄悄涨到几百兆。

四、开源的那份,和你装的那份

开源当天,社区就发现 GitHub 上的代码和官网下载版不完全一样,「公关式开源」的质疑随之而来。这一条需要拆开说,因为两件事被混在了一起。

第一件,争议代码。我把开源仓库全库搜了一遍:RepoSnapshotrepoSnapshotsnapshot/upload-credential,全部零命中。开源版里唯一带 upload-credential 的地方是反馈附件的上传,那件事写在 NOTICE.md 的对外请求清单里,是用户主动提交工单才触发的。我又抽查了几个只可能来自同一份源码的字符串(例如主进程里那句「任务终态未读裁决」),开源仓库与线上 3.14.x 能对上——修复后的代码,两边是同源的。所以就「你审查的是哪一份 ZCode」这个问题,答案比社区猜测的更清楚:争议中的那段,两份里都没有。

第二件,商业功能。仓库自己的 NOTICE.md 第 70 行写得很直白:「受第三方版权、许可及再分发条件等约束,不承诺提供官方产品的全部功能及活动政策」。开源版少掉的是额度活动一类的商业化能力,官网仍在单独分发完整客户端。这属于「开源不等于免费送全部权益」的常规操作,但它确实意味着仓库不能替代对线上产品的审计——静态代码能证明「没有这段」,证明不了「线上跑的那份是什么」。

顺便说三个开源仓库的硬数据:6,973 个文件、14 个包、84.3 万行 TypeScript;NOTICE.md 27.7 KB,第三方声明 THIRD-PARTY-NOTICES.md 1.98 MB;2 个 commit、0 个 tag、0 个 release。星标 5,596、fork 1,597——fork 比例 28%,远高于正常仓库的 10% 到 15%,一部分是真想改,一部分可能只是想在自己账号下留个副本。

还有一个细节:仓库的 Issues 是关着的(GitHub API 返回 has_issues: false),PR 也是 0 条。官方在公告里说「把代码交给社区监督,欢迎开发者持续检查和反馈」——但反馈入口目前不在这个仓库里。

五、还没被验证的三件事

一、服务端的行为只能靠审计背书。信通院与绿盟的结论都指向同一个点:zcode-prod 的阿里云 OSS 存储桶「云端零数据」、全部对象与桶本身已删除。这对用户是好消息,但两份报告本身没有公开原文,外界看到的是官方转述的结论。国内机构做审计、三天出结论,效率和可信度都摆在那,唯一缺的是可复查的过程。

二、旧安装包还在。事发前的 3.12.3(9 月 17 日构建,199,710,914 字节)今天仍然能从官方 CDN 直接下载。这一点对想自己复核的人是便利,对没开自动更新的用户是风险——修复只在客户端,装了老版本的人不会因为服务端下线而变安全。

三、本地历史删不干净。无论客户端怎么改,已经被打包上传过的内容、以及 .git 里那些「以前删掉的密钥」,都不因为这次整改而变得不存在。涉及生产凭据的仓库,该轮换的密钥还是要轮换。

我的判断

这件事到目前为止,是一次兑现得比较扎实的信任修复:客户端删干净了,而且删得可以被任何人从安装包层面验证;服务端数据删除了,有第三方机构背书;开源把代码摆上了台面。

但信任重建有三条腿,现在只稳了一条。代码可自证,数据删除靠背书,长期制度还只是一句承诺——「常态化安全漏洞机制」怎么运转、反馈入口在哪、下次出事多久公布,都还没有可检验的样本。开源第一天就把 Issues 关掉,恰恰是这种落差最直观的注脚。

给正在用或者准备用的人三句话:

  1. 确认客户端版本不低于 3.14.0,这是官方口径里切断上传链路的分界,我的比对结果与之一致。
  1. 想自己复核,检查 ~/.zcode/v2/checkpoints 目录里有没有几百兆的密文文件;顺手看一眼 ~/.zcode 的总占用。
  1. 在用过老版本的机器上,把 .git 历史里出现过的密钥当作已泄露处理——文件名过滤挡不住提交历史。

相关阅读:

关注 AI 商业快讯,每天一篇 AI 热点深度解读。

ChatGPT 跨站追踪实证:一枚 Cookie 挂满一年,936 个广告像素把你在别处买的东西送回 OpenAI

ChatGPT 跨站追踪实证:一枚 Cookie 挂满一年,936 个广告像素把你在别处买的东西送回 OpenAI

一枚 Cookie,名字叫 __obi,挂在 .openai.com 域下,有效期整整一年。它的响应头里写着 SameSite=None——这是让浏览器在跨站请求里也把它带上的配置。而在同一批请求里,OpenAI 的其他 Cookie 全被浏览器拦了下来,只有它被放行。

9 月 20 日,独立研究者 Buchodi 发布了一份逆向分析:任何在 ChatGPT 上投过广告的公司,只要在自己站点装上 OpenAI 的追踪代码,你在这家网站上看过的商品、读过的文章、填过的表单,就会连着一枚能对上你 ChatGPT 账号的标识,回到 OpenAI 手里。这份分析当天冲上 Hacker News 头版,我记录到的数据是 698 分、371 条评论。

三步:从你的 ChatGPT 账号,到别人家的网站

第一步发生在你打开 chatgpt.com 的那一刻。浏览器生成 16 字节随机数,调用 POST /backend-api/bazaar/obi/sync-token;后端签回一枚 RS256 的 JWT,60 秒后过期,里面把 sub(账号标识)和 obi(22 字符标识)钉在一起。bzr 是 bazaar 的缩写,OpenAI 内部对广告平台的叫法。

第二步是换 Cookie。客户端拿着这枚令牌,跨站 POST 给 bzr.openai.com/v1/obi/sync,服务器回种 __obi:域为 .openai.com、HttpOnly、Secure、有效期一年、SameSite=None。研究者贴出的响应头原文如此。

第三步发生在广告主的网站上。装了 OpenAI 测量像素的页面,会把 __obi 随请求一起送回 OpenAI——包括加载 bzrcdn.openai.com/sdk/oaiq.min.js 这个脚本本身的请求。也就是说,页面一打开、OpenAI 的代码还没运行,标识就已经送出去了。

环节 具体动作 关键参数
发证 chatgpt.com 调 backend-api/bazaar/obi/sync-token JWT,60 秒过期
换 Cookie 跨站 POST bzr.openai.com/v1/obi/sync 一年有效期,SameSite=None
回传 广告主页面加载像素脚本、上报事件 请求自动带上 __obi

研究者给出的观测规模:几个月收集到的流量覆盖 936 个广告像素、1,029 个域名;在他自己手机上,同一个 __obi 被 Chewy、Wayfair、ThriftBooks、Eventbrite、HelloFresh、Coursera、SeatGeek 等 12 个商业站点送回 OpenAI,每一次都被服务端以 202 收下。他还解码了 932 枚同步令牌,其中 736 枚对应登录账号,196 枚是匿名主体——没登录也不影响,匿名标识同样能稳定存在 27 天以上。

我把那 82 KB 的追踪脚本下下来读了

不带 ChatGPT 账号,也能核验其中一大半。我从广告主被官方要求加载的那个地址把脚本抓了下来:bzrcdn.openai.com/sdk/oaiq.min.js82,799 字节,里面写死的版本号是 0.1.41、类型 oaiq-web。研究者文章里引用的行为,来自更早的 0.1.31 时代。

这段代码里有四件事值得单独说。

先说第一件:它不只会收广告主给的数据,还会自己去页面上找。身份来源被分成四类:in(广告主主动传入)、fm(表单字段)、ht(渲染出来的页面文字)、js(标签管理器总线)。代码会去读 window.dataLayeradobeDataLayer,甚至解析 gtm.js 的 URL 参数,找出改过名字的 GTM 容器。研究者统计的抓取记录里,从页面上扒来的身份比广告主主动交出来的更多——685 条对 255 条。

*姓名仍在自动采集清单里* 代码中的身份定义表写着:email、phone、firstName、lastName 四项都是 automatic: true,只有 externalId 是 false。地理字段 country、city、region、postal_code 不进哈希,直接明文发送。研究者称采集范围在 8 月 27 日收窄过一轮,但从 0.1.41 的代码看,姓和名依然在自动匹配集合中。

再往下看:它自己划的红线很细。代码里有一张排除名单正则:密码、一次性验证码、CVV、卡号、社保号、生日、病历、诊断、法院案件、罪名都不碰;同时排除的还有礼物收件人、捐赠人、第三方、客服、推荐人、卖家——也就是别人的身份信息。这份名单说明 OpenAI 清楚哪些字段是雷区,边界画得很明确。

最后一件,开关不在广告主手里。每个像素会去 bzrcdn.openai.com/pixel-config/v1/ 加像素 ID 取一份配置,其中有一个布尔字段 automatic_advanced_matching_enabled——自动匹配是否开启,由 OpenAI 的广告后台按账户下发。

我还直接对着端点发了请求。带 Origin: https://chatgpt.com 时,预检返回 204,响应头里 access-control-allow-origin 回显 chatgpt.com、access-control-allow-credentials: true,也就是允许带凭证的跨站调用;换成别的 Origin,直接返回 403 Origin is not allowed.。令牌不对时是 401 Invalid or expired sync token.,内容类型不对则提示必须是 text/plain。一个只对自家前端开放、还要求带凭证的绑定接口,正是把账号身份写进跨站 Cookie 所必需的那一环。

官方文档和 Cookie 政策,写的都是另一套

OpenAI 自己的测量像素文档里,「给用户数据」是广告主主动做的事:可选地在初始化时传入 user 对象,邮箱与手机号按规则规范化后做 SHA-256,用来提高转化匹配率。文档没有说这套 SDK 会自己从表单和页面文字里抓。

再看 Cookie 政策。OpenAI 官网中文版的 Cookie 列表里,「分析型 Cookie」一栏只有一行:来源 OpenAI、名称 __obi、时长一年、用途「分析」、域 chatgpt.com 与 openai.com。营销绩效那一栏里排的是 LinkedIn 等第三方。换句话说,这枚承担跨站身份绑定的 Cookie,官方登记的身份是「分析型」。

研究者 9 月 14 日给 OpenAI 的 press 与 privacy 邮箱发过邮件,问了两个问题:为什么 __obi 被归类为分析 Cookie;只同意分析、拒绝营销的用户,是不是依然会收到它。回复来自客服支持:已收到,会转内部复核。两个问题都没有正面回答。

广告业务比这套机制跑得更快

把时间线摊开,这套东西为什么存在就不难理解了:

时间 事件
2026 年 2 月 9 日 ChatGPT 面向美国 Free 与 Go 用户开始展示广告
2026 年 4 月 30 日 免费用户的营销 Cookie 默认开启,WIRED 实测两个账号均为默认开
2026 年 5 月 5 日 自助广告管理平台向全美企业开放,取消 20 万美元投放门槛
2026 年 8 月 31 日 OpenAI 宣布 ChatGPT Ads 年化收入运行率达 10 亿美元,上线不足 200 天

按 OpenAI 8 月 31 日官方公告的口径:数万家广告主在使用,业务覆盖 40 多个国家,ChatGPT 周活跃用户超过 10 亿;「Pixel 和转化 API 已成为衡量与优化的重要基础」;并强调广告主无权访问用户的私人对话。据投资人披露的口径,OpenAI 2026 年广告收入目标 25 亿美元,2030 年 1000 亿美元。

广告主确实拿不到你的对话,但「衡量转化」需要知道看过广告的人有没有在别处下单——__obi 就是这条链路里的中间件。它把「在 ChatGPT 里看过一则广告」和「在 Chewy 上买了一次狗粮」接在了同一个人身上。

它证明了什么,没证明什么

边界要说清楚,这决定了你该有多紧张。

已被独立核验的:机制与代码(我下载脚本逐段读的)、绑定端点的访问控制(我实测的)、Cookie 分类(OpenAI 官方政策页原文)。研究者实测、我未能复现的__obi 真的随广告主页面的请求回传。我没有登录态的 ChatGPT 账号和安卓 Chrome 环境,这一步没跑通。仍是推断的:OpenAI 服务端是否把回传落到你的账号上——观测到的只有 202(已接受),研究者本人在文末写明「这个 join 没有被观测到」。

受影响的人也没那么多:观测环境是安卓版 Chrome;iOS 上所有浏览器跑的都是 WebKit,Safari 的智能防跟踪拦第三方 Cookie,机制不生效;桌面 Chrome 未测;大约每 5 次 ChatGPT 会话才下发一次令牌。

放在广告行业里,这套机制与 Meta Pixel、Google 标签是同构的:登录态、第三方 Cookie、站外转化归因。不一样的地方在于它跑在一个 AI 对话产品上——人们会告诉 ChatGPT 一些不会发朋友圈的事,而这个产品正在越来越多地替人做决定。研究者的原话是:机制本身是标准广告技术,没有先例的是它跑在 AI 聊天产品上。

想关的话,路径在 ChatGPT 的设置 → 数据控制,那里有分析和营销两个独立开关,可以只留一个。另外,广告主自己也看不到 __obi,它在广告主脚本读不到的域上——所以别指望商家能替你把这件事关掉。

我的判断是:这不是漏洞,是选择。OpenAI 在 Cookie 政策里如实登记了这枚 Cookie,也在代码里划了红线,但它没有把「分析型 Cookie 会被用来做跨站身份绑定」这件事讲明白。在广告收入年化冲上 10 亿美元的当口,讲明白的代价,大概比划一条红线要高。

相关阅读:OpenAI推出自助广告管理工具:AI广告投放如何变现?OpenAI 与微软未删节文件曝光:Copilot 把纽约时报点击率打掉 93%,内部称抓取是「史上最大劳动盗窃」三人用 Claude 黑进 OpenAI 内部代码库:一个图片上传漏洞,72 小时打通到代码提交

关注 AI商业快讯,每天一篇 AI 热点深度解读。

Jev Ultrafast 端到端实测:三种静默假成功,与一个 HTML 属性的分界线

Jev Ultrafast 端到端实测:三种静默假成功,与一个 HTML 属性的分界线

上篇结尾我留了一句遗憾:没有 TypeSafe 的 API key,端到端跑不通,只能做离线审计。现在 key 有了,我在沙盒里装起 Chromium 136,让 browser-harness 接上 CDP 调试端口,把这个 Agent 真跑了起来。

六个场景跑完,结论比上篇更尖锐:模型是好的,眼睛是瞎的

而且瞎得很有讲究——有一个场景,我只往 HTML 里加了一个属性,任务就从「静默失败」变成「顺利完成」。

模型这一侧,我几乎挑不出毛病

先把 TypeSafe 的 API 单独拉出来测。观测点在中国大陆(沙盒出口是广州联通),到服务端的网络单程约 120 毫秒。

延迟。同一个请求连打 30 次,连接复用前提下:最小 334 毫秒、中位 382 毫秒、p90 422 毫秒、最大 999 毫秒。拆开网络路径看——DNS 22 到 43 毫秒,TCP 握手 237 到 375 毫秒,TLS 完成 496 到 738 毫秒,首字节 825 到 1215 毫秒。官方说的「端到端 70 到 500 毫秒」是在美国西岸笔记本上测的,从国内发出去,光网络往返就吃掉两百多毫秒。扣掉这部分,服务端处理大约在一百七十毫秒上下,和官方录制里那个「中位决策延迟 178 毫秒」对得上。

加问题不增延迟,这条是真的。官方文档原话是「Adding questions barely changes the response time」。我直接测:1 个问题 373 毫秒,5 个 393 毫秒,20 个 426 毫秒,60 个 426 毫秒。输入 token 从 305 涨到 1299,翻了 4.3 倍,延迟只涨 14%。这是它并行采样架构的真正红利,也是 jev-ultrafast 敢在一次请求里同时问四个问题(操作、点击目标、填文本目标、下拉目标)的底气。

255 这个数字是硬边界。官方博客提到 Jev 的选项基数上限是 255。我逐个试:250 个选项正常返回,255 个正常返回,256 个直接 HTTP 400,错误信息是「Too many choices. Must have at most 255 choices.」而 jev-ultrafast 的快照最多保留 250 个动作候选——这个数字不是随手取的,它是在 255 上留了安全余量。

校准稳定得反常。同一个判断连问 15 次,15 次全选同一个选项,被选项概率落在 0.78 到 0.83 之间,标准差 0.014,置信度 0.67 到 0.74。这个抖动幅度比大多数 LLM 的温度采样小得多。

真实页面上的决策质量也对。我把上篇从浏览器里抓下来的 Google Flights 真实元素表(21 个元素)连同完整任务喂进去,连跑 10 次:10 次全部选「Change ticket type. Round trip」——任务要求单程票,而页面默认往返,改票种确实是正确的第一步。置信度稳定在 0.70 到 0.77。

顺便修正上篇一个数字。当时我用「字节数 ÷ 4」粗估 token,现在有真值了:Google Flights 首页的真实请求体是 3,422 输入 token(我粗估 2,469,低估 39%),GitHub issue 列表是 6,729(粗估 4,316,低估 56%)。官方录制里那个「17 次请求 90,558 输入 token」,统计口径是可信的。

端到端:六个场景,三类失败

关键前提:Google Flights 在中国大陆访问不了,所以我复现不了那 7.1 秒。我换了能跑的目标,并自己写了两个本地页面做对照。

需要说明一件事:jev-ultrafast 的 TYPE_TEXT 要另外配一个 OpenAI 兼容的文本模型(官方示例用 OpenRouter 的 mercury)。我没有第二个 key,所以自己起了一个本地桩服务顶替,按字段语义返回站名。下面凡是涉及打字的场景,文本是本地桩给的,不是真模型写的——这一点先讲清楚。

场景 结果 步数 DONE 置信度 成本
百度首页,点「新闻」进新闻首页 假成功 3/3 4 / 3 / 4 0.21 / 0.27 / 0.25 $0.0009–0.0011
百度新闻页,打开一条新闻 正确 blocked 3 $0.0010
本地页 A:规范 button、同标签跳转,三步下单 真成功 4/4 3 0.97 / 0.98 $0.00019
本地页 B:联想行用裸 div + onclick 假成功 3/3 2 0.85 / 0.86 $0.00022
本地页 C:B 的同一个页面,联想行加一个属性 真成功 3/3 3 0.92 / 0.93 $0.00030
12306 购票页,填两个站名 抛异常中断 1

三类失败,逐个说。

第一类:点得动,但点在了看不见的新标签页上。百度首页顶部那个「新闻」是个 target="_blank" 链接。Agent 点它——点击执行成功了,浏览器里也确实多了一个 news.baidu.com 的标签页——但它自己那个标签页纹丝不动,于是它开始 WAIT,等了三次之后,以 0.21 到 0.27 的置信度宣布任务完成。最终 URL 还是 https://www.baidu.com/。三次复跑,三次同样结果。

顺带一个副作用:每跑一次就在浏览器里留下一个没人回收的僵尸标签页。我三次复跑之后,浏览器里静静躺着五个 news.baidu.com

换上百度新闻页,链接同样是新标签打开,但这次 Agent 选择了连续重试点击——而连续三次「没变化的非等待动作」会触发它自己的停滞检测,于是正确报了 blocked。同一个根因,两种结局,取决于模型当时挑的是 WAIT 还是 CLICK。这个随机性本身就是问题。

第二类:看不见的选项,它就当不存在。本地页 B 是我照 12306 的控件结构做的:出发站输入框旁边有一排联想行,用裸 divonclick 实现,没有任何 ARIA 语义。Agent 的表现是——打字填「北京南」(成功)、点「显示建议」(成功)、然后直接 DONE,置信度 0.85。页面下方的「出发站:未选择」它压根没碰。

因为那三行联想行不在元素表里。它的眼睛是一张最多 250 项的清单,清单上没有的东西,它不知道自己没看见。

这正是仓库 issue #23 里那位用户拿 12306 真实页面跑出来的现象——60 个动作全部往同一个框里打字、77 秒、两个车站最后都填成「北京」。我用一个 20 行的本地页面,把那个机制精确复现了。

第三类:缺依赖时直接崩,不是降级。12306 真实页面能正常加载,快照抓到 54 个元素。但 Agent 第一步就去填顶部搜索框——那个输入框没有可访问名称,快照给它的 label 退化成 "textbox",只有 placeholder 简拼/全拼/汉字 留在 value 里。文本助手拿到 {"label": "textbox"} 这种上下文,当然判断不出该填什么,返回了 null,而 model.py 对 null 的处理是直接抛 ValueError 终止整个运行。这是一次都没走完就结束的第六个场景。

一个 HTML 属性的分界线

上面 B 和 C 两个本地页面,除了联想行是否带 role="option",其余 HTML 完全一样

  • B(裸 div):2 步,假成功,DONE 置信度 0.85–0.86,成本 $0.00022
  • C(加了 role):3 步,真成功,DONE 置信度 0.92–0.93,成本 $0.00030

多出来的那一步就是「点击北京南」。加一个属性,多花 $0.00008,结果从「它以为完成了」变成「真的完成了」。

这不是 jev-ultrafast 独有的毛病,任何靠元素表工作的浏览器 Agent 都会被这个问题绊住。区别在于它失败的方式:不是报错,不是卡住,而是干净利落地告诉你 done。

置信度不能当成功闸门

看到百度那三次 0.21 到 0.27 的 DONE 置信度,我一度觉得找到了通用解法:拿置信度当闸门,低于 0.8 就拒绝接受 DONE。本地成功案例都在 0.92 以上,看起来分得很干净。

然后本地页 B 打脸了:假成功,置信度 0.85。真成功的 C 是 0.92。0.85 和 0.92 之间画不出一条可靠的线,样本量也不支持我这么画。

背后的道理其实很朴素:Jev 的概率是诚实的,但它只能对「看得见的东西」打包票。看不见的选项不在它的视野里,它不知道自己没看见什么,于是给出的高置信度在语义上完全成立——在它能看到的那张表上,任务确实做完了。

所以真正能兜底的还是那老三样:独立的结果校验、任务级的断言、以及别把「模型说完成」当成完成。仓库自己也写了「DONE requires visible evidence」,还写了「A DONE choice still requires independent outcome verification」——问题是示例代码 examples/run.py 里没有任何校验,直接打印最终状态就退出了。

值得用吗

分三层说。

Jev 这个模型本身,值。$0.042 每百万输入 token、输出免费、同一判断连问 15 次结果逐位一致、255 个选项也能精确挑一个、加 60 个问题只慢 14%。我在这次全部测试里花的钱加起来不到一毛钱人民币,其中单个任务最便宜的只花了 $0.00019。要是有「分类、路由、打分、护栏」这类形状的任务,这是目前成本最低的选择之一。

jev-ultrafast 这个运行时,现在的状态是「能演示、不能托付」。它在规范控件加同标签导航的页面上确实快——三步任务 2.6 秒、$0.00019、动作序列和 token 数每次都逐位一致。但它对网页的可见性依赖得太死:target="_blank"、裸 div 造的控件、没有可访问名称的输入框,任意一个都会让它要么假装成功,要么直接崩。

如果真要接,先做三件事。一是给它一套你自己的结果校验,别信它报的 done;二是拿你真实要跑的站点先压一遍,特别是所有会开新标签的链接;三是确认那个 250 项上限够不够用——真实复杂页面的元素表随时会顶到天花板。

一句话总结:这 7 秒的演示是真的,$0.0039 的账单也是真的,但它省下的是「决策时间」,不是「网页理解」。真正卡住浏览器的从来不是模型不够快,是它只看得到被预先定义好的那一类控件。

想接着看,可以读这三篇:上篇《Jev Ultrafast 深度评测》 讲的是它的架构和 90,558 token 那笔账怎么算;Pi Agent 实测 讲的是同一件事的另一个方向——把工具数压到四个;unlazy 深度评测 解决的正是「Agent 说做完了怎么验」。

a-stock-data 深度评测:7,288 行的单文件塞进 34 个 A 股数据源,我实测跑通 76 个端点

a-stock-data 深度评测:7,288 行的单文件塞进 34 个 A 股数据源,我实测跑通 76 个端点

想让 AI 帮你查 A 股,最麻烦的从来不是写策略,而是把数据接进来:K 线藏在腾讯的分段参数里,盘后包是通达信的二进制格式,研报 PDF 要带东财的 Referer 头,龙虎榜和两融散在不同域名下,还要防着哪天 IP 突然被风控。a-stock-data 把这件事压缩成了一个文件:408 KB 的 SKILL.md,15 层、85 个端点、34 个数据源、零鉴权(只有一家要 Key)。

我把它 clone 下来做了独立复核:作者自带的 142 条测试我跑了,全过;我把 SKILL.md 里 89 个代码块里的代码全部抠出来,用真实参数调了 103 个函数名,76 个返回了非空真实数据。最大的那个端点一次给我 52,314 行,那是一个交易日沪深北全部证券的日线,下载加解析 10.4 秒。

但同一个文件也藏着一个代价:一次加载约 11 万 token。

一个文件,34 个数据源,零鉴权

先说清楚它是什么。simonlin1212/a-stock-data 2026 年 5 月 11 日建仓,到今天 132 天,9,992 星、1,819 fork,Apache-2.0,最新版本 V3.9.0 发布于 9 月 20 日(昨天)。

它不是 Python 包,没有 requirements.txt——作者明确说过这是有意设计的:整个项目就是一个 SKILL.md,拷进 ~/.claude/skills/a-stock-data/,Claude Code / Codex / OpenClaw 都能直接识别。文件里内嵌了 89 个 Python 代码块、5,638 行可运行代码,不是「文档告诉你怎么写」,而是「代码直接抄」。

覆盖的范围按作者自己的分层是 15 层:行情 K 线(腾讯日周月前后复权 + 1 至 60 分钟、通达信官网盘后包、百度、新浪复权因子)、研报(东财 + 新浪 + 同花顺 + iwencai)、市场信号(强势股归因、北向、板块归属、龙虎榜、解禁)、资金面与筹码(两融、大宗、股东户数、分红、ETF 份额、本地推演的筹码分布)、新闻(财联社、东财、华尔街见闻、新闻联播文字稿)、财务三表与 F10、公告(巨潮)、打板四池、ETF 期权希腊字母、舆情互动、宏观与利率(社融、PMI、中债收益率曲线、回购定盘利率、LPR、宏观日历)、指数与交易日历、期货与大宗商品(五家期货交易所)、事件驱动、可转债。另有 5 个备胎源,主源被封时降级用。

34 个数据源里,只有 iwencai 需要 API Key。这一点我实测验证过:不填 Key 调 iwencai 的两个函数,返回的是 HTTP 401 no auth / not_found_apikey,报错清清楚楚,没有拿空表糊弄。

它的测试工程值得单独说:142 条测试,测的是 SKILL.md 里那份代码

这是我这次复核里最意外的部分。仓库根目录只有 14 个文件,其中两个测试文件合计 11.4 万字节。它们的加载方式是这样的:

skill = (Path(__file__).resolve().parents[1] / "SKILL.md").read_text(encoding="utf-8")
# 按  之类的标记块切出来,再正则取 ```python 段
exec(compile(block, "SKILL.md:official-data-core", "exec"), namespace)

测试不测第二份实现,而是把 SKILL.md 里的代码当场抠出来执行。这个选择很关键:绝大多数「文档型工具包」的测试会和文档漂移,这里从机制上漂不了。

我跑的完整离线套件:142 条测试,23.1 秒,全部通过(2 条跳过)。断言写得也很具体,比如「腾讯 K 线三段窗口每段都回同一根日期时,只按总区间过滤会静默返回 1 根」「盘后包里空的北交所文件会被沪深 13,000 行盖过去」「代码表用 replace 解码会把坏字节变成 �00000 放行」。

作者在 docs 目录留了两份《数据源整合记录》,里面写了验证方法:每个修复都做变异检查——把修复改回去,对应测试必须失败。V3.9.0 那份记录里写着 209 处变异,发布前复跑适用的 190 处,186 处全部失败,4 处属双重保护。

同一份记录里还有一句很诚实的话:「本次没有重跑旧版 60 个入口的全部真实请求,它们的历史验证日期保留在原章节。」——这也正好说明我这次独立复核补上了什么。

我的独立复核:76 个端点返回真实数据,两次扫描的失败项还不一样

先说作者自带的联网测试。V3.9.0 的 31 个新入口用真实交易日跑,我跑了两轮,每轮 30/31 通过,但两轮失败的不是同一个端点:第一轮挂在通达信盘后包(下载被截断,BadZipFile),第二轮挂在 ST 名单(返回空,报「不能当成完整快照」),而单独复跑这两个端点又都正常(ST 名单 208 行,盘后包 52,314 行)。同一份代码、同一个网络,失败项在漂——这就是这类工具的日常。

官方数据源的联网用例 142 条里 140 过 2 错:中证指数那台 xls 主机连不上(同一次运行里国证成分 100 行是好的),以及上交所两融备份报「该日数据未发布或分页不完整」,而同一天的深交所版返回 2,105 行。

然后是我自己的扫描。用真实参数(贵州茅台 600519、2026-09-18 交易日)逐个调用:

端点 拿到什么 行数
tdx_daily_package 一个交易日沪深北全部证券日线 52,314
options_daily(中金所) 股指期权日行情与 Delta 6,546
sge_spot 上海金现货日线 2,368
equity_pledge 股权质押 2,212
lpr_history 1 年 / 5 年 LPR 全历史 1,538
futures_position_rank 会员持仓排名 1,320
etf_shares 上交所 ETF 份额 912
repo_fixing_rates 回购定盘利率 747
eastmoney_reports 个股研报 500
st_stock_list 沪深京 ST 名单 208
em_zt_pool 涨停池(78 只) 78
sina_research_reports 新浪研报列表(第二来源) 40

103 个函数名里 76 个返回非空真实数据。没通过的那批,我把原因分成了三类:沙盒环境(申万站点在这台机器上 SSL 证书校验失败,curl 同样失败;通达信 TCP 那条路因为 #52 已经失效,报错前要等 93.57 秒逐台验活 10 台服务器)、源侧风控(东财 push2 系连着调之后直接拒连)、我自己的参数(期货实时接口不吃股票代码)。

还有一类要特别点出来:报错质量。北交所快照接口传旧日期会明确抛「北交所快照不是请求的交易日;本接口不提供历史回填」,而不是给你一份错的行情。这个项目把「确实没有数据」和「接口坏了」分开报错,是它跟一般爬虫脚本最大的区别。

装上去才会撞见的六个坑

第一,lxml 不在安装命令里。SKILL.md 的安装说明是 pip install mootdx requests pandas stockstats numpy baostock xlrd openpyxl,但 ths_eps_forecast()(机构一致预期 EPS)和 full_valuation() 走的是 pd.read_html,缺 lxml 就直接 ImportError: Missing optional dependency 'lxml'。我补装后,这两个端点分别返回 3 行和 12 行。有意思的是,被拒的社区 PR #22 里恰好有一条改动就是「ths_eps_forecast() 增加 lxml 依赖说明」。

第二,baostock 是硬依赖。估值历史(PE/PB/PS/PCF + 换手率 + 停牌 + ST)和上市退市日这两个端点只走 baostock,装上才有数据(6 行标的信息、14 行估值历史)。作者在 CHANGELOG 里承认过:「零第三方封装依赖」这句话现在只适用于其余端点。

第三,日期格式是 YYYYMMDD,填错不报错。em_zt_pool("2026-09-18") 返回 0 行、没有任何提示;em_zt_pool("20260918") 返回 78 行。同一个库里多数端点的日期参数是 YYYY-MM-DD,只有打板层这几个要紧凑格式,是很容易踩的静默空。

第四,东财风控是真的,而且表现为「静默空表」。作者的对策做得很扎实:所有东财请求统一走 em_get()——串行、最小间隔 1 秒加随机抖动、复用 Keep-Alive 会话、403 不重试(重试反而加重)、带正常 UA 与 Referer。但我连着扫了一百多次调用之后,push2 系端点开始连接被拒;更麻烦的是同一组参数在两次扫描里,资金流端点第一次返回 100 行、第二次返回 0 行。调用方拿到的不是报错,是空表

第五,通达信那条路已经半废。tdx_client() 依赖的 mootdx 库 2024 年就停更了,2026 年 9 月起通达信公开服务器的 K 线、盘口、逐笔全部返回 0 行(issue #52,作者自己开的)。现在只剩财务快照和 F10 能用,K 线改走腾讯和通达信官网盘后包。作者没有删掉这个端点,而是让报错直接指路——这个处理是对的,但你要是照抄了半年前的教程,会先浪费 90 秒等它失败。

第六,SKILL.md 里没有免责声明。README 的最后有「本项目仅提供数据获取工具,不构成任何投资建议」,但这份 408 KB、真正被 AI 读进上下文的文件里,一个字都没有。它面对的是「帮我看看这只股票」这类问题,而投资建议的边界只写在不会进模型上下文的那个文件里。

争议:社区要拆四次,作者的原话是「有意产品决策,长期保持」

a-stock-data 最有意思的地方不是它写了什么,是它长成了什么形状。

SKILL.md 现在是 408,549 字节、7,289 行,其中 41,945 个汉字、89 个代码块、5,772 行代码。Anthropic 官方《Skill 编写最佳实践》里有一句:「将 SKILL.md 正文保持在 500 行以内以获得最佳性能;接近此限制时将内容拆分为单独的文件。」这里是那个数的 14.6 倍。

它不是一天长成的。我把每个提交点的文件大小拉了出来:5 月 30 日的 v3.2.1 是 2,090 行 / 78 KB,7 月 10 日 2,648 行,8 月 19 日 4,137 行,9 月 20 日的 v3.9.0 一步从 4,552 行加到 7,288 行——113 天里行数涨了 3.5 倍,字节数涨了 5.2 倍。

社区不是没看见。6 月 2 日 issue #21 的原话是「当前 skill 巨大,读一次 token 就没好多」;6 月 3 日有人交了 PR #22,一份完整的渐进式披露重构:把 SKILL.md 改成轻量路由入口,端点实现拆进 scripts/,说明拆进 references/,连 agents/openai.yaml 和 smoke test 脚本都写了;6 月 17 日 #27 建议用 Anthropic 的 skill-creator 重新 review;6 月 22 日 #29 逐条给出了拆分方案,包括统一 JSON 输出契约。

作者 7 月 10 日给了最终答复,并把理由摊开:单文件自包含是有意产品决策,长期保持,不做目录化拆分。三条理由——① 「形态即卖点」,拷一个文件就能用,过去两周有 3,000+ 人 clone、1,400+ 人直接在 GitHub 上读 SKILL.md,拆分换不来这种可携性;② 单人维护下「拆分版 + 单文件版」双形态必然漂移,漂移比 token 成本更伤用户;③ token 痛点用不改形态的方式缓解——把 description 收窄,因为「误触发才是最大的浪费」,当时的口径是「此前任何 A 股话题都可能误触发加载 50K token」。

第 ③ 条是真的落地了:现在的 description 明确写着「仅在需要调用数据接口取数时使用」,并且点名排除「A 股概念解释、投资观点讨论、策略问答」;文首还有一张「端点路由速查」总表,鼓励按需局部读取。

但数字也摆在明面上:他当时说「误触发一次 5 万 token」的时候,文件是 2,177 行;现在是 7,289 行。按常见分词器粗算,一次完整加载约 11 万 token(我的算法:4.2 万个汉字约 1 token 一个,26 万字符的代码与英文按约 3.5 字符一个 token,实际数字取决于分词器,但量级没有争议)。他自己在 #21 里留了后门:「如果未来端点规模翻倍、单文件确实不可持续,会重新评估」——v3.2 到 v3.9,端点从大约 30 个走到 85 个。

还有一个数字值得一起看:这个仓库 12 个 PR,一个都没合并。作者在 issue 里承认过 PR 里的问题,然后自己重写一遍进 CHANGELOG(比如 PR #20 的巨潮 orgId 动态化,v3.2.2 里以作者自己的改动落地)。这不一定是坏事——issue #27 里一位用户让 GLM 跑 review,报的五条里最重的一条被作者核对后确认并修掉:full_valuation() 按列位置 iloc[2] 取 EPS,实际取到的是同花顺的「最小值」列而不是「均值」,导致 PE 与 PEG 长期系统性偏差。作者改成了按列名取。但你也该知道,这个仓库的演进节奏完全由一个人决定。

顺带一句:这类工具的地基一直在动。CHANGELOG 的 FAQ 里有一节叫「已死透别用」——网易财经整站下线、和讯、凤凰行情、腾讯资金流接口、雪球免登录数据,全死了;mootdx 库 2024 年停更;2026 年 9 月通达信公开服务器的行情命令集体返回 0 行。「34 个数据源」不是一个稳定数字,而是一份随时会过期、需要有人持续跟进的快照。

判断:什么时候该拷这个文件

它值得用的场景很明确:你要让 AI 或者脚本以最低的安装摩擦拿到 A 股数据,能接受「一个人维护、会随版本跟进」;你在国内网络(我这台机器出口是广州联通的 IP,实测 76 个端点直接返回真实数据);你需要的是单次或低频取数,认可它把数据边界写清楚的做法——每个端点标注数据来源、口径、实测日期,连「大商所官网有 JS 反爬、HTTP 返回 412 所以没接」都写在文档里。这种诚实度在国内数据接口项目里并不多见。

不该用的场景也一样明确:别把它装成常驻自动触发的 skill,除非你已经想好每次触发 11 万 token 的代价,更划算的做法是把它当一个手册放在项目目录里,让 agent 按层局部读——这也正是作者推荐的用法;别拿它做高频批量,东财的风控会以「空表」而不是报错的形式找上你;别指望回测,作者的 FAQ 里写明了本 skill 不带回测;也别指望所有源永远活着,你真正买到的是「源死了有人改」这条流水线。

类似的取舍在其他评测里也出现过:零密钥的方案往往要靠轮换多个不稳定的公开源来换取免注册(Wigolo,18 个搜索源实测只剩 1 个在干活);而当一个生态由单人维护时,社区贡献会以「被采纳但不合并」的方式落地,这一点在 Spec Kit 那份评测里也能看到同一个规律。

至于「单文件还是渐进式披露」,这不是一个非黑即白的工程问题。作者用 113 天和一个 408 KB 的文件给出了他的答案:可携性优先,token 靠收窄触发来省,而不是靠拆目录。这个答案在「拷走就能用」的传播场景里是成立的,在「长期常驻、天天触发」的用法里就不成立——所以真正需要你自己判断的,不是他对不对,而是你打算怎么用它。

阿里达摩院 RADAR 深度拆解:一次腹部 CT 看 146 项发现,26 位放射科医生里赢 23 位,但权重禁止商用

阿里达摩院 RADAR 深度拆解:一次腹部 CT 看 146 项发现,26 位放射科医生里赢 23 位,但权重禁止商用

26 位放射科医生坐在同一场测试里,23 位的平均准确率输给了一个模型。

9 月 17 日,这篇研究登上了《Science》,题目是《An expert-level generalist AI for abdominal CT diagnosis》;9 月 18 日,阿里巴巴达摩院把模型权重放上 HuggingFace,宣布开源。国内媒体当天跟进的口径几乎一致:全球首个「专家级」通用医学影像 AI,一次腹部增强 CT 能识别超过 146 种病症。

我把代码仓库拉下来、把权重页面和许可证逐个点开之后,第一句话就卡在许可证那一行:权重写的是 CC BY-NC-SA 4.0,NC 是 NonCommercial,禁止商业使用。

数字先摆出来:这篇论文证明了什么

论文的核心是一个叫 RADAR 的模型(Rapid Abdominal Diagnosis with AI and Radiology)。它跟此前影像 AI 最大的区别是打法:过去一个模型对应一种病,RADAR 把一例腹部增强 CT 按解剖结构拆开,再对照放射科报告学「这个部位的这句话对应什么影像表现」,一次性输出整份发现清单。

官方新闻稿与论文摘要给出的数字如下:

项目 数字
训练数据 424,911 例腹部增强 CT、150 万图文对、1500 万解剖级配对
覆盖范围 18 个解剖结构、146 项影像发现
平均 AUC 0.913(同批对比中最好的同类视觉语言模型为 0.776)
急诊场景 27,000 例以上急诊 CT 上 AUC 0.904,且训练未使用急诊数据
外部泛化 8 家外部中心,AUC 0.895
读者研究 26 位放射科医生,AI 辅助下诊断敏感度提升约 10%
作者与机构 40 位作者,达摩院与多家医院合作,含浙江大学医学院附属第一医院

AUC 是区分有病与没病的能力指标,1.0 是完美,0.9 以上在影像 AI 里属于可用的高水平。论文摘要的结论句是:通用型 AI 已经能在常规与复杂阅片任务上达到人类专家水平。

数据之外还有一段传播更广的说法:模型的平均准确率超过了 26 位参与者中的 23 位。这句话来自达摩院对研究的转述,被南华早报等媒体引用后,变成了中文标题里的「AI 赢了 23 位医生」。它和摘要里那句「辅助提升敏感度 10%」其实是两组不同的实验。

开源清单:我把仓库逐个点了一遍

「开源」这个词在这件事里需要拆开看,因为同一项目在三个地方用了三种许可证。

内容 是否开放 口径
代码 开放 GitHub 仓库 alibaba-damo-academy/damo-radar,Apache-2.0,可商用
模型权重 开放下载 HuggingFace 上共 6.4 GB,许可证 CC BY-NC-SA 4.0,禁止商业使用
训练数据 不开放 424,911 例只存在于论文里,一例影像都没放出来
外部测试数据 部分开放 用的是斯坦福 MERLIN 数据集,需向斯坦福申请下载
处理后的掩膜与重采样图 开放下载 HuggingFace 数据集,960 次下载,同样是非商用许可
代码归档 开放 Zenodo 存档 379 MB,许可证又写成了 CC-BY-4.0

代码仓库本身 510 MB,89 个 Python 文件、18,718 行,其中 7,633 行是从 Salesforce 的 LAVIS 视觉语言框架搬来的底座,达摩院自己的工程量大约一万行上下。仓库 7 月 3 日就建好了,比论文上线早了两个半月,45 次提交,最后一次推送是 9 月 18 日。

权重文件也能看出这个模型的体量:RADAR+ 主检查点 1.65 GB,预训练版 1.57 GB,单独的 UNet 视觉分支 208 MB,另有中英文两个 BERT 文本编码器,分别 412 MB 与 440 MB。也就是说,它的文本端是 BERT-base,视觉端是 3D UNet 与 ResNet,不是大语言模型。

想真正跑起来,门槛写得挺实在:官方文档要求单张 A100 或 H20 显卡,演示用的一例原始腹部 CT 体积 98 MB,预处理还要装 TotalSegmentator 分割 104 个解剖结构,报告解析脚本则要填 DashScope 的 Qwen 接口密钥。仓库里附带的外部测试结果有 5,125 例样本,但只覆盖 20 项发现——那是斯坦福 MERLIN 数据集有标签的那部分;146 项的完整逐例结果并不在仓库里。

还有一个细节值得记一笔:两天过去,仓库 323 星、37 次 fork,两个 issue 都还开着没人回。一个问「会不会有在线 demo」,另一个来自苹果芯片用户,说自己花时间把推理路径改成 MPS 跑通,只需要改 3 个文件、14 处设备调用,推理链路里没有任何自定义 CUDA 算子、纯 fp32,并附上了数值等价的验证。这是一个挺客气的补丁,目前还挂着。

三个被标题盖住的细节

第一,146 是「发现」,不是「病」。 我把模型输出的 146 列标签导出来看了一遍,里面既有直肠癌、胆管癌、胰腺肿瘤这类疾病,也有大量描述性条目:主动脉钙化、肝脂肪肝、脾副脾、膀胱憩室、肾上腺钙化、肋骨骨折、肝内钙化灶。官方中文口径写的是「识别超过 146 种病症」,读者很容易理解成能查出 146 种独立疾病,实际清单里相当一部分是阅片时顺带记录的表现。

第二,「赢了 23 位医生」是另一组实验。 论文摘要里读者研究的原句是「RADAR 辅助把 26 位放射科医生的诊断敏感度提升了约 10%」;而「平均准确率超过 23 位参与者」是模型单独阅片与医生单独阅片的对比。前者说的是 AI 帮医生少漏诊,后者说的是 AI 与医生同台竞争,两者都会被引用,但混在一起说就成了「AI 取代医生」的标题。官方还提到,在 AI 辅助下医生用时减少 30% 以上。

第三,它只吃增强 CT。 腹部增强 CT 要注射造影剂,属于有创的诊断检查,不是体检筛查。达摩院自己那条更出名的产品线走的是相反路线:用最常见的平扫 CT 做「一扫多筛」。所以 RADAR 的定位是诊断环节里的读片助手,不是把体检变成 AI 初筛。

另外,从论文摘要和官方新闻稿看,所有评测都是在已有病例上完成的回顾性评估,公开材料里没有前瞻性临床试验的结果;同批对比中那个 AUC 0.776 的「最好的同类模型」也没有被点名。

达摩院的医疗 AI 已经走了四年,这是通用化那一步

把 RADAR 放回时间线,会更容易理解它为什么值得上《Science》:

  • 2023 年 11 月,胰腺癌平扫 CT 早筛研究登上《自然·医学》,在两万多例真实病例的回顾性试验里找出 31 例临床漏诊病变
  • 2025 年 4 月,胰腺癌筛查模型 DAMO PANDA 拿到美国 FDA 的「突破性医疗器械」认定
  • 2025 年 11 月,GE 医疗与达摩院签署合作框架意向书,把 CT 影像 AI 往设备侧推
  • 2026 年 3 月,「胰腺病变 CT 图像辅助分诊软件」进入 NMPA 创新医疗器械特别审查程序
  • 2026 年 4 月,肠癌「无感」筛查研究登上国际肿瘤学期刊

这条路线一直是「一个模型查一种病」,RADAR 则是把单病种模型收拢成一个通用底座,再靠解剖级对齐把泛化撑起来——外部 8 家中心 AUC 只掉 0.018,急诊场景没训练过也能到 0.904,这两个数字才是它进《Science》的理由。

对照物也很清楚。RADAR 的外部测试集就是斯坦福的 MERLIN 数据集,而 MERLIN 团队自己在 2024 年发布的 3D CT 视觉语言基础模型,走的正是同一条「通用模型」路线,并在 2026 年发在《自然》上。这一年里,通用影像模型这条线被两本顶级期刊各认可了一次。

但商业化的距离还摆在那:许可证禁止商业使用,模型也没有医疗器械注册证。对医院和厂商来说,短期内它只能当研究基座,不能直接变成产品。

结论:值得抄的是方法,不是权重

这件事最值得带走的不是 6.4 GB 的检查点,而是它证明了一条可复制的训练路径:用现成的分割工具把 CT 按解剖结构切开,用大模型解析临床报告拿到弱标签,再用解剖级对比学习把影像和文字对齐。 整条链路不依赖人工标注,这才是 42 万例数据能跑出结果的原因。国内做影像 AI 的团队真正能借鉴的,是这套「不靠人标注」的工程范式,以及官方在仓库里公开的预处理代码与报告解析脚本。

至于那份权重,科研可以下,产品化要谨慎:非商用许可加上没有注册证,决定了它在国内医院里暂时只能以研究合作的形式出现。

对普通读者,一句话判断:一次 CT 给出 146 项发现,这件事是真的,也是影像 AI 近年少见的硬进展;但它替代的是读片流程的第一步——把该看的地方全部标出来,而不是放射科医生。

关注 AI 商业快讯,每天一篇 AI 热点深度解读。

相关阅读:

Jev Ultrafast 深度评测:7 秒搜完机票的浏览器 Agent,一次决策只发一个请求

Jev Ultrafast 深度评测:7 秒搜完机票的浏览器 Agent,一次决策只发一个请求

7.1 秒,从一句自然语言,到 Google Flights 上列出苏黎世飞伦敦的航班,全程 1 倍速录屏,包含文本生成、模型调用和加载等待。Browser Use 与 TypeSafe 合作的开源 Agent 仓库 jev-ultrafast 靠这个数字刷屏,9 月 16 日创建,三天冲到 8,346 星。

我把它 clone 到本地,跑了官方全部离线测试,审计了它「一次决策要发几次网络请求」,把两个真实页面的动作表重放成请求体算了账,还独立复核了那段 7.1 秒视频和 $0.0039 的账单。

先说清楚一件事:我没有 TypeSafe 的 API key,没能跑通端到端任务。TypeSafe 目前是 waitlist 制,仓库 issue 里有人直接问「怎么拿到 TYPESAFE_API_KEY」。所以下面所有结论来自三处可独立验证的材料:官方 31 个离线测试与源码、官方公布的录制数据、以及我用真实网页 DOM 做的重放。跑不通的部分我会标出来。

7.1 秒是真的,但计时器是后开的

官方性能文档写得很直白:计时起点是「初始首页观察之后的第一次预测」,终点是「被接受的 DONE 选择」。浏览器启动、初始导航、以及任务结束后的独立结果校验,全部在计时之外。

这不是注水,是常规口径,但读者该知道这 7.1 秒买的是什么:页面已经打开、正文已经渲染完之后,Agent 从「看第一眼」到「确认结果正确」的耗时。

视频我也复核了。ffprobe 读出来 7.566 秒、227 帧、恒定 30fps;7.566 秒 = 公布的 7.073 秒运行 + 0.5 秒结尾停留,时间轴对得上。把浏览器画面区域单独裁出来逐帧比对,227 帧里有 224 帧互不相同——它不是靠重复帧把时长凑出来的。

有一处对不上:测量文件里写 video/source_frames = 187,而视频实际是 227 帧。这更可能是渲染脚本重跑之后元数据没同步,但可以确定的是,视频右下角那个跳动的秒表是渲染时按帧序号算出来的,不是硬件计时器。所以「1 倍速」这件事,外部无法只靠看视频证明,它依赖录屏时间戳被忠实映射。

还有一点值得给作者加分:官方在性能文档里保留了匹配对照的完整数据,三对样本,中位耗时 9.450 秒降到 7.092 秒,然后自己写了一句「三对样本太少,做不了强统计声明(双尾符号检验 p = 0.25)」。同一份文档里还留着自己失败的开发尝试——有一次跑到 8.697 秒更快,但独立校验没通过,被毙了。愿意把推翻自己的数据留在仓库里,这在爆款项目里不多见。

它把「决策」从字符串生成里抠了出来

jev-ultrafast 不是一个模型,是 Browser Use 给 TypeSafe 的 Jev 模型写的一层浏览器运行时。

Jev 是 TypeSafe 9 月 15 日发布的 System One 模型。它的输出不是文本,而是类型安全的决策值加校准概率——你事先定义好问题和选项,它一次查询并行吐出所有选项的概率,不做逐 token 自回归。官方定价 $0.042 每百万输入 token,输出 token 免费,端到端 70 到 500 毫秒。名字取自杰文斯(William Stanley Jevons),那位提出「效率提升反而推高总消耗」的经济学家。

这套东西落到浏览器里,做法是这样的:每次观察页面,运行时生成一张带编号的元素表,每个可见控件占一个索引(同一个 DOM 节点即使既能点又能填,也只占一个索引)。然后把整个目标、页面正文、元素表、最近十步动作打包,一次请求里同时问四个问题:下一步做哪个操作、如果点那么点哪个、如果填那么填哪个、如果下拉那么选哪项。

只有被选中的那个操作对应的目标头会被读取,其余的即使模型答了也不执行。这样一来,过去「先问该做什么,再问点哪里」的两次往返被压成一次,同时保证了不会拿一个 TYPE_TEXT 的目标去执行点击。

整个 Agent 主循环 agent.py 是 174 行。快照逻辑 snapshot.js 107 行。

我把它的每一步都拆开算了

离线部分全部通过。官方测试 31 个断言 1.04 秒跑完,一个不挂;ruff 静态检查干净;两个前端脚本 node --check 通过;uv build 能正常打出 wheel。代码总量 1,681 行 Python(其中测试 320 行),对一个需要驱动真实浏览器的项目来说小得反常。

一次决策确实只有一次网络往返。 我替换掉 HTTP 客户端做拦截,捕获到的请求体里同时挂着四个问题头:operationclick_targettype_text_targetselect_target。返回的答案里,目标头带着完整的概率分布,但代码只取与所选操作匹配的那一个。README 里「两个决策,一次网络往返」的说法成立。

真实页面的账单我也算了。我用浏览器在目标站点上原样跑了一遍官方的快照脚本,拿到真实的动作表,再喂回官方 Python 的 action_space()choose() 生成请求体:

页面(1120×780 视口) 可点元素 请求体 粗估 token
Google Flights 首页 21 个元素 / 24 个动作候选 9,935 字节 2,483
GitHub issue 列表页 57 个元素 / 60 个动作候选 17,395 字节 4,348

拿这个数字去对官方录制:那次跑动用 17 次请求消耗 90,558 输入 token,均摊每次 5,327 token。我的重放是 2,483 到 4,348,量级一致——说明 90,558 这个统计可信,而且后续步骤因为要带上历史动作和更满的结果页,单次开销还会涨。

账单也算得回来。90,558 × $0.042/百万 = $0.0038,官方宣传的任务成本是 $0.0039,差 2.6%,基本就是四舍五入。输出 token 不收费。折算下来一次跨境航班搜索不到 3 分钱人民币,而且这个数字里还不含浏览器和文本助手的开销(那部分官方实测是 $0.00006272)。Doom 那个演示跑 10 次决策每秒,作者说约合 $7 每小时。

安全边界经得起打。README 声明「模型输出永远不会变成选择器、坐标、shell 命令或可执行 JavaScript」。我构造了六种畸形响应去打它:把 choice 换成 document.querySelector('#x')、换成一段 script 标签、概率之和只有 0.5、概率里塞 NaN、选了个不是最大概率的选项、概率集合和候选对不上。六种全部被拦,一行动作都不会执行。

顺带发现一个代码里没写的原因:快照最多保留 250 个动作候选,而 TypeSafe 官方博客明确说 Jev 的选项基数上限是 255。250 这个数字大概不是随手取的。

视频、代理,和两个 AI 编出来的 issue

代理这一条,中文用户几乎必踩。issue #16 报告:httpx 在模块导入时就建了连接池且不处理代理,只要环境变量里有 ALL_PROXY=socks5://,程序在 import 阶段直接崩,报 ImportError: Using SOCKS proxy, but the 'socksio' package is not installed。我在沙盒里原样复现了。Clash、v2ray、xray 的默认配置都会导出这个变量。

代码默认值里还埋了一个坑。文本助手的 base URL 在代码里的默认值是 https://api.deepseek.com/v1,而 .env.example 和 README 写的是 OpenRouter。也就是说,一个人照着 README 只填了 TEXT_MODEL_API_KEY 就运行,他填进去的 OpenRouter 密钥连同页面文本会被发到 DeepSeek 的接口上。这条是 issue #36,我核对源码 164 行属实。

生态侧的数据就不那么好看了。仓库三天收了 40 个 PR,39 个没合并,唯一合掉的是作者自己改 README 的一条。16 个 issue 全部处于 open,一个都没关闭。三位贡献者里只有一位(作者本人),3 个 commit。

更麻烦的是信噪比。这里面混着明显是 AI 生成的幻觉报告,其中一条标着 HIGH:声称 README 的 clone 地址指向了错误的仓库——我 clone 过了,地址是对的;另一条说 agent.py 被压缩成了一行行的超长代码、违反项目自己的 120 字符行宽——实际文件 174 行、格式正常、ruff 检查干净。两条出自同一个账号,前后相隔 7 分钟。

也有真材实料的报告。issue #23 里,一位用户拿中国铁路 12306 的购票页去跑,结果是:60 个动作全部是往同一个输入框里打字,跑了 77 秒,120 次决策预算耗尽,出发站和到达站最后都被填成了「北京」。原因是快照只收集原生控件(a[href]buttoninput 等)和固定清单里的 ARIA 角色,而 12306 的站点联想行是用裸 lidiv 自己绑点击事件做的,模型根本看不见,只能反复重试它唯一看得见的那个框。

这暴露了动态索引动作空间的真实边界:它不是「看得懂网页」,而是「只看得见被预先定义好的那一类控件」。Google Flights 能用,是因为 Google 老老实实写 ARIA 标注。

值得看,但现在别急着拿它当脚手架

把结论分三层说。

方法层面,这个 demo 真的有价值。它证明了一件事:把「决策」从 LLM 的字符串生成里抠出来,换成一次并行的概率输出,是 Agent 提速最直接的一刀——不需要换更强的模型,不需要减少步骤,只是把「生成一段话再解析」改成「直接给答案」。这和 Pi Agent 砍工具数、unlazy 给完成状态装闸门是同一个方向:约束模型能做什么,比让它更聪明更有效

工程层面,代码值得读。1,681 行、31 个测试、零运行时依赖、主循环 174 行,还能把「模型输出不变成选择器」这条安全不变量守住。想自己写浏览器 Agent 的人,这个仓库一小时能读完,比啃框架文档快得多。

产品层面,别急着接。三点:TypeSafe 还是 waitlist,拿不到 key 的话开源代码只能跑离线测试;中文站点上表现堪忧,12306 那种非标准控件直接崩;官方自己承认这不是基准测试,只是「一个任务在一个已有浏览器配置上跑三次」,而且性能对照的 p 值只有 0.25。

一句话:7.1 秒是真的,$0.0039 也是真的,但这两个数字测量的是「决策够快」,不是「网页够懂」。

想继续往下看,可以读这三篇:Pi Agent 实测 讲的是同一件事的另一个解法——默认只给模型四个工具;unlazy 深度评测 解决的是「Agent 说做完了怎么验」;OpenRouter 免费大模型全量拆解 里则有 Jev 上架 OpenRouter 之后的路由逻辑。

Plugin4Shell 实测:分支名伪装成 SHA,四大 AI 编程助手的插件校验全线失守

Plugin4Shell 实测:分支名伪装成 SHA,四大 AI 编程助手的插件校验全线失守

你什么都没点,插件自己换了。

Claude Code、OpenAI Codex、GitHub Copilot、Gemini CLI——四款最主流的 AI 编程助手,插件市场用的是同一套校验逻辑,也犯了同一个错误。9 月 17 日,安全公司 Air 公开了这处漏洞,取名 Plugin4Shell:不点链接、不装新插件、不改任何设置,只要攻击者控制了你已装插件的上游仓库,恶意代码就会自己走进你的电脑。Air 称它是「AI Agent 生态的第一个供应链漏洞」,受影响的是「数百万个 agent」。

校验通过了,代码为什么还是会被换掉

给 AI 编程助手装插件,走的是包管理器的老路:市场把插件锁在一个具体 commit 的 40 位 SHA 上,这叫 SHA pinning。逻辑很干净——审过的代码就是这一版,谁再改都会露馅,这也是企业敢用第三方插件的前提。

四款 agent 都老老实实执行了「checkout 市场钉下的那个 SHA」,但没有一家检查「checkout 完,工作区里到底是哪个 commit」。这一处缺失就是整个漏洞。git 在解析一个名字时,如果它既能当 ref(分支/标签)又能当对象 id,会优先当成 ref,只在 stderr 打一行 refname '…' is ambiguous。攻击者在自己的插件仓库里建一条名字就是那串 SHA 的分支,把它设为仓库默认分支,agent 的 git checkout 就会把这条分支当成目标——审查、pin、安装流程全部显示正常。

要强调的是,受害者的操作没有任何问题。Air 的原话是:受害者只需要装了一个插件,来自他信任的市场,经过审查、并且「完全按照安全模型的设计」被 pin 住——企业把插件 pin 到审过的 commit 再分发,本来是把风险往下压的做法,这一层也同样被穿透,「所有建立在 pin 上的下游审查流程,都继承了这个失效」。

攻击有两条路。一条是先当好人:往市场里提交一个真良性插件,过审、被装,之后再把它变恶意——这件事 Air 此前已经做过一遍,那个假 skill 拿到了 26,000 个 agent 的控制权。另一条更省事:直接接管别人的仓库,让恶意版本顺着这条路径推给所有已装用户,而 pin 存在的意义本来是拦住这件事。

我把两个变体都跑了一遍

Air 描述了两条路径。我在本地沙盒(git 2.47.3)把它们都复现了一遍。

变体一是 Claude Code、Codex、GitHub Copilot 共用的写法:

git clone <插件仓库> ./
git checkout 59276317d87a72f4396ef9b61b0ba4be3e005e95   # 市场钉下的 SHA

这条 SHA 同时是攻击者建的默认分支名。执行结果:只有一行警告 refname is ambiguous,然后 plugin.txt 的内容是 MALICIOUS PAYLOAD,当前分支显示为那串 SHA。顺带核了一下前提条件,git check-ref-format refs/heads/<40位十六进制> 返回 0——git 自己就接受这种分支名

我还做了对照组:同样存在一条 SHA 同名分支,但它不是默认分支。这次 clone 下来它只是一条 remote-tracking ref,git checkout 落回了真正的 commit,HEAD 与 pin 完全相等,文件还是良性版本,攻击不成立。也就是说,「把 SHA 同名分支设成默认分支」是攻击的必要条件,不是可选动作。

变体二是 Gemini CLI 的三步写法:

git clone --depth 1 <插件仓库> ./
git fetch origin 41d0bc0a4aeb2fbf797dacea39e876d98c95024b
git checkout FETCH_HEAD

如果仓库的默认分支恰好叫 FETCH_HEAD,第三步同样只打一行 ambiguous 警告,然后落地恶意内容;此时 .git/FETCH_HEAD 文件里躺着的,仍然是那个被正确拉取的 commit——拉回来了,然后被丢掉了。

修复只要一行断言,Air 给的原话是:checkout 之后解析工作区真正的 HEAD,不等于 pin 就中止。

test "$(git rev-parse HEAD)" = "" || abort

这行必须写在 agent 里、不能交给市场,因为 pin 是在客户端解析的。这也正是它叫「零点击」的原因:后台自动更新是 Claude Code 和 Codex 的默认行为,市场一改 pin,所有已装用户会在没有任何提示的情况下被换成恶意版本——攻击者甚至不需要你装任何新东西,只需要那个良性插件本来就在你机器上。

四家的响应,和我在 npm 上核到的版本

厂商 产品 当前状态
Anthropic Claude Code 已修复,2.1.179(2026-06-17 确认)
OpenAI Codex 已修复,0.146.0(2026-08-12 验证)
GitHub / 微软 GitHub Copilot 未发补丁
谷歌 Gemini CLI 不修,直接弃用

Air 给出的时间线是:2026 年 5 月发现并对四款都做出可用 PoC,6 月完成披露,8 月 4 日谷歌确认不修、让用户迁到 Antigravity,9 月 17 日公开。

修复版本是不是真的发出去了,可以直接在 npm 上核:Claude Code 当前 2.1.278、Codex 0.155.1,都已经越过修复线;@github/copilot 停在 1.0.86,仍在更新但没修这个洞。Gemini CLI 更有意思——谷歌 8 月就说弃用,可 npm 上的 nightly 一直发到 0.62.0-nightly.20260919(9 月 19 日),仓库活着,只是这个漏洞不打算修了,已装的每一台都永久暴露。

微软一侧的说法值得单独记一笔。GitHub 发言人对 The Register 表示:为防止 SHA 被滥用,GitHub 不允许创建形似 commit SHA 的分支名或标签名,因此这个漏洞在 GitHub 上无法利用。Air 的回应是这条缓解不够,因为 Claude Code 官方文档明确写着市场可以托管在「任何 git 服务」上——GitLab、Bitbucket、自建服务器都行,而 Bitbucket 和自建 git 都允许 40 位十六进制分支名;微软自家的 Copilot 同样支持这些来源。Air 还补了一句:6 月起就向微软报告过,因为对方披露量太大,没有收到回复。

规模上有一组可查的数字:近 30 天 npm 下载量,Claude Code 6,486 万次、Codex 7,850 万次、GitHub Copilot 1,026 万次、Gemini CLI 139 万次,合计约 1.55 亿次(下载量不等于机器数,CI 会放大,但量级可参考)。这也不是 Air 第一次做这件事——此前它用一个假 skill 拿到过 26,000 个 agent 的控制权,SkillJacking 里发现 925 个在用 skill 的仓库可被接管、波及 134,000 个 agent,8 月又找出 155 个依赖过期域名、可被劫持的 MCP。

需要声明的是,Air 是一家 9 月 1 日刚走出隐身状态的创业公司,卖的产品正是 agent 防护,研究文末还写着「使用我们产品的企业不受此漏洞影响」「数据来源方在卖解药」这件事,读数字时要一起考虑。漏洞本身不受影响,因为上面的复现是我自己跑的。中文圈的报道到 9 月 19 日基本还是快讯:新浪财经、凤凰网各一条,其中凤凰写的是「除 GitHub 外其余三家已修复」——按 Air 的时间线,谷歌是明确不修、直接弃用,不是修复。

这次坏掉的其实是一个假设

Plugin4Shell 里没有一行复杂的利用代码,它打掉的是行业默认的一个安全假设:把 hash 钉死,就等于把代码钉死

这个假设在包管理世界里早就被拆过一遍——npm 后来补上了包签名和透明日志,因为「内容的哈希」只能证明内容没变,不能证明「你解析到的就是那份内容」。agent 生态正在把插件、skill、MCP 当作基础设施大规模铺开,校验逻辑却还停在「拿到一个 SHA 就 checkout」的水平上。四家实验室写出了同一个 bug,不是巧合,是这一层还没有人认真做过。

你该做什么

  • Claude Code 与 Codex 用户:升级到 2.1.179 / 0.146.0 以上(当前版本已远超),这是唯一完整的修复。
  • GitHub Copilot 用户:官方没有补丁。Air 给出的现实约束是,尽量只从 GitHub 托管的 marketplace 装插件,因为 Bitbucket 和自建 git 托管的市场都能被这种手法打穿。
  • Gemini CLI 用户:官方建议迁到 Antigravity,它没有这套插件 SHA pinning 机制,因此攻击面不存在;留在 Gemini CLI 上就是永久暴露。
  • 所有人:如果你所在团队的内部市场是自己 pin 的 commit,去检查一遍默认分支名有没有 40 位十六进制的;同时考虑关掉插件的后台自动更新,把更新动作变成需要人确认的一步。

一行断言就能修的东西,从披露到公开花了四个月,还有两家没修。Agent 的供应链安全,现在还处在包管理器的 2015 年——插件越多,这个账越难还。

相关阅读:

OpenRouter 免费大模型全量拆解:447 个模型里 25 个免费,最贵的三笔账不在价格表上

OpenRouter 免费大模型全量拆解:447 个模型里 25 个免费,最贵的三笔账不在价格表上

OpenRouter 上的「免费大模型」,价格是 0,但从来不是没有代价。今天官方模型接口返回 447 条记录,输入与输出价格同时为 0 的只有 25 条,占 5.6%。我把这 25 个逐条拉了下来——模型页、端点、延迟、吞吐、供应商数量、数据条款——结论是:免费池真正的成本,写在三张不在价格表上的账单里。(文中价格、额度与性能数据截至 2026-09-19,下单前请以官网为准)

免费额度怎么算:20 次/分钟、50 次/天,充值 10 美元换 1000 次/天

OpenRouter 做的是模型路由:一个 key、一份账单,覆盖 447 个模型、88 家供应商。2026 年 8 月它被 Stripe 以 70 亿美元收购,成为支付巨头押注的「模型路由入口」。

免费模型在这套体系里的位置,官方规则一共三档:

档位 每分钟 每天 条件
免费变体(累计充值少于 10 美元) 20 次 50 次 注册即可
免费变体(累计充值至少 10 美元) 20 次 1000 次 一次性充值 10 美元
付费变体 无平台级请求上限 不适用 按 token 计费

这 25 条免费记录里,22 个是带 :free 后缀的文本变体,2 个是 Google Lyria 音乐生成模型,1 个是随机路由。三个细节决定了这套规则的真实手感。第一,:free 不是一个开关,而是模型目录里单独的一行,有自己的定价、上下文长度和端点。第二,开小号没有意义——官方原文是「额外账号或 API key 不会改变限流,容量按全局治理」。第三,免费额度不花 OpenRouter 的钱,端点由供应商自己挂:NVIDIA 5 个、Google AI Studio 4 个、Novita 3 个,其余 9 家各 1 到 2 个,一共 24 个免费端点,外加一个随机路由的 openrouter/free

换句话说,免费池是供应商拿算力换曝光、换数据、换榜位的地方。这直接决定了下面三张账单。

账单之一:8 个免费模型,由「可能拿你的数据训练」的供应商托管

OpenRouter 给 88 家供应商都标了数据条款。整张表里,承认可能用提示词训练模型的只有 4 家:DeepSeek、Liquid、Thinking Machines、NVIDIA。除 DeepSeek 之外的 3 家正是免费池主力,一共托管了 8 个免费模型,占免费池的三分之一。

另外 10 个免费端点属于「保留提示词但不训练」:Google AI Studio 保留 55 天、Nex AGI 保留 30 天、Cohere 保留 30 天,Poolside 与 AtlasCloud 没有给出天数。真正零保留的只有 6 个:Novita 的 3 个 Ling、ModelRun 托管的小参数 Qwen、OpenInference 托管的是 DeepSeek V4 Flash、以及 Decart 托管的 GLM-5.2。

这里有个容易被忽略的开关:账户设置里,付费模型与免费模型的「允许训练」是两套独立设置。你关掉它,那 8 个免费模型会直接从可用列表里消失——免费档的「免费」,一部分就是用数据条款换来的。

账单之二:免费版只有一个供应商,付费版最多 26 个

这是全量拉取后最扎眼的一组数字。24 个免费端点,每一个都只有单一供应商;同一个模型的付费版本却动辄十几二十个源:DeepSeek V4 Flash 有 26 个、GLM-5.2 有 23 个、Qwen3.8 27B 有 16 个、Gemma 4 31B 有 12 个。付费端点的多源意味着挂了会自动切到别家,免费端点没有 fallback,供应商一抖就整个不可用。

还有 7 个免费模型在 OpenRouter 上根本没有付费版本:Nex-N2.5 的大小两档、Ling 3.0 Flash Sante、Dots3-Note Preview、LFM 2.5、Cohere North Mini Code、Nemotron 3 Nano。对它们来说,免费是唯一入口。

规格也不是同一份。免费的 GLM-5.2 上下文只有 32768,付费版是 1048576,相差 32 倍;免费的 Qwen3.8 27B 是 262144,付费 1000000;反过来 Nemotron 3 Ultra 的免费端点上下文 100 万,比付费版的 262144 还大。免费端点不是付费端点的打折通道,而是另一套参数完全不同的部署。

可用率同样不均匀。24 个端点里有 3 个状态异常;过去三天,Nemotron 3 Nano 的日可用率是 80.1%、83.8%、83.8%,Inkling 最低 88.2%,DeepSeek V4 Flash 最低 94.0%。72 个「模型乘日期」的样本里,19 个低于 99%。

账单之三:免费最强只有旗舰的 64.6%,而且用量榜第一并不是分数第一

模型接口自带 Artificial Analysis 的智能指数,全部 447 个模型里有 145 个给出了分数。把这 25 个免费模型放进去排序是这样的:

免费模型 上下文 智能指数 p50 往返延迟 吞吐 免费端点数据条款
DeepSeek V4 Flash 0731 1.05M 34.5 2064 ms 25 tok/s 零保留
GLM-5.2 32768 34.0 1164 ms 37 tok/s 零保留
Qwen3.8 27B 262K 33.9 626 ms 28 tok/s 零保留
Inkling 1.05M 25.5 1840 ms 35 tok/s 可能训练
Ling 3.0 Flash VL 262K 25.0 2361 ms 60 tok/s 零保留
Nemotron 3 Ultra 1M 23.4 3143 ms 19 tok/s 可能训练
Ling 3.0 Flash Fin 262K 23.0 1342 ms 136 tok/s 零保留
Gemma 4 31B 262K 15.4 1291 ms 22 tok/s 保留 55 天
Nemotron 3.5 Lightning 1M 13.6 5134 ms 16 tok/s 可能训练
Cohere North Mini Code 256K 9.9 601 ms 80 tok/s 保留 30 天

三个结论。免费最强 34.5 分,在 145 个有分模型里排第 40,只有付费旗舰 53.4 分的 64.6%——免费档够做事,但够不到第一梯队。用量榜第一不等于能力榜第一:官方按近 7 天真实 token 用量排的免费榜,第一是 Nemotron 3 Ultra(4.32T tokens),智能指数只有 23.4;分数第一的 DeepSeek V4 Flash 用量排第 4;分数第二的 GLM-5.2 连前 16 都没进。延迟与吞吐也和分数无关,最快的 LFM 2.5(2.6B 参数)吞吐 185 tok/s,最慢的 Lyria 只有 4 tok/s。

延迟高有一半要怪拥挤:官方 30 分钟统计窗口里,免费池一共处理了约 50.1 万次请求,其中 Nemotron 3 Ultra 一家 10.96 万次、DeepSeek V4 Flash 9.83 万次。这些请求共享 20 次/分钟的平台限流。

该不该用:三种用法可以,三种用法别碰

先说额度值多少钱。额度按请求数计,不按 token 计。以一次请求 800 输入加 300 输出 token 估算,同样是每天 1000 次,按各自最便宜的付费端点价折算:

免费模型 付费价(每百万 token 输入/输出) 1000 次折算 一个月折算
Inkling 0.95 / 4.05 美元 1.98 美元 59.2 美元
Nemotron 3 Ultra 0.50 / 2.20 美元 1.06 美元 31.8 美元
GLM-5.2 0.554 / 1.742 美元 0.97 美元 29.0 美元
Qwen3.8 27B 0.10 / 1.80 美元 0.62 美元 18.6 美元
Gemma 4 31B 0.09 / 0.34 美元 0.17 美元 5.2 美元
DeepSeek V4 Flash 0731 0.04 / 0.08 美元 0.06 美元 1.7 美元

同样是一次性充 10 美元解锁每天 1000 次,选错模型,一个月的额度只值 1.7 美元;选对模型值 59.2 美元,差 34 倍。这个换算的口径是请求数不是 token 数,长上下文任务的实际价值会更高。

还要留意免费池的周转速度:这 25 个免费模型里,14 个是最近 90 天上线的,23 个在半年内上线,最早的一个也只到 2026 年 2 月。名单变得很快,今天能用不代表下个月还在——官方 FAQ 的原话是「这些模型限额低,通常不适合生产使用」。

横向看,Google AI Studio 的免费层是按项目、按模型分别限额,官方文档已经把逐模型的免费额度移出文档页;Groq 的免费层是另一套独立限流。OpenRouter 免费档的独特点在于覆盖面:一个 key 能试到 NVIDIA、Google、Cohere、DeepSeek、Qwen、GLM 全家共 24 个模型,代价就是上面那三张账单。

三种用法可以:一是原型验证与选型,一个 key 横评多个实验室的模型;二是非实时批处理,每天 50 到 1000 次足够跑小批量实验,慢一点不影响结果;三是学习与风格对比,openrouter/free 随机路由反而适合感受不同模型的差异。

三种用法别碰:一是生产环境,单源、20 次/分钟、可用率最低到 80%;二是隐私敏感内容,三分之一的免费端点来自可能保留训练权的供应商;三是需要一致性的 agent 长链,额度按请求数计,一次 agent 任务动辄几十次请求,而随机路由每次换模型,行为无法复现。

判断很明确:OpenRouter 免费档值得开,但要把定位从「省钱的生产方案」改成「低成本试模型加非敏感批处理」。它是目前最便宜的横评 24 个模型的方式;把它当生产环境用,或者把敏感代码贴进 NVIDIA、Thinking Machines、Liquid 托管的模型里,那就是在拿另一样东西付费。

相关阅读: