4ROUTER / 接入

保留你的客户端。 接入新的基础设施。

更新 base_url 与密钥,继续使用现有 OpenAI 客户端。模型路由、用量计费与决策记录,在同一次调用中接入。

协议
OpenAI 兼容
额外 SDK
无需新增
服务模型名
enthalpy-1
一次调用的路径POST/v1/chat/completions
  1. 你的客户端messages + enthalpy
  2. 路由与约束enthalpy-1
  3. 响应与决策记录choices + enthalpy_route

更换 base_url

OpenAI 兼容。忽略掉 enthalpyenthalpy_route 这两个对象的客户端,拿到的仍然是一个完全合法的 chat completion。

curl -sS http://127.0.0.1:8080/v1/chat/completions \
  -H "Authorization: Bearer $ENTHALPY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "enthalpy-1",
    "messages": [{"role": "user", "content": "把这段 changelog 总结成三行"}],
    "enthalpy": {"cost_weight": 1, "explain": true}
  }'

model 填的是服务模型名(ENTHALPY_SERVICE_MODEL_NAME,默认 enthalpy-1),意思是「你来挑」。这里改填池里某个真实模型 id,就切成 PINNED:路由器被跳过,那个模型直接回答,而鉴权、准入、计费、决策日志一样不少。这是让人敢迁过来的那个逃生口。

enthalpy 块里的未知字段是 400(extra="forbid")—— 打错一个字是一个响亮的错误,不是一个被静默忽略的设置。cost_weight 的取值范围是 [0, 8],单位是「每 log1p(est_cost / $0.01) 一个 logit」,默认 0。

enthalpy_route 对象

{
  "model": "kimi-k2.5",
  "enthalpy_route": {
    "selected_model": "kimi-k2.5",
    "billed_usd": "0.00044520",
    "router_latency_ms": 71.1,
    …
  }
}

钱一律是字符串:billed_usd 精确到 1e-8 美元,JSON float 会把账本小心保住的精度又 round 掉。router_latency_ms 是路由这一步自己花的时间,和 total_latency_ms 一起给出,所以这一层的开销是可以被单独看见、单独质疑的。

完整响应体:usage、attempts、候选表与 plan 字段
{
  "id": "chatcmpl-…",
  "object": "chat.completion",
  "model": "kimi-k2.5",
  "choices": [{ "index": 0, "message": { "role": "assistant", "content": "…" },
                "finish_reason": "stop" }],
  "usage": { "prompt_tokens": 41, "completion_tokens": 260, "total_tokens": 301 },
  "enthalpy_route": {
    "request_id": "…",
    "mode": "select",
    "selected_model": "kimi-k2.5",
    "attempts": [ { "step": 0, "model_id": "kimi-k2.5", "score": 14.678,
                    "accepted": true, "error": null,
                    "prompt_tokens": 41, "completion_tokens": 260,
                    "upstream_cost_usd": 0.000371, "latency_ms": 2841.0 } ],
    "upstream_cost_usd": 0.000371,
    "billed_usd": "0.00044520",
    "router_latency_ms": 71.1,
    "total_latency_ms": 2912.4,
    "accept_prob": null,
    "checkpoint_id": "…",
    "pool_fingerprint": "…",
    "notes": [],
    "candidates": [ /* explain: true 时,每个候选一行 */ ],
    "plan": null
  }
}

上面的 base URL 是文档里那个回环地址。托管版的 4router.cn/v1 还在接上游凭证,没通之前这里不会印一个打不通的地址。

接口约定

接入之后,每一步都有依据。

调用方式保持熟悉;模型、费用、流式结果与错误,都有明确的字段可读。

01
response.model

读到实际生成模型

你发的是 enthalpy-1,回来的 model 字段是真正生成这段文本的模型 id。记账、评测、复现都按这个字段走。

02
stream: true

先读决策,再结束流

enthalpy_route 帧在 data: [DONE] 之前发出 —— 因为客户端读到 [DONE] 就会停。按顺序读,不要跳。

03
max_cost_usd

在选择前落实预算

enthalpy.max_cost_usd 不是建议值。超出预算的候选在打分阶段就被标成不合格,exclusion_reason 会写明原因。

eligible: falseexclusion_reason: "budget"

04
error.type

让失败可以被处理

错误对象包含稳定的 type、可读的 message、可选的结构化 contextrequest_id。按类型处理错误,并通过请求标识关联日志。

402 · budget_exceeded429 · quota_exceeded

本地运行与复现

从调用,继续走到实现。

示例指向本地开发端点。启动服务、运行评测,并检查产生的报告;接入过程中的每个关键步骤都能继续验证。

展开运行命令与复现清单

自行部署与复现

这一页上没有一个数字是手打的 —— 它们由 web/crates/ui/build.rs 在编译期从 reports/ 里的 JSON 生成成带类型的常量。改一个评测结果,页面跟着变;删掉一个字段,构建会带着文件名和 JSON 路径失败,而不是静默渲染出一个 0。

启动完整服务

docker compose -f deploy/docker-compose.yml up -d
docker compose -f deploy/docker-compose.yml logs -f gateway

复现评测

# 1. 对你自己的池采一份矩阵(docs/TRAINING.md §1b 给了报价)
enthalpy data harvest --dataset gsm8k --dataset math500 --split test \
    --limit 1000 --out data/matrices/mine.jsonl.gz

# 2. 训一个 checkpoint
enthalpy train sft --matrix data/matrices/mine.jsonl.gz --name gen1

# 3. 评测 —— 免费,不调用任何 provider
enthalpy eval --matrix data/matrices/mine.jsonl.gz \
    --checkpoint gen1 \
    --test-fraction 0.3 --split-seed 0 \
    --reference best_single \
    --sweep-cost \
    --out reports/gen1.json

--out 会同时写出 reports/gen1.json(每一个数字,用来做回归)和 reports/gen1.md(headline、出处行、结果表、† 注、bound 注、对比表)。

引用数据前的核对项

引自 docs/BENCHMARKS.md §7:

  • 矩阵、它的数据集列表、它的 --limit 和 --n 都写出来了
  • --test-fraction 和 --split-seed 写出来了
  • 参照 router 点名了,而且它不是一个 bound
  • correct 阈值写出来了
  • 每一个 Δ 旁边都有置信区间和 sign test p 值
  • 跨过零的区间按「没有结论」报告
  • pool 指纹和 checkpoint_id 就记在表格旁边
  • models used 不是 1
  • 延迟数字写明了设备,而且冷启动那一次没有被热态 p50 顶替掉

原始产物就在仓库里:reports/crb-gen2.jsonreports/crb-gen2.sweep.jsonreports/crb-gen2-vs-knn.jsonreports/router-latency.cpu.jsonreports/stage0-routereval.report.json。页面上任何一个数,都能在这几个文件里找到它的出处。

4ROUTER / 系统研究

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

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

在 Resources 中阅读系统笔记
ATTENTION / MEMORY

FlashAttention 与 PagedAttention:不同层的内存问题

一个优化读写路径,一个组织持久状态。

PREFIX / REUSE

RadixAttention:复用前缀,不是复用答案

复用的单位是具有一致计算历史的前缀状态。

TIERS / TRANSFER

LMCache:把 KV 状态放进存储层级

少算一次 prefill,要先付一次状态访问的成本。

开始接入

下一次调用,从这里开始。