Laya 三三制:三检查点、三模式实、三原语

举报
Uncle_Tom 发表于 2026/09/24 15:29:07 2026/09/24
【摘要】 Laya 提供三个检查点:英语、多语言和类型化决策微调版。提供三种工作方式:Router 默认在英语与多语言间按语言路由;直连模式手动指定检查点;预设工作流只是问题模板,可修改后复用。在每种模式中,可以采用三种输出方式:`choice` 用于互斥分类,`score` 用于有序量表,`noul` 输出命题为真概率。

1. Laya 的“检查点”

Laya 的“检查点”(checkpoint)可以理解为同一套决策框架下的三个专用版本。它们共享相同的调用方式和决策逻辑,但骨干模型、上下文长度和适用范围不同。

1.1. 检查点的本质:同一套决策框架下的专用版本

Laya 并不是一个单一的模型文件,而是一套包含三个检查点的系统:

检查点 底层架构 核心定位 理解
laya (English) ModernBERT-large (421M) 纯英文专用 英文场景的基准检查点,英文效果最好,但不应处理非英文。
laya-multilingual mmBERT-base (322M) 多语言通用 牺牲一点英文精度,换取100+ 种语言的覆盖能力,且速度更快。
laya-typed-decisions ModernBERT-large (421M) 特定任务专家 在特定类型化决策工作流上微调过的检查点,默认不自动启用;可显式指定或开启任务检测。

1.2. 为什么需要三个检查点?关键是“语言崩塌”

Laya 设置多检查点的核心原因在于,英文检查点在处理非英文(特别是非拉丁字母)文本时会灾难性地失效。

根据官方基准测试,英文检查点在高棉语上的准确率是 0.000,但它的平均置信度却高达 0.952。这意味着模型会极其自信地给出完全错误的答案,而你无法通过“置信度低就转人工”的策略来挽救。因此,路由决策必须在推理前就做好,而不是依赖模型自身的置信度。

这就引出了 Router 的核心作用:在 <0.5ms 内通过检测书写系统和语言,将请求分发给正确的检查点,避免英文检查点去处理它根本读不懂的文本。

1.3. 各自最适合的场景

  • laya (English):如果你的用户群绝大部分是英文,优先用它。它在英文任务上表现最好,例如在 MASSIVE 英文意图识别上准确率 0.783,XNLI 英文推理达 0.860。
  • laya-multilingual:如果你的用户可能使用中文、印地语、德语等非英文语言,或者中英夹杂,优先用它。虽然它在英文上略弱(MASSIVE 0.657),但在非英文语言上明显更可靠(MASSIVE 其他语言 0.451)。你的手机银行场景如果面向中文用户,建议使用这个检查点。
  • laya-typed-decisions:这是一个默认不会被 Router 自动选中的特殊检查点,专门针对四种合成工作流微调过(客服、发票、安全事件、Agent 追踪)。它可通过显式 model="typed-decisions" 指定,或在开启 auto_task_detection=True 时按问题集匹配。不要把它当作通用意图识别器。除非你的业务场景匹配这四种工作流之一,否则用标准的 laya 或 laya-multilingual 即可。

1.4. 实践中的检查点管理

在实际部署时,有两点值得注意:

  1. 内存与加载策略:Router 默认 max_loaded=1,冷启动后首次使用才会加载检查点。为避免语言切换时反复重建模型,生产环境建议按需预载两个基础检查点:Router().preload(["english", "multilingual"])。这会把 max_loaded 提升到 2;不要用 Router(preload=True),因为那会预载全部三个检查点。
  2. 显式覆盖:你可以在调用 predict 时用 model="multilingual" 强制指定检查点,绕过自动路由。例如,如果你发现某段短文本被误判为英文,可以手动强制走多语言版本。

简单总结:用 Router 让系统自动在 laya 和 laya-multilingual 之间选择,适合手机银行的中英文混合场景。laya-typed-decisions 只有在问题集明确匹配其微调工作流时才考虑。


