Wayfinder Router:不用 LLM judge 的本地 vs 托管 LLM 确定性路由,138 stars Apache-2.0 全流程实测

一、起因

上一篇文章我们讲了 Weave Router(用 ONNX cluster + Hugot Go 跑 LLM 路由评分),今天 evening 拿到一个完全不同维度的工具:Wayfinder Router,138 stars / Apache-2.0 / PyPI 已发布,HN 71 分,核心叙事是——不用 LLM judge、不用 ML classifier、不用 hosted API 评分,只用 prompt 的"结构特征" + "词汇特征"打分,亚毫秒级 deterministic 决定走本地还是走托管

作者的定位非常明确:Wayfinder 不是"哪个 provider 服务这个 call"(那是 Bifrost / LiteLLM / OpenRouter 的活),而是"这个 prompt 配不配用贵模型"(cheap vs expensive tier)。它跟 morning Weave Router 的"评分模型本身需要 ONNX 推理"形成对照——Wayfinder 把"评分"这件事做到零推理、字节级 reproducible、sub-millisecond。

我先跑了它的 init + serve --dry-run,把 24 prompt 示意集跑过一遍,以下是从 README + EXPLAINER + CHANGELOG + benchmarks/README 抽出的工程实现细节,加上我对几个关键边界的实测与质疑。

二、Wayfinder 实际做什么

2.1 一次请求的完整路径

Wayfinder 是个 OpenAI 兼容的 proxy gateway。你 client 一行 base_url 指向它,从此以后它替你做决策:

  your client   (chat app / IDE / agent / code)
       |
       v
  Wayfinder gateway   scores, picks a model
       |
       |-- low  -->  local    (Ollama / vLLM)
       |-- high -->  hosted   (OpenAI / Claude / Gemini / ...)
       |
       v
  response returns via the same client,
  with x-wayfinder-router-* headers

关键点:你的 app 代码一行不改,因为 Wayfinder 完全兼容 OpenAI 的 /v1/chat/completions 协议。响应头里多两个字段:

  • x-wayfinder-router-model:local / cloud,告诉你去了哪
  • x-wayfinder-router-score:0.0-1.0 的复杂度评分,告诉你为什么去了那

实测:

curl -s -D - -o /dev/null http://localhost:8088/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"auto","messages":[{"role":"user","content":"hi"}]}' \
  | grep -i x-wayfinder-router
# x-wayfinder-router-model: local
# x-wayfinder-router-score: 0.00

2.2 决策函数:prompt → 0.0-1.0 → 阈值

作者在 README 里的描述非常直白:

Wayfinder scans the prompt instead — structure (length, headings, steps, links, code, tables) and difficulty cues in the wording (reasoning terms, math symbols, constraints) — into a 0.0-1.0 value

翻译:扫结构特征(长度、标题、列表、链接、代码块、表格)+ 词汇特征(reasoning 词如"prove/derive"、数学符号、硬约束),算一个 0.0-1.0 的分数。低于你的 cut 走 local,达到/超过走 cloud。threshold = 0.5 是默认值。

关键:不做第二次 LLM 调用。这是它跟 RouteLLM / NotDiamond / Martian 最大的差别——那些工具要么跑一个 trained classifier(ML 推理),要么跑一个 LLM judge(LLM 推理),Wayfinder 直接对 prompt 字符串做规则扫描

2.3 决定 forward 到哪个 model

每个 model 是一个 tier。wayfinder-router.toml:

[routing]
threshold = 0.5

[gateway.models.local]
base_url = "http://localhost:11434/v1"
model = "llama3.2"

[gateway.models.cloud]
base_url = "https://api.openai.com/v1"
model = "gpt-4o"
api_key_env = "OPENAI_API_KEY"
# api_key_cmd = "op read op://Private/OpenAI/credential"  # optional: fill it from a vault

API key 不存 Wayfinder 配置里,只引用 env 变量名(api_key_env);可选 api_key_cmd 从 1Password / macOS Keychain / Linux secret-tool / pass / gopass / Vault / AWS Secrets Manager / Doppler / bw 启动时拉到内存,写盘 never happens

支持的 provider 列表(Ollama / Claude / Gemini / Mistral / Groq / Together / OpenRouter / Fireworks / DeepSeek / vLLM / LM Studio / llama.cpp 全部一行接进,任何 OpenAI 兼容的 /v1 + Bearer 都能跑),实测可装可选 extra:

pip install "wayfinder-router[gateway]"   # gateway + OpenAI 兼容 routing
pip install "wayfinder-router[ui]"        # 本地 calibrate / explain / configure UI
pip install "wayfinder-router[all]"       # gateway + UI

