解读:_avichawla《本地造一个 Jev》——固定答案打分、SGLang /v1/score,以及它不等于完整 Jev
本文是对 @_avichawla 一篇 X Article《Build your own Jev (100% local)》的摘要与评论。读帖时约 118.5 万曝光、约 3113 赞、6118 收藏、485 转发、65 回复。文章开篇定位很清楚:把开源大模型变成快速、本地的决策引擎,而且不必为了这件事再训一遍模型;覆盖 next-token scoring(下一词元打分)、固定选项上的概率分布、SGLang,以及与同模型普通文本生成的对照实验。本稿只做摘要与读法整理,不是全文转载,也不是逐步可复现实验手册。
站内已有 Awesome Jev 目录解读,另有同日已发的 Av1dlive × Keel / Jev harness 解读。三篇同族、切面不同: Awesome 讲生态目录;Av1dlive 讲应用边界与收据;本稿讲推理侧机制——应用已知全部合法答案时,如何一次读出分布,而不是让模型再写一段 JSON。
这篇在说什么
先讲场景。客服工单写着:「同一笔订阅被扣了两次。」应用其实只需要把它派给三个团队之一:billing(账单)、technical support(技术支持)、account access(账号访问)。常规大模型调用往往会让模型写出答案——可能是句子、标签,或一段 JSON;应用再等待、解析、抠出团队名。作者认为:若合法答案事先已知,这条链路是多余的。
更好的做法是把请求当成一次决策(这正是 Jev 一类系统在做的事):应用提供工单与三个允许答案;模型一次返回各答案的分数与概率,选出胜者,并且应用能看见赢得多坚决。文章要在本地用开源模型复现这条推理路径——输入查询与允许答案,一次 scoring 请求拿到决策与分布,不生成句子或 JSON 对象。实现上走 SGLang 的 /v1/score,并用 Qwen、DeepSeek 等模型做测试,对照结构化输出与普通生成。
作者一上来就降调:本文复现的是推理路径,不是完整的 Jev 系统。 Jev 还有训练与校准等工作,一个打分端点提供不了。
全文主线可以压成一句:当输出空间事先已知时,读「下一个词元位置」上几个标签的 logit 并做受限 softmax,往往比让模型自回归写出答案更合适;概率是相对偏好,不等于正确率。
1. 固定答案打分 ≠ 结构化输出
两者都会限制应用最终拿到的东西,但在推理服务器内部干的活不同。
- 结构化输出(structured output) 约束的是对象语法:模型仍可能逐 token 写出
{、字段名、值、};生成结束后,应用再读team字段。schema 能挡住非法对象,但不会在生成开始前就把「三个团队」当成完整结果空间来打分。 - 固定答案打分(fixed-answer scoring) 则由应用直接提交完整合法结果列表;服务器为每个结果读一个模型分数并返回分布——不生成 JSON。
同是选 billing,分布可以差很远:一种是 0.91 / 0.06 / 0.03(偏好清晰),另一种是 0.46 / 0.44 / 0.10(几乎打平)。应用可以自动路由前者、把后者送人工复核。阈值(例如最高分 > 0.80 且领先第二名 ≥ 0.20)写在应用代码里,便于测试与修改——模型只给分,规则在代码。
还要分清:0.91 表示在这三个选项之间,billing 分到了约 91% 的概率质量;它不证明模型在真实世界上有 91% 正确率。正确率要用带标签的例子去测,那是校准(calibration)问题。文中后文也会回到这一点。
解读: 产品讨论里常把「强制 JSON」和「类型化决策」混为一谈。这篇最有用的切割是:结构化输出管语法;固定答案打分管「已知菜单上的相对偏好」。
2. 机制:只关心「第一个输出位置」的那根向量
因果语言模型平常怎么生成:分词器把提示变成 token ID → 模型产出词表大小的向量(logits,尚未是概率)→ 按温度等规则挑一个 token 拼回去 → 再重复,直到停止。决策场景往往只需要第一根向量。
做法是:在提示里给每个答案一个短标签(如 A / B / C),语义说明仍写在提示中;提示以 Label: 结尾,于是「下一个位置」正是模型本会写出 A、B 或 C 的地方。打分路径于是:
- 查出 A、B、C 的 token ID;
- 只读词表向量上这三个位置的 logit;
- 丢掉其余 logit;
- 在这三个值上做 softmax,映射回 billing / technical / account。
归一化发生在已声明的选项之间,不是问「A 在整个词表上有没有 91%」。SGLang 的 /v1/score 已经实现「跑提示、读指定 token 位置、返回分数」,省得自己改模型实现去抠张量。
为什么不用「billing」「technical support」整词直接打分?因为可见词不一定是单 token;多词短语需要序列打分,长度也会搅进比较。单 token 标签让每个选项在同一输出位置对应一个词表项,语义仍靠提示里的描述传达。但仍须用 /tokenize 校验每个标签确实是单 token——前导空格、chat template 都可能改 ID;跨模型也不能假设分词一致。对外 API 应继续暴露语义选项(如 billing),不要把 A/B/C 或 token ID 泄给业务调用方。
若名单不穷尽,还要留逃生口:只给三个错选项时,受限 softmax 仍会把全部概率质量分给它们。名单里应加 OTHER / ESCALATE 一类,在「可能都不对」时有路可走。
解读: 工程上真正难的往往不是「会不会 softmax」,而是标签与分词对齐、提示模板与对外 API 解耦、以及不穷尽菜单时的 OTHER。略过这三步,本地 demo 很容易「看起来像 Jev,线上却静默乱路由」。
3. 本地路径与对照实验(摘要级)
文章用一节走完本地闭环(细节以原文代码块为准):起 SGLang 加载 Qwen → 用字母标签写决策提示 → tokenize 标签 → 一次 /v1/score → 把概率映回业务选项。示例里 billing 可能以约 0.678 获胜;若策略要求 0.70,就应送审而不是自动路由——阈值应来自带标签评测,而不是单次 demo。
作者还做了小应用与并排演示:Jev 风格车道走 decide()(内部 /v1/score,不生成 token);标准车道走同引擎的生成接口(如 chat completions,最多约 32 token,再从文本里解析允许选项名)。两边可同开、同用一块 GPU 上的 SGLang,经 continuous batching 调度。文中展示支持若干开源小模型(如 Qwen3 4B、Qwen2.5 0.5B/1.5B、SmolLM2、TinyLlama、DeepSeek-R1-Distill-Qwen 1.5B 等,以原文列表为准),并用本地固定数据集(客服路由、候选人筛选、费用审核等)看速度与正确性。速度优势来自「不必自回归写答案」;正确性仍取决于模型与校准,不是打分 API 自动送的。
4. 什么时候用打分、什么时候仍要生成
作者的选择规则很干净:
| 需要的输出 | 更合适的路径 |
|---|---|
| 推理前内容未知(要写新句子、新字段值) | 生成(含需要时的结构化生成) |
| 输出集合已知,且只要标签 + 分布 | 打分(读第一根 next-token 向量上的排序即可) |
结构化输出定义的是响应句法;解码器仍在逐 token 写字段。仅当候选值事先无法枚举时,才更该用结构化生成。文末再次强调:本项目复现 Jev 风格推理机制,不复现 Jev 的权重、RLCD 过程或评测栈;训练与校准侧作者表示另文再讲。
解读: 和 Av1dlive / Keel 那篇对起来看更完整——那边说「selector 只点 host 备好的菜、记录可回放」;这边说「点菜这件事在推理上可以是一次受限 softmax,而不是再写一篇散文」。Awesome Jev 则帮你找生态里还有谁把这类决策嵌进产品。三篇叠在一起,才不容易把「本地跑通 /v1/score」误读成「已经拥有完整 Jev」。
适合谁读、不适合谁
更适合:要在已知标签集合上做路由 / 分类、并希望拿到可设阈值的分布的人;已经在用或评估 SGLang、想理解 /v1/score 语义的人;读过 Jev 宣传、想分清「推理模式 vs 完整产品」的人。
不太适合:指望本稿代替官方 Jev 训练与校准文档的人;需要开放式写作、检索增强长文生成的场景(那仍是生成路径);以及把单次 0.91 的分布当成线上正确率承诺的人。
原文与延伸
- X Article 与帖:@_avichawla / 2101563610644496464
- 站内对照:Awesome Jev;Av1dlive × Keel / Jev harness