HuggingFace镜像/laya
模型介绍
文件和版本
分析

Laya

多语言、非自回归的系统 1 决策模型。 给它一个状态(文本、邮件、工单或 JSON)和带类型的问题,它会在 100 多种语言中通过单次前向传播(约 33 毫秒)返回带类型的答案,并给出经数学校准的概率。该模型基于严格恰当评分规则(RLCD)进行强化学习训练,因此报告诚实的概率是最大化奖励的唯一途径。它从不生成文本,因此既无内容可解析,也无幻觉可产生。

安装

pip install laya

Python 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 长文档按文档长度的准确率

快速开始

长文档: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 参考。

laya 0.3.20 的新特性

检查点本身未发生变化。运行 pip install -U laya 以获取最新的运行时修复:

  • laya-multilingual 在 max_len=8192 下处理长文档:实测表格展示了不同文档长度对应的准确率与耗时。

  • 更稳健的快速路径。 出现 CUDA 内存不足错误后,回退到 CPU 时会先关闭 TileLang 快速路径;单选项 choice 不再导致其崩溃;并发调用也不会再相互覆盖 CUDA-graph buffers。

  • 服务端与运行时。 laya-serve 在关闭时会排空推理池,并对格式错误的 bearer 头返回 401;ONNXAgent 在空问题集合和长对话列表上与 Agent 行为一致。


Laya 与 TypeSafe Jev 对比:准确率、所有应用工作流、全部 51 种语言、速度、校准与路由成本

本仓库包含全部三个检查点,也是该系列模型的枢纽。英文检查点位于仓库根目录;另外两个以打包子文件夹形式提供,并且只会下载你所请求的那一个:

检查点骨干编码器参数量上下文最佳场景
convaiinnovations/laya(本仓库根目录)ModernBERT-large421M512英文文本、安全护栏、邮件分诊
convaiinnovations/laya-multilingualmmBERT-base322M1024(最高 8k)100+ 种语言,约快 2.2 倍
convaiinnovations/laya-typed-decisionsModernBERT-large421M1024四个 typed-decisions 工作流(准确率 0.766)

快速入门:Route Mode(推荐)

Laya 内置的 Router 是在生产环境中使用 Laya 的推荐方式。它能评估任意语言中的任意状态,在亚毫秒级内自动检测脚本与语言,并通过单次前向推理将其路由到最优检查点。

pip install laya
import 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.7830.6570.783
MASSIVE 意图,其他 13 种语言0.3060.4510.451
XNLI,英语0.8600.8430.860
XNLI,其他 14 种语言0.5210.7310.731
可用语言数(>3 倍随机)23 / 5145 / 5145 / 51
延迟,1 个问题(T4 GPU)39.5 ms32.8 ms32.8 ms
延迟,10 个问题批处理158.6 ms72.3 ms72.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)无

单模型模式(Direct SDK)

如果专用流水线只需要一个 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 运行。


自托管:Jev 兼容的 HTTP 服务器

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 checkpoints
curl -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>。


Architecture

  • 主干模型: ModernBERT-large(395M,双向,全量微调)+ 从零训练的决策头:2 层 transformer、选项标记评分器以及执行/升级头。总计 421M。(多语言版使用 mmBERT-base,22 层,256k 词表,总计 322M)。
  • 选项标记: 每个选项都在其自身的 [MASK] token 处打分,然后在该问题的选项集上执行 softmax。答案空间在请求时定义,因此新增 schema 无需重新训练。
  • 预算: 英文问题每问 512 token(head_max_len = 192);多语言问题每问 1024 token(head_max_len = 256)。
  • 批处理: 一次调用中的每个问题都在单次前向传播中得到回答。

Training

RLCD(用于校准决策的强化学习)。 策略输出一个分布;探索阶段向 logits 添加零均值高斯噪声;奖励采用严格恰当评分规则(log + spherical,有序问题另加排序概率分数)。只有报告诚实概率时,期望奖励才会最大化。更新采用带组均值基线的 REINFORCE(GRPO 风格)。多轮对话基于前缀切片使用 TD(λ=1.0)。


Benchmarks

在 Tesla T4 上测量;同一运行中的每个检查点都回答逐字节一致的问题。

Speed

questions per calllayalaya-multilingual
139.5 ms32.8 ms
584.5 ms40.1 ms
10158.6 ms (15.9 ms/q)72.3 ms (7.2 ms/q)
50771 ms337 ms (6.8 ms/q)

单张 T4 上的批处理吞吐量为 103–332 问题/秒。作为参考,TypeSafe Jev 的独立测量 p50 为 236–276 ms(AbdelStark, nibzard),因此 Laya 回答单个问题大约快 6–8 倍。

Laya(带路由)与 TypeSafe Jev

Laya 中的每项数据均为 Router().predict(...) 的返回值,即路由器针对该输入所选择的 checkpoint。Jev 的数据为第三方公开数值,未在此处实测(无法访问 TypeSafe API);样本量与 prompt 均有所不同。

基准 / 指标TypeSafe Jev 1.13.0Laya(带路由)对比
typed-decisions,2,000 个决策0.7270.766+0.039(超过 0.735 教师上限)
AG News,4 个标签0.9100.950+0.040
DAIR Emotion,6 个标签0.4800.595+0.115
Banking77(72 对 77 个标签)0.8700.425Jev 在 >20 个选项中领先
ECE (越低越好)0.2460.081好 3 倍(温度缩放后)
p50 延迟,1 个问题236–276 ms32.8 ms快 7.8 倍
可用语言(>3 倍随机基线)未公开基准51 个中的 45 个全球语言覆盖
权重闭源 APIApache 2.0开放权重,可本地部署
成本$0.042 / 1M tokens自托管 $0100% 免费

在 DAIR Emotion 上,Jev 在 16% 的样本中将真实标签的概率置为零。

Jev 领先之处

  • 高基数标签空间(默认设置下 >20 个选项): 在 Banking77 上,Jev 得分为 0.870(72 个标签),而 Laya 得分为 0.425(默认 256-token head 预算下的 77 个标签)。各选项共享固定的 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 个以上选项。
  • 软分布匹配: 在 typed-decisions 上,尽管 Laya 的 argmax 准确率更高(0.766 对 0.727),但 Jev 相对于教师模型的完整概率分布取得了更高的软准确率(0.580 对 0.471)。
  • 开箱即用的原始校准: 在温度缩放之前,基础 checkpoint 的原始 ECE 更高(0.213 对 0.144)。Laya 在领域温度拟合后达到 0.081 的 ECE。

完整报告:BENCHMARKS.md.

typed-decisions,已在全部三个检查点上测量

400 个案例、2,000 个决策、4 个工作流——均在此测量。

modelaccuracysoft accBrierECEscore MAE
laya-typed-decisions0.7660.4710.0620.2130.242
laya0.3620.3320.3160.1750.694
laya-multilingual0.3420.3260.4390.2850.687
Jev 1.13.0(已发布)0.7270.5800.1480.1440.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 个及以上选项:
    1. 提高 agent.cfg["head_max_len"] = 512 和 agent.cfg["max_len"] = 1024(或提升到 2048 / 4096 / 8192),确保每个选项都有足够 token 保持可区分。
    2. 或将大选项集拆分为两阶段由粗到细的层级选择。
  • 有序 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。


链接

  • GitHub: https://github.com/NandhaKishorM/laya
  • PyPI: https://pypi.org/project/laya/
  • 在线演示: https://huggingface.co/spaces/convaiinnovations/laya-demo
  • 技术文章: 在 Dev.to 上阅读

Apache 2.0 · Convai Innovations