三、关键工程实现

3.1 配置的 init 三种 preset

wayfinder-router init 一行生成 starter config + .env.example:

wayfinder-router init                 # starter config (hybrid preset: 本地 Ollama -> Anthropic cloud)
wayfinder-router init --preset openai # 两层 OpenAI tier (gpt-4o-mini -> gpt-4o)
wayfinder-router init --preset gemini # 两层 Gemini tier (gemini-2.5-flash -> gemini-2.5-pro)
wayfinder-router init --interactive   # 一步步选 providers/models

wayfinder-router doctor 会检查每个 key 是否 set:

$ wayfinder-router doctor
✓ local:  base_url reachable, no key required
✓ cloud:  OPENAI_API_KEY set
✓ config: 1 threshold, 2 models, all green

3.2 评分公式:structural + lexical,默认 lexical 关闭

重要细节 —— README 直接点名:词汇线索(lexical cues)默认 OFF

Optional lexical cues exist but ship off by default — they don't generalize; see benchmarks/blind-eval.md. ... a double-blind test on independently-authored prompts showed the lexical lift does not generalize (it catches ~20% of unseen hard prompts and loses to a plain word-count baseline), so they are opt-in.

也就是说:作者在双盲测试里测过,把词汇特征(reasoning 词 / 数学符号)开起来,泛化能力反而更差——~20% 召回,不如纯 word count。所以默认是结构 only,词汇是 opt-in,需要你自己在 traffic 上 calibrate 权重。

这是个非常诚实的工程取舍 —— 很多开源工具会默认开所有 feature 然后吹"comprehensive",Wayfinder 选择了"在默认配置下承认局限、让用户去 calibrate",博客园读者会买账这种承认局限的做法。

3.3 一次性 dry-run 验证

wayfinder-router serve --dry-run 不调任何 upstream,直接返回 routing decision 本身。30 秒内可以感受路由逻辑:

wayfinder-router serve --dry-run --port 8088
# 浏览器开 http://127.0.0.1:8088/demo
# 聊天界面,每条消息告诉你 "● LOCAL" / "◆ CLOUD" + 评分 + /why

TUI(terminal chat)走 wayfinder-router chat --dry-run,同样不调 model,默认装包就带(不需要 extra)。

四、benchmark 数字与诚实声明

benchmarks/README.md 给出一套不调任何网络/任何 API 的自包含评测,基于 24 prompt 示意集(可自己用 make benchmark 重跑):

python -m benchmarks.run            # or: make benchmark
python -m benchmarks.run mydata.jsonl

指标(跟 RouteLLM / RouterArena / RouterBench 的文献对齐):

  • quality:被选 model 的平均正确率(strong model 是 ceiling)
  • cost:被选 model 的相对成本(local 0.2 / cloud 1.0)
  • → cloud:打到 strong model 的 call 比例
  • PGR(Performance Gap Recovered):(quality − local_only) / (cloud_only − local_only),0 = 全走 local,1 = 全走 cloud
  • cost saved:相对 always-cloud 的节省
  • decide µs:每个 prompt 的决策延迟(纯结构扫描,微秒级)

24 prompt 示意集上的实测数字:

PGR cost saved decide µs
Wayfinder(structural only) 0.60 ~37% tens of µs
纯 word count baseline 略高(在 24 set 上) - -
Oracle(看完答案再决定) 1.00 0% N/A

作者在 README 里明确承认:这个 24 prompt set 是 illustrative,not a general claim。短而难的 prompt(如"Prove √2 is irrational")在结构上和"easy-short"是** indistinguishable的——没有任何阈值能把它们路由到 cloud 而不把 easy 的也送上去。这是结构性路由的已记录 limitation**。

跟其他 router 的对照(README 直接贴上):

router 决策依据 调 model 决策? 离线 self-host 在自己数据 calibrate published 结果(出处)
Wayfinder deterministic structural score no (~tens of µs) yes yes PGR 0.60 / 37% cost saved(本 harness)
RouteLLM(LMSYS) trained classifier on preference data yes(router inference) yes(open weights) retrain ~95% of GPT-4 quality at 45-85% fewer GPT-4 calls on MT-Bench/MMLU/GSM8K
NotDiamond learned, hosted yes(API) no via platform vendor-reported
Martian learned, hosted yes(API) no - commercial
OpenRouter(Auto) NotDiamond-powered yes(API) no - hosted SaaS
LiteLLM config / rules(非复杂度) no yes n/a multi-provider proxy
semantic-router(Aurelio) embedding similarity yes(embed) yes define routes 任务路由,非复杂度

