Jev 模型爆火,如何训练自己的决策模型?
一条客户工单进来,系统需要判断:该交给哪个部门?是否需要人工介入?处理优先级有多高?
过去,我们通常把这些问题交给大模型,让它生成一段 JSON,再解析、校验,接入业务流程。
但这里有一个值得追问的问题:
如果我们只需要几个判断结果,为什么一定要让模型先“写一段话”?
Jev 展示了另一种方向:输入业务状态,直接输出结构化决策和概率。对个人开发者来说,更有意思的是,我们已经可以借助开源项目 Kev,在自己的电脑上尝试这条路线。
本文以一台 Apple M5 Pro、24 GB 内存的 Mac 为例,从环境准备开始,介绍如何训练和运行一个小型决策模型。以下是操作教程,尚未完成这台机器上的训练与性能实测。
一、Jev 改变了什么?
TypeSafe 将 Jev 定位为 System One 模型。与逐 token 生成文本的大模型不同,官方强调它放弃字符串生成,直接并行输出类型明确的决策结果,并使用称为 RLCD 的训练方法优化决策概率。官方介绍
以工单分流为例,我们需要的可能只是:
{
"department": "billing",
"probabilities": {
"billing": 0.92,
"shipping": 0.05,
"account": 0.03
}
}
这里的数字只是格式示例,不是实测结果。
对于程序来说,明确的选项和概率可以直接进入后续流程:分派部门、调整优先级,或者提交人工复核。
不过,输出格式正确与判断正确是两件事。模型只能从指定选项中选择,并不意味着它一定选对。
二、个人训练的入口是 Kev
Jev 的完整架构和训练配方没有公开,因此不能把下面的过程称为“复现 Jev”。
我们使用的是 Kev:一个基于 Qwen 构建的开源决策模型项目,公开了模型实现、训练入口和评估工具。
它的基本处理过程是:
业务材料+问题+候选选项
↓
Qwen 主干
↓
决策位置和选项的隐藏向量
↓
PointerHead 打分
↓
各选项的概率
普通语言模型通过词表输出头预测下一个 token。Kev 将它替换为对候选选项打分的决策头,因此能够省去文本生成循环。它并没有跳过 Transformer 主干层:输入仍然经过主干网络,省去的是逐 token 生成输出时的重复计算。
训练时,Kev 冻结原始底座权重,更新 LoRA 适配器和决策头,让模型学会根据问题选择答案。模型实现
我们要做的,就是准备环境和数据,把这套训练过程跑起来。
三、先选一个能在个人电脑上验证的模型
本文选择:
| 项目 | 配置 |
|---|---|
| 电脑 | Apple M5 Pro,24 GB 内存 |
| 底座 | Qwen3-0.6B-Base |
| 计算设备 | Apple GPU,PyTorch MPS |
| 训练方式 | LoRA+决策头 |
| 起步任务 | 使用公开数据训练通用决策原型 |
为什么不直接使用更大的模型?
第一次训练最需要确认的是:数据能否正确加载、损失是否正常、检查点能否保存,以及训练后的模型是否真的优于训练前。
小模型可以更快暴露这些问题。
本文采用 Qwen3,而不是当前 Kev 默认推荐的 Qwen3.5 系列,也是考虑到 Mac 上的执行效率。项目说明指出,Qwen3.5 的 DeltaNet 层目前缺少 Apple Silicon 高效内核。性能说明
四、安装环境,检查 GPU
以下命令需要先安装 Git 和 uv。uv 的安装方式可以参考其官方文档。
打开终端:
git clone https://github.com/jaredpalmer/kev.git
cd kev
uv python install 3.12
uv sync --python 3.12 --extra serve
记录仓库版本,方便之后重现实验:
git rev-parse HEAD
检查 MPS:
uv run python - <<'PY'
import torch
print("PyTorch 版本:", torch.__version__)
print("MPS 是否可用:", torch.backends.mps.is_available())
assert torch.backends.mps.is_available(), "请先检查 MPS 环境"
PY
输出 True 后,再开始训练。
首次运行会下载模型和数据。下载耗时与训练耗时应分开记录,不要据此判断本机 GPU 的训练速度。
五、先跑一次小规模训练
先从每个默认数据源抽取 40 条,训练一轮:
uv run python -m kev.train \
--base Qwen/Qwen3-0.6B-Base \
--device mps \
--dtype fp32 \
--n_per_source 40 \
--epochs 1 \
--lr 1e-4 \
--lora 16 \
--batch 1 \
--accum 4 \
--out runs/mac-smoke
几个参数值得理解:
--device mps:使用 Apple GPU。--batch 1:每次处理一条记录,控制内存占用。--accum 4:积累四次微批次梯度后更新参数。--lora 16:使用 rank-16 LoRA。--dtype fp32:使用适合这条 Mac 训练路径的单精度。
当前训练脚本的 --dtype bf16 使用 CUDA autocast,不应直接把 NVIDIA 示例里的这个参数照搬到 Mac。训练源码
训练结束后:
ls -lh runs/mac-smoke
cat runs/mac-smoke/training_metrics.json
检查输出目录中是否包含适配器、head.pt 和训练指标。
这一步的成功标准是训练链路完整,不是模型已经可以上线。
训练器会拒绝覆盖已有输出目录。再次尝试时,换用 runs/mac-smoke-02 等新名称。
六、扩大数据,训练自己的原型
小规模训练正常后,可以扩大到每个默认数据源 1,500 条,训练两轮:
uv run python -m kev.train \
--base Qwen/Qwen3-0.6B-Base \
--device mps \
--dtype fp32 \
--n_per_source 1500 \
--epochs 2 \
--lr 1e-4 \
--lora 16 \
--batch 1 \
--accum 8 \
--out runs/mac-kev-06b
这是一套便于个人电脑起步的配置,不等同于当前发布版 Kev 的完整复现配方。
训练时接通电源,并保持只有一个训练进程使用 Apple GPU。如果出现内存不足,可以在命令中加入:
--checkpointing 1
同时换一个输出目录。梯度检查点通过重新计算部分中间结果来降低内存需求,代价是训练会变慢。
不要只盯着 loss。损失下降说明模型在拟合训练数据,能否处理新问题,需要单独验证。
七、训练之后,先评估
使用仓库提供的迁移评估集:
uv run python -m kev.benchmark \
--run runs/mac-kev-06b \
--suite evals/v4/transfer-v4 \
--out runs/mac-kev-06b-eval
这条命令评估的是该套件的开发集。
除了准确率,还应关注概率预测误差,以及模型在不同类别上的表现。一个整体准确率不错的模型,可能恰好在你最关心的类别上表现很差。
选项顺序也值得测试。同一条材料,把“退款、物流、账号”换成“账号、退款、物流”,如果答案频繁变化,就需要继续检查数据和模型。
Kev 的评估工具覆盖了准确率、Brier score、校准等指标。评估说明
八、把模型作为本地 API 运行
启动服务:
uv run --extra serve python -m kev.serve \
--run runs/mac-kev-06b \
--port 8009
保持这个终端运行,在另一个终端发送请求:
curl -sS http://127.0.0.1:8009/v1/systemone \
-H 'Content-Type: application/json' \
--data-binary @- <<'JSON'
{
"state": "我的订单被重复扣款了,请退回多扣的钱。",
"model": "kev-latest",
"questions": {
"department": {
"type": "choice",
"instructions": "选择应该处理这条工单的团队。",
"criteria": {
"billing": "付款、账单和退款",
"shipping": "发货、物流和配送",
"account": "登录、密码和账号权限"
}
}
}
}
JSON
接口应返回选项及其概率。现在可以把它接入一个简单应用,观察真实输入下的表现。
这还不是训练流程的终点。公开数据训练出来的模型,未必理解你的业务分类方式。继续训练前,在服务终端按 Ctrl+C 停止服务,释放模型占用的内存。
九、让模型学会自己的中文业务
真正决定业务效果的,往往是标注是否清楚。
例如“付款成功但实例没有创建”,到底交给支付团队还是计算团队?如果标注人员自己没有统一规则,模型也很难学到稳定边界。
先整理一批真实业务记录,保存为 JSONL,每行一个完整 JSON:
{"state":"订单被重复扣款,请退回多扣的钱。","questions":{"department":{"type":"choice","instructions":"选择处理团队。","criteria":{"billing":"付款、账单和退款","shipping":"发货、物流和配送","account":"登录、密码和账号权限"},"label":"billing"}}}
建议先从几百条人工核对过的数据开始,覆盖常见问题、易混淆问题和信息不足的情况。
将数据按事件或工单划分为:
train.jsonl 用于训练
validation.jsonl 用于调参和选择模型
test.jsonl 用于最终验收
同一工单的不同改写应放在同一个集合,避免模型在测试时遇到几乎见过的内容。
然后从已有检查点继续训练:
uv run python -m kev.train \
--base Qwen/Qwen3-0.6B-Base \
--init_from runs/mac-kev-06b \
--data train.jsonl \
--device mps \
--dtype fp32 \
--epochs 2 \
--lr 2e-5 \
--lora 16 \
--batch 1 \
--accum 8 \
--out runs/mac-kev-business
这里最重要的是 --init_from:它加载已经训练好的 LoRA 和决策头,继续学习新业务。它不会保证旧能力完全保留,因此微调后还应检查原有任务是否退化。
用同一份验证集比较微调前后:
uv run python -m kev.benchmark \
--run runs/mac-kev-06b \
--data validation.jsonl \
--out runs/business-before
uv run python -m kev.benchmark \
--run runs/mac-kev-business \
--data validation.jsonl \
--out runs/business-after
选定配置后,再评估测试集:
uv run python -m kev.benchmark \
--run runs/mac-kev-business \
--data test.jsonl \
--out runs/business-final-test
最后,把服务命令中的模型路径换成 runs/mac-kev-business,就能调用自己的业务模型。
个人训练最值得追求的第一个结果,是一个具体、可验证的小能力:能把自己业务里的工单分对,知道哪些输入容易出错,并在实际软件中稳定运行。
Jev 让人看到了直接决策的应用空间,Kev 则提供了一个可以动手实验的入口。选定一个高频判断任务,整理真实数据,完成训练前后的对照,比一开始追求更大的参数规模更有价值。
评论