pi-model-auto-router

Pi extension that exposes virtual models and routes requests across real provider/model targets with load balancing and failover.

Packages

Package details

extension

Install pi-model-auto-router from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-model-auto-router
Package
pi-model-auto-router
Version
0.3.1
Published
Sep 1, 2026
Downloads
2,174/mo · 76/wk
Author
weisanju
License
unknown
Types
extension
Size
157.6 KB
Dependencies
0 dependencies · 2 peers
Pi manifest JSON
{
  "extensions": [
    "./dist/index.js"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-model-auto-router

Pi 扩展:将虚拟路由模型注册为 model-auto-router provider,把请求按策略分发到真实 provider/model 目标,内置负载均衡、故障切换(failover)、重试退避、冷却机制。

安装

bun add -g pi-model-auto-router   # 或按 Pi 插件方式安装到 ~/.pi/agent

需要 @earendil-works/pi-ai >= 0.84.0@earendil-works/pi-coding-agent >= 0.84.0

配置

配置文件(按优先级查找第一个存在的):

路径 说明
.pi/model-auto-router.routes.json 项目级配置
~/.pi/agent/extensions/model-auto-router.routes.json 全局配置

支持 JSONC(注释 + 尾逗号)。修改后执行 /auto-router reload 生效,或直接使用 TUI /auto-router config 可视化编辑(保存即生效)。

完整字段说明

{
  // ═══ 重试与冷却(可选,缺省用默认值;也可在 TUI 的 "⚙️ 重试与冷却设置" 中配置)═══
  "retry": {
    "maxRetries": 4,              // 所有目标瞬态失败后的整轮重试次数,0 = 禁用重试(默认 3)
    "backoffBaseMs": 2000,        // 退避起始间隔 ms,每轮翻倍(默认 2000)
    "backoffMaxMs": 30000,        // 退避等待上限 ms(默认 30000)
    "transientCooldownMs": 60000, // 瞬态失败(限流/超时/网络)冷却 ms(默认 60000 = 1m)
    "longCooldownMs": 43200000,   // quota/config 类失败冷却 ms(默认 43200000 = 12h)
    "retryEmptyResponses": true    // 结束检测:响应无任何内容时视为失败并 failover/重试(默认 true)
  },

  // ═══ 路由分组 ═══
  "routes": {
    "default": {                   // 路由 id 即模型 id,在 provider model-auto-router 下选择
      "strategy": "least-loaded",  // least-loaded(默认) | round-robin | cache-first
      "targets": [
        {
          "provider": "ducky",    // 对应 ~/.pi/agent/models.json 中的 provider id
          "model": "qwen3.8-max", // 模型 id
          "weight": 2,            // 负载均衡权重(least-loaded 按 active/weight 计分,默认 1)
          "maxConcurrency": 3,    // 该目标最大并发,超过则跳过(可选)
          "api": "openai-completions",        // 覆盖 api(可选)
          "baseUrl": "https://...",           // 覆盖 baseUrl(可选)
          "contextWindow": 200000,            // 覆盖窗口(可选,路由取各目标最小值)
          "maxTokens": 8192,                  // 覆盖 maxTokens(可选)
          "compat": { "supportsDeveloperRole": false } // 追加 compat(可选)
        }
      ]
    }
  },

  // ═══ 隐藏 provider(可选)═══
  // 下列 provider 会被注册为空模型来"隐藏",避免 Pi 直接列出目标 provider。
  // 路由里出现的 provider 会自动隐藏;show 可豁免 hide。
  "hide": ["anthropic"],
  "show": []
}

优先级

  • 重试routes.json retry.* > 环境变量 MODEL_AUTO_ROUTER_MAX_RETRIES > 内置默认
  • API Key<PROVIDER>_AUTH_TOKEN / <PROVIDER>_API_KEY 环境变量 > models.json 中 provider 的 apiKey(支持 ${ENV_VAR} 展开)
  • baseUrl:目标 baseUrl > models.json provider.baseUrl > <PROVIDER>_BASE_URL env > provider id

支持的环境变量

变量 默认 说明
MODEL_AUTO_ROUTER_MAX_RETRIES 3 最大重试轮数(被 routes.json retry.maxRetries 覆盖)
MODEL_AUTO_ROUTER_STALL_TIMEOUT_MS 90000 目标流超过该时长无任何事件判定为挂起,强制终止(90s)
MODEL_AUTO_ROUTER_RETRY_EMPTY on 设为 off 关闭空响应 failover/重试(routes.json retry.retryEmptyResponses 优先)
MODEL_AUTO_ROUTER_STALL_CHECK_MS 5000 挂起检查的间隔(测试可调小)
MODEL_AUTO_ROUTER_LOG 设为 off 关闭日志
MODEL_AUTO_ROUTER_LOG_PATH ~/.pi/agent/model-auto-router.log 日志文件路径

注意:重试完全由 auto-router 统一控制(retry.maxRetries + 退避)。透传给底层 provider 时已剥离 maxRetries/maxRetryDelayMs,避免 pi-ai 的 provider 层(OpenAI/Anthropic SDK 风格,指数退避 0.5s→8s 封顶)在路由重试之上再叠加一层不可见的重试。

TUI 配置

运行 /auto-router config 打开可视化配置:

  • + 添加分组:输入名字 → 选策略 → 添加目标模型(从注册表挑选 provider/model,可设权重)
  • 编辑分组:改名称 / 改策略 / 管理目标(增删、改权重)/ 删除分组
  • ⚙️ 重试与冷却设置:最大重试轮数、退避起始间隔、退避上限、瞬态失败冷却、严重失败冷却、空响应自动重试开关
    • 时长输入支持 5 / 30s / 2m / 1h,留空恢复默认,可一键全部恢复默认

命令

命令 说明
/auto-router status 查看路由、目标负载、冷却、失败统计
/auto-router log [N] 最近 N 条路由/切换/重试事件(默认 20)
/auto-router reset 清空冷却和运行时计数
/auto-router reload 重新加载 routes 与隐藏 provider
/auto-router config 打开 TUI 配置
/auto-router debug 列出注册表可用模型

路由策略

  • least-loaded(默认):按 active/weight + failures*0.05 计分选最低,兼顾当前并发与历史失败
  • round-robin:按累计被选次数轮询
  • cache-first:固定优先第一个可用目标,失败才切换

状态行会实时显示:api-waitstreamingretry pass=x/y / last=served failovers=n

失败分类与重试机制

错误按类型处理:

分类 判定(关键字) 行为
transient 429、rate limit、timeout、502/503/504、overloaded、网络错误等 failover 到下一目标;全部失败后整轮退避重试(2s 起指数翻倍,上限 30s,可配);结束后目标冷却 1m(可配)
quota 402、insufficient balance、credits exhausted 等 failover;目标冷却 12h(可配)
config model not found、404、401/403、invalid key 等 failover;目标冷却 12h
fatal 其他未知错误 立即终止,不再重试

结束检测(空响应)

流式结束(done)时检查响应结构:若 content 为空或所有块都是空文本/空思考(无 toolCall),判定为空响应,视为 transient 失败 → failover 到下一目标,全部失败后进入重试退避(受 retry.maxRetries 控制)。

  • 默认开启,TUI 中可关闭(⚙️ 重试与冷却设置 → 空响应自动重试),或配置 retry.retryEmptyResponses: false / MODEL_AUTO_ROUTER_RETRY_EMPTY=off
  • 只在尚未输出任何内容时生效(此时切换目标对用户无感知、可干净重试);已输出内容后的错误仍按 mid-stream 处理(原样透传,由 Pi 的 agent 重试机制接管)

流式输出中途(已提交内容后)出现瞬态错误时,只能原样透传错误给前端,无法回滚已输出的内容。

目标流长时间无事件(默认 90s,MODEL_AUTO_ROUTER_STALL_TIMEOUT_MS 可调)或用户中止(Esc)时,即使底层流卡死,也会立即清理 streaming 状态、下发错误并结束请求,不会一直停留在 streaming。

开发

bun run build    # tsc 编译到 dist/
bun test         # 运行 e2e 测试(含重试配置覆盖测试)