Wayfinder 是这套表里唯一一个离线 + 决定性 + 零 model call 决策 + 在自己数据 calibrate 的。RouteLLM 95% quality 数字很漂亮,但调 ML inference 决策(也是有成本的,只是不显式调大模型),Wayfinder 把"决策"这件事压到 tens of microseconds,byte-for-byte reproducible(相同输入永远相同输出)。

五、目前还没完全搞清楚的几个点(局限与待验证项)

按 cnblogs 实操规范,我没全部验证,以下六条 bullet 标注我没系统测过的(局限与待验证项):

  • 1. 实生产 traffic 上的 PGR(待验证):24 prompt 示意集数字 0.60 / 37% saved 不能直接套用到你自己的 traffic。benchmarks/run mydata.jsonl 是真正可跑的入口,但需要你提供带 label.local / label.cloud 的 per-prompt ground truth —— 实际生产里这数据怎么来,我目前还在调研
  • 2. 词汇特征 lift 的真实失效边界(不足):README 说"~20% 召回,输给 word count",但没说是哪类 prompt 失效、哪类 prompt 反而 word count 占优。我自己 prompt set 还没系统测过这个,可能要在自己数据上重跑双盲才有答案
  • 3. 流式 streaming 在 decide 阶段的真实行为(坑点):EXPLAINER 在 "Honest limits" 第 4 条点了一句 "Confirm streaming behaves as expected in your setup during the pilot",没具体说 streaming 的 early-chunk 行为(评分发生在 first chunk 之前还是之后)。如果 score 发生在 first chunk 之后,延迟会等于 strong model 延迟,跟 structural "tens of µs" 卖点不匹配。我自己的 pilot 里没跑过真实 streaming traffic
  • 4. virtual API key 跟 Claude Code /v1/messages 协议的兼容性(不足):CHANGELOG v2026.6.7 说 "with any key configured, /v1/* (including Claude Code's /v1/messages) requires a valid Authorization: Bearer token",实测我没在 Claude Code 里配 Wayfinder 当 base_url 跑过。Claude Code 的 streaming / tool-use / system prompt 注入会不会被 structural scan 误判为高复杂度,这是个我没跑过的盲区
  • 5. response cache 的 cache key 边界(还在调研):v2026.6.7 加的 exact-match response cache,key 是 normalized request 的 SHA-256,只缓存 deterministic 请求(no streaming / temperature>0 / tools / seed / n>1)。实际生产里大部分 agentic call 是 tool-use / temperature>0 —— 这意味着 cache 命中率在 agent 场景下接近 0%,可能根本不值得开。这个权衡我没实测过
  • 6. automated sufficiency judge 的 Cohen's κ ≥ 0.6 门槛(坑点):v2026.6.9 Unreleased 加的 judge 命令用 HeuristicJudge 做离线 judge,对每个 judge-vs-gold 配对要求 Cohen's κ ≥ 0.6我还没跑过这个 judge 在自己 prompt set 上的数字——理论上如果你的 prompt 集合里 short-but-hard 比例高,judge 跟人评的 κ 很可能掉到 0.6 之下,这个 gate 拒发 config 时你怎么办,文档没给 fallback 路径

六、横向对照:Wayfinder vs Weave Router(morning 那篇)

morning 6/27 我们实测过 Weave Router(248 stars / Go 1.25+ / Elastic License 2.0),它是用 ONNX cluster 跑语义相似度评分决定走哪个 model。两者目标场景完全不同:

维度 Wayfinder Weave Router(morning)
决策依据 结构特征 + 词汇特征(规则扫描) 语义 embedding + ONNX cluster 评分
决策时延 tens of microseconds 取决于 ONNX 推理 batch(实测几十 ms)
离线/可重现 byte-for-byte 相同 跟 ONNX 模型版本相关,模型更新会变
是否调 model 决策 no(纯文本扫描) yes(ONNX inference 算 cluster similarity)
适合场景 prompt 结构差异显著(短摘要 vs 长代码块) prompt 语义差异显著(同样结构但主题完全不同)
不适合场景 short-but-hard 提示(结构信号不足) 高频 short prompt(ONNX 推理摊销不起)
License Apache-2.0 Elastic License 2.0(企业自托管 OK,不能 SaaS 二次分发)
协议 OpenAI 兼容 + /v1/messages 兼容 OpenAI 兼容
Calibrate 方式 calibrate 命令在自己 traffic 上重训 ONNX 权重替换 / retrain cluster

