Skip to content

认识 AnyJev:把选项换个顺序模型就改口,诺基亚用零标注把这个概率从 23% 压到 7.3%

先说一个让我很不舒服的数字。

你让 Qwen3-8B 做一个 20 选 1 的分类题(BANKING77,银行客服意图识别),它答对了。

然后你什么都不改,只把 20 个选项的顺序倒过来,再问一遍同样的题——

它有 23% 的概率给出另一个答案。

不是模型变笨了,也不是温度没设好。就是"选项排在第 3 位还是第 17 位"这件事,改变了它的答案。

我第一次看到这个数字的反应是:那我过去半年写的那些"让 LLM 输出 A/B/C 然后取 logits"的代码,全都是在赌运气?

答案是:对,而且比你想的还普遍。

2026 年 9 月 23 日,诺基亚应用研究院(Nokia Applied Research)把一个叫 AnyJev 的 Python 库推上了 PyPI 和 GitHub,Apache-2.0 协议,版本号 v0.1.0。它干的事非常窄,也非常狠:

不微调、不训练、不要标注,把你已经在跑的开源大模型,变成一个"输出带真实概率的决策模型"。

顺带一提,作者四个人里有一位来自腾讯混元。这个组合本身就挺有意思——诺基亚出工程,中国团队出模型侧的经验。

什么是 AnyJev

AnyJev 是诺基亚应用研究院开源的 Python 库(Apache-2.0,v0.1.0,2026 年 9 月 23 日发布)。它把任意一个开源大模型包装成"类型化决策模型":你给它一个带固定选项的问题,它不生成文字,而是从模型 next-token 分布里直接读出每个选项的概率,返回一个可以设阈值的决策。核心修的是直接读 logits 的两个老毛病——选项换顺序答案就变(位置偏置)、以及概率根本不可信(先验偏置 / 未校准)。

先把"它不干什么"说清楚,这个比"它干什么"更重要:

  • 不是一个新模型,也不动你模型的任何权重;
  • 不生成文字,一次 prefill 就读完,没有解析、没有 JSON 修复、没有"请只输出 A 或 B"的咒语;
  • 不是 Jev 的复刻。Jev 是 TypeSafe AI 在 2026 年 9 月发布的决策模型(System One),AnyJev 借的是它的接口风格(typed question),底层是一层跑在你已有模型上的适配器。

它支持三种问题类型,基本覆盖了生产里 90% 的"分类"需求:

类型干什么例子
choiceK 个选项选一个"这个工单该转给哪个团队?" billing / technical / sales / other
noul是或否"这次工具调用是破坏性或不可逆的吗?"
score有序分档"这个任务完成度多少?" 5 档

然后是它的核心设计——四个等级,每个决策都自带 level 标签,下游代码可以明确拒绝用错等级的结果:

等级需要什么做什么不做什么
raw直接在选项 token 上受限 softmax(大多数开源项目的做法)不处理任何偏置与校准
L0零标注K 次循环移位平均掉位置偏置 + 除掉无标注估计的标签先验不让模型的不确定性变得可信
L1每个问题 100~500 条标注在 L0 之上加温度缩放(temperature scaling)不改变答案排序
L2每个问题 100~300 条标注 + 本地模型~2/3 深度的隐藏状态上解一个闭式解头部(shrunk LDA / ridge),一次前向、提前截断不能迁移到别的问题或别的模型

"每个决策都带着自己的等级"这件事,是我认为这个库最工程化的地方。 因为它承认了一个现实:零标注的校准和几百条标注的校准,不是一回事,混着用会出事。 大多数库会帮你悄悄选一个,AnyJev 逼你把等级写在脸上。

