首页
/ OmniRoute 免费供应商排行榜的用量可靠性:24 小时真实成功率如何补上 ELO 排序的盲区

OmniRoute 免费供应商排行榜的用量可靠性:24 小时真实成功率如何补上 ELO 排序的盲区

2026-09-06 09:09:22作者:庞队千Virginia

本篇指南围绕 OmniRoute 的 Free Provider Rankings(免费供应商排行榜)功能展开,重点讲解 #11546 引入的"用量可靠性"(usage reliability)维度:排行榜不再只看 Arena ELO 模型质量分,而是叠加展示每个供应商过去 24 小时实际处理的请求数与成功率。读完本文,你将理解该功能的完整数据链路——从 API 参数、call_logs 聚合 SQL,到小样本返回"破折号"的判定规则与前端展示逻辑,并能据此做出更可靠的免费供应商接入决策。

一、背景:ELO 单维排序的盲区

OmniRoute 注册了数百个供应商,其中 150 余个目录条目标记为免费/免鉴权(no-auth、免费档 OAuth 或免费档 API key)。免费供应商的模型质量差异极大,因此 OmniRoute 用 Arena AI(LMArena 风格)ELO 分对免费供应商的模型质量打分,并在仪表盘的 Free Provider Rankings 页展示排名。

但仅凭 ELO 排序存在一个致命盲区:一个对所有请求都返回错误的供应商,只要它的模型 ELO 高,依然会排在第一位。连接状态(connection state)描述的是"此刻的凭证与限流",看不到"这个供应商是否真的在成功服务流量"。

#11546 的修复思路是:用量数据(usage data)此前已经由 API 提供,但前端从未主动请求。现在排行榜页显式请求并在表格中展示每个供应商在最近 24 小时窗口内实际服务的请求量与成功率;样本太小的供应商显示破折号(—),而不是一个没有统计意义的数字

二、数据来源:三个真实信源的 Join

排行榜的分数体系由三个真实来源计算而成(详见 Free Provider Rankings 文档):

  1. 免费供应商清单NOAUTH_PROVIDERS,加上标记 hasFreeOAUTH_PROVIDERS / APIKEY_PROVIDERS 条目(定义于 src/shared/constants/providers.ts)。
  2. 模型目录:来自 provider registry(open-sse/config/providerRegistry.ts),并合并运营者手工添加的自定义模型(src/lib/freeProviderRankings.ts 中的 mergeProviderModels,注册表条目在 ID 冲突时优先)。
  3. ELO 派生的任务适配分:由 Arena ELO 同步引擎(src/lib/arenaEloSync.ts)写入 model_intelligence 表,source = "arena_elo"

Join 逻辑位于 src/lib/freeProviderRankings.tscomputeFreeProviderRankings:对每个免费供应商的每个模型做三级模糊匹配(findMatchingIntelligence:精确匹配 → 去除尾部版本后缀如 kimi-k2.6 → kimi-k2 → 前缀匹配),然后取最高分模型作为 Top Model、全体已评分模型的均值作为 Avg Score,供应商按 Top Model 分数降序、再按平均分排序。

ELO 分数按榜单归一化到任务适配区间 [0.4, 0.98]

taskFit = 0.4 + 0.58 * ((elo - minElo) / (maxElo - minElo))

前端把分数渲染为人类可读标签(Elite / Excellent / Very Good / Good / Average / Below Average),因为它是相对排名质量而非百分比。

三、API 层:withUsageusageRange 参数

排行榜页由公开只读端点 src/app/api/free-provider-rankings/route.ts 支撑,查询参数经 Zod 校验:

GET /api/free-provider-rankings
GET /api/free-provider-rankings?category=coding&limit=20
GET /api/free-provider-rankings?configuredOnly=1&withUsage=1&usageRange=24h
参数 类型 默认值 说明
category string (无) defaultcodingreviewdocumentationdebugging 之一;省略返回综合排名
limit number 50 钳制到 1–100,非法值回退为 50
configuredOnly boolean false 只保留至少配置了 1 条(激活)连接的供应商
availableOnly boolean false 只保留至少 1 条未耗尽、未限流的连接(隐含 configuredOnly)
withUsage boolean false 追加每个供应商在窗口内实际服务的统计(reliability.usage
usageRange string 24h 可选 1h24h7d30d拼写错误会被 400 拒绝而非静默改写窗口

两个值得注意的实现细节:

  • 布尔参数宽容解析、严格拒绝:布尔参数会把 "1" / "true" / "yes" 统一转换为 true(路由文件中的 boolParam);而 usageRange 采用 z.enum,注释明确写道"拒绝而非静默转换:一个拼写错误不能悄悄返回与调用方要求不同的窗口"。
  • withUsage 是纯增量、默认关闭:因为它要付出一次对 call_logs 的聚合查询代价,"只关心排名的调用方不必为此买单"。同时 withUsage 会连带加载连接快照——源码注释指出,过去单独开 withUsage 会静默返回没有 reliability 的排名,现在 needsConnectionSnapshot 会自动触发快照加载。

响应形如:

{
  "rankings": [
    {
      "id": "<provider-id>",
      "name": "<provider name>",
      "category": "noauth | oauth | apikey",
      "topModel": {
        "modelId": "<registry model id>",
        "modelName": "<model display name>",
        "score": 0.0,
        "eloRaw": 0,
        "confidence": "high | medium | low"
      },
      "averageScore": 0.0,
      "modelCount": 0,
      "reliability": {
        "state": "healthy | degraded | down",
        "connections": [{ "testStatus": null, "rateLimitedUntil": null, "state": "healthy" }],
        "usage": {
          "requests": 0,
          "successes": 0,
          "successRate": null,
          "avgLatencyMs": null,
          "lastRequestAt": null,
          "windowHours": 24
        }
      }
    }
  ]
}

四、用量统计的 SQL 层:getProviderUsageSince

withUsage 打开后,引擎调用 src/lib/db/callLogStats.ts 中的 getProviderUsageSince(since),在 call_logs 上做单窗口聚合:

SELECT
    c.provider,
    COUNT(*) as requests,
    SUM(CASE WHEN c.status >= 200 AND c.status < 400 THEN 1 ELSE 0 END) as successes,
    ROUND(AVG(c.duration)) as avgLatencyMs,
    MAX(c.timestamp) as lastRequestAt
FROM call_logs c
WHERE c.provider IS NOT NULL AND c.provider != '-'
  AND c.timestamp >= @since
  AND EXISTS (
    SELECT 1 FROM provider_connections pc WHERE pc.provider = c.provider
  )
GROUP BY c.provider

从源码结构看,这条查询是有意不直接复用同文件的 getProviderMetrics()(后者带两个关联子查询,而 call_logs 仅按 timestamp 建索引,关联扫描会主导成本):这里只保留排名真正需要的四列,单次有界 GROUP BY 即可走 idx_cl_timestamp。成功率的定义与邻居查询保持一致——2xx/3xx 计为成功EXISTS 子句则保证已删除连接的供应商不会因历史日志残留为"幽灵节点"(对应 #10714)。

窗口时长由 usageRange 决定(复用健康矩阵 RANGE_MS),默认 24h,即 changelog 中"过去 24 小时"的由来。

五、小样本规则:为什么不足 5 次请求就显示破折号

聚合结果经 src/lib/freeProviderRankings.ts 中的 attachProviderUsage 挂到每个排名的 reliability.usage 上,其中核心判定是:

successRate: row.requests >= MIN_USAGE_REQUESTS ? row.successes / row.requests : null

常量 MIN_USAGE_REQUESTS = 5(约 L279),源码注释解释得很直白:"2 次里挂 1 次不等于'坏了一半',没人调用过的供应商也不是'0% 健康'"。样本量低于 5 时 successRate 置为 null,把"没有把握下结论"与"成功率为 0"区分开。

展示侧由纯函数 formatUsageReliabilitysrc/lib/freeProviderRankingsUsage.ts,刻意零依赖、可被客户端组件直接引用)把用量归为三种展示形态:

kind 触发条件 展示
rate successRate !== null(窗口内 ≥ 5 次请求) 百分比数字,如 97%
insufficient successRate === nullrequests > 0(0–4 次请求) 破折号
none 窗口内无流量或未请求 usage 破折号

百分比还按阈值着色:good(≥ 95%,绿)、fair(≥ 80%,黄)、poor(< 80%,橙);破折号场景显示为中性色,且三种形态都有各自的 tooltip 文案(完整样本数、"请求过少"、"无流量"),即 changelog 所说"too small a sample shows a dash, not a number"。

六、前端:排行榜页如何消费用量数据

仪表盘页面位于 src/app/(dashboard)/dashboard/free-provider-rankings/page.tsx/dashboard/free-provider-rankings/page.tsx),入口为 Costs → Free Provider Rankings 或直接访问 /dashboard/free-provider-rankings。页面包含:

  • Top-3 领奖台(前三名免费供应商卡片);
  • 完整排名表,列为 Rank / Provider / Top Model / Score / Avg Score / Reliability / Models / Type;其中 Reliability 列就是 #11546 新增的 24 小时成功率列;
  • 类别过滤按钮(All Categories / Default / Coding / Review / Documentation / Debugging)、可用性开关(Configured only / Available only)、Type 过滤与按 Type 分组排序(客户端派生,不触发重新请求)。

关键改动在请求构造处:

// Always: an ELO-only ranking describes a provider that errors on every
// call as healthy. `usageRange` matches the health matrix default.
params.set("withUsage", "1");
params.set("usageRange", "24h");