2. Laya 的三种工作模式

Laya 在使用有三种模式:Router 路由模式、单模型直连模式和内置预设工作流模式。三种模式分别对应 Laya 的三种使用层次。它们的核心区别在于:抽象程度不同、控制粒度不同、适用场景不同。

2.1. 模式一:Router 路由模式

代码本质:

router = Router()
router.preload(["english", "multilingual"])
result = router.predict(state, questions)

它在做什么:

你不需要关心输入是什么语言,也不需要指定用哪个检查点。Router 会自动检测书写系统和语言,然后分发到最合适的检查点。

输出:

[英语输入] routing -> english  (2100 ms)
           reason  -> English Latin text
[中文输入] routing -> multilingual  (540 ms)
           reason  -> non-Latin script (han, 100% of letters); the English checkpoint cannot read it
[仅路由不推理] 德语 -> multilingual  reason: Latin script but language looks like 'de', not English
[显式覆盖] model='multilingual' -> multilingual

核心特点:

  • 自动路由:英文走 laya,中文走 laya-multilingual,德语也走 laya-multilingual。你不需要手动判断。
  • 路由原因可解释:reason 字段告诉你为什么选了某个检查点。
  • 支持仅路由不推理:router.route() 可以在不跑前向的情况下,只告诉你该用哪个检查点。
  • 支持显式覆盖:router.predict(..., model="multilingual") 可以强制指定检查点,绕过自动路由。

适合场景:多语言生产环境。例如:手机银行场景如果面向中文用户,同时可能混杂英文,这是最省心的选择。

代价:需要额外维护 Router 对象,且预载会占用更多内存。上面实测的 65.5 秒是冷加载耗时,不是每次推理耗时。


2.2. 模式二:单模型直连模式

代码本质:laya.load("convaiinnovations/laya").predict(state, questions);加载多语言检查点时使用 laya.load("convaiinnovations/laya", subfolder="multilingual")。以下输出样例来自英语检查点。

它在做什么:

代码手动加载一个检查点,然后所有请求都走这个检查点。没有自动路由,没有语言检测。

输出样例:

agent 已加载,device=cpu
predict 一次前向完成 4 个问题,耗时 2186 ms,input_tokens=348
[PASS] 返回 answers / usage 结构
[PASS] 答案覆盖全部问题
[PASS] choice: 返回最优标签与逐选项概率
[PASS] choice: confidence 在 [0,1]
[choice] department=billing confidence=0.864 probabilities={'billing': 0.9653, 'technical': 0.014, 'sales': 0.0101,'other': 0.0107}
[PASS] score: 期望分值在量表范围内
[PASS] score: 概率分布归一
[score]  urgency=1.44/2.0 legend=['not urgent', 'soon', 'critical deadline or blocking issue']
[PASS] noul: P(true) 在 [0,1]
[noul]   churn_risk=0.8248 refund_requested=0.843

核心特点:

  • 单一检查点:所有输入都走同一个模型。如果你加载的是 multilingual,英文输入也走它;如果加载的是 laya,中文输入也走它,但效果会急剧下降。
  • 三种决策原语完整可用:choice、score、noul 都在这里展示。这是 Laya 最核心的推理能力。
  • 一次批量前向完成所有问题:4 个问题在一次批量前向中处理,耗时 2186ms(CPU 上)。
  • 返回结构完整:answers 和 usage 都有,choice 返回逐选项概率,score 返回期望值和分布,noul 返回 P(true)。

适合场景:已经明确知道输入语言,或者只需要一种语言。比如手机银行只服务中文用户,直接加载 multilingual 即可,不需要 Router 的额外开销。

代价:没有自动语言检测。如果输入语言不匹配,效果会急剧下降(英文检查点遇到中文会给出高置信度的错误答案)。


2.3. 模式三:内置预设工作流

代码本质:agent.predict(state, laya.guard_questions()) 等

它在做什么:

Laya 预置了四套问题模板,你不需要自己定义 questions,直接调用对应的函数即可。

输出样例:

[guard] 1698 ms
  jailbreak          -> 1.0
  prompt_injection   -> 1.0
  sensitive_data     -> 0.452
  harm_severity      -> 1.8659
  topic              -> coding (conf 0.4314)

[triage] 3809 ms
  intent             -> refund (conf 0.948)
  is_urgent          -> 0.4027
  frustration        -> 2.0653
  refund_requested   -> 0.901
  churn_risk         -> 0.681

[router] 2820 ms
  difficulty         -> 2.0321
  domain             -> code (conf 0.9186)
  needs_tools        -> 0.0326
  is_sensitive       -> 0.0738

[moderation] 2595 ms
  toxic              -> 0.0004
  harassment         -> 0.0
  threat             -> 0.0
  spam               -> 0.0
  severity           -> 0.3387

四套预设的用途:

四套预设只是 Laya 官方提供的参考模板,每个预设本质上就是一个返回 questions 字典的 Python 函数。

预设 用途 包含的决策
guard 安全防护 越狱检测、提示注入、敏感数据、危害程度、主题
triage 工单分诊 意图、紧急程度、挫败感、退款要求、流失风险
router 模型路由 难度、领域、是否需要工具、是否敏感
moderation 内容审核 毒性、骚扰、威胁、垃圾信息、严重程度

核心特点:

  • 开箱即用:不需要自己写 questions 字典,直接调用 laya.triage_questions() 等函数。
  • 按场景预先定义:这些模板的选项和描述是官方预设的,便于快速搭建原型,但不代表模型为这些模板单独调优。
  • 仍然共享同一套推理引擎:底层还是 choice、score、noul 三种原语,只是问题定义被封装好了。

适合场景:快速验证、原型开发,或者你的业务问题与预设维度基本一致。手机银行的“理财/转账/聊天”意图不能直接使用 triage 默认 intent 类别,应修改后使用。

代价:灵活性受限。如果你的意图不是 refund 这样的预设类别,需要自己定义 questions。

2.3.1. 预设的本质:函数返回的字典

laya.triage_questions() 这类预设函数,做的事情就是返回一个字典。triage_questions() 的实际结构如下:

# triage_questions() 返回的字典结构
{
    "intent": {
        "type": "choice",
        "instructions": "What does the customer want in `message`?",
        "criteria": {
            "refund": "money returned or a duplicate charge reversed",
            "technical_help": "a bug, outage or integration problem",
            "billing_question": "a question about an invoice, plan or payment method",
            "information": "general information, pricing or how-to",
            "cancellation": "wants to cancel or downgrade",
            "other": "none of the other options fits"
        }
    },
    "is_urgent": {
        "type": "noul",
        "instructions": "Does `message` communicate time pressure or a deadline?"
    },
    "frustration": {
        "type": "score",
        "instructions": "How frustrated does the customer sound in `message`?",
        "criteria": [
            "calm and neutral",
            "concerned but civil",
            "clearly annoyed",
            "very angry or using strong language"
        ]
    },
    "refund_requested": {
        "type": "noul",
        "instructions": "Does the customer ask for money back?"
    },
    "churn_risk": {
        "type": "noul",
        "instructions": "Does `message` suggest the customer may leave for a competitor or cancel?"
    }
}

这里的选项、量表和命题都是函数返回的默认值。常规做法是复制或修改返回后的字典,再传入 predict()。

2.3.2. 四套预设的“可替换性”

预设 它默认在做什么 你能改成什么
triage_questions() 客服意图、紧急程度、挫败感、退款要求、流失风险 改成业务意图、有序评分和独立命题
guard_questions() 越狱、提示注入、敏感数据、危害程度、主题 改成业务安全检测维度
moderation_questions() 毒性、骚扰、威胁、垃圾信息、严重程度 改成业务内容审核维度
router_questions() 难度、领域、是否需要工具、是否敏感 改成业务路由维度