它有什么特点

  • L0 是零标注的,而且效果是真的。 两个机制都不复杂,但都想明白了:

    循环移位(cyclic shifts):K 个选项就展示 K 次,每次轮转一格,保证每个选项都在每个位置上出现过一次,最后在对数空间取几何平均。如果位置偏置在 logit 空间是可加的,这个轮转能精确消掉它。

    先验校正(batch calibration):在真实输入上维护一个预测分布的滑动均值,以 0.75 的强度除掉它,从第 8 条开始生效。这一刀砍的是"模型天生更爱说 Yes、更爱选 A"这类标签偏好。

    代价是 K 次 prefill:H100 上 batch 32、K=20 的情况下约 0.25 秒一次决策。不是免费的,但共享前缀可以批处理掉大部分。

  • 最有说服力的那一行不是准确率,是"可自动决策流量"。 官方主表(Qwen3-8B,BANKING77 20 分类,300 条测试):

    指标raw logitsAnyJev L0AnyJev L1
    需要的标注100~500
    选项倒序时翻答案率0.2300.0730.077
    准确率0.7470.8030.807
    校准误差(ECE)0.2400.1840.095
    误差 ≤5% 可自动决策的比例7.7%46.3%52.0%

    准确率只涨了 6 个点,但能安全交给机器的流量从 7.7% 涨到 52.0%,差 6.8 倍。

    这才是真正值钱的那一行。准确率高 6% 只是"报表好看",而"可自动决策比例"决定的是你要养多少人工审核

    raw logits 给的那个"0.9",是不能拿去干活的。 一旦概率说的是真话,你才敢设阈值——**阈值之上自动过,阈值之下转人工。**这才是从"AI 演示"走到"AI 上线"的分界线。

  • 9/9:所有被测的模型 × 任务组合,L0 都降低了翻答案率。 3 个模型 × 3 个任务,全中,而且是在零标注的前提下。消融表覆盖了 Qwen、OLMo、Granite、Phi、Mistral——不是只在 Qwen 上成立。

  • L2 是这次新落地的东西,也是最骚的一层。 它不是训练,是一次闭式解:CPU 上几秒,没有梯度,模型权重动都不动。头部是「一个 [hidden, K] 矩阵 + 偏置 + 标准化向量 + 温度」,约 100 KB,Qwen3 1.7B–8B 上 2~8 秒解完。

    更狠的是成本比一次普通前向还低——因为它在固定 block 处就把前向停了(Qwen3-8B 停在 36 层中的第 24 层),实测 0.68×

    在 LocalLLaMA/typed-decisions(20 个问题,每个 300 条标注,2000 条留出决策)上的 Jev mode 成绩:

    模型L0(零标注)L2截断位置相对一次前向的成本
    Qwen3-1.7B0.4940.73018 / 280.70×
    Qwen3-4B0.5640.78624 / 360.69×
    Qwen3-8B0.6470.77124 / 360.68×
    Qwen3-30B-A3B0.6300.79940 / 48未测
    Qwen3-32B0.7000.79852 / 640.84×

    对照组:Jev 官方公布 0.727,微调过的 Laya(421M)0.768

    **一个 1.7B 的模型在 64% 深度处,打到了 Jev 公布的数字;一个 4B 打平了专门微调过的 Laya。**而 L2 的池化 ECE 只有 0.03~0.05

    另外,100 条标注就能把 8B 的头部推到 0.740(20 条是 0.654,300 条是 0.772)。这个"标注量—收益"曲线对资源紧张的小团队极其友好。

  • 头部会自己维护自己。 这点我最喜欢。你改了问题的措辞,头部会掉(Qwen3-8B 从 0.77 掉到 0.65~0.70),但喂 30 条无标注的新措辞请求,它就自己重新居中回 0.74~0.75——完全重新标注再拟合是 0.77。

    30 条无标注 ≈ 300 条全标注的 96% 效果。 选项顺序变了?按选项文本重新映射就行。只有"换了一个新问题"或"换了一个基础模型",才需要回到标注这一步。

    d.observe(route, state, label) 还能让标注边来边攒,攒到 30 条自己解一次头部,60、120 条再重解。

  • 官方直接把丑话写在 README 里。 这在今天的开源项目里属于稀有品质:

    • typed-decisions 上的"准确率",本质是"和教师模型的一致性"——金标是一个教师模型三次采样的均值,而该教师重新采样一次,和自己的一致性只有 0.735。也就是说 0.80 已经接近这个金标能测出的天花板了。
    • L2 是按问题、按模型的,别的问题上拟合的头部对新问题没用,且目前只发了 Qwen3 的头部。它需要隐藏状态,所以只有 transformers 后端能跑 L2
    • 校准救不了答不对的模型。 在迷宫和扫雷这类任务上,没有任何读取方式能赢过平凡基线。
    • L0 不总是白赚。 当某个标签压倒性占多数时,batch 先验反而会损失准确率(官方专门写了 docs/when_l0_helps.md)。
    • 字母读取法最多 26 个选项;5% 风险下的覆盖率是 n=300 的高方差估计;主表全是 Qwen;所有决策都是孤立打分的,没有放进真实 agent 循环里测过

    我特别想夸这一条:一个刚发 v0.1.0 的项目,愿意写"我们在扫雷任务上打不过平凡基线"。 现在太多开源 README 是把最好看的一张图放最上面,剩下的靠你自己踩。 AnyJev 的 README 里连"研究日志(含负面结果)"都单独放了一个文档。

