返回
Kevin Riedl

14 分钟 阅读 · 2026年9月28日
最近审核

下一篇
图片在你的设备上生成,不连接 Instagram。文章链接会复制到剪贴板,供链接贴纸使用。

AnyJev:LLM 概率校准与选项顺序偏差

核查日期:。软件包基线为 AnyJev 0.2.0,源代码快照为 10d5db91dda38dbde74c6abc1c075ce6463723d1。本文是文档与源代码分析,不是我们自行运行的 GPU 基准测试,也不是 Wavect 生产部署案例。AnyJev 0.2.0 发布记录

AnyJev 是什么,“无需训练”究竟意味着什么?

AnyJev 是一个开源库,用于从现有语言模型中读取结构化决策,而不是让模型生成一段回答。它的重点不只是速度:它处理选项顺序偏差,并区分经过偏差修正的分数与利用标签校准过的置信度。 项目列出的作者为 Jiamu Zhang、Tianze Yang、Yucheng Shi 和 Liang Wu,所属机构包括 Nokia 与腾讯混元。其接口受到 TypeSafe AI 的 Jev 启发,但项目与 TypeSafe 没有隶属关系。项目介绍与作者信息

软件包以 Apache 2.0 许可发布。这并不自动涵盖所有配套模型或数据集的使用许可。软件包许可信息。

实际问题很简单:智能体已经拿到了工单、文档或工具结果,现在必须从几个允许的答案中选择一个。如果有人调整了选项顺序,这个选择还能保持一致吗?返回 0.9 的置信度,是否意味着相似决策在实际中大约有 90% 是正确的?

这是两个不同的问题。稳定的答案可能仍然错误,归一化后的分布也可能过度自信。 AnyJev 提供的是不同处理层级,而不是一种万能修正。

“无需训练”准确描述了不需要标签的 L0 路径。L1 使用带标签样本拟合温度;L2 拟合一个有监督的线性输出头,虽然这一过程不修改骨干模型,也不使用梯度下降。把三者都笼统称为“无需训练”,会掩盖数据与验证工作。更有用的区分是:不微调骨干模型,不等于不使用标签进行拟合。 各层级的能力与限制

关于产品背景,可以阅读我们的 Jev 评测与 Laya 和 Jev 基准分析。本文专门讨论 AnyJev 的校准、选项顺序与评估机制,不再重复决策模型排名。

Raw、L0、L1、L2:哪些路径需要标签?

AnyJev 处理层级:数据要求与能力边界
层级数据与机制不能据此证明什么
raw不需要标签;读取限定在答案标签 token 上的分布。不能证明顺序鲁棒性,也不能证明不确定性经过校准。
L0不需要标签;合并选项轮换结果,并可选择修正标签先验。置信度不是经过验证的正确率估计。
L1通常每个问题使用 100–500 个标签,在 L0 上拟合温度。不能抵御分布变化,也不能修复错误的模型知识。
L2通常每个问题使用 100–300 个标签,在隐藏状态上闭式拟合输出头。不能普遍迁移到不同问题或另一个基础模型。

这些范围是项目给出的经验指导,不是样本量充分性的保证。低频但高成本的错误,可能需要多得多的验证数据。同样,auto 的含义是“使用当前可用的最高层级”,而不是“自动安全”。必须检查实际返回的层级。上表概括了文档中的层级约定。

为什么只改变选项顺序,模型就可能改变答案?

假设三个语义答案分别是账单、技术支持和销售。简单实现会将它们映射为 A、B、C,读取下一个 token 的分数,再选择最高者。但是,模型对“A”、靠前位置或相邻选项的偏好,可能被误当成对该位置所代表业务答案的偏好。

这是已有的研究问题,并非 AnyJev 首次发现。Zheng 等人研究了大语言模型多项选择结果对选项排列的敏感性,这也是项目置换方法的研究基础之一。多项选择顺序敏感性研究