预设的“用途标签”是官方给它的命名和定位,不代表只能做这件事。triage_questions() 返回的就是一个普通的 questions 字典;修改后可用于其他业务,只要 state 包含问题引用的字段(如 message)。

2.3.3. 自定义的修改

triage 预设不是只能用于工单分诊。它是一组默认问题,可以按业务需要替换选项和命题。常见做法有两种:

2.3.3.1. 方式一:修改字典后传入

import laya

# 获取预设,但改掉你不需要的部分
my_questions = laya.triage_questions()

# 把 intent 换成你的业务分类
my_questions["intent"]["instructions"] = "用户当前轮次的意图是什么?"
my_questions["intent"]["criteria"] = {
    "理财": "咨询、购买或赎回理财产品",
    "转账": "向他人或自己账户转账、汇款",
    "聊天": "与银行业务无关的闲聊"
}

# 如不需要退款判断,可删除该问题
del my_questions["refund_requested"]

# 用你修改后的字典预测
result = agent.predict(state, my_questions)

这样保留了预设的问题结构,但决策维度已改成手机银行业务逻辑。

2.3.3.2. 方式二:直接自定义,完全不用预设

my_bank_questions = {
    "intent": {
        "type": "choice",
        "instructions": "用户意图是什么?",
        "criteria": {"理财": "...", "转账": "...", "聊天": "..."}
    },
    "refund_requested": {
        "type": "noul",
        "instructions": "用户是否要求退款?"
    }
}
result = agent.predict(state, my_bank_questions)

2.3.4. 修改时需要注意

预设里的 type(choice/score/noul)决定了输出结构。如果把 intent 的 criteria 改成中文“理财/转账/聊天”,Laya 会正常输出 choice 结果。但如果要把一个 noul 问题改成 choice,必须同时修改 type 和对应的 criteria 结构,而不是只改 instructions。


2.4. 三种模式的关系

三种模式不是单向的层层封装,而是围绕同一个推理内核的两种扩展:

模式二(单模型直连)
    ├── 模式一:增加检查点选择和语言路由
    └── 模式三:提供预设问题模板
  • 模式二是最基础的:手动加载检查点,手动定义问题,手动推理。
  • 模式一在模式二之上增加自动语言路由,负责选择检查点。
  • 模式三在模式二之上提供预设问题模板,负责简化问题定义。

你也可以组合使用:用 Router 自动路由,同时用 triage_questions() 预设模板。


3. Laya 三个决策的解读

Laya 的三个决策原语——choice、score、noul——可以理解为三种不同形态的“问题模板”。
它们决定了你能问什么类型的问题,以及模型会以什么格式回答。

3.1. choice:多选一

问题形态:“属于哪一类?”

输出结构:最优标签 + 逐选项概率 + confidence

逐项解读:

[choice] department=billing confidence=0.864 
         probabilities={'billing': 0.9653, 'technical': 0.014, 'sales': 0.0101, 'other': 0.0107}
  • department=billing:模型选出的最优标签是 billing。
  • confidence=0.864:模型对这个选择的整体确定性是 86.4%。它不是 probabilities["billing"],而是基于校准后概率分布计算出的归一化熵置信度。
  • probabilities:模型对每一个选项给出的概率分布:
    • billing: 0.9653
    • technical: 0.014
    • sales: 0.0101
    • other: 0.0107

这里有一个关键细节:confidence=0.864 和 probabilities['billing']=0.9653 不相等。

模型先用温度调整 logits,再生成 probabilities;confidence 再从这个概率分布计算归一化熵。因此,它衡量的是分布的确定性,不等于被选标签的概率。若温度被截断或未在目标数据上校准,confidence 也应视为未校准。


3.2. score:量表打分

问题形态:“在量表上处于什么位置?”

输出结构:期望分值 + 概率分布 + confidence

逐项解读:

