33ms 决策引擎为何爆火

非自回归多语种决策引擎 laya 单次推理 33ms,三个 checkpoint + Router 自动路由,支持 choice / score / noul 类型决策,Apache 2.0 开源,4 天斩获 9431 stars。本文拆解它如何替代 LLM 做 System 1 决策,并给出可运行代码。

源仓库: NandhaKishorM/laya

laya 是 NandhaKishorM 推出的 “System 1 决策引擎”,本质是一个非自回归分类器:把任意文本、邮件、工单或 JSON 当作 state,把”分给哪个部门""紧急程度""是否涉及退款”这类结构化问题用 choice / score / noul 三种类型表达,一次 forward pass 同时回答上百个问题,单卡 T4 跑出 33 ms。它和 LLM 的最大区别是不生成文本——没有要解析的字符串,也没有幻觉。Apache 2.0 开源,截至 2026-09-22 在 GitHub 拿下 9431 stars,从创建到 9k+ 只用了 4 天。

Q1: 三个 checkpoint 不能合并成一个吗?

现象:仓库里同时挂着 layalaya-multilinguallaya-typed-decisions 三套权重,对应三个 HuggingFace repo。

根因:合并的多语种 ModernBERT-large 在 512 context 下显存吃紧;mmBERT-base 在 1024 context 下参数量更小、推理更快。强行合并要么牺牲上下文长度,要么牺牲速度,英语场景还会被多语种 tokenizer 稀释。

解法:用 Router 做”晚绑定”。先做脚本/语种检测,再选模型:

from laya import Router

router = Router(preload=True)
res = router.predict(
    {"body": "मुझसे दो बार शुल्क लिया गया, कृपया पैसे वापस करें।"},
    questions,
)
print(res["routing"]["reason"])
# -> 'non-Latin script (devanagari, 100% of letters); the English checkpoint cannot read it'

Q2: 为何不用 LLM 直接回答”退款需求”?

现象:很多团队会用 GPT-4 + JSON schema 做客服路由,结果是延迟 500 ms–2 s,偶尔输出不合法。

根因:自回归模型每一 token 都是前一个 token 的条件概率,越长的 JSON 越容易跑偏;同时它会产生额外 token,触发限流与账单。

解法:把这类”分类 / 打分 / 是与否”问题降维成一次分类。laya 输出的是 dict,不是字符串:

import laya

agent = laya.load("convaiinnovations/laya")
result = agent.predict(state, questions)
result["answers"]["churn_risk"]["noul"]   # -> 0.892
result["answers"]["urgency"]["score"]      # -> 1.84 / 2.0

Q3: Router 怎么在 < 0.5 ms 决定走哪个 checkpoint?

现象:README 的 routing reason 会输出 Latin script but language looks like 'de',这是纯 Python 推理。

根因:在 forward pass 之前先跑一遍字符集统计——非拉丁(Devanagari、Khmer、CJK)直接走 multilingual;拉丁里再用字符 n-gram 简单判断英语还是其它欧语。Khmer 这种长尾语言在英语 checkpoint 上是 0.000 准确率、0.952 置信度,gate 不动,必须路由切换。

解法:调用 router.route() 可以单独验证路由而不跑模型:

print(router.route({"body": "Der Kunde wurde zweimal belastet"}, questions).reason)

Q4: 置信度是不是又一种”0.99 自信但全错”?

现象:传统 softmax 出来的概率校准很差,没法当业务阈值。

根因:laya 的训练目标是 RLCD(reinforcement learning against strictly proper scoring rules),把 Brier score 直接塞进 reward,输出概率在数学意义上等于”答对的期望”。

解法:可以把 confidence 当业务阈值直接用:

conf = answers["department"]["confidence"]
if conf < 0.6:
    escalate_to_human()

Q5: 生产环境怎么避免 7–10 s 冷启动?

现象:默认 Router(max_loaded=1) 会在每次语言切换时重新加载模型。

根因:每个 checkpoint 几百 MB,磁盘 + CUDA 初始化加起来就是秒级。

解法:服务器启动时一次性 preload,并限制常驻模型数量:

router = Router(preload=True, device="cuda", max_loaded=2)
router.preload(["english", "multilingual"])
router.unload()  # 释放

preload 后单请求 32.8 ms(GPU)/ 193–464 ms(CPU),不再有 reload。

Sources