AnyJev 通常会评估 K 个选项的 K 次循环轮换,让每个选项在每个位置出现一次。默认 logmean 方法先将概率映射回语义选项,再对其对数取平均、指数化并重新归一化。在理想化的“logit 中包含可加的位置偏差”假设下,位置项能够抵消。轮换与边缘化实现

理想条件下的抵消,不等于对所有真实提示词排列都具有不变性。 完整循环保留了选项之间的邻接关系,而真实模型可能对这些交互产生不同响应。此前公布的 BANKING77 结果仍存在残余答案翻转。

0.2.0 版本提供另一项需要显式启用的措施:canonical_order=True 在轮换前按选项文本排序。这样,同一个选项集合无论调用方如何排列,都会产生相同的提示词布局。在推理条件与先验状态一致时,这是确定性的输入规范化属性。它不保证答案正确,不消除数值波动,也不会让持续累积的批次先验摆脱请求历史影响。轮换预算文档还解释了为什么只读取部分轮换时,这一点尤其重要。

验证顺序鲁棒性时,应比较返回的语义标签,而不是选项索引。列表反转后,索引零对应的内容已经不同。还应区分单次轮换之间的分歧,以及两次完整调用在输入顺序变化后的分歧。

批次先验修正何时有效,何时会适得其反?

L0 可以利用无标签输入上的模型预测估计标签先验,再进行修正。直观来说,就是将每个答案的分数除以模型通常偏好该答案的程度,然后重新归一化。默认批次先验强度为 0.75;每个问题的累积器至少看到八个输入后才开始修正。在此之前,诊断信息会表示未应用先验修正。Decider 默认配置、校准与状态管理

难点在于:某种答案频繁出现,可能说明模型有偏差,也可能说明真实类别本来就常见。仅凭无标签预测频率,无法可靠区分这两种情况。如果大部分真实工单都属于账单问题,强行把多数类向均衡分布修正,反而可能降低路由质量。

项目的诊断研究涵盖 230 个模型与问题组合。在平衡的 20 分类任务上,它报告了有价值的提升;在部分严重不平衡的问题上,也报告了明显下降。因此项目保留 prior="none",以便在已知标签分布偏斜时单独测试轮换效果。这是一个需要评估的消融配置,而不是“关闭先验总是更好”的保证。L0 的正面结果与失败案例

批次校准的基础方法来自 Zhou 等人的研究。AnyJev 将其与轮换机制和实用接口组合起来,并不是从零发明了所有方法。Batch Calibration 研究

项目还支持基于空输入或 N/A 等探针的无内容校准,沿用了 Zhao 等人的思路。不过,模型对空输入的回答本身也可能具有语义。应将 prior="content_free" 视为另一项需要测量的配置,而不是普遍更可靠的基线。Calibrate Before Use

对于工单路由试点,可以同时在类别平衡的诊断集与按时间抽样的自然流量集上,对比 raw、仅轮换的 L0 和默认 L0。前者帮助发现弱势类别,后者反映系统实际会遇到的分布。

L1 校准了什么,为什么温度不是准确率升级按钮?

温度缩放改变的是固定概率向量的集中程度。其概念形式为 softmax(log(p) / T),其中 T 为正值。较大的温度通常让置信度更平缓,较小的温度则让分布更尖锐。AnyJev 在带标签的校准样本上最小化负对数似然来确定 T,并把校准所使用的先验保存到制品中。温度缩放实现

对于一个固定向量,正温度缩放不会改变获胜类别。它不会把错误类别变成正确类别。 校准研究区分概率估计质量与分类准确率;Guo 等人的工作提供了这里采用的基础框架。On Calibration of Modern Neural Networks

那么,为什么 AnyJev 的 L0 与 L1 准确率列有时略有不同?因为完整流程不只包含温度:L1 冻结从校准样本估计出的先验,而常规 L0 可能积累出另一个运行时先验。不要把差异解释成温度改变了最大值类别。这一点来自 Decider 实现以及上述单调变换。

