Hugging Face 详解决策模型:接口、三类原语与生态支持
Decision Models in Hugging Face
Hugging Face 发文介绍决策模型,即让模型对预设答案分配概率而非逐 token 生成,并给出 Choice、Score、Noul 三类决策原语及置信度计算方式。文章说明 Transformers 已支持 DecisionPipeline、AutoModelForDecision 和 DecisionConfig,llama.cpp 可通过同一 /v1/systemone 接口提供服务,Hub 也新增了决策模型标签。文中还给出用 Trainer API 微调 JEV-9B 做客服请求路由的示例,并提到 TRL 的一等支持仍在 PR 阶段。
推荐理由
精选AI 评分 65
原文把决策模型的三类原语、概率输出和置信度公式讲清楚,并给出在 Transformers 与 llama.cpp 中调用的具体路径。
主题
正文 · AI 翻译
什么是决策模型?
决策模型接收一些输入上下文(状态),用一组预定义的可能答案(原语)来评估一个问题,并返回一个结构化的决策及其概率。我们不是让模型逐 token 生成答案,而是让它为我们应用已经理解的答案分配概率。
TypeSafe AI 推出了 Jev,并将其描述为 System One 模型。这个名字的灵感来自快速、直觉的思维(系统 1)与较慢、审慎的思维(系统 2)之间的区别。
社区已经统一采用“决策模型”这一术语,因为它描述的是模型的计算角色,而不是援引某种特定的认知理论。在本文的剩余部分,我们将把这些模型称为“决策模型”,而不是“系统一模型”。(一条 Twitter 投票决定了我们应该如何称呼这类模型)
对于决策模型,基本接口是:
为什么不直接用 LLM 做所有事情?
我们完全可以简单地提示 LLM 返回一个包含我们决策的 JSON 对象。事实上,许多应用已经以这种方式使用语言模型进行分类、路由和其他结构化任务。
然而,这种方法存在几个问题。
LLM 不保证遵循所要求的模式:即使有明确的指令,模型也可能产生无效的 JSON、引入意外的键,或返回允许选项之外的答案。
约束解码有帮助,但并不能消除计算开销:Outlines 和 XGrammar 等库可以通过限制模型在每一步允许生成的 token 来强制执行语法或 JSON 模式。这确保了输出遵循支持的结构约束,但引入了额外的工作。
为什么要生成整个响应:LLM 是为开放式生成而设计的,但当我们的应用只需要在预定义答案之间做出选择时,自回归解码可能是不必要的工作。
决策模型与分类模型有何不同?
在理解决策模型的接口之前,有必要回顾两种密切相关的方法,即传统分类和零样本分类。
传统分类
假设我们训练一个分类器,将客户支持请求路由到三个部门:
传统分类模型学习从输入到预定义标签集的映射。在训练期间,模型学习从示例中预测这些标签。分类头通常为每个类别产生一个 logit,softmax 将这些 logit 转换为概率分布。
这里的局限在于输出类别被固化在模型的分类头中。
如果我们引入第四个部门,例如法务部,现有分类器不会自动获得相应的输出类别。我们可能需要修改分类头、收集训练数据,并重新训练或调整模型。
零样本分类
零样本分类解决了这一局限的重要部分。我们不需要分类器专门针对每个输出类别进行训练,而是在推理时提供候选标签。
例如:
与传统的固定标签分类器不同,类别可以因请求而异。让我们再添加一个部门,例如“法务部”,看看模型的输出。
一种常见的实现使用为自然语言推理(NLI)训练的模型。每个候选标签被转换为一个假设,模型衡量输入对该假设的蕴含程度。
这听起来已经与决策模型非常相似。而且在许多方面,确实如此。
决策模型的不同之处
决策模型将这一想法扩展到不仅仅是将输入分配到一个类别。决策模型可以接受关于同一状态的多个命名问题,并具有不同的答案类型。这些类型可以是:在备选项之间进行选择(choice)、在有序量表上评分(score),或估计某个陈述为真的概率(noul)。
更重要的是,它的接口是围绕可能决策上的概率分布设计的。
考虑这三种方法:
决策模型的优势不在于它发明了运行时定义的标签或概率分类。而在于它将这些能力组织成一个一致的接口,并可能由专门为决策优化的架构和训练程序提供支持。
决策模型接口
一个决策模型请求包含以下两个组成部分:
状态是模型应评估的信息。它可以是字符串、结构化 JSON 对象,或对于支持的全模态模型而言的其他模态。
例如:
问题及其原语
问题描述我们想了解状态的哪些方面。在决策模型接口中,三种基本原语代表不同形式的决策:
Choice:从多个可能答案中选择一个。
Score:在有序量表上评估某事物。
Noul:以概率方式回答是/否问题。
让我们逐一介绍它们。
Choice:选项上的概率分布
Choice 是最直观的原语,也最接近传统分类。
假设我们问:
哪个部门应处理这个客户请求?
可用选项是账单、技术支持和销售。
模型为每个选项分配一个 logit。对于 logits($z_1,\ldots,z_K$)(共 K 个类别),我们可以使用 softmax 得到概率:
p i = exp ( z i / T ) ∑ j = 1 K exp ( z j ) p_i=\frac{\exp(z_i/T)}{\sum_{j=1}^{K}\exp(z_j)} p i = ∑ j = 1 K exp ( z j ) exp ( z i / T )
这里,(K) 是选项的数量。
考虑这个示例分布:
概率之和为一:
∑ i = 1 K p i = 1. \sum_{i=1}^{K}p_i=1. i = 1 ∑ K p i = 1.
模型选择概率最大的选项:
y ^ = arg max i p i \hat y=\arg\max_i p_i y ^ = ar g i max p i
在本例中,选择的是 Billing,概率为 0.998,但其余概率也很有用。它们告诉我们模型如何在各个备选项之间分配其信念。
Score:有序分布的期望
当存在多个不同的备选项时,Choice 可以发挥作用。但如果我们想在有序量表上衡量某些东西呢?
考虑这个问题:
这个客户请求有多紧急?
模型同样会生成一个概率分布:
Score 原语不是只返回最可能的等级,而是计算等级索引的期望值。
对于表示等级的随机变量 (X),期望为:
E [ X ] = ∑ i = 0 K − 1 i p i \mathbb{E}[X]=\sum_{i=0}^{K-1}ip_i E [ X ] = i = 0 ∑ K − 1 i p i
对于我们的示例:
E [ X ] = 0 ( 0.10 ) + 1 ( 0.26 ) + 2 ( 0.72 ) = 1.7 \mathbb{E}[X] = 0(0.10)+1(0.26)+2(0.72)=1.7 E [ X ] = 0 ( 0.10 ) + 1 ( 0.26 ) + 2 ( 0.72 ) = 1.7
因此报告的分数为 1.7。
这并不意味着模型选择了一个介于中等和高之间的虚构等级。它意味着其概率分布的期望值为 1.7。
Noul:伯努利决策
第三个原语是 Noul,它表示一个二元问题。
例如:
客户是否在申请退款?
我们不是定义一组选项,而是要求模型返回答案为真的概率。我们可以使用伯努利分布来理解这一点(noul 来自 Bernoulli)。
令 (Y) 表示一个二元结果:
Y ∼ Bernoulli ( p ) Y\sim\operatorname{Bernoulli}(p) Y ∼ Bernoulli ( p )
其中
P ( Y = 1 ) = p , P ( Y = 0 ) = 1 − p . P(Y=1)=p,\qquad P(Y=0)=1-p. P ( Y = 1 ) = p , P ( Y = 0 ) = 1 − p .
如果模型返回:
它为“是”分配 0.92 的概率,为“否”分配 0.08 的概率。
模型在这里并不是随机采样一个二元答案。它返回的是概率参数本身,由应用决定如何据此采取行动。
Confidence:模型有多确定?
到目前为止,我们已经从模型获得了概率分布。但决策模型接口还会为 Choice 和 Score 返回一个名为 confidence 的字段。
完整分布可能包含多个可能的答案,总结模型的信念有多集中是很有用的。借助 confidence,我们正好可以实现这一点。
对于有 (K) 个选项的 Choice,置信度为:
p max − 1 K 1 − 1 K \frac{p_{\max}-\frac{1}{K}}{1-\frac{1}{K}} 1 − K 1 p m a x − K 1
其中($p_{\max}$)是最大的预测概率。
这里的直觉是:
均匀分布的置信度为 0。($p_{\max} = \frac{1}{K}$)。这意味着模型估计所有选项的可能性相同。
完全集中于一个选项的分布置信度为 1。($p_{\max} = 1$)
获胜概率相对于均匀分布越大,置信度就越高。
在我们之前的三个选项示例中,Billing 的概率为 0.80:
C = 3 ( 0.99 ) − 1 2 = 0.98 C=\frac{3(0.99)-1}{2}=0.98 C = 2 3 ( 0.99 ) − 1 = 0.98
请注意,获胜概率为 0.99,但报告的置信度为 0.98。置信度将最大概率相对于可用选项数量进行了归一化。相比之下,有序 Score 示例的置信度仅为 0.558。
Hugging Face 生态系统中的决策模型
决策模型是一个年轻且快速发展的领域。每个模型在底层做出决策的方式各不相同(对整个 schema 联合打分的头、在 LLM 主干之上单独的读出层、边缘规模和多模态变体等)。这种多样性是健康的,但也有代价。如果每个模型都暴露自己的接口,那么围绕它的每个工具都需要针对特定模型进行适配。
我们在 Hugging Face 的目标是就一个通用接口达成一致,而不强制采用通用实现。决策模型在内部可以自由地以任何方式工作,只要它接受相同的状态和问题,并返回相同的类型化决策。一旦这一契约存在,生态系统的其余部分就可以一次性构建在其之上:
像 llama.cpp 这样的推理引擎可以通过同一 API 为任何决策模型提供服务
Hub 可以一致地打包和展示它们
训练工具可以针对共享原语,而不是针对单个架构
本节其余部分将逐一介绍这些部分。
1. 使用 Transformers 提供服务
Transformers 现在支持 DecisionPipeline、AutoModelForDecision 和 DecisionConfig 类。它们遵循 transformers 中 pipeline 和模型类的整体结构,但专为决策模型量身定制。
也可以像这样检查配置和模型:
Transformers 还支持 /v1/systemone 端点。
我们可以使用服务依赖启动本地服务器:
使用兼容版本的 Transformers,我们就可以发送决策请求:
响应中包含三个具名答案,以及相应的类型化结果和概率。
一个有趣的细节是,上述 API 也适用于兼容的自回归语言模型。Transformers 会构造决策提示,在一次批量前向传播中评估答案标签的 logits,并应用 softmax,而不生成响应文本。这意味着我们可以在不必训练新模型的情况下试验决策接口。
2. 使用 llama.cpp 提供服务
llama.cpp 也通过相同的 /v1/systemone API 支持决策模型。
例如,我们可以从 Hub 启动一个 GGUF 决策模型:
默认服务器运行在 9931 端口。
然后,我们可以使用 http://localhost:9931/v1/systemone 发送包含相同状态和问题的请求。由于模型由服务器选定,我们可以在请求中省略 model 字段。
其有用之处在于接口兼容性。
3. 在 Hugging Face Hub 上发现模型
Hugging Face 推出了专门的决策模型标签,用于发现兼容模型。这很有用,因为决策模型不必共享单一主干或架构。
例如,该生态既包括基于 ModernBERT 等编码器架构的模型,也包括源自更大生成式语言模型主干的模型。
4. 使用 Hugging Face 工具训练决策模型
理解了推理之后,下一个问题是能否适配决策模型。由于决策模型已集成到 transformers 中,我们可以用 Trainer API 对其进行微调。
下面是一个玩具示例,用于微调 JEV-9B 来路由支持请求。它有意保持小巧,但展示了关键部分:
每个示例都是一个决策请求(一个状态加若干问题),并与金标准答案配对。
model.decision_config.prepare_inputs 会将请求转换为模型输入,方式与推理时相同。
模型为每个选项返回一个 logit,因此选择题通过对选项使用普通交叉熵损失进行训练。
对训练决策模型的一等支持也即将登陆 TRL( huggingface/trl#8040 ),这样我们就不必手写这些管道代码。截至撰写本文时,该 PR 仍处于开放状态。
如果我们想更进一步,将生成式 LLM 转变为决策模型,Unsloth 提供了一套方案,使用 LoRA 和决策评分头对 Qwen 等模型进行微调。
最终思考
决策模型之所以有趣,并不是因为分类本身是新的,而是因为它们让决策和概率成为软件的一等输出。
传统分类器已经能产生概率,零样本分类器也已经允许在运行时定义类别。决策模型将这些想法带入一个类型化接口,具备多种问题原语、非生成式评分,以及通过专门训练获得可靠、校准决策的可能性。