限制与 FAQ¶
已知限制¶
noul概率是只对两个候选字母做 softmax;阈值要在自己的标注集上校准。- Choice 当前最多 16 个候选,Score 最多 10 档;超出会被拒绝。
- 候选落在
top_logprobs窗口之外时概率会被截断;API 不公开该内部诊断,需自行设置足够大的窗口。 - Box 和图片使用 TypeSafe 的资产引用格式;图像及 box 功能仍取决于本地后端是否支持视觉输入。
- 超出后端真实能力的部分应靠水平扩展解决,而不是继续调高
max_concurrency。
校准¶
决策模型对校准敏感。阈值门禁(p < 0.7 转人工)成立的前提是概率诚实,而激进量化
可能保住 argmax 却毁掉置信度。
用于门禁的模型优先 Q8_0 或 F16;Q4_K_M 按实验对待,并用对比两个后端 里那套方法测量,而不是靠假设。
两个习惯能让阈值保持可信:
- 每次换模型、换量化、换服务之后都重跑一次对比,盯 Brier 距离而不是 argmax 一致性。
- 留一份来自你自己流量的小标注集,核对网关给出的分数。托管 API 的校准结论不会自动 迁移到你硬件上的 4B 模型,必须重新测量。
FAQ¶
为什么直连工具调用路径更慢?¶
因为它必须生成内容:每个问题要解码一整段工具调用 JSON。同一组 10 条用例(noul × 4、
choice × 4、score × 2)× 3 轮,两条路径都关思考,严格单线程:
| 后端 | 路径 | 准确率 | 延迟 mean | 延迟 median | 输出 tok |
|---|---|---|---|---|---|
| 27B(远端,跨境) | 网关 | 30/30 | 1027 ms | 977 ms | 1.0 |
| 直连 | 27/30 | 2005 ms | 1820 ms | 41.9 | |
| 0.8B(本地 llama.cpp,有缓存) | 网关 | 18/30 | 67 ms | 47 ms | 1.0 |
| 直连 | 21/30 | 599 ms | 528 ms | 47.5 |
两条路径都付同一笔跨境固定开销,所以它作差时抵消了:网关 1027 ms、直连 2005 ms,中间 差的 ~978 ms 是真实省下的解码。远端上网关确实更快也更准(30/30 对 27/30,快 1.95 倍)。
这笔固定开销毁掉的是另外两件事:绝对值不可解读(1027 ms 里绝大部分不是决策,不能拿它 推算吞吐),以及比值被摊薄(真实收益是省下的 ~978 ms,除以含地板的总时延就只显出不到 2 倍)。实测输入放大 100 倍、输出放大 10 倍,延迟都不变。远端部署要优化延迟,方向不是压 prompt,而是减少往返次数或换更近的接入点。
本地 0.8B 是干净的测量。 单次 67 ms,无网络底噪,网关快 8.9 倍、输出 token 少 47.5 倍——这才是协议自身效率的诚实读数,远端那个 1.95 倍是同一收益被 1 秒地板摊薄后的样子。 但它的 60% / 70% 反映的是 0.8B 的能力上限,不是协议水平(同一题 27B 上网关 6/6)。
每个问题都报 BACKEND_PROTOCOL_ERROR,为什么?¶
两种最常见的原因都会静默失败——后端返回 HTTP 200,日志里没有错误,只有
logprobs 是 null:
- 推理模型没关思考,思考内容吃掉了
max_tokens: 1里唯一那个 token(响应里会出现reasoning字段); top_logprobs超过服务端上限(默认 128,而 OpenAI 规范只允许 20)。
两步诊断和对应的修法见静默失败。第三种原因是服务不
返回 logprobs.content[0].top_logprobs,或者 chat template 永远不产生裸字母。改任何设置
之前先用 curl 看原始响应。
能给 17 个选项吗?¶
不能。单题 2 – 16 个候选,17 个会以 INVALID_REQUEST 拒绝。字母从 A 排到 P。
一个问题失败会拿到部分结果吗?¶
不会。任一问题失败则整次请求失败,报出的是按问题顺序的第一个错误。这与参考实现一致—— 一组决策只有作为整体才有意义。
候选概率不稳定怎么办?¶
某个候选字母可能落在 top_logprobs 窗口之外,被截断到实际返回的最低 logprob。那是下界,
不是估计值。API 不公开内部截断标记;可上调 backend.top_logprobs(16 – 4096)并重新测量。
上调之前先看静默失败那节:服务端有自己的上限,超限
不报错、只是把 logprobs 变成 null。用网关当前的窗口先去探一下,确认服务端接受得
了,再谈调大。
问题真的是并行的吗?¶
是的,上限为 backend.max_concurrency(默认 32)。无论完成顺序如何,响应都保持请求里的
问题顺序;request.total_timeout_seconds 约束整次请求,而不是每个问题。
我怎么知道这些概率不是编出来的?¶
自己构造一组对照:一份评分标准写得精确,一份写得模糊;再打乱候选顺序各跑一轮。如果打乱 候选顺序只改变胜出的字母,而概率质量跟着证据走,说明分布反映的是模型的判断。如果标签 随着位置翻转,模型读的是位置而不是含义,这些数字就不该拿来设阈值。
能配推理模型用吗?¶
可以,用 backend.extra_body 关掉思考即可——各服务端的写法见
推理模型。DeepSeek 的 deepseek-reasoner 没有关闭开关,请改用
deepseek-chat。
多大模型够用?¶
0.6B – 4B 适合二值门禁。同一组用例在 0.8B 上 noul 是 12/12,但 score 是 0/6——
排列实验显示模型根本区分不了档位,只会把概率压向最保守的一档;同一题在 27B 上是 6/6。
参考基准上更大的收益来自改写判据,而不是放大模型,但多档分级确实需要更大的模型。
要知道协议本身的上限,看远端 27B 那组;0.8B 的低准确率只是模型能力到顶了。
网关为什么不流式?¶
没有东西可以流式返回。一个决策只解码一个 token,流式只会增加复杂度而不带来信息。
始终发送 stream: false。
发给后端的 prompt 可以看吗?¶
可以,而且这是有意为之——整个设计就是可审计的。fused 与参考网关逐字节兼容,system
prompt 只有一条常量。想要可缓存的前缀而不是字节兼容时,用 request.prompt_layout: split。
我该怎么扩容?¶
在负载均衡器后面跑多个网关实例。把 max_concurrency 提到后端真实容量之上,只是把队列
从你的进程挪进推理服务,那里更难观测。
许可¶
Apache-2.0。请求/响应契约与 logprob 分类的思路参考了 David-Lolly/Jev-Compatible。