[score] urgency=1.44/2.0 
        legend=['not urgent', 'soon', 'critical deadline or blocking issue']
  • urgency=1.44/2.0:模型给出的期望分值。量表是 0 到 2,模型认为“紧急程度”的期望值是 1.44。
  • legend:量表的语义锚点。0 = not urgent,1 = soon,2 = critical deadline or blocking issue。所以 1.44 大致落在“soon 和 critical 之间,偏 critical 一点”。
  • [PASS] 概率分布归一:内部对每个档位(0、1、2)都有一个概率,这些概率加起来等于 1。期望分值就是这些档位的加权平均。

和 choice 的区别:

choice 是无序的互斥分类——billing 和 technical 之间没有大小关系。score 是有序量表——0 < 1 < 2,档位之间有顺序;但把档位映射为连续分数时,隐含了档位距离可比的假设。

为什么输出期望值而不是直接选档位:

因为“紧急程度”本身是连续的。直接选“1”或“2”会丢失信息。输出期望值 1.44 保留了“偏向 2 但还没到 2”的细微差别。你也可以自己设阈值,比如 urgency > 1.5 才算紧急。

适用场景:有序判断。比如紧急程度、挫败感、危害严重程度、满意度。这些维度的共同点是:档位之间有顺序,但边界模糊。


3.3. noul:二值判断

问题形态:“这个命题是否成立?”

输出结构:P(true),0 到 1 之间的概率

为什么叫 noul:

它是 “no/yes” 或 “null-or-not” 的缩写。名字表达的是:这个命题要么为真、要么为假,但模型输出的是为真的概率,而不是硬性的 0/1 标签。

这和它的训练方式有关。Laya 用 RLCD(面向校准决策的强化学习)训练,奖励的是概率的校准质量,而不是单纯的准确率。在温度拟合充分且评估数据与业务分布接近时,noul 输出具有统计意义:如果说 0.8,在大量类似样本中约有 80% 为真。若检查点温度未拟合或业务分布差异较大,应先在自有数据上验证和校准。

为什么输出概率而不是直接输出“是/否”:

因为很多判断本身是模糊的。“用户有流失风险”不是一个非黑即白的问题。输出 0.8248 比输出“是”保留了更多信息。你可以自己设阈值,比如 > 0.8 才算高风险。

适用场景:独立的二元判断。比如是否要求退款、是否提到竞品、是否要转人工、是否包含敏感信息、是否涉及欺诈。这些判断的共同点是:它们不是互斥的类别,而是可以叠加的辅助信号。

逐项解读:

[noul] churn_risk=0.8248 refund_requested=0.843
  • churn_risk=0.8248:命题“用户有流失风险”为真的概率是 82.48%。
  • refund_requested=0.843:命题“用户要求退款”为真的概率是 84.3%。

和 choice 的关键区别:

choice 是互斥的——在当前问题定义下,一次只会返回一个主意图。但用户的一句话可能同时表达“理财”和“转账”需求;若业务允许多意图,应拆成多个 noul 问题或使用层级分类。noul 是独立的——“用户有流失风险”和“用户要求退款”可以同时为真,互不排斥。

你可以把它理解为一系列独立的开关,每个开关都可以单独打开或关闭,而不是一组互斥的按钮。

3.3.1. 在意图识别里应用

对于手机银行场景,noul 可以用来处理那些不属于互斥意图、但需要单独判断的维度。比如:

questions = {
    "intent": {
        "type": "choice",
        "instructions": "用户当前轮次的意图是什么?",
        "criteria": {
            "理财": "咨询、购买、赎回理财产品",
            "转账": "向他人或自己账户转账、汇款",
            "聊天": "与银行业务无关的闲聊"
        }
    },
    "is_urgent": {
        "type": "noul",
        "instructions": "用户是否表达了紧急或时间敏感的需求?"
    },
    "wants_human": {
        "type": "noul",
        "instructions": "用户是否要求转人工客服?"
    },
    "mentions_competitor": {
        "type": "noul",
        "instructions": "用户是否提到了其他银行或竞品?"
    }
}