也就是说,页面现在无条件附带 withUsage=1usageRange=24h——这正是 changelog 所说"用量数据早已由 API 提供,但此前从未被请求"的落点:修复不是新增数据能力,而是把已有能力接进默认视图。Reliability 列与 state(连接当前状态)互补:state 读的是连接此刻的样子,看不见"每次调用都报错"的供应商,只有调用日志能看见。

七、ELO 分数体系的支撑机制

用量维度建立在 ELO 分数体系之上,理解以下机制有助于解读页面数据(完整说明见 docs/guides/FREE_PROVIDER_RANKINGS.md):

  • 数据源:Arena AI 排行榜 API 的 textcode 两个榜单;text 映射到 default/review/documentation/debugging 类别,code 映射到 coding
  • 置信度:按 Arena 投票数分档——high(≥ 5,000 票)、medium(≥ 1,000)、low(< 1,000)。
  • 新鲜度:条目写入 model_intelligence 表后 7 天过期,停止同步的供应商会自然掉出排名而不是提供陈旧数据。
  • 同步开关:同步引擎默认开启,服务启动时运行一次并周期执行,非阻塞、永不致命(上游拉取失败时排行榜展示最后一次有效数据或空态)。两个环境变量(见 ENVIRONMENT.md):
变量 默认值 用途
ARENA_ELO_SYNC_ENABLED true 设为 false 可关闭出站同步
ARENA_ELO_SYNC_INTERVAL 86400(24h) 同步间隔(秒)
  • 手动运维:管理端点 src/app/api/intelligence/sync/route.ts(需管理鉴权):GET 查看同步状态、POST 触发手动同步(body 可传 {"dryRun": true} 预览)、DELETE 清除全部 arena_elo 条目。排行榜页为空时,手动 POST 或重启服务即可重新填充。

八、连接状态过滤与可靠性三态

configuredOnly / availableOnly 过滤与 reliability 标注复用同一份连接快照(零额外查询)。单条连接按健康矩阵同一词汇分类(classifyConnection):

  • testStatus ∈ {credits_exhausted, banned, expired}down(终态,不会自愈);
  • rateLimitedUntil 仍在未来 → degraded(限流冷却,惰性恢复);
  • 其余 → healthy

供应商级聚合规则为:所有连接 downdown;任一非 healthydegraded;否则 healthy。需要留意的是:availableOnly 会直接丢弃无健康连接的供应商,因此在该过滤下 state 不会出现 down——down 只在单独使用 configuredOnly 时可见。

九、测试覆盖

该功能的纯函数层均有独立单测,可在仓库中直接查看验证:

由于过滤、标注、展示判定都被拆成"完全同步、无副作用"的纯函数(filterFreeProviderRankingsattachProviderReliabilityattachProviderUsageformatUsageReliability),测试无需数据库即可断言全部边界。

十、实战建议:如何组合 ELO 与用量可靠性选供应商

  1. 先看类别,再看双维度:代码任务用 Coding 过滤,通用对话用 Default/All。同一供应商在不同类别排名可能不同(其 Top Model 随榜单变化)。
  2. Reliability 列优先于 ELO 分数做排除:一个 97%+ 绿色成功率 + Elite 分数的供应商是最佳接入目标;ELO 高但成功率 < 80%(橙色)的供应商说明模型质量与实际交付存在落差,应谨慎或等冷却结束后复看。
  3. 破折号不是坏信号,是"未知"信号 表示窗口内无流量或请求少于 5 次,不构成失败证据;可以先小额试用再评估。
  4. 连接多个 Top 供应商,交给 Auto-Combo 决策:同一份 Arena ELO 数据也驱动 Auto-Combo 评分引擎的任务适配因子(open-sse/services/autoCombo/taskFitness.ts,解析顺序 user_override → arena_elo → models_dev_tier → static table)。接入头部免费供应商后,以 model: "auto"(如 auto/coding)发请求即可按请求质量偏好自动路由,完整 15 因子说明见 Auto-Combo 文档
  5. 接入凭证参考NOAUTH 供应商无需凭证最快接入;OAUTH/APIKEY 免费档需要简单注册但常暴露更强的模型,具体步骤见 Free Tiers Guide,完整免费目录见 FREE_TIERS.md

小结

#11546 的核心价值在于把"模型理论上有多强"(ELO)与"实际交付是否可靠"(24 小时调用日志成功率)放到同一张表里,并以严格的样本量门槛(≥ 5 次请求才给出百分比,否则显示破折号)避免小样本误导。整条链路——Zod 参数校验(route.ts)、有界窗口聚合 SQL(callLogStats.ts)、小样本置空(freeProviderRankings.ts)、展示形态判定(freeProviderRankingsUsage.ts)——均可在仓库中按上述路径逐一核对。

登录后查看全文
热门项目推荐
相关项目推荐