多语言、非自回归的系统 1 决策模型。 给它一个状态(文本、邮件、工单或 JSON)和带类型的问题,它会在 100 多种语言中通过单次前向传播(约 33 毫秒)返回带类型的答案,并给出经数学校准的概率。该模型基于严格恰当评分规则(RLCD)进行强化学习训练,因此报告诚实的概率是最大化奖励的唯一途径。它从不生成文本,因此既无内容可解析,也无幻觉可产生。
pip install layaPython 3.10 或更高版本。可选附加包:laya[serve](HTTP 服务器)、laya[mcp](MCP 服务器)、laya[langchain](LangChain 和 LangGraph)、laya[onnx](ONNX Runtime)、laya[fast](TileLang GPU 快速路径)。各平台安装说明见 GitHub README。
长文档。 laya-multilingual 在 max_len=8192 下最多可读取 8,192 个 token。按文档长度实测的准确率与耗时(基准脚本):
长文档:
laya-multilingual最多可读取 8,192 个 token。 默认带有 1,024 个 token 的上限,会将长文档截断,因此对长文档请传入max_len=8192:result = router.predict(long_document, questions, model="multilingual", max_len=8192)上表中,在请求前带有最多约 4,000 个 token 的文本时,20 个请求中有 16 至 18 个回答正确;超出该范围后,结果会有波动(20 个请求中有 8 至 17 个回答正确),因此请在自己的数据上检查长文档准确率。短输入在
max_len=8192下会得到相同答案,且速度取决于输入的实际长度,而不是限制值:短输入不受影响,4,000 个 token 的输入在 Apple GPU 上约需 1.7 秒。请通过model="multilingual"指定模型检查点,因为较长的以英语为主的文本否则会被路由到英语检查点。
from laya import Router
router = Router() # downloads a checkpoint on first use; Router(preload=True) loads all three up front
state = "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?",
"criteria": {"billing": "invoices, payments, refunds",
"technical": "bugs, outages, system errors",
"other": "everything else"}},
"urgency": {"type": "score", "instructions": "How urgent is this?",
"criteria": ["not urgent", "soon", "blocking"]},
"churn_risk": {"type": "noul", "instructions": "Does the user threaten to cancel or leave?"},
}
result = router.predict(state, questions)
print(result["answers"]["department"]["choice"]) # billing
print(result["answers"]["churn_risk"]["noul"]) # probability the answer is yes
print(result["routing"]["model"]) # english同一调用适用于 100+ 种语言。Router 会检测脚本和语言,并将非英文文本发送到 laya-multilingual:
for text in ["मुझसे मार्च में दो बार शुल्क लिया गया, कृपया डुप्लिकेट राशि वापस करें।",
"La aplicación se cierra cada vez que abro la configuración."]:
r = router.predict(text, {"department": questions["department"]})
print(r["routing"]["model"], r["answers"]["department"]["choice"])
# multilingual billing
# multilingual technical随包提供的检查点已可零样本运行,但使用你自己领域中的决策数据进行微调,才是准确率大幅提升的关键。在 typed-decisions 基准测试(覆盖 4 个工作流的 2,000 个决策)中,微调后的 laya-typed-decisions 检查点准确率为 0.766,而基础英文检查点在相同决策上的准确率为 0.362。
微调 Notebook:在 Kaggle 免费 2 块 T4 GPU 上完成完整流程(构建数据集、训练、拟合校准温度、评估,并将结果推送到 Hub)。详见 GitHub README。
nandhakishorm.github.io/laya:提供 预测钩子、schema 驱动的决策、Docker 和 LangChain 与 LangGraph 指南,以及完整的 API 参考。
检查点本身未发生变化。运行 pip install -U laya 以获取最新的运行时修复:
laya-multilingual 在 max_len=8192 下处理长文档:实测表格展示了不同文档长度对应的准确率与耗时。
更稳健的快速路径。 出现 CUDA 内存不足错误后,回退到 CPU 时会先关闭 TileLang 快速路径;单选项 choice 不再导致其崩溃;并发调用也不会再相互覆盖 CUDA-graph buffers。
服务端与运行时。 laya-serve 在关闭时会排空推理池,并对格式错误的 bearer 头返回 401;ONNXAgent 在空问题集合和长对话列表上与 Agent 行为一致。
本仓库包含全部三个检查点,也是该系列模型的枢纽。英文检查点位于仓库根目录;另外两个以打包子文件夹形式提供,并且只会下载你所请求的那一个:
| 检查点 | 骨干编码器 | 参数量 | 上下文 | 最佳场景 |
|---|---|---|---|---|
convaiinnovations/laya(本仓库根目录) | ModernBERT-large | 421M | 512 | 英文文本、安全护栏、邮件分诊 |
convaiinnovations/laya-multilingual | mmBERT-base | 322M | 1024(最高 8k) | 100+ 种语言,约快 2.2 倍 |
convaiinnovations/laya-typed-decisions | ModernBERT-large | 421M | 1024 | 四个 typed-decisions 工作流(准确率 0.766) |
Laya 内置的 Router 是在生产环境中使用 Laya 的推荐方式。它能评估任意语言中的任意状态,在亚毫秒级内自动检测脚本与语言,并通过单次前向推理将其路由到最优检查点。
pip install layaimport laya
from laya import Router
# Preload checkpoints into memory for instant sub-35ms routing
router = Router(preload=True)
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?"
}
}
# 1. English state -> automatically routed to ModernBERT-large (39.5 ms)
res_en = router.predict(state, questions)
print("Department :", res_en["answers"]["department"]["choice"]) # -> billing (confidence: 0.94)
print("Routing :", res_en["routing"]["model"]) # -> english
# 2. Hindi state -> automatically routed to mmBERT-base (100+ languages, 32.8 ms)
res_hi = router.predict({"body": "मुझसे दो बार शुल्क लिया गया, कृपया पैसे वापस करें।"}, questions)
print("Department :", res_hi["answers"]["department"]["choice"]) # -> billing (confidence: 0.86)
print("Routing :", res_hi["routing"]["model"]) # -> multilingual
# 3. Explicit override when you already know the checkpoint
res_td = router.predict(state, questions, model="typed-decisions")每条结果都包含完整的路由元数据,说明为何做出该选择:
res_hi["routing"]
# {
# 'model': 'multilingual',
# 'repo': 'convaiinnovations/laya/multilingual',
# 'reason': 'non-Latin script (devanagari, 100% of letters); the English checkpoint cannot read it'
# }在统一基准测试上(17,416 个问题,单块 T4 GPU,各模型使用完全相同的问题):
| 基准测试 / 任务 | 英语(laya) | 多语言(laya-multilingual) | Router(已路由) |
|---|---|---|---|
| MASSIVE 意图,英语 | 0.783 | 0.657 | 0.783 |
| MASSIVE 意图,其他 13 种语言 | 0.306 | 0.451 | 0.451 |
| XNLI,英语 | 0.860 | 0.843 | 0.860 |
| XNLI,其他 14 种语言 | 0.521 | 0.731 | 0.731 |
| 可用语言数(>3 倍随机) | 23 / 51 | 45 / 51 | 45 / 51 |
| 延迟,1 个问题(T4 GPU) | 39.5 ms | 32.8 ms | 32.8 ms |
| 延迟,10 个问题批处理 | 158.6 ms | 72.3 ms | 72.3 ms |
英语检查点在面对非拉丁文字时失效(高棉语准确率为 0.000,置信度为 0.952)。由于模型在出错时仍然保持高置信度,置信度门控无法发挥作用。Router 会在前向传播前,用纯 Python 在 <0.5 ms 内检测文字系统。
如果你已经在运行语言识别模型,请传入它的结果,而不是依赖内置启发式规则。lang_guess 接受语言代码或可调用对象,它会在显式 lang= 之后、检测之前被检查;如果可调用对象返回 None,则会回退到检测:
router.predict(state, questions, lang_guess="ro") # a code you already know
router = Router(preload=True, lang_guess=my_lid) # or install one for every request冷启动 checkpoint 构建以秒计,语言检测以微秒计。默认惰性配置会保持 两个 checkpoint 常驻(english 和 multilingual,也就是自动路由唯一可能选择的两个选项),因此每种语言首次加载后,切换成本仅为检测耗时。单语言部署永远不会构建第二个 checkpoint。max_loaded=1 会在每次切换时重新构建(实测 CPU 上重载中位数为 7.4 秒,T4 上为 10.3 秒)。
针对服务器或演示环境,请预加载:
# Every checkpoint resident in memory; language flips cost detection only (<1 ms)
router = Router(preload=True)
router = Router(preload=True, device="cuda")
# Or preload only the specific checkpoints you serve:
router.preload(["english", "multilingual"])
# If your app already built an agent, attach it to avoid duplicate VRAM:
router.attach("english", existing_agent)
# Manage resident memory (default keeps two hot: english + multilingual, LRU eviction)
router = Router(max_loaded=3) # all three hot, e.g. with auto_task_detection
router = Router(max_loaded=1) # memory-constrained host, reloads on every switch
router.unload() # free memory
with Router() as r: # releases the models when the block ends
r.predict(state, questions)| 部署模式 | 单次请求延迟 | 模型重载 |
|---|---|---|
Router()(lazy,max_loaded=2) | 每种语言首次加载后仅检测(<1 ms) | 每种语言首次出现时 1 次 |
Router(max_loaded=1) | 每次切换语言需 7–10 s | 每次切换 1 次 |
Router(preload=True) | 32.8 ms(GPU)/ 193–464 ms(CPU) | 无 |
如果专用流水线只需要一个 checkpoint:
import laya
# 1. Load from the repo root or subfolders (downloads only the requested weights)
agent = laya.load("convaiinnovations/laya") # English root (~808 MB)
agent_ml = laya.load("convaiinnovations/laya", subfolder="multilingual") # 100+ languages (~647 MB)
agent_td = laya.load("convaiinnovations/laya", subfolder="typed-decisions")
# 2. Run all questions in ONE single forward pass (~35 ms on GPU)
result = agent.predict(state, questions)
answers = result["answers"]
print("Department :", answers["department"]["choice"]) # -> billing (confidence: 0.94)
print("Urgency :", answers["urgency"]["score"]) # -> 1.84 / 2.0
print("Churn Risk :", answers["churn_risk"]["noul"]) # -> 0.892 (89.2% probability)如果
laya.load()挂起:transformers在导入时会探测 TensorFlow,而当 TF 已安装时,其 abseil 运行时可能导致模型构建死锁。请使用USE_TF=0运行。
laya-serve 将 Router 暴露在与 TypeSafe Jev 相同的 POST /v1/systemone 请求和响应结构上,因此现有 TypeSafe 客户端只需更改基础 URL 即可使用:
pip install "laya[serve]"
LAYA_DEVICE=cuda LAYA_PRELOAD=1 laya-serve # 0.0.0.0:8000, preloads the checkpointscurl -s localhost:8000/v1/systemone -H 'Content-Type: application/json' -d '{
"state": {"document": "I was charged twice. Please fix this ASAP."},
"questions": {"billing": {"type": "noul", "instructions": "Is this ticket about billing?"}}
}'它接受 Jev API 所支持的所有问题形态(例如将 criteria 作为列表),忽略未知字段,并对格式错误的问题返回 422,同时指明问题所在。它绑定 0.0.0.0,未设置 LAYA_API_KEY 时不启用认证;若已设置,则要求提供 Authorization: Bearer <key>。
[MASK] token 处打分,然后在该问题的选项集上执行 softmax。答案空间在请求时定义,因此新增 schema 无需重新训练。head_max_len = 192);多语言问题每问 1024 token(head_max_len = 256)。RLCD(用于校准决策的强化学习)。 策略输出一个分布;探索阶段向 logits 添加零均值高斯噪声;奖励采用严格恰当评分规则(log + spherical,有序问题另加排序概率分数)。只有报告诚实概率时,期望奖励才会最大化。更新采用带组均值基线的 REINFORCE(GRPO 风格)。多轮对话基于前缀切片使用 TD(λ=1.0)。
在 Tesla T4 上测量;同一运行中的每个检查点都回答逐字节一致的问题。
| questions per call | laya | laya-multilingual |
|---|---|---|
| 1 | 39.5 ms | 32.8 ms |
| 5 | 84.5 ms | 40.1 ms |
| 10 | 158.6 ms (15.9 ms/q) | 72.3 ms (7.2 ms/q) |
| 50 | 771 ms | 337 ms (6.8 ms/q) |
单张 T4 上的批处理吞吐量为 103–332 问题/秒。作为参考,TypeSafe Jev 的独立测量 p50 为 236–276 ms(AbdelStark, nibzard),因此 Laya 回答单个问题大约快 6–8 倍。
Laya 中的每项数据均为 Router().predict(...) 的返回值,即路由器针对该输入所选择的 checkpoint。Jev 的数据为第三方公开数值,未在此处实测(无法访问 TypeSafe API);样本量与 prompt 均有所不同。
| 基准 / 指标 | TypeSafe Jev 1.13.0 | Laya(带路由) | 对比 |
|---|---|---|---|
| typed-decisions,2,000 个决策 | 0.727 | 0.766 | +0.039(超过 0.735 教师上限) |
| AG News,4 个标签 | 0.910 | 0.950 | +0.040 |
| DAIR Emotion,6 个标签 | 0.480 | 0.595 | +0.115 |
| Banking77(72 对 77 个标签) | 0.870 | 0.425 | Jev 在 >20 个选项中领先 |
| ECE (越低越好) | 0.246 | 0.081 | 好 3 倍(温度缩放后) |
| p50 延迟,1 个问题 | 236–276 ms | 32.8 ms | 快 7.8 倍 |
| 可用语言(>3 倍随机基线) | 未公开基准 | 51 个中的 45 个 | 全球语言覆盖 |
| 权重 | 闭源 API | Apache 2.0 | 开放权重,可本地部署 |
| 成本 | $0.042 / 1M tokens | 自托管 $0 | 100% 免费 |
在 DAIR Emotion 上,Jev 在 16% 的样本中将真实标签的概率置为零。
head_max_len 预算(英文为 192 tokens,多语言为 256 tokens),因此 77 个选项每个标签仅分得约 3 到 4 个 tokens,导致文本难以区分。Jev 开箱即支持最多 255 个选项。尽管 laya-multilingual 支持 1,024 上下文长度(编码器中最多 8,192),并且可以在运行时设置 agent.cfg["head_max_len"] = 512,但 Jev 目前更适合在不调参的情况下处理单个 prompt 中的 50 个以上选项。完整报告:BENCHMARKS.md.
400 个案例、2,000 个决策、4 个工作流——均在此测量。
| model | accuracy | soft acc | 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.804、安全事件 0.766、客户服务 0.764、agent-trace 可观测性 0.730。按原语:noul 0.857、choice 0.733、score 0.723。
基础检查点在此低于多数类基线——该基准上的能力来自微调,而 微调 notebook 正是为此准备的。
基础检查点在 typed-decisions 上接近零样本随机水平——此处为 0.362,multilingual 为 0.352;随机基线为 0.318,多数类基线为 0.461。0.766 来自在该基准自身训练集上微调后的检查点。Laya 是一个便于快速专精化的基础底座,而不是零样本决策引擎。
高基数选择题与 token 预算: 序列被切分为选项提示预算(head_max_len)和剩余文档/状态预算(max_len - head_max_len):
laya(英语)默认上下文长度为 512(head_max_len = 192,状态约 320 个 token)。laya-multilingual 和 laya-typed-decisions 默认上下文长度为 1,024(head_max_len = 256,状态约 768 个 token;mmBERT-base 编码器配合 RoPE 最高支持 8,192)。
在默认设置下,像 Banking77 这样有 77 个选项的问题,每个标签仅分配 (256 - 16) // 77 ≈ 3–4 个 token,导致准确率显著下降(0.425,而 Jev 为 0.870)。如果要在单个问题中评估 50 个及以上选项:agent.cfg["head_max_len"] = 512 和 agent.cfg["max_len"] = 1024(或提升到 2048 / 4096 / 8192),确保每个选项都有足够 token 保持可区分。有序 score 问题是表现最弱的原语(SST-5 0.372)。
noul 可能跟随其选项标签而非状态作答,在该英语检查点上尤为明显。 noul 将两个选项渲染为 false: / true:,在这里该标签对可能主导答案,对明显正向输入返回自信的“否”(#156)。请在自己的数据上检查 noul 的回答。如果它们看起来卡住,可将同一问题改写为两个选项的 choice,使用中性键,并将你的是/否表述作为描述:
{"type": "choice", "instructions": "Is this review positive?",
"criteria": {"A": "yes, the review is positive", "B": "no, the review is negative"}}action.act_probability 目前还没有可用信号(#185)。它几乎对所有输入都返回 1.0,且其原始 logits 与正确性方向相反(在 396 个带标签决策上 AUROC 为 0.30)。应改为基于 confidence 做门控,它在相同样本上达到 AUROC 0.77。
默认置信度过高: 为每个(问题类型,选项数量)重新拟合一个温度,可将平均 ECE 从 0.466 → 0.081(laya)和 0.314 → 0.106(laya-multilingual)。在信任概率之前,请先在自己的数据上执行。
root 仅支持英语: 任何非英语场景请使用 laya-multilingual。
Apache 2.0 · Convai Innovations