这样一次前向就能同时得到:

  • 主意图(choice)
  • 是否紧急(noul)
  • 是否要转人工(noul)
  • 是否提到竞品(noul)

这些 noul 维度可以叠加在意图之上,用来做更细的路由。比如意图是“转账”且 is_urgent=0.9,就可以优先处理;意图是“聊天”但 wants_human=0.95,就直接转人工。


3.4. 三者对比总结

维度 choice score noul
问题形态 属于哪一类? 在量表上处于什么位置? 这个命题是否成立?
选项关系 互斥 有序 独立
输出 最优标签 + 逐选项概率 + confidence 期望分值 + 分布 + confidence P(true)
样例 department=billing (0.864) urgency=1.44/2.0 churn_risk=0.8248
适合场景 意图分类、部门路由 紧急程度、挫败感 流失风险、退款要求
选项/档位数量限制 约 20 个以内 通常 3-5 档 每个命题只有真假两项;问题总量受上下文和推理预算限制

4. 对手机银行应用场景的启示

4.1. 模式的选择

开发阶段:以模式三的 triage 模板为参考,直接修改 intent 为“理财/转账/聊天”,快速验证效果;必要时再完全自定义 questions。

生产阶段:用模式一(Router 自动路由),因为你的用户可能中英文混杂。同时自己定义 questions,把意图精确控制为“理财/转账/聊天”三类。

如果只服务中文用户:可以跳过 Router,直接用模式二加载 multilingual 检查点,省掉路由开销和内存占用。

关键区别一句话总结:模式一帮你选检查点,模式二让你直接推理,模式三帮你减少问题定义工作。

4.2. 判断方式的选择

对于“理财/转账/聊天”的意图识别:

  • 主意图用 choice:三个选项互斥,正好适合。
  • 辅助维度用 noul:比如“用户是否在催促”“用户是否提到竞品”“用户是否要求转人工”。这些信号可以叠加在意图之上,用来做更细的路由。
  • 如果需要判断紧急程度,用 score 而不是 noul。因为紧急程度是有序的,0/1/2 比单纯的“紧急/不紧急”保留更多信息。

一个关键原则:互斥的用 choice,有序的用 score,独立的用 noul。选错原语会导致模型输出结构不符合你的业务逻辑。


5. 总结

Laya 的价值不在于替代 LLM,而在于把高频、结构化、低延迟的分类与判断从 LLM 中剥离出来:它不生成文本,而是在一次批量前向中回答 choice、score、noul 三类类型化问题。

5.1. Router 选择

先按输入语言和任务特性选择检查点:英文优先用 laya,中文或多语言优先用 laya-multilingual;laya-typed-decisions 只在问题集明确匹配其四类微调工作流时使用。

中英文混合的手机银行生产环境,建议使用 Router().preload(["english", "multilingual"]),让 Router 在英语和多语言检查点之间自动路由。语言稳定且明确时,可以绕过 Router,直接加载对应检查点,减少内存和路由开销。

5.2. 调用方式选择

调用方式按控制粒度选择:需要自动语言路由时用模式一 Router.predict();语言固定、希望减少依赖时用模式二 laya.load(...).predict();快速原型可从模式三的预设问题出发。

预设工作流只是问题模板,不是业务答案。手机银行应以 triage_questions() 为参考,修改 intent 为“理财/转账/聊天”,或完全自定义 questions。

5.3. 具体问题类型选择

定义问题时,先判断业务结构:互斥主意图用 choice,有序程度用 score,可叠加的独立命题用 noul。手机银行可将“理财/转账/聊天”作为主意图,用 choice 输出;紧急程度用 score;转人工、提及竞品、要求退款等辅助信号用 noul。

落地原则可以概括为一句话:Router 负责选检查点,直连负责推理,预设负责起步,自定义问题负责贴合业务;上线前必须用真实样本验证效果和校准概率。

6. 参考

  • Laya:https://github.com/NandhaKishorM/laya
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。