因此,一个可用于部署的校准制品,不应只有温度值。我们的建议是同时记录基础模型版本、tokenizer、问题文本、精确选项顺序、先验配置、软件包版本与校准数据时间窗。问题或服务配置发生变化后,应重新验证,而不是静默复用一个看起来效果不错的阈值。

已发布的基准结果到底说明了什么?

以下是项目自行报告的结果:Qwen3-8B、BANKING77 的 20 类子集、300 个测试样本。这不是完整的 77 分类评估,不是 Nokia 的生产 SLA,也不是较新的可选规范排序与自适应配置的测量结果。版本化基准表

Qwen3-8B、banking20、300 个测试样本:raw、L0 与 L1 的报告结果
指标rawL0L1
准确率74.7%80.3%80.7%
期望校准误差,越低越好0.2400.1840.095
反转顺序后的答案翻转率23.0%7.3%7.7%
错误率 5% 时的经验覆盖率7.7%46.3%52.0%

这些提升值得进一步验证,但最后一行必须谨慎解读:覆盖率是对这组按置信度排序的测试样本进行回顾性分析得到的属性。它不能证明某个固定阈值未来一定能在错误率 5% 的条件下自动处理 52% 的流量。对于这组样本,52% 大约对应 156 次决策。156 次接受决策中多一个错误,观测错误率就会变化约 0.64 个百分点。这只是说明统计不确定性的计算,并非还原未公布的错误数量。

同一份结果还包含很有价值的反例。在 Qwen3-8B 的 newsgroups 任务上,L1 将 ECE 从 0.309 降到 0.138,但错误率 5% 时的经验覆盖率却从 42.3% 降到 23.7%。平均校准质量更好,不代表低风险筛选效果必然更好。必须同时评估概率质量与风险覆盖曲线。基准来源。

L2 结果还有一层区别。仓库报告 Qwen3-8B 在针对每个问题使用标签拟合后,对 2,000 次结构化决策达到 77.1%。但该数据集的“准确率”是与教师模型派生标签的一致率,并不代表每个业务结果都经过独立人工裁定。README 明确标记,Jev 对照行来自其他作者已发表的数字,而非重新运行的直接对比。不能据此宣布一个整体产品赢家。项目限制。

自适应轮换:1% 的目标不等于 99% 的正确率

自适应轮换尝试在读完全部 K 种布局前提前停止。它使用无标签状态校准,因为参照答案是模型自己的完整轮换结果。停止阈值依据与该参照答案之间分歧率的置信上界选取。它估计的是与另一种读取方式的一致程度,而不是相对于真实任务答案的正确性。 轮换预算实验与限制

在项目报告的一项 Qwen2.5-7B 实验中,任务有 18 个选项,硬件为 H100 NVL,服务版本为 vLLM 0.7.0。完整轮换达到每秒 16.73 次决策;每轮读取两个布局的自适应方案达到每秒 37.20 次,平均每次决策使用 7.28 个请求,测得吞吐比为 2.22×。不过,与参照答案的一致率是 98.7%,即 1.3% 的分歧率,高于名义上的 1% 目标。作者公开披露了这一点。它不是对未来请求的合同式保证。

实用顺序是:先建立完整轮换基线,启用规范排序,在独立且有代表性的状态上校准自适应预算,再在保留数据上同时测量参照分歧与真实错误。校准样本量、上下文长度和服务引擎变化,都可能影响结果。不能把轮换次数减少的比例,直接视为整个智能体的端到端加速比例。

如何开始一个可复现的工单路由实验

下面是用于说明的离线流程,不是已测量的生产部署。AnyJev 0.2.0 要求 Python 3.10 或更新版本。请使用隔离环境,并锁定实际解析出的依赖版本。只固定 AnyJev 版本,并不能同时固定 PyTorch、Transformers 与模型权重。软件包基线。

python -m venv .venv
. .venv/bin/activate
python -m pip install "anyjev[hf]==0.2.0"

当前 Question.choice 接受两个到 26 个不重复的选项字符串。校准标签必须是这些选项的整数索引。保持语义映射稳定,避免设计连人工标注者都难以判断的重叠类别。结构化问题的验证与哈希