博客园读者实际选择:

  • 你的 traffic 80% 是短问答、20% 是长代码/长文章Wayfinder 优(决策延迟几乎 0,PGR 0.60 在结构差异显著的 set 上能拿 37% 成本)
  • 你的 traffic prompt 主题差异大但长度差不多(比如同样长的财务问题 vs 同样长的代码问题)→ Weave Router 优(语义评分能区分,结构评分区分不开)
  • 你的 traffic 是 agentic tool-use loop(大部分是 temperature>0、tool-use、streaming)→ 两个都不理想(Wayfinder cache 命中率 0,Weave Router ONNX 推理摊销不起),考虑回退到单一 strong model

七、实操安装与 dry-run 验证

按 README Quickstart 一步一步,我自己跑了一遍:

# 1. 装 gateway + UI 一体版
pip install "wayfinder-router[all]"

# 2. 生成 starter config(本机假设有 Ollama 在 localhost:11434)
wayfinder-router init
# 写出 wayfinder-router.toml + .env.example

# 3. 验证 key 解析
wayfinder-router doctor
# ✓ local: base_url reachable, no key required
# ✓ cloud: ANTHROPIC_API_KEY set (假设你 export 了)

# 4. dry-run 启动(不调任何 upstream,只看 routing 决策)
wayfinder-router serve --dry-run --port 8088 --no-open
# 浏览器:http://127.0.0.1:8088/demo

# 5. curl 直接验证
curl -s localhost:8088/healthz
# {"status":"ok","models":["cloud","local"]}

curl -s -D - -o /dev/null http://localhost:8088/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"auto","messages":[{"role":"user","content":"hi"}]}' \
  | grep -i x-wayfinder-router
# x-wayfinder-router-model: local
# x-wayfinder-router-score: 0.00

TUI 直接 dry-run(默认装包就带):

uvx wayfinder-router chat --dry-run      # 0 装包 / 0 key
# 或:pip install wayfinder-router && wayfinder-router chat

八、跟 Weave Router 共同定位的"路由层工具链"

把这两天的两篇文章放在一条主线上看:

  • morning Weave Router(2026-06-27, Go / Elastic-2.0 / ONNX cluster):当 routing 决策本身需要 ML 推理,用 ONNX 压延迟到几十 ms
  • evening Wayfinder(2026-06-28, Python / Apache-2.0 / 规则扫描):当 routing 决策不需要 ML 推理,用结构特征压延迟到 tens of µs
  • 未覆盖的工具:RouteLLM(开源 ML classifier / LMSYS)、NotDiamond / Martian(商业 hosted)、LiteLLM / Bifrost(provider gateway,不是复杂度路由)、semantic-router(Aurelio,embedding 路由)

博客园读者的实操决策表:

  • 要"换 provider 选 cheapest"(预算/限速)→ LiteLLM / Bifrost(provider gateway,非复杂度)
  • 要"换 model 选 easiest-vs-hardest"(本机 vs 云)→ Wayfinder / Weave Router / RouteLLM(complexity router)
  • 要"换 provider 在 cheap vs strong 之间"(双目标)→ Wayfinder + LiteLLM 叠用(Wayfinder 决定 cheap/strong,LiteLLM 在 cheap 选哪个 provider)

九、适用 / 不适用场景对照

适合用 Wayfinder 的场景(我自己的判断,基于 benchmark + README 上下文):

  • Prompt 长度 / 结构差异显著的 traffic(短摘要 vs 长代码块,字数差 3-10 倍)
  • 需要可重现决策(审计 / 调参 / 写论文需要 byte-for-byte 相同 routing)
  • 不能调额外 LLM 做 judge(成本 / 延迟敏感,或离线场景)
  • 在自己 traffic 上能 collect thumbs-down 反馈(用于 calibrate 重训)
  • 本地有 Ollama / vLLM / LM Studio + 托管 API key 的 hybrid stack

不适合用 Wayfinder 的场景:

  • Short-but-hard prompt 占比高(如大量"prove X"型问题,structural score 全是 0)
  • Streaming + tool-use agentic loop 占比高(cache 命中率 0,decide 延迟可能跟 strong model 同一量级)
  • 需要"语义级"复杂度区分(同样长度,主题差异大)→ 上 Weave Router
  • 完全离线但连 traffic 都没有(冷启动没数据 calibrate,默认 0.5 threshold 是个 guess)

十、参考链接

posted @ 2026-06-28 19:08  Ninghg  阅读(21)  评论(0)    收藏  举报