Laya:33ms、零幻觉、$0——别让 LLM 干分类的脏活
1. 什么是Laya
Laya 是 Convai Innovations 开源(Apache 2.0)的多语言、非自回归(non-autoregressive)System 1 决策引擎。它对任意状态(文本、邮件、工单或 JSON 文档)上的类型化问题(choice / score / noul)在单次前向传播中给出答案——单问题约 33 ms(T4 GPU),批量时 7.2 ms/问题。它不生成任何文本,因此没有输出需要解析,也没有幻觉问题。模型通过强化学习(RLCD,基于严格恰当评分规则 proper scoring rules 的奖励,GRPO 风格策略梯度)训练,并内置一个 Router 在每次请求前选择最合适的检查点。
Laya 家族包含三个检查点(同一 Hugging Face 仓库 convaiinnovations/laya 的不同子目录):
| 检查点 | 编码器 | 参数量 | 上下文 | 用途 |
|---|---|---|---|---|
laya |
ModernBERT-large | 421M | 512 | 英语 |
laya-multilingual |
mmBERT-base | 322M | 1024(编码器支持至 8192) | 100+ 语言,速度快 2 倍 |
laya-typed-decisions |
ModernBERT-large | 421M | 1024 | typed-decisions 工作流(微调版) |
在线资源:
- Hugging Face 模型:
convaiinnovations/laya - 交互式 Demo:
convaiinnovations/laya-demo - 工程博客:dev.to 文章
1.1. Laya 模型的架构
Laya 是纯编码器(encoder-only)架构,没有解码器、不做文本生成——这是它"非自回归"的本质:所有选项并行打分,一次前向即出结果。
1. 决策模型主体(DecisionModel,laya/common.py)
- 双向 Transformer 编码器骨干:ModernBERT-large(
英语/typed-decisions)或 mmBERT-base(多语言,RoPE 支持最长 8192 上下文)。 - 类型化决策头,由以下部件组成:
- 追加的 TransformerEncoder 层(默认 2 层)进一步加工表示;
type_emb:3 种问题类型(choice/score/noul)的类型嵌入;scorer打分器(LayerNorm → Linear → GELU → Linear):对每个选项的标记位置输出一个分数,softmax 后得到选项的概率分布;act_head动作头:把 CLS 池化表示与 4 个决策特征(top1 概率、top1-top2 差、归一化熵、选项数)拼接后映射为动作 logits(GRPO 训练用);- 每种问题类型各带一个温度参数(temperature scaling),用于校准。
2. 输入序列格式
[CLS] <类型> instructions [SEP] [MASK] opt0 [MASK] opt1 ... [SEP] state [SEP]
每个选项前插入一个 [MASK] 标记,模型对每个标记位置打分作为该选项的得分——这是"选项并行打分、单次前向"的实现方式。选项文本与问题指令共享固定的头部 token 预算(head_max_len,英语 192、多语言 256),其余 token 留给待评估的状态文本。这也解释了它的一个架构限制:选项过多时每个选项只能分到很少的 token(见"测试集表现"中的 Banking77)。
3. 训练方式:RLCD(RL from strictly-proper scoring rules)
奖励函数是严格恰当评分规则的组合:log score + 球面分数(spherical score);对有序的 score 型问题额外加上排序概率分数 RPS(Ranked Probability Score)。恰当评分规则保证"如实报告概率"是最优策略,因此训练出的概率具有统计意义,可用于置信度门控。训练采用 GRPO 风格策略梯度,并支持 TD(λ) 目标处理多轮对话轨迹。
4. Router(检查点路由)
纯 Python 的脚本/语言检测(<0.5 ms)在前向传播之前决定用哪个检查点:非拉丁文字直接送多语言检查点;拉丁文字则判断语言是否为英语;也可显式指定 model= 覆盖。每次结果都带完整路由元数据(选择的模型、原因)。Router 支持 preload 预载、max_loaded LRU 淘汰、attach 复用已有 agent、unload 释放显存。
5. 校准(Calibration)
两个基础检查点出厂时均偏过度自信,需在留出数据上按(问题类型, 选项数)逐组拟合温度:laya 的 ECE 从 0.466 降到 0.081,laya-multilingual 从 0.314 降到 0.106。laya-multilingual 出厂时完全没有拟合温度,依赖其概率前必须自行拟合。
1.2. Laya 和 BERT 的区别
Laya 和你以前用过的 BERT 模型,核心区别在于模型定位不同。
Laya 并没有创造全新的网络架构,它的“大脑”本身就是 ModernBERT。ModernBERT 可以看作是 BERT 时隔六年的一次“现代化大修”,用上了不少大模型领域的新技术。
但 Laya 和原始的 BERT 或 ModernBERT 最关键的不同,在于它要解决的问题和输出的结果完全不一样。
1.2.1. 基础架构:ModernBERT 与原始 BERT 的区别
你可以把 ModernBERT 理解为一个“Pro”版的 BERT,它在好几个维度上都做了升级,主要目的就是更快、更省、能处理更长的文本。
| 对比维度 | 原始 BERT (以 base 为例) | ModernBERT (Laya 的基础) |
|---|---|---|
| 上下文长度 | 通常为 512 个 token | 原生支持 8192 个 token,是前者的 16 倍 |
| 位置编码 | 可学习的绝对位置编码 | 旋转位置嵌入 (RoPE),能更好地理解相对位置,也更容易扩展到长序列 |
| 注意力机制 | 全注意力 | 交替注意力:大部分层用局部窗口,少数层用全局注意力,大幅降低长文本的计算量 |
| MLP 层 | GeLU 激活函数 | GeGLU,一种性能更好的门控线性单元 |
| 效率优化 | 相对较少 | Unpadding、Sequence Packing、Flash Attention 等,减少计算浪费,速度可达 DeBERTa 的 2-4 倍 |
| 训练数据 | 维基百科、书籍等 | 2 万亿 token,包含网络文档、代码、科学文章等,数据更多样 |
1.2.2. 核心定位:Laya 与 BERT/ModernBERT 的本质不同
这是最关键的一点。原始的 BERT 和 ModernBERT 是通用基础模型,像一块未经雕琢的“料子”。你需要用它来微调某个具体任务,比如训练一个分类器来判断一封邮件是“投诉”还是“咨询”。
而 Laya 的定位是直接可用的“决策引擎”。它在 ModernBERT 的基础上,额外训练了一个专门的“决策头”,让你可以直接提出结构化的“问题”,并立刻得到结构化的答案。
| 对比维度 | BERT / ModernBERT (作为基础模型) | Laya (作为决策引擎) |
|---|---|---|
| 输出形式 | 文本的嵌入向量 (embeddings) 或单个分类标签 | 结构化的判断:从预设选项中选择 (choice)、评分 (score) 或概率 (noul) |
| 核心功能 | 提供通用的文本理解能力,需要微调才能用于特定任务 | 直接回答类似“这封邮件属于哪个部门?”这样的类型化问题,零样本能力有限,但微调后效果更好 |
| 使用方式 | 需要你定义并训练一个分类头,然后进行推理 | 定义问题 → 输入文本 → 直接得到答案和置信度 |
| 速度 | 已优化,但任务不同 | 针对决策任务做了极致优化,一次前向传播即可输出所有问题的答案,T4 GPU 上单问题约 33ms |
| 意图识别中的角色 | 作为特征提取器,提取文本的语义特征用于后续分类 | 作为开箱即用的分类器,直接输出意图类别和校准过的置信度 |
1.3. Laya 对多语言的支持
laya-multilingual(mmBERT-base 编码器)宣称支持 100+ 种语言,在 MASSIVE 基准的 51 种语言上做了完整评测。- 英语检查点
laya在英语之外不是退化而是崩溃,且崩溃时依然自信:高棉语(Khmer)准确率 0.000 而置信度高达 0.952;其平均置信度在任何准确率水平下都不低于 0.885,因此置信度门控救不了它——这正是 Router 必须在前向传播之前完成路由的原因。 - 关键数字(MASSIVE 意图分类,20 选项,随机基线 0.050;XNLI 自然语言推理):
| 任务 | laya |
laya-multilingual |
|---|---|---|
| MASSIVE 意图 — 英语 | 0.783 | 0.657 |
| MASSIVE 意图 — 其他 13 种语言 | 0.306 | 0.451 |
| XNLI — 英语 | 0.860 | 0.843 |
| XNLI — 其他 14 种语言 | 0.521 | 0.731 |
| 51 语言宏平均准确率 | 0.227 | 0.366 |
| 51 语言宏平均 ECE(越低越好) | 0.733 | 0.387 |
| 可用语言数(>3 倍随机) | 23 / 51 | 45 / 51 |
- 中文表现(MASSIVE 意图):zh-CN 0.620(laya)/ 0.630(multilingual),zh-TW 0.460 / 0.540。
- 使用建议:英语和多语言检查点各有擅场(
laya英语最强但英语外崩溃;laya-multilingual覆盖广但英语略弱),不要手工二选一,直接用Router自动路由。
1.4. Laya 是否需要训练
分情况:通用任务可直接用,领域任务必须微调。
- 基础检查点在通用任务上开箱可用:邮件垃圾过滤 0.993、钓鱼检测 0.980–0.993、AG News 0.937–0.947、BoolQ 0.830。
- 但在 typed-decisions(发票处理、安全事件、客服、agent 轨迹观测四类工作流)上,基础检查点零样本接近瞎猜:准确率 0.362 / 0.342,而随机基线 0.318、多数类基线 0.461——基础检查点甚至低于多数类基线。该基准上 0.766 的成绩全部来自微调。
- 官方定位很明确:“Laya 是一个用于特化(specialise)的快速底座,不是零样本决策引擎。” 微调才是价值所在。
- 微调成本不高:官方提供 Kaggle notebook(
notebooks/laya_finetune_typed_decisions_2xT4_kaggle.ipynb),在免费的 2xT4 上完成全流程——构建数据集、RLCD 训练(恰当评分规则奖励 + GRPO 风格策略梯度)、拟合校准温度、评估并推送回 Hub;约 3 万问题跑 4 个 epoch 约 4–5 小时。 - 即便不微调,也强烈建议在自有数据上重新拟合温度:这是性价比最高的单项改进(ECE 0.466 → 0.081)。
1.5. Laya 在测试集上的表现
所有 Laya 数字均为官方实测(T4 Colab 与 CPU sweep,固定种子、字节级相同的问题);Jev(TypeSafe Jev 1.13.0)数字为第三方公开发表,未在本仓库复测。完整报告见仓库 BENCHMARKS.md。
1. typed-decisions(400 案例、2,000 次决策、四个工作流)
| 模型 | 准确率 | 软准确率 | Brier | ECE | score MAE |
|---|---|---|---|---|---|
laya-typed-decisions(微调) |
0.766 | 0.471 | 0.062 | 0.213 | 0.242 |
laya(基础) |
0.362 | 0.332 | 0.316 | 0.175 | 0.694 |
laya-multilingual(基础) |
0.342 | 0.326 | 0.439 | 0.285 | 0.687 |
| Jev 1.13.0(发表值) | 0.727 | 0.580 | 0.148 | 0.144 | 0.391 |
| 教师自一致上限 | 0.735 | ||||
| 多数类基线 | 0.461 | ||||
| 随机猜测 | 0.318 |
微调检查点超过 Jev 3.9 个点并突破教师上限;四个工作流全部领先:发票处理 0.804、安全事件 0.766、客服 0.764、agent 轨迹观测 0.730。按原语分:noul 0.857、choice 0.733、score 0.723。落后 Jev 的两项:软准确率(0.471 vs 0.580,argmax 更准但分布匹配较差)与出厂 ECE(0.213 vs 0.144,温度拟合后解决)。
2. 与 Jev 的对比(Router 实际路由结果 vs 第三方发表的 Jev 数字)
| Jev 1.13.0 | Laya(路由) | ||
|---|---|---|---|
| typed-decisions,2,000 决策 | 0.727 | 0.766 | +0.039 |
| AG News(4 标签) | 0.910 | 0.950 | +0.040 |
| DAIR Emotion(6 标签) | 0.480 | 0.595 | +0.115 |
| Banking77(72 vs 77 标签) | 0.870 | 0.425 | Jev 在 >20 选项时领先 |
| ECE(越低越好,温度拟合后) | 0.246 | 0.081 | 好 3 倍 |
| p50 延迟,1 问题 | 236–276 ms | 32.8 ms | 快 7.8 倍 |
| 可用语言数 | 无公开基准 | 45 / 51 | — |
| 权重 | 闭源 API | Apache 2.0 | — |
| 成本 | $0.042 / 1M tokens | 自托管 $0 | — |
DAIR Emotion 上 Jev 在 16% 的样本上给真实标签分配了零概率——对任何依赖置信度做分支的系统都是硬故障。
注:typed-decisions 的 0.766 来自微调检查点;
Router默认不会自动选中它(需auto_task_detection=True或显式model="typed-decisions",见router.py),表中"路由"口径以官方 README 为准。
3. 应用工作流(六个主题,各 400 案例,真实标注数据;"数据"列标注该主题是否在 Laya 训练集中)
| 主题 | laya | laya-multilingual | laya-typed-decisions | 数据 |
|---|---|---|---|---|
| 邮件垃圾 | 0.993 | 0.993 | 0.958 | 在训练集中 |
| 钓鱼 | 0.980 | 0.993 | 0.940 | 在训练集中 |
| LLM 护栏(越狱检测) | 0.708 | 0.755 | 0.762 | 留出集 |
| 内容审核(毒性) | 0.530 | 0.525 | 0.530 | 留出集 |
| RAG 段落相关性 | 0.625 | 0.657 | 0.625 | 在训练集中 |
| 客服分诊(10 路队列) | 0.502 | 0.522 | 0.505 | 在训练集中 |
| 模型路由(领域) | 0.639 | 0.123 | 0.659 | 留出集 |
4. 英语任务
| 任务 | laya |
laya-multilingual |
备注 |
|---|---|---|---|
| AG News | 0.947 | 0.937 | 在训练集中 |
| BoolQ | 0.830 | 0.787 | 在训练集中 |
| DAIR Emotion | 0.573 | 0.513 | 留出集 |
| prompt-injections | 0.698 | 0.578 | 留出集,n=116 |
| SST-5(有序) | 0.372 | 0.282 | 留出集 |
5. 速度(Tesla T4,实测)
| 每次调用问题数 | laya |
laya-multilingual |
|---|---|---|
| 1 | 39.5 ms | 32.8 ms |
| 5 | 84.5 ms | 40.1 ms |
| 10 | 158.6 ms(15.9 ms/题) | 72.3 ms(7.2 ms/题) |
| 50 | 771 ms | 337 ms(6.8 ms/题) |
批量吞吐达 103–332 问题/秒(单块 T4)。CPU 上预载后为 193–464 ms/请求。
6. 诚实的局限(官方自述)
- 基础检查点在 typed-decisions 上零样本接近随机——0.766 属于在该基准自身训练集上微调过的检查点。
choice问题请控制在 约 20 个选项以内:77 选项的 Banking77 上每个选项只分到约 3–4 个 token,两个检查点都恰好得 0.425(预算上限而非能力差距)。可用predict_shortlist(嵌入预筛 top-k 后一次前向)、调大head_max_len/max_len或拆分为粗/细两级问题缓解。- 留出集上的内容审核只有 0.530(宏 F1 0.400),平衡二分下仅略高于随机。
- 有序
score是最弱的原语(SST-5 0.372)。 - 选项顺序鲁棒性:20 选项时换序后答案变化率 0.150(laya)/ 0.230(multilingual),逊于 Jev 的 0.13。
- 出厂偏过度自信,务必自行拟合温度。
2. Laya 的安装和运行
2.1. Laya 的安装
pip install laya
要求 Python 3.10+(依赖决定了下限:huggingface_hub 1.x、transformers 5.x、torch 2.14 均要求 3.10)。模型权重从 Hugging Face Hub 自动下载(仅下载所用子目录,不用拉全家族)。
Laya 推理对硬件要求很低,普通无独显的笔记本即可运行:
- 纯 CPU 推理是官方测试过的路径:51 语言评测的 CPU sweep 就是在 CPU 上跑的;官方 CPU 延迟为每请求 193–464 ms(预载后,服务器 CPU 实测)——笔记本 CPU 实测明显更慢(0.7–5 s/次,见 2.3 节)
- 模型很小:磁盘下载 english 804 MB / multilingual 614 MB(fp16 safetensors),加载到内存约 1.7 GB / 1.3 GB(fp32)——笔记本选 multilingual 即可,一块 T4 都不需要,更不用说 GPU
- 依赖轻:Python 3.10+、
torch/transformers标准栈,pip install laya 即装即用
注意事项:生产模式务必预载,否则语言切换时 CPU 上会有约 7.4 秒的模型重建。
preload=True会预载全部三个检查点(含 typed-decisions,多下载约 800 MB、多占约 1.7 GB 内存),按需预载请用preload(["english", "multilingual"])。16 GB 内存的笔记本可同时预载两个检查点。微调则不同——官方流程按 Kaggle 2xT4 设计(约 4–5 小时),笔记本上不建议做。
国内网络环境:huggingface.co 不可达时设置 HF_ENDPOINT=https://hf-mirror.com 走镜像;huggingface_hub 1.x 默认的 Xet 后端无法走镜像(401),需再设 HF_HUB_DISABLE_XET=1;pip 官方源易超时可换清华源。以上变量必须在 import laya 之前设置,详见 2.3 节。
2.2. Laya 的运行
方式一:Router 路由模式(推荐)
Router 是官方推荐的入口:自动检测脚本与语言(亚毫秒级),把任意语言的请求分派到最优检查点。
import laya
from laya import Router
# 生产环境务必预载,避免语言切换时 7–10 秒的模型重建
router = Router(preload=True) # 预载全部三个检查点(含 typed-decisions)
# router = Router(preload=True, device="cuda")
# router = Router(); router.preload(["english", "multilingual"]) # 按需预载,省下载和内存
# router.attach("english", existing_agent) # 复用已构建的 agent,避免显存重复占用
# router = Router(max_loaded=2) # 常驻两个热检查点,LRU 淘汰
state = {
"from": "user@acme.com",
"subject": "Duplicate charge on invoice #4411",
"body": "Hi, we were billed twice for March. Please refund the duplicate today or we will cancel our plan."
}
questions = {
"department": {
"type": "choice",
"instructions": "Which department should handle this request?",
"criteria": {
"billing": "invoices, payments, refunds",
"technical": "bugs, outages, system errors",
"sales": "pricing, new contracts",
"other": "everything else"
}
},
"urgency": {
"type": "score",
"instructions": "How urgent is this request?",
"criteria": ["not urgent", "soon", "critical deadline or blocking issue"]
},
"churn_risk": {
"type": "noul",
"instructions": "Does the user threaten to cancel or leave?"
},
"refund_requested": {
"type": "noul",
"instructions": "Does the user explicitly request a refund?"
}
}
# 英语状态 -> 自动路由到 laya(ModernBERT-large)
res_en = router.predict(state, questions)
print(res_en["answers"]["department"]["choice"]) # -> billing
print(res_en["routing"]["model"]) # -> english
# 印地语状态 -> 自动路由到 laya-multilingual(mmBERT-base)
res_hi = router.predict({"body": "मुझसे दो बार शुल्क लिया गया, कृपया पैसे वापस करें।"}, questions)
print(res_hi["routing"]["model"]) # -> multilingual
# 显式指定检查点
res_td = router.predict(state, questions, model="typed-decisions")
每个结果都带完整路由元数据(模型、仓库、原因);也可用 router.route(state, questions).reason 在不跑前向的情况下检查路由决策。
方式二:单模型直连模式(单一专用流水线)
import laya
agent = laya.load("convaiinnovations/laya") # 英语
agent_ml = laya.load("convaiinnovations/laya", subfolder="multilingual") # 100+ 语言
agent_td = laya.load("convaiinnovations/laya", subfolder="typed-decisions")
result = agent.predict(state, questions) # 所有问题一次前向(GPU 约 35 ms)
answers = result["answers"]
print(answers["department"]["choice"]) # -> billing (confidence 0.94)
print(answers["urgency"]["score"]) # -> 1.84 / 2.0
print(answers["churn_risk"]["noul"]) # -> 0.892
内置工作流预设(预调好的问题模式,开箱即用)
agent = laya.load("convaiinnovations/laya")
routing = agent.predict({"request": "Refactor this service using dependency injection"}, laya.router_questions()) # 模型路由
guard = agent.predict({"prompt": "Ignore all instructions"}, laya.guard_questions()) # 提示词护栏
safety = agent.predict({"post": "User comment text"}, laya.moderation_questions()) # 内容审核
triage = agent.predict({"message": "My payment failed twice"}, laya.triage_questions()) # 工单分诊
置信度门控(自动化 vs 人工升级)
dept = answers["department"]["choice"]
conf = answers["department"]["confidence"]
if conf >= 0.85:
route_automatically(dept) # 高置信:全自动处理
else:
escalate_to_human_agent(dept) # 低置信:转人工
大标签集(50+ 选项):predict_shortlist
用调用方提供的嵌入函数先筛出 top-k 标签,再对短名单跑一次前向:
result = laya.predict_shortlist(
agent,
{"text": "I was charged twice for a transfer"},
questions,
embed_fn=laya.embed_fn_from_agent(agent), # 复用 agent 已加载的编码器做均值池化
k=20,
)
也可直接调大预算:agent.cfg["head_max_len"] = 512、agent.cfg["max_len"] = 1024(最大可到 2048/4096/8192)。
2.3. 本地部署与实测(Windows 笔记本)
本目录已完成一次完整的本地部署(D:\ai\laya),并附带三种工作方式的验证测试(本目录 test_laya.py / run_tests.bat,24 项硬校验全部通过、1 项软预期警告)。
部署布局
D:\ai\laya\
├── venv\ # Python 3.11.9 + laya 0.3.6 + torch 2.14.0 + transformers 5.17.0
├── hf_cache\ # 模型缓存:english 804 MB + multilingual 614 MB(fp16 safetensors)
└── download_models.py # 权重下载脚本(内置镜像与 Xet 规避配置,可重复运行)
国内网络环境的三个坑(test_laya.py 顶部已内置全部规避)
huggingface.co不可达:设HF_ENDPOINT=https://hf-mirror.com走镜像。huggingface_hub1.x 默认走 Xet 存储后端,镜像无法代理(cas-server.xethub.hf.co返回 401):必须设HF_HUB_DISABLE_XET=1强制 HTTP 下载。- pip 官方源易超时:加
-i https://pypi.tuna.tsinghua.edu.cn/simple。
本机实测延迟(CPU 推理、无独显笔记本、单次调用、含首次前向的 torch 预热)
| 操作 | 延迟 |
|---|---|
| Router:英语输入(4 问题 → english,421M) | 2.7 s |
| Router:中文输入(4 问题 → multilingual,322M) | 0.7–0.8 s |
| 直连 laya:4 问题(choice + score + noul) | 3.4–4.9 s |
| 内置预设:5 问题(guard / triage / router / moderation) | 3.2–5.1 s |
对比官方 CPU 数字(193–464 ms/请求,服务器 CPU):笔记本 CPU 慢约一个数量级,能用但仅适合低频/离线场景;吞吐敏感的生产路径需服务器 CPU 或 GPU。两个检查点常驻内存约 3 GB(fp32),16 GB 内存笔记本无压力。
实测中的语义验证(英文 instructions):英语/中文重复扣费邮件均判 department=billing(中文置信度 0.981)、越狱提示 jailbreak=1.0、客服样本 intent=refund(0.948)、代码请求 domain=code(0.919)。另注:加载检查点时会出现温度 clamp 警告(choice:11+=0.1006),即 11 个选项以上的 choice 置信度应视为未校准。
3. Laya 模型能做什么
Laya 对任意状态(文本、邮件、工单、JSON 文档)输出类型化决策,三种决策原语覆盖结构化判断的绝大部分需求:
| 原语 | 输出 | 典型用途 |
|---|---|---|
choice |
最优标签 + 各选项概率 + 置信度 | 部门路由、意图分类、话题归类 |
score |
有序量表上的期望等级 + 分布 + 置信度 | 沮丧程度、工单紧急度、危害严重性 |
noul |
真值概率 P(true),0.0–1.0(温度拟合后可作校准置信度) | 钓鱼检测、垃圾过滤、越狱检测、流失风险 |
具体应用场景:
- 邮件/工单智能路由:意图分类、紧急度打分、部门分派(choice + score 组合,一次前向全部完成)。
- 垃圾邮件与钓鱼检测:0.993 准确率、ECE 约 0.01——但注意两项数据源均在训练集中,数字偏乐观;留出集任务(护栏、内容审核)只有 0.53–0.76。
- 实时 LLM 提示词护栏:越狱检测 0.70–0.76(留出集;注入/泄露类问题未单独公布数字),可用于 LLM 调用前的低成本预过滤。
- 智能模型路由:判断请求该走小模型还是前沿大模型,为 LLM 网关省成本。
- RAG 段落相关性判断、客服流失风险预警、发票处理、安全事件分类、agent 轨迹可观测性(官方四个 typed-decisions 工作流)。
- 置信度门控体系:高置信全自动执行、低置信转人工, probabilities 经恰当评分规则训练 + 温度拟合后具有统计意义。
它不做的事:不生成、不总结、不写代码、不做多步推理——它是 Kahneman 意义上的 System 1(快速直觉判断),不是 System 2。
3.1. 与 LLM 相比它的优势是什么?
| 维度 | LLM(生成式) | Laya |
|---|---|---|
| 机制 | 自回归逐 token 生成 | 编码器单次前向,选项并行打分 |
| 延迟 | 数百 ms 到数秒 | 单问题 33 ms,批量 7.2 ms/题(T4) |
| 输出 | 自由文本,需要解析,可能幻觉/格式漂移 | 结构化类型化结果,无生成即无幻觉、无解析失败 |
| 概率质量 | 逐 token 概率,难以直接当决策置信度 | RLCD 恰当评分规则训练 + 温度拟合,ECE 0.081,置信度可统计信任 |
| 吞吐 | 受生成长度限制 | 103–332 问题/秒(单块 T4),可批处理 |
| 成本 | API 按 token 计费 | Apache 2.0 权重,自托管 $0,一块 T4 甚至 CPU 即可跑(官方 193–464 ms,笔记本实测 0.7–5 s) |
| 多语言/路由 | 前沿 LLM 天然多语言 | 45/51 语言可用 + 亚毫秒 Router |
核心优势总结:
- 快一个数量级:比同类决策 API(Jev 236–276 ms)快约 7 倍,比典型 LLM 调用快 1–2 个数量级,适合放在请求热路径上。
- 可靠性来自结构而非约束:不生成文本,就不存在输出解析失败、提示注入式"越狱回答"、幻觉编造标签等问题。
- 置信度可信任:这是它与"让 LLM 输出一个数字"最本质的区别——恰当评分规则保证概率如实,温度拟合后 ECE 0.081,即平均而言置信度与实际正确率的偏差仅约 8 个百分点,可安全地用作自动化/转人工的分界线。
- 成本与部署门槛极低:开源权重、单卡可跑、无需 API key、无按 token 费用。
同时要清醒看到它不能替代 LLM 的地方:零样本泛化弱于 LLM(领域任务必须微调,基础检查点在 typed-decisions 上甚至低于多数类基线);不支持高基数标签(<20 选项);不做生成、总结与多步推理。
实践中两者的关系是互补而非替代:用 Laya 这类 System 1 做高频、低成本、可校准的门控决策(护栏、路由、分诊、相关性),把 LLM 留给真正需要生成和推理的任务——Laya 官方的模型路由预设(router_questions)本身就是这个模式的体现。
4. Laya 用于意图识别:以手机银行的意图识别为例说明
4.1. 从 BERT 迁移到 Laya:使用方式的变化
与 1.2.2 节的定位对比一致,落到意图识别上:用 BERT 你需要准备数据、设计分类头、微调后才能上线;用 Laya 定义好意图选项即可零样本先跑起来看效果,不满意再微调,且输出自带可用于门控的置信度。可以把 Laya 理解为:ModernBERT 这个更强的“引擎”,加装了一套专用于快速决策的“变速箱和控制系统”——继承 BERT 架构在理解任务上的优势,把使用门槛从“需要微调”降到“定义问题即可调用”。
4.2. Laya 在手机银行意图识别中的应用
以手机银行多轮对话为例,意图分为理财、转账、聊天三类,下面构造一个基于 Router 的完整方案。
4.2.1. 构造状态(State):处理多轮对话
Laya 本身不管理对话历史,你需要自己维护一个 state。对于多轮对话,最直接的方式是把最近几轮的用户话语拼接起来。
# 模拟一个多轮对话历史
conversation_history = [
{"role": "user", "text": "我想看看有什么理财产品"},
{"role": "assistant", "text": "好的,我们有多款理财产品,您对什么期限感兴趣?"},
{"role": "user", "text": "短期的,三个月左右吧"},
{"role": "assistant", "text": "推荐这款90天期的,年化3.5%"},
{"role": "user", "text": "收益还行,那就买这个吧"}
]
# 构造 Laya 的 state:把最近几轮用户话语拼接起来
# 可以只取最近 N 轮,避免过长
def build_state(history, max_turns=3):
recent = history[-max_turns*2:] # 取最近几轮对话
text = " ".join([turn["text"] for turn in recent if turn["role"] == "user"])
return {"body": text}
state = build_state(conversation_history)
# state = {"body": "我想看看有什么理财产品 短期的,三个月左右吧 收益还行,那就买这个吧"}
4.2.2. 定义意图问题
questions = {
"intent": {
"type": "choice",
"instructions": "用户当前轮次的意图是什么?",
"criteria": {
"理财": "咨询、购买、赎回理财产品,关注收益、期限、风险等",
"转账": "向他人或自己账户转账、汇款、支付",
"聊天": "与银行业务无关的闲聊、问候、测试、无明确意图的对话"
}
}
}
4.2.3. 使用 Router 进行预测
from laya import Router
# 纯中文场景只需多语言检查点;按需预载,省下载和内存
router = Router()
router.preload(["multilingual"])
result = router.predict(state, questions)
intent = result["answers"]["intent"]["choice"]
confidence = result["answers"]["intent"]["confidence"]
print(f"意图: {intent}, 置信度: {confidence:.2f}")
# 可能输出: 意图: 理财, 置信度: 0.94
注:以上输出为演示性质。中文 instructions + 中文 criteria 的零样本效果未在本机实测(本机实测组合为英文 instructions + 中文正文,见 2.3 节);上线前建议先用真实对话样本跑一轮评估。
4.2.4. 结合置信度做路由决策
Laya 的置信度经过校准后可以用于自动化决策。对于手机银行场景,可以这样设计:
if confidence >= 0.85:
# 高置信度:直接路由到对应业务模块
if intent == "理财":
open_wealth_management()
elif intent == "转账":
open_transfer()
elif intent == "聊天":
reply_chitchat()
else:
# 低置信度:转人工或请求澄清
ask_clarification("请问您是想办理理财、转账,还是其他业务?")
4.2.5. 多轮对话中的注意事项
(1)上下文窗口限制
Laya 的 laya-multilingual 默认上下文是 1024 token,去掉选项头预算后,留给状态约 768 token。对于多轮对话,不要把所有历史都塞进去,建议只取最近 2-3 轮用户话语,避免超长。
(2)意图切换的检测
多轮对话中,用户可能中途切换意图。比如先说“转账”,中途又问“你们有什么理财产品”。这时需要每一轮都重新预测,而不是只在第一轮判断。
# 每一轮用户输入后,都重新构造 state 并预测
for turn in conversation_history:
if turn["role"] == "user":
state = build_state(history_up_to_current_turn)
result = router.predict(state, questions)
# 处理当前轮意图...
(3)避免“聊天”类被过度触发
“聊天”类作为兜底类别,容易吸收一些边界模糊的输入。如果发现“理财”或“转账”的意图被误判为“聊天”,可以在 criteria 中把“聊天”的描述写得更严格,比如明确“与银行无关的纯粹闲聊”。
4.2.6. 如果零样本效果不理想
对于“理财/转账/聊天”这种区分度较高的场景,零样本效果可能还不错。但如果实际数据中用户表达很口语化(如“那个钱怎么弄过去”),零样本可能不够。
这时就需要微调:
- 数据需求不大:3 个意图属于低基数分类,构造标注数据的成本远低于通用任务,官方微调 notebook 支持自定义数据集。
- 训练量小:官方 notebook 在 2xT4 上处理 3 万个问题约 4–5 小时;3 个意图的小数据集规模远小于此,训练时间相应缩短(按数据量估算,未实测)。
微调后调用接口不变,只是把检查点换成你的模型目录:laya.load("你的模型目录"),或 Router(models={"english": "你的模型目录"})。
4.2.7. 一个简化的 Router 封装
class BankIntentRouter:
def __init__(self):
self.router = Router()
self.router.preload(["multilingual"]) # 纯中文场景只需多语言检查点
self.questions = {
"intent": {
"type": "choice",
"instructions": "用户当前轮次的意图是什么?",
"criteria": {
"理财": "咨询、购买、赎回理财产品,关注收益、期限、风险等",
"转账": "向他人或自己账户转账、汇款、支付",
"聊天": "与银行业务无关的闲聊、问候、测试、无明确意图的对话"
}
}
}
def predict(self, conversation_history):
state = self._build_state(conversation_history)
result = self.router.predict(state, self.questions)
return {
"intent": result["answers"]["intent"]["choice"],
"confidence": result["answers"]["intent"]["confidence"],
"routing": result["routing"]["model"]
}
def _build_state(self, history, max_turns=3):
recent = history[-max_turns*2:]
text = " ".join([t["text"] for t in recent if t["role"] == "user"])
return {"body": text}
这个封装可以直接用在手机银行对话系统中。如果有具体的对话样本,可以先用零样本跑一下看看效果,再决定是否需要微调。
5. 总结
一句话:Laya 是“快、省、可校准”的结构化决策引擎,最适合做 LLM 体系里的 System 1 门控层;它不是零样本万能分类器,价值在微调后的专用部署。
它做对了什么(数据见 1.5 节):
- 架构选对了赛道:encoder-only + 选项并行打分,单次前向 33 ms(比 Jev 快约 7 倍)、批量 7.2 ms/题;不生成文本,就没有幻觉、没有输出解析失败。
- 概率是训练出来的:RLCD 恰当评分规则 + 温度拟合,ECE 0.081——置信度可以真的拿来当自动化/转人工的阈值。
- 对自己的弱点诚实:官方自曝“基础检查点零样本接近瞎猜”、留出集审核仅 0.53、>20 选项会崩,这种基准文档在开源项目里少见。
- 工程完整度:Router 前置路由解决英语检查点“自信地崩溃”问题;预载/LRU/attach 等生产细节齐备;Apache 2.0、单卡甚至 CPU 可跑。
它做不了什么:零样本泛化弱于 LLM(typed-decisions 上基础检查点低于多数类基线);choice 建议 <20 选项;score 是最弱原语;出厂偏过度自信,必须自行拟合温度;不生成、不总结、不推理。
选型建议:
| 场景 | 建议 |
|---|---|
| 高频分类/门控(分诊、护栏、钓鱼检测、模型路由) | 值得用,微调后官方数据 0.77–0.99 |
| 低频、需要解释/生成的场景 | 直接用 LLM |
| 中文场景 | multilingual 检查点(zh-CN 0.630);中文 instructions 效果未实测,上线前先评估 |
本地状态:已部署两个检查点(约 1.4 GB),test_laya.py 24 项硬校验全过;笔记本 CPU 单次 0.7–5 s,够验证与低频离线场景,生产需服务器 CPU/GPU。
- 点赞
- 收藏
- 关注作者
评论(0)