引擎

打分与选择

Enthalpy 为池内每一张模型卡计算一个分值,减去成本项后取最大者,并保存完整的候选表。本页说明打分函数、四种路由模式,以及泛化测量的结果。

打分头参数量
263,169

1,138 个候选时也是这个数:W 和 P 的形状里没有「模型数」这一维。

backbone
Qwen/Qwen3-0.6B
这一步的上游调用
0

录制的决策

四条真实查询在各成本权重下的完整候选表,录自当前 checkpoint。

Rename the local variable `n` to `count` in this function and update its three uses. Nothing else changes.

成本权重 γ174 ms · 模式 select
模型概率(按原始分)原始分成本项最终分预估成本
  1. MiniMax-M2.710.6%+14.593+14.593$0.004673
  2. Qwen3-Max11.2%+14.648+14.648$0.000220
  3. claude-opus-4-618.1%+15.132+15.132$0.006240选中
  4. claude-sonnet-4-614.4%+14.900+14.900$0.004436
  5. glm-510.3%+14.569+14.569$0.005619
  6. gpt-5.414.3%+14.895+14.895$0.002615
  7. kimi-k2.512.1%+14.725+14.725$0.000487
  8. qwen3.5-plus9.1%+14.446+14.446$0.001811

打分不产生上游调用。

录制于 2026-09-14T12:10:51.491103+00:00 · checkpoint sft-f23a · pool 3520b40d · 来源 enthalpy route --json --checkpoint crb-gen2。为录制结果,非实时调用。

实测结果 →

一次决策的完整候选表

同一条查询,成本权重由 0 调至 1 后所选模型发生变化。原始分不变,成本项改变,最终排序随之改变。

查询:「一行重命名」。claude-opus-4-6 的原始分最高(+15.132),预估成本也最高($0.006240)。γ 由 0 调至 1 后,其成本项为 -0.485kimi-k2.5-0.048;最终分 +14.678 高于 +14.647,差值 0.0307

概率一列在两个 γ 下取值相同:softmax 作用于原始 logit,不受成本项影响。改变选择结果的是一个显式的、可调回零的价格项。

成本权重 γ
模型概率(按原始分)原始分成本项最终分预估成本
  1. MiniMax-M2.710.6%+14.593+14.593$0.004673
  2. Qwen3-Max11.2%+14.648+14.648$0.000220
  3. claude-opus-4-618.1%+15.132+15.132$0.006240选中
  4. claude-sonnet-4-614.4%+14.900+14.900$0.004436
  5. glm-510.3%+14.569+14.569$0.005619
  6. gpt-5.414.3%+14.895+14.895$0.002615
  7. kimi-k2.512.1%+14.725+14.725$0.000487
  8. qwen3.5-plus9.1%+14.446+14.446$0.001811

这不是为落地页导出的特例。网关把每一次路由都写进 route_decisions 表,无条件地:请求里的 explain 只决定候选表进不进响应体,不决定它存不存。所以客户能在控制台里打开自己发过的任意一条请求,看到的就是这张表。

打分在本地完成,不产生上游调用。一次本地前向推理决定模型归属,被选中的模型在此之后才收到请求。

打分函数

模型池可配置,不是重训一个 head。

打分的数据流你的 prompt模型卡描述符(一段话)Qwen/Qwen3-0.6BQwen/Qwen3-0.6B(同一个)h(q) ∈ R^1024d_j ∈ R^1024× We_j ∈ R^128× P,归一化s_j = (h(q)ᵀW)·e_j每个模型一个分数

query 过一次 backbone 得到 h(q) ∈ R^1024;模型卡的描述符段落过同一个 backbone,再经 P 投影并归一化,得到 e_j ∈ R^128。打分是一个双线性内积:

s_j = (h(q)ᵀ W) · e_j

关键在于 WP 的形状里没有「模型数」这一维。模型是输入,不是参数。

打分头参数

张量形状参数
P1024 × 128131,072
W1024 × 128131,072
b_accscalar1
w_acc10241,024
合计263,169

checkpoint 里另有 8 组、共 8,192 个浮点数,是这 8 段描述符的 backbone 输出缓存。它们是输入的缓存,不是权重 —— 把它们算进参数量,等于承认 head 会随模型数增长,而那正是这个架构要否掉的说法。

参数量与池大小无关

增删一个模型只改描述符文本和它的缓存向量;WPw_accb_acc 一个字节都不动。池里 8 个模型时 head 是 263,169 个参数,池里上千个候选时还是这个数。