用在哪儿

工单 / 意图路由。 这是最直白的场景,也是 README 里的首个例子:来一条会话,判断转 billing / technical / sales / other。BANKING77 这个基准本身就是银行客服意图 77 分类,诺基亚团队说他们在一个内部的路由问题上试过,结果"promising"。

Agent 的工具调用风控。 这个我认为是 AnyJev 最有价值的用法。Question.noul("Is this tool call destructive or irreversible?")——在 Agent 真正执行 rm -rf、发邮件、下订单之前,用一个带阈值的概率决定要不要拦下来问人类。

注意这里的关键差别:生成式模型会"解释"为什么安全,而决策模型给你一个可以设阈值的数字。 Agent 安全这件事上,一个可信的 0.12 比一段"我认为这个操作是安全的因为……"有用一万倍。

审核与分流。 内容是否违规(noul)、严重程度分档(score)、是否需要人工复核(noul + 阈值)。你要的不是"模型写一段审核意见",你要的是"这批里有百分之多少能自动过"。

任务完成度 / 质量打分。 Question.score(..., bins=5) 给 Agent 的产出打分,替代"让模型自己给自己打 8 分"这种自我吹嘘式评测。

RAG 的"要不要检索"判定。 判断这个问题是否真的需要查库,避免每次都无脑检索一遍——成本敏感的场景里,这一类"小决策"才是大头。

不适合的地方也说清楚:需要模型真正动脑推理的开放任务(它压根不生成)、选项超过 26 个的分类(当前字母读取法上限)、以及模型本身就答不对的任务(校准不能凭空创造准确性,迷宫和扫雷就是铁证)。

初体验

先跑零下载的 demo,30 秒建立体感:

bash
pip install "anyjev[hf]"

# 用一个合成模型跑完整流程,不到 1 秒,不下载任何权重
python -m demo.jev_mode --backend fake

# 看完整部署生命周期:day 0 在 L0,标注一条条进来,30 条时头部自己解出来
python -m demo.jev_mode --backend fake --lifecycle

然后是自己上手,L0 默认开启,零标注:

python
from anyjev import Decider, Question
from anyjev.backends.hf import HFBackend

d = Decider(HFBackend("Qwen/Qwen3-8B"))

route = Question.choice("Which team should handle this?", ["billing", "technical", "sales", "other"], name="route")
risky = Question.noul("Is this tool call destructive or irreversible?", name="risky")
done  = Question.score("How complete is the task?", bins=5, name="done")

r = d.decide({"conversation": [...], "tool_call": {...}}, [route, risky, done])
r["route"].distribution    # {"billing": 0.81, "technical": 0.07, ...}
r["risky"].p_true          # 0.12
r["done"].value            # 0.35
r.level                    # "L0"

有标注之后升级到 L1 / L2:

python
d.calibrate(risky, states, labels)          # 100~500 条 → L1(一个温度)
d.fit_head(route, states, labels)           # 100~300 条 → L2,一次前向 + 闭式解,几秒
d.save_artifacts("qwen3-8b.json")           # 下次 d.load_artifacts(...);每个头部约 100 KB