这个例子需要兼容的 CUDA 环境,以及足以运行所选基础模型的内存。HF 后端会加载模型和 tokenizer,支持指定模型 revision,并且默认不启用远程模型代码。AnyJev 软件包很小,不代表骨干模型的运行需求也很小。HF 后端与模型加载

按顺序运行 Python 代码前,请将 ANYJEV_MODEL_REVISION 设置为所选 Qwen3-8B 模型真实的 40 位 commit。这里需要模型版本,不是 AnyJev 源代码的 commit。

import os
import re
from anyjev import Decider, Question
from anyjev.backends.hf import HFBackend

# Set this to the actual Qwen model commit, not the AnyJev commit.
revision = os.environ.get("ANYJEV_MODEL_REVISION", "")
if not re.fullmatch(r"[0-9a-f]{40}", revision):
    raise ValueError("Set ANYJEV_MODEL_REVISION to a Qwen3-8B commit SHA")

backend = HFBackend(
    "Qwen/Qwen3-8B", revision=revision,
    device="cuda", dtype="bfloat16",
)
route = Question.choice(
    "Which internal queue should review this ticket? Classify only.",
    ["Billing", "Technical support", "Sales", "Manual review"],
    name="route",
)
d = Decider(
    backend, level="L0", prior="none",
    canonical_order=True, adaptive_shifts=False,
)
result = d.decide("I need a copy of my invoice.", [route])["route"]
print(result.level, result.distribution)  # Inspection only; no dispatch.

示例有意使用完整轮换、规范排序和 prior="none",建立只考察置换效果的基线,避免隐式依赖已经预热的运行时先验。在用于真实流量前,应与默认批次先验进行对照。各语言版本保留同一组英文问题和标签,确保示例代表同一个实验。

随后准备互相独立的校准文件与保留评估文件。每个非空 JSONL 行都应包含 id、state 和与某个选项字符串相同的 label。下面的示例行只说明格式,不能作为足够的校准数据集。

{"id":"ticket-example-001","state":"Please resend my invoice.","label":"Billing"}
# Continue after the setup above. Supply your own labeled JSONL files.
import json
from pathlib import Path


def load_rows(filename: str, minimum: int = 1) -> list[dict]:
    rows, ids, states = [], set(), set()
    for line_no, line in enumerate(Path(filename).read_text(encoding="utf-8").splitlines(), 1):
        if not line.strip():
            continue
        row = json.loads(line)
        if not isinstance(row, dict) or not all(
            isinstance(row.get(k), str) and row[k].strip()
            for k in ("id", "state", "label")
        ):
            raise ValueError(f"{filename}:{line_no}: id, state and label must be strings")
        if row["label"] not in route.options:
            raise ValueError(f"{filename}:{line_no}: unknown label")
        if row["id"].strip() in ids or row["state"].strip() in states:
            raise ValueError(f"{filename}:{line_no}: duplicate id or state")
        ids.add(row["id"].strip())
        states.add(row["state"].strip())
        rows.append(row)
    if len(rows) < minimum:
        raise ValueError(f"{filename}: need at least {minimum} rows for this example")
    return rows


calibration = load_rows("calibration.jsonl", minimum=100)
heldout = load_rows("heldout.jsonl")
for field in ("id", "state"):
    if {r[field].strip() for r in calibration} & {r[field].strip() for r in heldout}:
        raise ValueError(f"Calibration and held-out {field} values overlap")
if {r["label"] for r in calibration} != set(route.options):
    raise ValueError("Calibration must cover every route in this example")

artifact = d.calibrate(
    route, [r["state"] for r in calibration],
    [route.options.index(r["label"]) for r in calibration], level="L1",
)
# Exclusive creation prevents accidental overwrite of an existing artifact.
with Path("route-calibration.json").open("x", encoding="utf-8") as f:
    json.dump(artifact, f, ensure_ascii=False, indent=2)

