Article · AI translation
大型语言模型(LLM)非常擅长生成文本。我们用它们回答问题、编写代码、推理问题,以及做更多事情。但并非每个问题都需要生成文本。
设想一个客户支持系统收到以下消息:
“我的订阅被扣了两次款。我今天需要退款。”
系统需要确定应由哪个团队处理该请求、该请求有多紧急,以及客户是否在要求退款。
我们可以让大型语言模型返回一个包含这些答案的 JSON 对象。
但如果模型无需生成任何文本,就能直接评估可选项并返回它们的概率分布呢?
这就是决策模型背后的核心思想。
什么是决策模型?
决策模型接收一些输入上下文(状态),针对一个具有一组预定义可能答案(原语)的问题进行评估,并返回结构化决策及相应概率。我们并非让模型逐个词元生成答案,而是让它为应用程序已经能够理解的答案分配概率。
TypeSafe AI 推出了 Jev,并将其描述为一种“系统一”模型。这个名称的灵感来自快速、直觉式思考(系统 1)与较慢、审慎式思考(系统 2)之间的区别。
社区逐渐统一使用“决策模型”这一术语,因为它描述的是模型的计算作用,而不是援引某种特定的认知理论。在本文余下部分,我们将这些模型称为“决策模型”,而不是“系统一模型”。(一项关于我们应该如何称呼此类模型的 Twitter 投票)
社区逐渐统一使用“决策模型”这一术语,因为它描述的是模型的计算作用,而不是援引某种特定的认知理论。在本文余下部分,我们将这些模型称为“决策模型”,而不是“系统一模型”。(一项关于我们应该如何称呼此类模型的 Twitter 投票)
对于决策模型,其基本接口是:
为什么不把大型语言模型用于所有任务?
我们完全可以直接提示大型语言模型返回一个包含决策结果的 JSON 对象。事实上,许多应用程序已经以这种方式使用语言模型执行分类、路由和其他结构化任务。
然而,这种方法存在几个问题。
大型语言模型不能保证遵循要求的模式:即使给出明确指令,模型仍可能生成无效的 JSON、引入意料之外的键,或返回不在允许选项之内的答案。
受约束解码有所帮助,但无法消除计算开销:Outlines 和 XGrammar 等库可以通过限制模型在每一步能够生成的词元,强制输出遵循语法规则或 JSON 模式。这能确保输出符合所支持的结构约束,但也会带来额外的工作量。
为什么要生成完整的回答:大型语言模型是为开放式生成而设计的,但当应用程序只需从预定义答案中做出选择时,自回归解码可能是不必要的工作。
决策模型与分类模型有何不同?
在理解决策模型的接口之前,先回顾两种密切相关的方法会有所帮助,即传统分类和零样本分类。
传统分类
假设我们训练一个分类器,将客户支持请求分配给 3 个部门:
账单部门
技术支持部门
销售部门
传统分类模型学习将输入映射到一组预定义标签。在训练过程中,模型从示例中学习预测这些标签。分类头通常为每个类别生成一个 logit,softmax 则将这些 logit 转换为概率分布。
这里的局限在于,输出类别被固定在模型的分类头中。
如果我们引入第 4 个部门,例如法务部,现有分类器不会自动获得相应的输出类别。我们可能需要修改输出层、收集训练数据,并重新训练或调整模型。
零样本分类
零样本分类解决了这一局限的一个重要方面。我们不必要求分类器针对每个输出类别专门训练,而是在推理时提供候选标签。
例如:
与传统的固定标签分类器不同,类别可以随请求而变化。让我们再添加一个部门,例如“法务部”,看看模型的输出。
一种常见实现方式使用针对自然语言推断(NLI)训练的模型。每个候选标签都会转换为一个假设,模型会衡量输入在多大程度上蕴含该假设。
这听起来已经与决策模型很相似了。在很多方面,确实如此。
决策模型的不同之处
决策模型将这一思路扩展到单纯将输入归入某个类别之外。决策模型可以接收多个关于同一状态的具名问题,而这些问题可以有不同的答案类型。这些类型可以是从备选项中选择(choice)、在有序量表上评分(score),或估计某个陈述为真的概率(noul)。
更重要的是,它的接口围绕可能决策的概率分布而设计。
请看以下 3 种方法:
属性
分类
零样本分类
决策模型
各选项的概率
是
是
是
在推理时定义标签
否
是
是
多个具有类型的问题
否
否
是
有序评分和是/否决策
取决于具体任务
经过调整可以实现
原生基本类型
决策模型的优势并不在于它们发明了运行时定义标签或概率分类,而在于它们将这些能力组织成一致的接口,并且可能由专门针对决策优化的架构和训练流程提供支持。
决策模型接口
决策模型请求包含以下 2 个组成部分:
state
questions
状态
状态是模型应评估的信息。它可以是字符串、结构化的 JSON 对象,或者对于支持全模态的模型,可以是其他模态。
例如:
问题及其基本类型
问题描述了我们想了解状态的哪些方面。在决策模型接口中,3 种基本类型代表不同形式的决策:
选择(Choice):从几个可能的答案中选出 1 个。
评分(Score):在有序量表上评估某个事物。
Noul:以概率形式回答是/否问题。
让我们逐一了解它们。
选择是最直观的基本类型,也最接近传统分类。
假设我们提出以下问题:
哪个部门应该处理这项客户请求?
哪个部门应该处理这项客户请求?
可选项为账单部、技术支持部和销售部。
模型为每个选项分配一个 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)}
这里,(K)是选项的数量。
请看以下示例性概率分布:
选项
概率
账单部
0.998
技术支持部
0.001
销售部
0.001
这些概率之和为 1:
∑ i = 1 K p i = 1.
\sum_{i=1}^{K}p_i=1.
模型选择概率最大的选项:
y ^ = arg max i p i
\hat y=\arg\max_i p_i
在这个例子中,选中的是账单部,概率为 0.998,但其余概率也有用。它们表明模型如何在各备选项之间分配其确信程度。
当存在几个不同的备选项时,可以使用选择。但如果我们想在有序量表上衡量某个事物呢?
请看这个问题:
这项客户请求有多紧急?
这项客户请求有多紧急?
我们定义 3 个级别:
0:紧急程度低
1:紧急程度中等
2:紧急程度高
模型同样会生成一个概率分布:
级别
概率
0 — 低
0.10
1 — 中
0.26
2 — 高
0.72
Score 原语并非只返回最可能的等级,而是计算等级索引的期望值。
对于表示等级的随机变量 (X),其期望值为:
E [ X ] = ∑ i = 0 K − 1 i p i
\mathbb{E}[X]=\sum_{i=0}^{K-1}ip_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
因此,报告的分数是 1.7。
这并不意味着模型选择了一个介于中和高之间的虚构等级,而是意味着其概率分布的期望值为 1.7。
第 3 种原语是 Noul,它表示一个二元问题。
例如:
客户是否在申请退款?
客户是否在申请退款?
我们不定义选项列表,而是让模型返回答案为真的概率。可以用伯努利分布来理解这一点(noul 一词源自 Bernoulli)。
设 (Y) 表示一个二元结果:
Y ∼ Bernoulli ( p )
Y\sim\operatorname{Bernoulli}(p)
其中
P ( Y = 1 ) = p , P ( Y = 0 ) = 1 − p .
P(Y=1)=p,\qquad P(Y=0)=1-p.
如果模型返回:
它为“是”赋予 0.92 的概率,为“否”赋予 0.08 的概率。
模型在这里并未随机抽样得出二元答案。它返回的是概率参数本身,由应用程序决定如何据此采取行动。
到目前为止,我们已经从模型获得了概率分布。但决策模型接口还会为 Choice 和 Score 返回一个名为 confidence 的字段。
完整的分布可能包含多个可能的答案,因此概括模型的判断有多集中很有用。confidence 正是用于此目的。
对于有 (K) 个选项的 Choice,置信度为:
p max − 1 K 1 − 1 K
\frac{p_{\max}-\frac{1}{K}}{1-\frac{1}{K}}
其中 ($p_{\max}$) 是最大的预测概率。
直观地说:
均匀分布的置信度为 0。($p_{\max} = \frac{1}{K}$)这意味着模型估计所有选项出现的可能性相同。
概率完全集中在一个选项上的分布,其置信度为 1。($p_{\max} = 1$)
胜出选项的概率相对于均匀分布越高,置信度就越高。
在前面有 3 个选项的示例中,Billing 的概率为 0.80:
C = 3 ( 0.99 ) − 1 2 = 0.98
C=\frac{3(0.99)-1}{2}=0.98
请注意,胜出选项的概率是 0.99,但报告的置信度是 0.98。置信度会根据可用选项的数量对最大概率进行归一化。相比之下,有序 Score 示例的置信度仅为 0.558。
Hugging Face 生态系统中的决策模型
决策模型是一个新兴且发展迅速的领域。各个模型在内部采用不同的决策方式(对整个模式联合评分的模型头、基于大语言模型骨干网络的独立输出层、适用于边缘设备的版本和多模态版本等)。这种多样性是好事,但也有代价。如果每个模型都提供自己的接口,围绕它构建的每个工具都需要针对具体模型进行适配。
我们在 Hugging Face 的目标是就通用接口达成共识,同时不强制采用统一的实现方式。只要决策模型接收相同的状态和问题,并返回相同类型的决策,它就应该能够自由选择内部的工作方式。一旦有了这样的约定,生态系统的其他部分就可以在此基础上统一构建:
llama.cpp 等推理引擎可以通过同一个 API 提供任何决策模型的服务
Hub 可以以一致的方式打包和展示这些模型
训练工具可以面向共享原语,而不是针对单个架构
本节其余部分将逐一介绍这些方面。
1. 使用 Transformers 提供服务
Transformers 现在支持 DecisionPipeline、AutoModelForDecision 和 DecisionConfig 类。它们沿用 transformers 中流水线和模型类的整体结构,但专为决策模型设计。
也可以像这样查看配置和模型:
Transformers 还支持 /v1/systemone 端点。
我们可以使用提供服务所需的依赖项启动本地服务器:
使用兼容版本的 Transformers,接下来我们可以发送一个决策请求:
响应包含 3 个具名答案,以及相应的类型化结果和概率。
一个有趣的细节是,上述 API 也适用于兼容的自回归语言模型。Transformers 会构造决策提示,在批量前向传播中计算答案标签的 logits,并应用 softmax,而不生成响应文本。这意味着我们不一定要训练新模型,就可以试验决策接口。
一个有趣的细节是,上述 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 引入了专门的 decision-model 标签,用于发现兼容模型。这很有用,因为决策模型不必共用同一种骨干模型或架构。
例如,该生态系统既有基于 ModernBERT 等编码器架构的模型,也有从更大的生成式语言模型骨干模型衍生而来的模型。
4. 使用 Hugging Face 工具训练决策模型
了解推理之后,下一个问题是我们能否调整决策模型。由于决策模型已集成到 transformers 中,我们可以使用 Trainer API 对其进行微调。
下面是一个使用 JEV-9B 进行微调以分流支持请求的玩具示例。它刻意保持简短,但展示了关键部分:
每个样本都是一个决策请求(一个状态加上若干问题),并配有正确答案。
model.decision_config.prepare_inputs 会将请求转换为模型输入,方式与推理时相同。
模型会为每个选项返回一个 logit,因此选择题使用针对各选项的普通交叉熵损失进行训练。
TRL 也即将提供对训练决策模型的一等支持(huggingface/trl#8040),这样我们就不必手动编写这些配套代码。撰写本文时,该 PR 仍未关闭。
如果我们想更进一步,将生成式大语言模型转变为决策模型,Unsloth 提供了一个方案,使用 LoRA 和决策评分头对 Qwen 等模型进行微调。
最后的思考
决策模型之所以有趣,并不是因为分类是新事物,而是因为它们将决策和概率作为软件中的一等输出。
传统分类器已经能输出概率,零样本分类器也已经允许在运行时定义类别。决策模型将这些理念纳入一个类型化接口,提供多种问题原语、非生成式评分,以及通过专门训练实现可靠且经过校准的决策的可能性。