r = d.decide(state, [route], level="auto")  # 有头部的走 L2,否则 L1,再否则 L0
r["route"].level                            # "L2"

懒人路线anyjev-heads/<model>.json 里已经为 Qwen3-1.7B / 4B / 8B / 30B-A3B / 32B 各发了 23 个现成头部(20 个 typed-decisions 问题 + 3 个基准任务),而且是用和你跑的同一条 fit_head → decide_batch 路径构建并验证的。

四个坑,提前说:

第一,也是最容易踩的——vLLM 后端现在不支持。 好几家媒体稿写"支持 transformers 和 vLLM 双后端、vLLM 走 prefix caching",那是照着早期 README 抄的。官方 0.1.0 的 README 和 docs 已经明确改口:**transformers 后端(anyjev.backends.hf)今天能跑全部四个等级,vLLM / SGLang 的服务化在 roadmap 上,不在这个版本里。**L2 需要隐藏状态,这也是它暂时只能跑 transformers 的原因。

第二,L0 要 K 次 prefill。 20 个选项就是 20 次,成本不是 1 次前向。真上量请走 d.decide_batch(states, question),并且认真算一下你的 QPS 扛不扛得住。

第三,别拿"准确率"当圣旨。 typed-decisions 的金标本身只有 0.735 的自身一致性,0.80 已经贴着天花板了。在自己的标注集上测,别信我的表,也别信官方的表。

第四,别把它当分类器训练用。 L2 的头部按问题、按模型绑定,换问题要重新标注,换基础模型要把所有头部重新解一遍。它省掉的是"训练",不是"标注流程"。

进阶

如果这篇文章你只记住一件事,我希望是这个判断:

2026 年开源大模型真正缺的,可能不是更强的模型,而是"让已有模型的输出变得可以设阈值"的那一层。

我们花了两年把 LLM 塞进生产系统,然后发现最痛的地方不是它不够聪明,而是它说"我 90% 确定"的时候,你根本不知道这个 90% 是真是假。没有可信概率,你就不能设阈值;不能设阈值,就只能全量人工复核——于是所有 Agent 项目都卡在"演示很惊艳、上线不敢开"这一步。

AnyJev 的赌注很特别:**它不做新的模型家族,它做一层任何人都能拧到自己已有模型上的校准层。**你不用换模型、不用微调、不用等下一个版本。

冷水照例要泼,而且这次要泼在两点上:

第一,7.7% → 52.0% 是 n=300 的点估计,官方自己说了区间很宽。6.8 倍这个数字很炸,但它是一个任务、一个模型、300 条测试上的结果。别拿它去做预算,拿你自己的标注集跑一遍再说。

第二,vLLM 不支持这件事,现在会卡住很多人。生产环境跑大模型,大部分人用的是 vLLM / SGLang,不是原生 transformers。在 L2 能跑在服务化引擎上之前(roadmap 里排第一项),AnyJev 更适合离线批处理内部工具,而不是高并发在线链路。

我的建议很具体:**挑一个你现在正在用 prompt 硬凑的分类任务(工单路由、是否要拦、是否要检索,都行),先用 --backend fake 跑通流程,再用 transformers 后端在你的标注集上跑一遍 L0,重点只看两个数——翻答案率和 5% 阈值下的覆盖率。**这两个数决定它对你有没有用,比任何准确率都准。

再往深一层,我建议你去读它的 docs/method_v3.md 和那份包含负面结果的研究日志。看清楚两件事:为什么"循环移位 + 对数空间几何平均"能精确消掉可加的位置偏置,以及为什么 L0 在标签极度不平衡时反而会掉点。这两个结论,对所有"从 logits 读分类"的代码都成立——不管你用不用 AnyJev。

至于"决策模型"会不会变成大模型的一个独立品类(Jev、Laya、AnyJev 三方在同一个月里扎堆出现,本身就说明有人押注),我的看法是:**现在下结论都太早。**但至少这一次,诺基亚给的不是一份 PPT,是一个 pip install 就能跑、把失败案例也写进 README 的东西。

更多开源技术干货和学习资料,关注公众号「遇码」,领取专属福利。

遇码MeetCoding 开源技术社区