predictions = d.decide_batch(
    [r["state"] for r in heldout], route, level="L1", require="L1",
)
for row, prediction in zip(heldout, predictions):
    print(json.dumps({
        "id": row["id"], "expected": row["label"],
        "predicted": prediction.argmax, "confidence": prediction.confidence,
        "level": prediction.level,
    }, ensure_ascii=False))

代码只在一份数据上拟合,并在另一份数据上输出分数。它不选择自动化阈值,也不把工单发送到任何队列。至少 100 行的检查只是示例策略,并不表示 100 个标签一定具有统计充分性。除了拒绝重复或跨集合重叠输入,还应检查时间与客户层面的数据泄漏,不能只比较标识符。

require="L1" 防止系统静默使用较低层级的结果;confidence 是返回分布中的最大概率。两者都不是权限检查,也不能证明业务错误率已经可接受。结果对象还提供实际层级和诊断字段。决策字段与最低层级要求

如果要选择生产阈值,应增加独立验证集。在验证集上确定接受规则,再对完全未参与选择的测试集评估一次。按类别报告接受数量和错误数量,不要只给一个总体置信度。

哪些服务与制品边界会让实验失效?

AnyJev 的 vLLM 适配器有两条不同路径。Raw、L0、L1 使用生成服务,通过允许的答案 token ID 和对数概率请求 max_tokens=1。它不需要解析自由文本,但适配器确实请求一个 token;“不生成回答”不能被理解为每个 API 边界都完全没有 token 计算。L2 则需要池化服务提供未归一化的末位置隐藏状态。服务适配器与端点约定

一般语义 embedding 端点不能自动替代这种隐藏状态接口。普通 vLLM 池化服务提供的是当前 checkpoint 的最后一层;如果输出头是在更早一层拟合的,就需要匹配的截断 checkpoint,或能够暴露该层的后端。模型身份、tokenizer、向量形状和预处理必须一起验证。

L2 为每个问题拟合独立线性头,使用闭式求解,并通过内部留出折选择输出头与层。即使没有更新骨干模型的梯度,这依然是有监督学习。一个问题拟合成功,并不能验证另一个只有标签看起来相似的问题。输出头的闭式拟合实现

常见运行错误有两种:在加载或拟合校准制品前就请求 L1,以及拟合之后仍继续调用默认 L0 路径。应显式指定 level 和 require。评估期间保持部署配置不变,并把回退、先验预热与制品不匹配记录为事件,不能让它们成为不可见的准确率变化。

真实决策系统应该如何做验收?

我们的建议是先评估范围较小、可以撤销的决策。测试应围绕“错误决定被接受后会付出什么代价”设计,而不是围绕接口有多新颖设计。

分别测试正确性与稳定性。 测量各类别准确率、macro F1、反转选项后的分歧率,以及多个非循环排列。每次比较使用相同先验状态。稳定答案可能错误;持续变化的先验也不一定意味着顺序处理有缺陷。

分别测试置信度与覆盖率。 记录 NLL、Brier 分数、ECE、接受决策中的错误率,以及预选阈值下的覆盖率。单独检查稀有类别和每种部署语言。上面的 newsgroups 反例说明,不能只优化 ECE。

在真实系统边界测量成本。 统计提示词数量、p50/p95 延迟、排队时间、前缀缓存行为与回退率。成本应包含模型服务和人工复核,而不只是 logits 之后的几步计算。对照现有路由器,也对照简单规则基线。

把执行控制放在分类器之外。 候选集只能包含被授权的动作,应保留人工复核或弃权路径,并由确定性业务规则执行权限约束。不能让置信度阈值直接授权退款、账户修改或生产命令。扩大范围之前,先观察漂移并重新校准。

仓库仍将完整智能体流程中的评估列为后续工作。因此,孤立决策结果还不能证明整个生产智能体已经更好。项目范围。更广泛的上线过程可参考 LLM 评估指南与试点终止或扩展评分卡。业务流程的成本收益分析仍由 Laya/Jev ROI 指南覆盖。

