Hugging Face力推决策模型:不生成文本,靠概率做路由
大语言模型擅长生成文本,但处理分类、路由等结构化任务时显得笨重且不可控。Hugging Face 推出的“决策模型”通过标准化接口,直接输出带概率的决策结果,支持多选、打分和二元判断。文章解析了其与传统分类及零样本分类的区别,并介绍了在 Transformers 和 llama.cpp 中的部署与训练方法,为构建更可靠
为什么不一定要让大模型每次“写”出答案
大语言模型确实全能。提问、写代码、推理复杂逻辑都难不倒它。可落到实际应用里,许多场景压根用不着它“生成”一段文本。
设想客服系统收到这么一句话:“我被重复扣款了,今天必须退款。”系统真正要做的只有三件事——判断转给哪个部门、评估有多急、确认用户是不是在提退款要求。
过去常见的做法,是提示 LLM 返回一个 JSON 对象。能跑通,毛病却不少:模型可能吐出无效的 JSON,可能编出选项里没有的部门,也可能为了那几个字符白白烧掉大量算力。哪怕用约束解码(Constrained Decoding)把格式卡死,实质仍是让一个擅长创作的模型去做填空题,效率谈不上高。
假如模型能直接给所有候选答案打分、返回一个概率分布,全程不生成任何文本呢?这正是 Hugging Face 近期重点推广的决策模型(Decision Models)的核心思路。
决策模型是什么
决策模型拿到输入的上下文(称为 State),对照预先定义好的问题和答案选项逐项评估,最终给出结构化的决策结果和对应概率。
TypeSafe AI 早前推出 Jev 模型时,叫它“System One 模型”,取名灵感来自《思考,快与慢》里那种凭直觉的快速思维。后来社区还是统一叫“决策模型”,理由是这个词更贴切地描述了模型承担的计算角色,而不是去套认知理论。
核心接口可以简化成这样:
State(状态) + Questions(问题) + Allowed Answers(允许的答案) → Decisions(决策) + Probabilities(概率)
它跟传统分类模型差在哪
想知道决策模型的价值,先得理清它同传统分类、零样本分类之间的关系。
传统分类卡在哪
传统分类模型在训练阶段就把标签定死了。拿一个客服路由模型来说,训练时只有“账单”“技术”“销售”三类。哪天想加个“法律”部门,就得改模型头部、收集新数据、重新训练或微调。业务一变,这种“硬编码”的做法就显得很僵。
零样本分类往前走了一步
零样本分类(Zero-shot Classification)把标签固定的问题解决了。推理时把候选标签传进去,模型借自然语言推断(NLI)算出输入跟每个标签的匹配度。也就是说,“法律”部门随时能加,不用重新训练。
可它还不够灵活。零样本分类一般只管单一的分类任务,各家模型的实现方式也不一样,缺少统一的工程接口。
决策模型的突破在哪
零样本分类“运行时定义标签”的好处,决策模型接了过来,还往外扩了一层:
- 多问题并行:一次请求就能同时问好几个不同类型的问题。
- 原生支持多种决策类型:多选之外,有序打分和二元判断也支持。
- 标准化的概率输出:接口围着概率分布来设计,下游系统可以按置信度做路由,或者转人工处理。
| 特性 | 传统分类 | 零样本分类 | 决策模型 |
|---|---|---|---|
| 输出概率 | 是 | 是 | 是 |
| 运行时定义标签 | 否 | 是 | 是 |
| 多类型问题并行 | 否 | 否 | 是 |
| 原生支持打分/二元 | 需定制 | 需适配 | 是 |
决策模型的三种基本原语
决策模型这套接口把问题拆成三种基本原语(Primitives)——Choice(选择)、Score(打分)、Noul(二元判断)。
1. Choice:多选概率分布
这也是最像传统分类任务的一种。举个例子:“该由哪个部门处理?”
模型不会直接把“Billing”这个词吐出来,它的做法是对每个选项各算一个 Logit,再用 Softmax 转成概率。
# 示例代码
from transformers import pipeline
decide = pipeline("decision", model="autotrust/GEV-26B-Decide")
decision = decide({
"state": "I was charged twice for my order and want a refund.",
"questions": {
"department": {
"type": "choice",
"instructions": "Which team should handle this?",
"criteria": {
"billing": "Payments and refunds",
"technical": "Bugs and technical issues",
"sales": "Pricing and subscriptions"
}
}
}
})返回结果里,billing的概率也许高达 0.998,而technical只有 0.001。这么一组分布,既能看出哪个选项最合适,也把模型的犹豫程度摆了出来。
2. Score:有序分布的期望值
要衡量某种程度的时候,比如“紧急程度如何?”,就该用 Score 原语了。
先把等级定下来:0(低)、1(中)、2(高)。模型照样给出各等级的概率,不过最终返回的是一个期望值(Expected Value)。
假设概率分布是:低 0.10,中 0.26,高 0.72。
期望值算出来是:$0 \times 0.10 + 1 \times 0.26 + 2 \times 0.72 = 1.7$。
返回的 1.7这并不意味着真存在一个“中高”的虚构等级,它表达的是模型判断紧急程度更偏向“高”。这种连续值输出,比单纯的离散分类携带的信息更多。
3. Noul:二元伯努利决策
Noul 这个名字来自 Bernoulli(伯努利分布),用来处理是非题。比如:“用户是否在要求退款?”
模型会直接给出答案为“真”的概率。假如返回noul: 0.92,就说明模型有 92% 的把握认为用户在要求退款,剩下 8% 认为不是。应用层拿到这个概率,可以自己决定是直接走退款流程,还是转给人工确认。
关于置信度(Confidence)
概率之外,接口还会返回confidence字段。Choice 类型的置信度,是按最大概率与均匀分布之间的偏差算出来的。所有选项概率一样时,置信度为 0;概率集中到某一个选项上,置信度就趋近于 1。开发者靠它就能快速判断模型是不是“拿不准”。
在 Hugging Face 生态中使用决策模型
Hugging Face 想做的是一套统一接口,并不强求某种实现。模型只要遵循同样的输入输出契约,就能无缝接入这个生态。
1. 使用 Transformers 部署
Transformers 库已经新增DecisionPipeline 和 AutoModelForDecision加载方式和普通模型没差别,决策模型也能直接载入,再通过/v1/systemone端点对外提供。
还有一点挺有意思:手上没有专门训练过的决策模型,Transformers 照样能拿现成的自回归语言模型把这件事模拟出来。做法是先拼提示词,再批量算出各答案标签的 Logits,套上 Softmax,整个流程一个文本 token 都不生成。想试的门槛因此低了不少。
2. 用 llama.cpp 来部署
llama.cpp 同样认这套/v1/systemoneAPI。也就是说,GGUF 格式的决策模型(比如ggml-org/Kev-4B-GGUF)可以放到边缘设备或者 CPU 上跑,接口体验和云端保持一致。对延迟敏感、对隐私要求高的场景来说,这个补充很关键。
3. 去 Hub 上找模型
Hugging Face Hub 上线了decision-model标签。眼下这个生态里,既有 ModernBERT 这类编码器架构撑起来的高效模型,也有在大型生成式 backbone 上微调出来的版本。选哪个,看性能要求和硬件条件自己定。
4. 训练和微调
微调决策模型,走的是 Hugging Face 的TrainerAPI。思路不复杂:把决策请求变成模型输入,再用交叉熵损失函数盯着正确选项去训。
例如,微调 JEV-9B拿客服路由来说,准备一份数据集就行,里面放上state 和 questions,再把正确标签标好。TRL 库对决策模型的支持还在完善,相关 PR 正在合并,等落地之后,用 LoRA 等技术微调决策模型会省事很多。Unsloth 这类第三方工具也已经拿出了针对 Qwen 等模型的决策头训练方案。
结语
决策模型不是来替掉分类算法的。它做的事情,是把“决策”和“概率”摆到软件的一等公民位置上。
过去开发时,常常得在两种东西之间选:一边是灵活的 LLM,一边是高效但死板的分类器。决策模型用标准化接口,加上运行时定义标签、非生成式评分和专用训练,趟出了一条中间路。LLM 的语义理解能力留住了,工程上要的确定性、效率和可解释性也一并有了。
搭复杂的 AI Agent 或者自动化工作流时,一个能清楚说出“我有多确定”的模型,或许比只会滔滔不绝生成文本的模型更管用。