通过将多个问题打包为一个序列并利用注意力掩码隔离问题间干扰,Laya 决策模型在 500 token 文档上实现单次前向传播回答 10 个问题。
很多生产环境中的"AI"其实根本不是生成任务。它是一堆针对一段文本的小决策:这个工单该哪个团队处理?紧急程度如何?客户是否威胁要离开?这封邮件是不是钓鱼?把这些问题一个个发给 LLM 再解析答案,速度慢、费用高,而且有时候会给出一些你并不需要的"创意"答案。
Laya 正是为这类任务设计的开源模型:你发送一个状态(工单、邮件、JSON 文档)和带类型的问题——choice、score 或 yes/no noul——ModernBERT 编码器在一次前向传播中返回校准后的概率。我基于它构建了 cbjev。本文讲的是让 cbjev 变快的那一个核心思路、如何复用 Laya 的权重,以及哪些做法没有奏效。
Laya 为每个问题构建一个序列:
[CLS] question 1 [SEP] options [SEP] document [SEP]
[CLS] question 2 [SEP] options [SEP] document [SEP]
...
对一篇 500 token 的文档提 10 个问题,编码器就要处理 10 次文档——一次调用的总 token 数约 5,500,而实际唯一内容只有约 1,000。
cbjev 将整个调用打包成一行:
[CLS] q1 | q2 | ... | q10 | document [SEP]
然后将注意力掩码塑造成这样:
问题之间互相不可见(每个段只attend自己和文档),
文档能读取每个问题(所以它的编码仍然感知问题,和 Laya 中一样),
每个问题段在紧接 [CLS] 之后重启自己的位置,文档在最长的段之后才开始。
最后这个细节是关键的。对于单个问题,这行序列在 token 级别和位置级别与 Laya 看到的完全一致。所以将 Laya 检查点直接放入这个布局就能工作(我在微调之前测量到 5 题 typed-decisions 基准为 0.749,而 Laya 自己布局是 0.768),微调从 Laya 的全部能力开始而不是重新学习这个任务。
我的第一个尝试没有做到这一点:文档在最前面,无法读取问题。它速度一样快,但微调必须重建 Laya 已经有的能力,在一半的基准测试中持续落败。切换到上面的"共享"布局才让准确率数字work了。
一旦 token 数降下来,一个小调用就被开销主导,而不是数学计算:
一个 from-scratch 的 ModernBERT 前向(运行时无 transformers 模型),bf16 矩阵乘法配合 fp32 残差流,
每层与 torch.compile 融合(一次动态形状编译,几秒,缓存),
整个前向作为 CUDA graph 按 32-token 形状桶回放——一次 launch 而不是约 300 次,
文档每个调用 tokenize 一次,问题文本 tokenize 一次并缓存。
在同一部 RTX 4090 上与 Laya 并排测量,相同 case,通过两个库的公开 predict API:
option-order 那个数字来自一个几乎免费的技巧:packed 布局使得每个 choice 和 score 问题也用反转后的选项问一遍,两个答案取平均。那只是一段额外的短内容,不是另一次 pass。
在训练中加入 prompt-injection 数据集让 prompt-injection 基准降低了 10 分。基准测试一半是德语且题目很短;新增的数据教会了模型看起来像指令的文本通常是无害的。
Weight soups(平均几个微调 run,或与 Laya 原始权重混合)让均值略微上升,但从未弥合那些具体的差距。
七轮训练之后,cbjev 在四个 suite 上仍然落后于 Laya:support triage(-4.0)、prompt injection(-3.5)、DAIR emotion(-2.5)和 AG News(-0.8,400 个 case 中有 3 个)。它们列在 README 里而不是被 tune 掉。
pip install "cbjev[serve] @ git+https://github.com/tomek7667/cbjev"
import cbjev
agent = cbjev.load() # weights download from Hugging Face
res = agent.predict(
{"body": "Billed twice for March. Refund it today or we cancel."},
{"team": {"type": "choice", "instructions": "Which team should handle this?",
"criteria": {"billing": "invoices, refunds", "technical": "bugs", "other": "anything else"}},
"churn": {"type": "noul", "instructions": "Does the customer threaten to cancel their subscription?"}},
)
它还附带一个 speak TypeSafe Jev 的 /v1/systemone 线格式的服务器,所以现有的 Jev 客户端可以直接指向它。
代码(GPL-3.0)、基准测试和训练 pipeline:https://github.com/tomek7667/cbjev
权重:https://huggingface.co/0010101010-1/cbjev
项目页面:https://tomek7667.github.io/cbjev/
感谢 Convai Innovations 开放发布 Laya;cbjev 是从他们的 Apache-2.0 检查点微调而来的。非常想知道它在你的数据上会在哪里 break。