对未训练模型的泛化:未达成

1,138 个候选、12 个分组上按 12.5% 留出 142 个候选,head 从未在它们上面训练过。结果:

切片路由器最强单模型oracle随机
val0.75710.76670.97580.4865
test0.75160.76370.97490.4915
holdout0.57020.65960.86680.4863

留出切片上 beats_best_singlefalsegap_closed-0.4313 —— 负数,意思是它比最强单模型还差。仍然为真的只有 beats_randomtrue)。所以:打分函数上换池不用重训,但换池之后的质量,今天没有证据,且已有的证据是反向的。上面那些正面数字,全部来自同一个池内。

四种模式

同一个端点,四条路径。前两种的区别是「要不要给自己的答案打分」,后两种的区别是「谁来决定调几次」。

SELECT

一次选择,一次调用queryroutermodel

选一次,调一次。延迟 = 路由 prefill + 一次上游补全,成本 = 一次补全。默认。

ESCALATE

便宜的先来,分不够再往上routerstep 0step 1a < 阈值返回

从较低成本的候选开始,逐级向上,最多 max_attempts 次。最后一次尝试的结果始终返回;未达到阈值时,notes 中记录该情况。

ORCHESTRATE

每一条边都指向更早的步骤planner012

planner 出一张图,executor 按深度分波并行跑。每一步只看得到原始问题 + 它的 access 列表点名的那几个更早的输出 —— 看不到别的子任务,看不到计划本身,也看不到同一波里兄弟步骤的输出。

access 只能向后指,所以上面这张图里每一条边都朝左。一张所有边同向的 DAG,本身就是那条隔离契约的证明。违反它的计划会被拒绝执行,而不是执行了再说。

PINNED

路由器被跳过,计费和日志照旧queryroutermodel

请求里的 model 写了池里的真实 id,路由器整个跳过。鉴权、准入、计费、决策日志照旧。这是迁移期该用的那一档:先把一个端点切过来,继续钉着,直到你愿意相信路由。

只有 SELECT 和 PINNED 是从上游真流式的 —— 另外两种在答案存在之前不知道哪个模型会产出它,所以它们在拿到答案之后回放成 SSE,并在 notes 里说明帧的时序不是上游的时序。先流式吐出 escalate 的第 0 步再把它收回去,比等一会儿更糟。

三处设计取舍

同一类工作里,Fugu 做了三个相反的选择。下面每一条都写清楚了证据在哪,以及证据到哪儿为止。

模型池可替换

head 的形状不随池的大小变化:263,169 个参数,在 8 个候选时是这个数,在 1,138 个候选时还是这个数。加一个模型要写的是一段描述文字,不是重训一个分类头。

这一条是可核对的机械事实。它等于「换了池质量也一样」—— 后面那句被测过,142 个从未训练过的候选上没成上面第 3 节印着三条切片的原始数字)。把两句话分开说,是因为它们的证据强度差了一个数量级。

成本参与打分,而非后处理

γ 直接进排序:adjusted = logit − γ·log1p(est_cost / c_ref)。不是先选完再看贵不贵,也不是一个 0–1 的比例旋钮 —— 它的单位是 logit,所以它和模型的把握度在同一个量纲上较劲,谁赢是可以算出来的。

证据是第 4 节那条前沿曲线,包括出厂默认值为什么是 0:γ=0.3 时胜势的置信区间跨过了零。

决策可展开查看

route_decisions 是无条件写入的。请求里的 explain 只决定这次响应体里带不带候选表,不决定存不存 —— 所以任何一个历史请求,事后都能在控制台里打开完整的候选分数、每一次 attempt(含失败的和被 accept 头拒掉的)、以及精确到 1e-8 美元的计费金额。

Fugu 的决策是 not exposed by design。决策记录是无条件写入的。

4ROUTER / 系统研究

把配置选择,放回系统原理。

理解算子、KV 状态与调度怎样共同决定一条推理路径。

在 Resources 中阅读系统笔记
GEMM / KERNELS

从算子到服务:cuBLAS 与 cuDNN

先识别限制执行的资源,再选择算子实现。

STATE / CAPACITY

KV cache:从张量形状到容量预算

上下文长度是一个随并发增长的状态预算。

SCHEDULING / SLO

从 Prefill 到 Decode:调度的实验设计

提升吞吐时,仍要知道谁在等待。

聊聊你的基础设施需求。

接入平台,或讨论模型、性能与部署方案。