关于编码器和输出头的服务部署,可以阅读 CLM-8B 自托管与动作缓存指南。该指南介绍候选向量复用与验证器搭建,本文则聚焦校准与选项顺序的验证。

一个有价值的 AnyJev 试点,最终应交付版本化的问题定义、可复现的概率处理流程,以及未被反复调参污染的测试结果。这比一个自信的答案,或者更快的下一个 token 读取,更适合作为自动化的依据。

需要集成支持,可以了解 Wavect 的 AI 工程服务。Twinsoft AI 案例仅提供独立的交付背景,不代表 AnyJev 部署证明。带上代表性决策和上线前 QA 清单,即可讨论以评估为先的集成方案。

AnyJev 校准常见问题

AnyJev 真的完全不需要训练吗?

L0 不需要标签,也不微调基础模型;L1 利用标签拟合温度,L2 拟合有监督输出头。不通过梯度更新骨干模型,不等于不从标签中学习。层级约定。

AnyJev 能彻底消除选项顺序偏差吗?

完整轮换能消除理想化的可加位置效应,但真实提示词可能保留交互影响。0.2.0 中可选的 canonical_order=True 会规范调用方顺序。应在相同推理与先验状态下比较语义答案;稳定性不代表正确性。顺序处理细节。

没有标签也能校准 AnyJev 吗?

无标签数据可以用于先验估计,以及校准自适应结果与完整轮换结果的一致率。但根据正确答案验证置信度是另一件事:L1 需要该问题的标签。自适应 1% 目标不是对真实错误率的保证。L0 与 L1。

为什么 ECE 降低,自动化覆盖率反而可能下降?

ECE 衡量总体校准,不保证任意阈值下最低风险子集的质量。已发布的 Qwen3-8B newsgroups 结果中,L1 降低了 ECE,却也降低了错误率 5% 时的经验覆盖率。应同时测量概率质量和接受决策的风险。公开反例。

AnyJev 支持任意托管 LLM API 吗?

不能默认支持。已检查的 vLLM logits 路径需要控制允许的 token 并获取其对数概率;L2 需要兼容隐藏状态。仅有通用聊天或 embedding API,并不足以证明兼容。后端约定。

AnyJev 最多支持多少个选项?

当前 Question.choice 构造函数接受 2 到 26 个唯一选项;有序 score 问题使用 2 到 10 个区间或等级。更大的候选集合需要不同设计或后续实现,不能默认绕过限制。问题验证。

设置 require="L1" 后就能安全执行吗?

不能。它只强制最低处理层级,不验证权限或业务风险。应使用代表性数据校准,在验证集选择阈值,再在未使用过的测试集评估。保留独立复核与确定性授权。层级检查。

能把 AnyJev 的 L2 输出头复用到另一个问题吗?

不能默认迁移到不相关的问题或另一个模型。AnyJev 按问题和模型拟合输出头。即使是同一问题改写文本或调整顺序后的路由,也需要用新输入验证。类别名称相似,并不能证明兼容。输出头范围与限制。

最终思考

把 AnyJev 用于验证具体决策接口,而不是默认置信度等于正确性。分别衡量顺序鲁棒性、概率校准与接受决策的风险。固定问题和服务约定,保留未参与调参的测试集,并将执行权限控制放在模型之外。

构建产品,而不只是 backlog

如果这篇文章对应的是一个真实产品决策,Wavect 可以用高级创始人级判断帮你界定范围、构建、加固或领导软件工作。

可选服务路径:

只收重要内容

关注与你相关的内容

每当我们发布新文章,你会收到一封简短邮件。你可以关注整个博客,也可以只选感兴趣的主题。

你希望接收哪些内容?
选择主题

免费、双重确认、不使用跟踪像素。

返回
Kevin Riedl

14 分钟 阅读 · 2026年9月28日
最近审核

下一篇

获取下一篇关于AI 与智能体的一线笔记

有新文章时发送一封简短邮件,不使用跟踪像素,也不发送填充内容。

免费、双重确认、不使用跟踪像素。