跳转到内容
OmniRoute source

Troubleshooting (中文 (简体))

第一次使用 OmniRoute? 从这里开始——这些方法能解决 90% 的问题:

我看到的情况 含义 该怎么做
“无法连接” OmniRoute 未运行 运行 omniroute 或 docker restart omniroute
“API 密钥无效” 你的密钥错误或已过期 从提供者网站重新复制密钥
“超出速率限制” 你发送了过多请求 等待 1 分钟,或使用 model: "auto" 自动回退
“超出配额” 你的免费/付费配额已用完 连接更多提供者,或使用免费提供者(Kiro、Pollinations)
“响应缓慢” 提供者繁忙或距离较远 使用 model: "auto/fast",或连接速度更快的提供者(Groq、Cerebras)
“使用了错误的提供者” auto 选择了其他提供者 这是正常现象!auto 会选择最佳提供者。使用 model: "openai/gpt-4o" 强制指定提供者
“502 网关错误” 提供者不可用 等待后重试,或使用 model: "auto" 切换提供者
“401 未授权” 你的凭据有误 检查 API 密钥,或使用 OAuth 重新进行身份验证
“无法识别 omniroute” Windows PATH 中缺少全局 node 模块 将 npm 全局前缀添加到 Windows PATH。使用 npm config get prefix 查找该前缀。
“429 请求过多” 受到速率限制 等待 1 分钟,或连接更多提供者

仍然无法解决? 请参阅下方的详细故障排除,或前往 Discord 提问。



免费提供者的速率限制(429 / 400 / 401)

Section titled “免费提供者的速率限制(429 / 400 / 401)”

症状:通过免费/无需身份验证的提供者(opencode、auggie 等)使用 model: "auto" 时,会间歇性收到 HTTP 429、400 或 401,而不是正常回答。稍后使用相同提示词重试时请求可以成功,但自动化任务(cron 作业、智能体、脚本)会在第一次失败时中断。

根本原因:三个相互独立的故障模式叠加在一起:

  1. 提供者速率限制(429):免费套餐可能会针对每个时间窗口实施配额限制。大量并行调用会耗尽配额,因此在时间窗口重置之前,后续请求都会被拒绝。
  2. 直通模式中的失效模型(400/401):auto/* 池中可能包含来自 opencode 的直通模型,这些模型已在目录中注册,但没有有效凭据(例如 oc/north-mini-code-free → 401)。自动路由器尝试调用其中一个模型并失败,错误会在回退机制启动前向上传播。
  3. 并发放大效应(负载下出现 429):当多个智能体/cron 会话同时调用 auto 时,总请求速率会超过免费提供者的承受能力,导致正常调用被标记为滥用。

已验证的修复方案(社区报告,2026-08-10):调整三个环境变量,使轮换、并发控制和回退机制能够消化免费套餐的不稳定性,而不是因此直接失败:

终端窗口
export OMNIROUTE_ROTATE_ON_400=true # 遇到 400/401 时跳转到其他模型/提供者(跳过失效的直通模型)
export OMNIROUTE_CHAT_MAX_HEAVY_IN_FLIGHT=4 # 明确设置重量级请求准入上限(默认未设置:不限制请求数量,参见下方说明)
export OMNIROUTE_CHAT_ADMISSION_QUEUE_MS=5000 # 在等待重量级请求容量时采用更长但有上限的等待时间,而不是立即返回可重试的 503

在 OmniRoute 进程环境中设置这些变量(即守护进程,例如通过 LaunchAgent plist 或 systemctl edit),然后重新启动 OmniRoute。轮换标志是效果最显著的单项设置:它可以将硬性失败转换为对池中健康提供者的透明重试。

注意:OMNIROUTE_CHAT_MAX_HEAVY_IN_FLIGHT 用于限制同时运行的重量级(即长上下文)请求数量;该限制是准入门控,而不是提供者速率限制器。**#503 扇出更新:**此变量默认不再设置(现在只有像上面那样显式配置时才会生效)——重量级请求准入将改由自动推导的字节预算(OMNIROUTE_CHAT_MAX_INFLIGHT_BYTES)进行控制,该预算会根据主机的实际内存上限自动调整,因此全新部署即使完全不设置此变量,也应该会遇到明显更少的 503 chat_admission_busy 拒绝;在此处显式设置它仍会完全按照文档所述工作。显式字节预算覆盖值会被限制在 8 MiB–2 GiB 之间。413 body_exceeds_budget 并非暂时性错误:请提高该字节预算、降低 OMNIROUTE_CHAT_HARD_MAX_BODY_BYTES,或提高进程内存上限。inflight_bytes_budget 导致的请求卸载属于暂时性资源争用,仍可重试。每个提供者的速率限制(open-sse/services/rateLimitManager.ts)由 RATE_LIMIT_MAX_WAIT_MS、RATE_LIMIT_MAX_QUEUE_DEPTH 和 RATE_LIMIT_AUTO_ENABLE 单独控制——请参阅 .env.example。

如何验证修复是否生效:快速连续运行两次你的代理/cron,并确认两次都成功。修复前,第二次运行通常会抛出 429/401。修复后,失败(如果有)会自动重试,并最终完成调用。你也可以执行 curl /monitoring/health,观察提供者连接中的 rateLimitedUntil 字段,以及受影响提供者对应的 circuitBreakers.providerBreakers[].state——状态可能是 CLOSED、DEGRADED、OPEN 或 HALF_OPEN(参见 src/shared/utils/circuitBreaker.ts);持续失败的提供者会依次从 CLOSED → DEGRADED → OPEN 切换,之后重置窗口会允许一次探测请求通过(HALF_OPEN)。

如果仍然看到 429:该提供者的当前活跃账户确实已耗尽其_配额_(而不仅仅是触发速率限制)。请在 OmniRoute 控制面板中依次进入 Providers → Accounts,为同一提供者添加第二个账户;或者混合使用另一个免费提供者(例如 routeway、auggie)。轮换仅有助于处理暂时性的速率限制/400/401;如果配额已彻底耗尽,则需要第二组凭据或改用其他提供者。

如果在视觉模型(auto/vision、bazaarlink/*)上看到 403:已连接的账户没有包含视觉功能的付费套餐,或者 API 密钥权限不足。请在提供者控制面板中确认该密钥的权限范围包含视觉/多模态功能,或者连接一个付费层级账户,并将其继续用作视觉任务的目标账户。


npm install 警告(ERESOLVE / peer / deprecated)

Section titled “npm install 警告(ERESOLVE / peer / deprecated)”

运行 npm install -g omniroute 时,你可能会看到大量警告,例如 npm warn ERESOLVE、对等依赖通知以及 deprecated 消息。这些是预期行为,不会造成影响。 如果输出中显示 added <N> packages,则表示安装已成功。

要抑制对等依赖解析警告,请使用 OmniRoute 支持的安装方式:

终端窗口
npm install -g omniroute --legacy-peer-deps

--legacy-peer-deps 仅抑制 ERESOLVE 和对等依赖通知。弃用通知仍然可见,因为它们来自传递依赖的第三方软件包;这些通知并不表示安装失败。

这些警告来自 OmniRoute 无法控制的第三方软件包中过时的对等依赖版本范围:

  1. marked-terminal 要求 marked >=1 <16,但检测到 marked@18 — 实际使用没有问题;只是上游的对等依赖版本范围已过时。
  2. deprecated prebuild-install@7.1.3 — 一个传递依赖的原生二进制文件获取辅助工具。它并不 用于安装固定版本的 wreq-js 传输绑定,也不表示 Web Cookie 提供程序的传输设置失败。

无需采取任何操作 — 如果不 fork 上游软件包,就无法完全消除这些警告。


如果 Gemini Web 请求返回 503,并显示 Playwright Chromium 尚未安装,则表示 npm 软件包已存在,但缺少浏览器二进制文件。 Playwright 有意将浏览器下载与 npm 软件包 安装分开,因此在安装浏览器之前出现此响应属于预期行为。

对于全局 npm 安装,请从 OmniRoute 软件包 目录安装 Chromium,以便浏览器缓存归属于同一个 Playwright 安装:

终端窗口
cd "$(npm root -g)/omniroute"
npx playwright install chromium

安装后重启 OmniRoute,然后重试 Gemini Web 请求。如果你 通过 Docker 镜像运行 OmniRoute,请使用 -web 镜像(或 runner-web 构建目标),其中已包含 Chromium 及其依赖项;基础镜像 不包含这些内容。


问题 解决方案
首次登录无法使用 在 .env 中设置 INITIAL_PASSWORD(没有硬编码的默认值)
仪表板在错误的端口上打开 设置 PORT=20128 和 NEXT_PUBLIC_BASE_URL=http://localhost:20128
没有日志写入磁盘 设置 APP_LOG_TO_FILE=true,并确认已启用调用日志捕获
EACCES:权限被拒绝 设置 DATA_DIR=/path/to/writable/dir 以覆盖 ~/.omniroute
路由策略无法保存 更新到最新的 v3.x 版本(用于设置持久化的 Zod 模式修复已在较早版本中发布)
登录崩溃/页面空白 检查 Node.js 版本 — 请参阅下方的 Node.js 兼容性
dlopen / slice is not valid mach-o file(macOS) 运行 cd $(npm root -g)/omniroute/app && npm rebuild better-sqlite3 && omniroute — 请参阅下方的 macOS 原生模块重新构建
代理出现“fetch failed” 确保在正确的层级设置代理配置 — 请参阅下方的 代理问题
Docker curl: (56) Recv failure: Connection reset by peer Docker 端口绑定可能落在 IPv6 上。使用 -p 127.0.0.1:20128:20128 强制使用 IPv4,或使用 curl -4 进行测试。请参阅下方的 Docker IPv6
杀毒软件隔离 README.md 误报 — 请参阅下方的 杀毒软件误报
Kaspersky 将桌面应用标记为木马 对未签名安装程序的行为误报 — 请参阅下方的 杀毒软件误报

Avast/AVG 以 MD:HttpRequest-inf[Susp] 为由隔离 README.md

Section titled “Avast/AVG 以 MD:HttpRequest-inf[Susp] 为由隔离 README.md”

这是误报。没有任何内容受到感染,也无需采取任何操作。

Avast 和 AVG 会运行一种启发式检测,将包含大量疑似 HTTP 请求链接的纯文本/Markdown 文件标记为可疑。OmniRoute 的 README.md 随 npm 包一起分发(它列在 package.json → files 中),因此在全局安装时会出现在 node_modules/omniroute/README.md;而且该文件包含约 15 个 http://localhost:20128/... 示例(MCP HTTP/SSE 端点、A2A .well-known URL 和 curl 代码片段)。如此高的链接密度足以触发该启发式检测。

如果这种情况只是最近才开始出现:文件的性质并没有改变。README 扩充了端点表(新增了 MCP HTTP + SSE + A2A)以及更多 curl 示例,因而超过了检测阈值。

该文件只是静态文档,不包含任何可执行内容。你可以放心地从隔离区恢复它。

处理方法:

  1. 停止通知 — 在杀毒软件中排除安装目录(Avast:设置 → 例外),添加你的全局 node_modules 路径和/或 OmniRoute 数据目录(~/.omniroute/)。
  2. 报告误报 — https://www.avast.com/false-positive-file-form.php,并附上被隔离的 README.md。这才是能帮助所有人的解决方式,因为问题在于厂商的启发式检测对文本文件反应过度。

**为什么我们不在自身这一侧“修复”它:**所有示例都使用 http://localhost,而 localhost 若不引入自签名证书带来的麻烦,就无法使用 https。为了规避某一家厂商的启发式检测而篡改文档,会损害所有读者的使用体验,仅仅为了迁就一个扫描器缺陷。

Kaspersky 将桌面应用标记为 PDM:Trojan.Win32.Generic

Section titled “Kaspersky 将桌面应用标记为 PDM:Trojan.Win32.Generic”

这是行为启发式检测造成的误报。没有任何内容受到感染。 Kaspersky 的 PDM: 前缀表示该判定来自其主动防御模块(系统监控),它会判断安装程序执行的_行为_,而不是将其与已知恶意软件进行匹配。触发检测时,Kaspersky 会“回滚”整个安装过程——删除它已经写入的文件——因此应用最终会损坏或消失。

它所标记的文件是桌面应用中已声明的开源依赖项的标准组成部分,例如:

  • resources/app/.build/next/node_modules/playwright-&lt;hash&gt;/lib/…/agentParser.js 和 workerProcessEntry.js — Playwright,用于应用内提供者登录和浏览器支持聊天的浏览器自动化库。
  • resources/app/.build/next/node_modules/@wreq-js/binding-win32-&lt;arch&gt;-msvc-&lt;hash&gt;/wreq-js.win32-&lt;arch&gt;-msvc.node — 固定版本的 wreq-js 原生绑定,用于在依赖 Web Cookie 的提供者上实现具有浏览器指纹特征的 HTTP(&lt;arch&gt; 为 x64 或 arm64)。

触发原因:Windows 安装程序尚未进行代码签名,因此未签名的 NSIS 安装程序没有任何信誉记录,行为启发式检测会以最高强度运行。再加上安装包中包含原生 DLL,并会在 %LOCALAPPDATA%\Programs\OmniRoute 下写入数百个 .js 文件(包括 Next.js 独立构建生成的带哈希后缀的包目录),这些因素足以触发该启发式检测。代码签名已列入计划;在实施之前,新版本仍可能重复出现此问题。

处理方法:

  1. 首先验证下载文件(以排除文件被篡改的可能)。每个版本都会发布 latest.yml,其中的 sha512 字段(base64)涵盖 OmniRoute.Setup.&lt;version&gt;.exe 安装程序。在 PowerShell 中,从包含安装程序的文件夹运行:
    终端窗口
    $b = [System.Security.Cryptography.SHA512]::Create().ComputeHash(
    [System.IO.File]::ReadAllBytes("$PWD\OmniRoute.Setup.&lt;version&gt;.exe"))
    [Convert]::ToBase64String($b)
    输出必须与 latest.yml → sha512 匹配。如果不匹配,请删除该文件,并仅从 GitHub 发布页面重新下载。
  2. 恢复并排除 — 从隔离区恢复被回滚的项目,并为 %LOCALAPPDATA%\Programs\OmniRoute 添加排除项(Kaspersky → 设置 → 威胁和排除项),然后重新安装。
  3. 报告误报 — https://opentip.kaspersky.com/。用户提交的误报报告确实有助于加快加入允许列表的速度。

登录页面崩溃或显示“Module self-registration”错误

Section titled “登录页面崩溃或显示“Module self-registration”错误”

原因: 您正在运行的 Node.js 版本不符合 OmniRoute 批准的最低安全运行时要求。最常见的情况是,所运行的 Node 22 或 24 补丁版本低于 OmniRoute 要求的已修复安全版本下限。

症状:

  • 登录页面显示空白屏幕或服务器错误
  • 控制台显示 Error: Module did not self-register 或类似的原生绑定错误
  • 如果运行时不符合受支持的安全策略,登录页面会显示一个包含您的 Node 版本的橙色警告横幅

修复方法:

  1. 安装受支持的 Node.js LTS 版本(推荐:Node.js 24.x):
    终端窗口
    nvm install 24
    nvm use 24
  2. 验证您的版本:node --version 应显示 24.x LTS 系列中的 v24.0.0 或更高版本
  3. 重新安装 OmniRoute:npm install -g omniroute
  4. 重新启动:omniroute

受支持的安全版本: >=22.22.2 <23 或 >=24.0.0 <27。完全支持 Node.js 24.x LTS (Krypton) 和 Node.js 26。

npm v11+:未安装 better-sqlite3(Cannot find module)

Section titled “npm v11+:未安装 better-sqlite3(Cannot find module)”

原因: npm v11(随 Node.js 24+ 提供)默认会阻止可选依赖项的安装脚本。由于 better-sqlite3 列在 optionalDependencies 中,并且需要进行原生编译(node-gyp rebuild),因此 npm 会静默跳过它。

症状:

  • 服务器启动时崩溃并显示 Cannot find module 'better-sqlite3'
  • ls node_modules/better-sqlite3 显示“No such file or directory”
  • npm ls better-sqlite3 显示 (empty)

修复方法:

  1. 批准安装脚本并重新安装:
    终端窗口
    npm approve-scripts better-sqlite3
    npm install
  2. 或手动安装预构建版本:
    终端窗口
    npm pack better-sqlite3@13.0.1
    tar -xzf better-sqlite3-*.tgz -C node_modules
    mv node_modules/package node_modules/better-sqlite3
    rm better-sqlite3-*.tgz
  3. 验证其是否正常工作:node -e "require('better-sqlite3')(':memory:').close(); console.log('OK')"

macOS:dlopen / “slice is not valid mach-o file”

Section titled “macOS:dlopen / “slice is not valid mach-o file””

原因: 全局执行 npm install -g omniroute 后,软件包内的 better-sqlite3 原生二进制文件可能是针对与本地运行环境不同的架构或 Node.js ABI 编译的。当预构建二进制文件与您的环境不匹配时,这种情况在 macOS(包括 Apple Silicon 和 Intel)上很常见。

症状:

  • 服务器启动时立即失败,并显示 dlopen 错误
  • 错误中包含 slice is not valid mach-o file
  • 完整示例:
dlopen(/Users/&lt;user&gt;/.nvm/versions/node/v24.14.1/lib/node_modules/omniroute/app/node_modules/better-sqlite3/build/Release/better_sqlite3.node, 0x0001): tried: '...' (slice is not valid mach-o file)

修复方法——针对您的本地环境重新构建(无需降级 Node.js):

终端窗口
cd $(npm root -g)/omniroute/app
npm rebuild better-sqlite3
omniroute

注意: 这会针对您的本地 Node.js 版本和 CPU 架构重新编译原生绑定,从而解决二进制文件不匹配问题。官方支持的运行时范围为 >=22.22.2 <23 或 >=24.0.0 <27(位于 src/shared/utils/nodeRuntimeSupport.ts 中的 SUPPORTED_NODE_RANGE,与 package.json 的 engines 字段保持一致)。完全支持将 Node.js 24.x LTS (Krypton) 和 Node.js 26 与 better-sqlite3 v12.x 搭配使用。


原因: API 密钥验证端点 (POST /api/providers/validate) 之前会绕过代理配置,导致在需要通过代理路由的环境中验证失败。

修复 (v3.5.5+): 此问题现已修复。提供者验证现在通过 runWithProxyContext 路由,并自动遵循提供者级别和全局代理设置。

令牌健康检查因 “fetch failed” 而失败

Section titled “令牌健康检查因 “fetch failed” 而失败”

原因: 后台 OAuth 令牌刷新未按连接解析代理配置。

修复 (v3.5.5+): 令牌健康检查调度器现在会在尝试刷新前按连接解析代理配置。请更新到 v3.5.5+。

SOCKS5 代理返回 “invalid onRequestStart method”

Section titled “SOCKS5 代理返回 “invalid onRequestStart method””

原因: 在 Node.js 22 上,undici@8 调度器与 Node 内置的 fetch() 实现不兼容。

修复 (v3.5.5+): 现在,当代理调度器处于活动状态时,OmniRoute 会使用 undici 自身的 fetch() 函数,以确保行为一致。请更新到 v3.5.5+。

WSL 下的 MITM 代理:Windows 主机上的桌面应用未被拦截

Section titled “WSL 下的 MITM 代理:Windows 主机上的桌面应用未被拦截”

原因: MITM 代理及其 CA 证书会安装到 OmniRoute 运行所在的环境中。在 WSL 下,该环境是 Linux 客户机,而 AI 桌面应用(Kiro、Trae、Copilot、Zed 等)运行在 Windows 主机上。主机应用不信任客户机的证书存储,也不会通过客户机的系统代理进行路由,因此无法对桌面应用启用拦截。

建议: 在与要拦截的桌面应用相同的操作系统上原生运行 OmniRoute(Windows 应用在 Windows 上运行;macOS/Linux 同理)。如果将 OmniRoute 保留在 WSL 内,同时以主机应用为目标,则需要在 Windows 主机上手动信任生成的 CA 证书,并将每个主机应用的网络/代理设置指向 WSL 代理端点——这种配置不受支持且非常脆弱。


“Language model did not provide messages”

Section titled ““Language model did not provide messages””

原因: 提供者配额已用尽。

修复:

  1. 检查仪表板中的配额跟踪器
  2. 使用带有回退层级的组合
  3. 切换到更便宜的层级或免费层级

原因: 订阅配额已用尽。

修复:

  • 添加回退:cc/claude-opus-4-6 → glm/glm-4.7 → if/qwen3.8-max-preview
  • 使用 GLM/MiniMax 作为低成本备用方案

OmniRoute 会自动刷新令牌。如果问题仍然存在:

  1. 仪表板 → 提供者 → 重新连接
  2. 删除并重新添加提供者连接

Kiro 多账户:第二个账户会使第一个账户失效

Section titled “Kiro 多账户:第二个账户会使第一个账户失效”

原因: Kiro 的后端强制要求每个 OIDC 客户端注册只能有一个活动会话。 当两个账户共享同一个已注册的客户端(即在 v3.8.0 之前导入的连接)时, 刷新其中一个账户的令牌会使另一个账户的刷新令牌失效。

修复 (v3.8.0+): 重新导入受影响的连接。 从 v3.8.0 开始,通过导入令牌、 Google/GitHub 社交登录或自动导入创建的每个新 Kiro 连接都会自动注册其自己 专用的 OIDC 客户端。因此,该连接将完全隔离,刷新一个 账户不会对任何其他账户产生影响。

在 v3.8.0 之前 导入的连接没有按连接分配的客户端 注册。这些连接会继续使用共享的社交身份验证刷新端点。 要实现隔离,请从仪表板 → 提供者中删除旧连接,然后通过 上述三种导入流程中的任意一种重新添加。

有关完整详情以及并行添加两个 Kiro 账户的分步说明, 请参阅 docs/guides/KIRO_SETUP.md。


  1. 确认 BASE_URL 指向正在运行的实例(例如 http://localhost:20128)
  2. 确认 CLOUD_URL 指向云端端点(例如 https://omniroute.dev)
  3. 保持 NEXT_PUBLIC_* 的值与服务端的值一致

症状: 在云端端点进行非流式调用时出现 Unexpected token 'd'...。

原因: 上游返回 SSE 负载,而客户端期望接收 JSON。

解决方法: 云端直连调用请使用 stream=true。本地运行时包含 SSE→JSON 回退机制。

云端显示已连接,但提示“Invalid API key”

Section titled “云端显示已连接,但提示“Invalid API key””
  1. 从本地仪表板创建新密钥(/api/keys)
  2. 执行云同步:启用云端 → 立即同步
  3. 旧密钥或未同步的密钥在云端仍可能返回 401

症状: curl http://localhost:20128/v1/models 返回 curl: (56) Recv failure: Connection reset by peer。仪表板和未认证的端点可以正常工作,但已认证的端点会失败——这看起来像认证问题,但实际上并非如此。

原因: docker run -p 20128:20128 会同时发布到 0.0.0.0(IPv4)和 ::(IPv6),但容器内的进程仅监听 IPv4。在 localhost 优先解析为 ::1 的主机上,连接会到达已发布的 IPv6 端口,但其后端没有监听器 → 连接被重置。

修复方法:

  1. 快速诊断: 运行 curl -4 http://localhost:20128/v1/models。如果添加 -4 后可以正常工作,而不添加时失败,则存在 IPv6 绑定不匹配问题。
  2. 永久修复: 在 docker run 命令中使用 -p 127.0.0.1:20128:20128,显式绑定到 IPv4:
    终端窗口
    docker run -d --name omniroute --restart unless-stopped --stop-timeout 40 \
    -p 127.0.0.1:20128:20128 -v omniroute-data:/app/data diegosouzapw/omniroute:latest
    这会强制绑定到 IPv4,同时避免将代理暴露在主机的所有网络接口上。

  1. 检查运行时字段:curl http://localhost:20128/api/cli-tools/runtime/codex | jq
  2. 对于便携模式:使用镜像目标 runner-cli(内置 CLI)
  3. 对于主机挂载模式:设置 CLI_EXTRA_PATHS,并以只读方式挂载主机的二进制文件目录
  4. 如果 installed=true 且 runnable=false:已找到二进制文件,但健康检查失败
终端窗口
curl -s http://localhost:20128/api/cli-tools/codex-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
curl -s http://localhost:20128/api/cli-tools/claude-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'
curl -s http://localhost:20128/api/cli-tools/openclaw-settings | jq '{installed,runnable,commandPath,runtimeMode,reason}'

  1. 在仪表板 → 用量中查看使用统计信息
  2. 将主模型切换为 GLM/MiniMax
  3. 对非关键任务使用免费套餐(Qoder、Kiro)
  4. 为每个 API 密钥设置成本预算:仪表板 → API 密钥 → 预算

在 .env 文件中设置 APP_LOG_TO_FILE=true。应用程序日志会写入 logs/。 在设置中启用调用日志管道后,请求产物会存储在 ${DATA_DIR}/call_logs/ 下。 启用管道捕获后,可设置 CALL_LOG_PIPELINE_CAPTURE_STREAM_CHUNKS=false 以省略 流数据块负载,或调整 CALL_LOG_PIPELINE_MAX_SIZE_KB 以更改以 KB 为单位的产物大小上限。

终端窗口
# 健康状态仪表板
http://localhost:20128/dashboard/health
# API 健康检查
curl http://localhost:20128/api/monitoring/health
  • 主要状态:${DATA_DIR}/storage.sqlite(提供者、组合、别名、密钥、设置)
  • 用量:storage.sqlite 中的 SQLite 表(usage_history、call_logs、proxy_logs)+ 可选的 ${DATA_DIR}/call_logs/
  • 应用程序日志:&lt;repo&gt;/logs/...(当 APP_LOG_TO_FILE=true 时)
  • 调用日志产物:启用调用日志管道后,存储于 ${DATA_DIR}/call_logs/YYYY-MM-DD/...

请求日志页面中的清理历史记录操作会清除 call_logs、旧版 request_detail_logs,以及本地 ${DATA_DIR}/call_logs/ 产物目录。


当提供者的熔断器处于 OPEN 状态时,请求将被阻止,直到冷却时间结束。

解决方法:

  1. 前往 控制面板 → 设置 → 弹性
  2. 查看受影响提供者的熔断器卡片
  3. 点击 全部重置 以清除所有熔断器,或等待冷却时间结束
  4. 重置前,请确认提供者确实可用

如果提供者反复进入 OPEN 状态:

  1. 在 控制面板 → 健康状态 → 提供者健康状态 中检查故障模式
  2. 前往 设置 → 弹性 → 提供者配置文件,并提高故障阈值
  3. 检查提供者是否更改了 API 限制,或者是否需要重新进行身份验证
  4. 检查延迟遥测数据——高延迟可能会导致基于超时的故障

  • 使用第一段为您已配置凭据的提供者的模型 ID(openai/whisper-1、openrouter/deepgram/nova-3)。直接使用 deepgram/nova-3 需要原生 Deepgram 密钥。
  • 确认提供者已在 控制面板 → 提供者 中连接
  • 检查支持的音频格式:mp3、wav、m4a、flac、ogg、webm
  • 确认文件大小未超过提供者限制(通常 < 25MB)
  • 在提供者卡片中检查提供者 API 密钥是否有效

使用 控制面板 → 翻译器 调试格式转换问题:

模式 使用场景
演练场 并排比较输入/输出格式——粘贴失败的请求以查看其转换结果
聊天测试器 发送实时消息,并检查包含标头在内的完整请求/响应载荷
测试台 对多种格式组合运行批量测试,以找出发生故障的转换
实时监控器 观察实时请求流,以捕获间歇性转换问题
  • 未显示思考标签——检查目标提供者是否支持思考功能以及思考预算设置
  • 工具调用丢失——某些格式转换可能会去除不支持的字段;请在演练场模式下进行验证
  • 缺少系统提示词——Claude 和 Gemini 处理系统提示词的方式不同;请检查转换输出
  • SDK 返回原始字符串而非对象——已在 v1.x 中解决;响应清理器会去除导致 OpenAI SDK Pydantic 验证失败的非标准字段(x_groq、usage_breakdown 等)。如果您在 v3.x+ 中仍遇到此问题,请提交 issue。
  • GLM/ERNIE 拒绝 system 角色——已在 v1.x 中解决;角色规范化器会自动将系统消息合并到用户消息中,以适配不兼容的模型。如果您在 v3.x+ 中仍遇到此问题,请提交 issue。
  • 无法识别 developer 角色——已在 v1.x 中解决;对于非 OpenAI 提供者,会自动将其转换为 system。如果您在 v3.x+ 中仍遇到此问题,请提交 issue。
  • json_schema 无法与 Gemini 配合使用——已在 v1.x 中解决;现在会将 response_format 转换为 Gemini 的 responseMimeType + responseSchema。如果您在 v3.x+ 中仍遇到此问题,请提交 issue。

  • 自动速率限制仅适用于 API 密钥提供者(不适用于 OAuth/订阅)
  • 验证 设置 → 弹性 → 提供者配置文件 是否已启用自动速率限制
  • 检查提供者是否返回 429 状态码或 Retry-After 标头

提供者配置文件支持以下设置:

  • 基础延迟 — 首次失败后的初始等待时间(默认值:1s)
  • 最大延迟 — 最长等待时间上限(默认值:30s)
  • 乘数 — 每次连续失败后延迟增加的倍数(默认值:2x)

当大量并发请求访问受到速率限制的提供者时,OmniRoute 会使用互斥锁 + 自动速率限制来串行化请求并防止级联故障。对于 API 密钥提供者,此机制会自动启用。

聊天请求失败并返回 503 / chat_admission_busy

Section titled “聊天请求失败并返回 503 / chat_admission_busy”

症状:

  • 聊天补全端点返回可重试的 503 响应,其错误代码为 chat_admission_busy。
  • 响应包含 Retry-After。自 #12135 起,该值根据观测到的 占用情况计算得出——取请求已经等待的 OMNIROUTE_CHAT_ADMISSION_QUEUE_MS 窗口 与当前重量级租约已持有时间中的较大值——向上舍入到整秒, 并以 60 秒为上限。在空闲准入门控上,它会保留历史下限:基于字节的路径为 2 秒, 基于结构的路径为 1 秒(后者还会包含 reason: "structure_limit")。
  • 当另一个重量级聊天请求或长时间运行的流式响应仍在 处理中时,可能会发生这种情况。

基于字节的响应正文为:

{
"error": {
"message": "Chat admission capacity is temporarily unavailable. Retry shortly.",
"type": "server_error",
"code": "chat_admission_busy"
}
}

基于结构的响应使用相同的类型和代码,其消息为 Local chat admission capacity is busy for this structurally heavy request; upstream provider routing was not attempted. Retry shortly. 并包含 reason: "structure_limit"。 在默认阈值下,如果请求包含至少 200 条消息、 至少 64 个工具或至少 32,000 个估算令牌,或者有界结构估算 耗尽了 10,000 个已访问节点或深度 12 的限制,则该请求会被视为结构重量级请求。

原因: 这是 OmniRoute 内部有意执行的负载卸除,而不是上游提供者故障。 每个进程都会使用进程本地守卫,在保留并解析大型请求正文之前预留有限的 重量级容量。重量级租约会在 SSE 响应的整个生命周期内保持占用。

#503 扇出: 在此修复之前,无论主机内存如何,守卫都会将并发限制为固定的请求数量 (OMNIROUTE_CHAT_MAX_HEAVY_IN_FLIGHT,默认值为 1),因此编码代理的 扇出(多个子代理/CLI,请求正文通常 > 256 KB)会使有效并发量骤降至约 1, 并在完全正常的负载下返回 503。现在,守卫会进行自我调优:它由自动推导的 摄取字节预算(OMNIROUTE_CHAT_MAX_INFLIGHT_BYTES)控制,该预算根据进程的 实际内存上限确定;同时还会参考实时资源压力信号——因此,它只会在主机确实 面临内存压力时卸除负载,而不会仅仅因为同时到达多个重量级请求就这样做。 旧的计数上限(OMNIROUTE_CHAT_MAX_HEAVY_IN_FLIGHT)仍然有效,但仅在你显式设置它时生效。

当容量繁忙时,重量级请求会先等待最多 OMNIROUTE_CHAT_ADMISSION_QUEUE_MS(默认值为 2000,设置为 0 将禁用等待),以便等待空位释放, 然后才返回可重试的 503。这种有界等待机制可让扇出并发重量级子请求的代理类客户端 (OpenCode、Claude Code、Cursor)将突发请求串行化, 而不是因立即遭到拒绝而耗尽全部重试预算并在任务中途终止。 当前重量级租约占用情况、解析后的字节预算和实时压力严重程度可在 GET /api/monitoring/health → chatAdmission(inflightBytes、maxInflightBytes、 budgetSource、pressureSeverity、countCapEnabled)中查看——在修改任何环境变量之前,请先检查这些值。 设置 → 弹性 → 请求队列 → 并发请求并不控制此机制;该设置 控制的是另一个独立的提供者请求队列机制。

修复方法:

  1. 首先重试。客户端应遵循 Retry-After 并使用退避,而不是立即 重复请求。
  2. 在调整任何设置之前,请检查 /api/monitoring/health → chatAdmission。countCapEnabled: false 且 maxInflightBytes 足够大,意味着自动推导的预算已经在正常 工作;如果 pressureSeverity 为 high/critical,则表示主机确实内存不足—— 这种情况无法通过准入环境变量修复,需要增加 RAM 或减少工作负载。
  3. 仅当 /api/monitoring/health 显示自动推导的预算对于你的 主机确实过小(这种情况很少见——它已经可以从容器扩展到裸机)时,才应直接使用 OMNIROUTE_CHAT_MAX_INFLIGHT_BYTES 覆盖该预算,而不是退回使用旧版请求数量上限。

有关权威的准入设置,请参阅环境变量参考。


可选的 RAG / LLM 故障分类(16 个问题)

Section titled “可选的 RAG / LLM 故障分类(16 个问题)”

一些 OmniRoute 用户会将网关部署在 RAG 或智能体技术栈之前。在这类配置中,经常会出现一种奇怪的情况:OmniRoute 看起来运行正常(提供者在线、路由配置正常、没有速率限制警报),但最终答案仍然是错误的。

实际上,这类事件通常源于下游 RAG 流水线,而不是网关本身。

如果你希望使用一套共同术语来描述这些故障,可以采用 WFGY ProblemMap。这是一个采用 MIT 许可证的外部文本资源,定义了十六种反复出现的 RAG / LLM 故障模式。总体而言,它涵盖:

  • 检索漂移和上下文边界破坏
  • 空索引或过期索引以及向量存储问题
  • 嵌入与语义不匹配
  • 提示词组装和上下文窗口问题
  • 逻辑崩溃和过度自信的回答
  • 长链路和智能体协调故障
  • 多智能体记忆和角色漂移
  • 部署和引导启动顺序问题

使用方法很简单:

  1. 调查错误响应时,记录:
    • 用户任务和请求
    • OmniRoute 中的路由或提供者组合
    • 下游使用的所有 RAG 上下文(检索到的文档、工具调用等)
  2. 将事件映射到一个或两个 WFGY ProblemMap 编号(No.1 … No.16)。
  3. 在你自己的仪表板、运行手册或事件跟踪器中,将该编号记录在 OmniRoute 日志旁边。
  4. 使用对应的 WFGY 页面来判断是否需要更改 RAG 技术栈、检索器或路由策略。

完整文本和具体方案请参阅此处(MIT 许可证,纯文本):

WFGY ProblemMap README

如果你没有在 OmniRoute 后运行 RAG 或智能体流水线,可以忽略本节。


以下是 v3.8.0 版本特有的问题及其当前解决方法。如果后续补丁中包含修复,此条目将被更新或删除。

症状:

  • 调用由 Devin 支持的工具时出现“Devin CLI not found”或“auth failed”
  • CLI 运行时检查报告 installed=false

原因:

  • CLI_DEVIN_BIN 指向不存在的路径
  • 主机上未安装 Devin CLI

解决方法:

  1. 安装适用于你平台的 Devin CLI
  2. 在 .env 中设置 CLI_DEVIN_BIN=/usr/local/bin/devin(或实际路径)
  3. 重启 OmniRoute,然后从仪表板 → CLI 工具重新测试

模型冷却状态卡住(手动重置)

Section titled “模型冷却状态卡住(手动重置)”

症状:

  • 即使过期时间已过,模型仍显示为处于冷却状态
  • 尽管时间戳已是过去时间,组合路由中的请求仍会跳过该模型

手动重置:

  • 仪表板:设置 → 模型冷却 → 在受影响的卡片上点击重新启用
  • **API:**使用管理身份验证请求头调用 DELETE /api/resilience/model-cooldowns

Command Code 提供者连接失败并返回 403

Section titled “Command Code 提供者连接失败并返回 403”

症状:

  • 测试 Command Code 提供者连接时返回 403
  • 刚添加后,提供者卡片显示“unauthorized”

**原因:**OAuth 流程未完成(未收到回调或令牌未持久保存)。

解决方法:

  • 从 CLI 运行 omniroute providers 以重新触发 OAuth 流程,或者
  • 从仪表板 → 提供者 → Command Code → 重新连接重新运行 OAuth

ModelScope 返回过于激进的 429 冷却

Section titled “ModelScope 返回过于激进的 429 冷却”

症状:

  • 在少量突发请求后,ModelScope 出现非常短或立即触发的冷却
  • 组合路由比预期更早跳过 ModelScope

**原因:**ModelScope 会发出提供者特有的 Retry-After 请求头。v3.8.0 对这些请求头提供了专门处理,因此旧版本会将其错误地解读为通用的速率限制提示。

解决方法:

  • 确保你使用的是 v3.8.0 或更高版本
  • 验证设置 → 弹性机制下的 useUpstream429BreakerHints 开关已启用

生产环境中缺少 OMNIROUTE_WS_BRIDGE_SECRET

Section titled “生产环境中缺少 OMNIROUTE_WS_BRIDGE_SECRET”

症状:

  • 在远程生产主机上运行时,每个 Codex/Responses WebSocket 桥接请求都返回 401
  • WebSocket 桥接握手在连接后立即关闭

**原因:**生产环境中缺少 OMNIROUTE_WS_BRIDGE_SECRET 环境变量。

解决方法:

  1. 生成一个随机密钥:openssl rand -hex 32
  2. 在生产服务器环境中设置 OMNIROUTE_WS_BRIDGE_SECRET=&lt;random-secret&gt;(以及在与该桥接通信的所有客户端中设置)
  3. 重启 OmniRoute

Responses API:后台模式降级为同步模式

Section titled “Responses API:后台模式降级为同步模式”

症状:

  • 日志中记录警告:background mode degraded to synchronous
  • background: true 请求返回普通同步响应,而不是后台作业句柄

**原因:**在 v3.8.0 中,Responses API 上的 background: true 会被有意降级为同步执行,同时发出警告。完整的异步后台执行功能将在未来交付。

解决方法:

  • 调整客户端,使其调用时不使用 background,或者
  • 等待提供完整异步后台模式的后续版本(请关注变更日志)

如果 CLI 输出 ⚠ Server did not respond within 60s,但服务器实际上正常运行,则说明就绪探测的超时预算对于你的环境而言过短。

这种情况常见于 Windows(受杀毒软件、文件系统监视器影响)或启动工作负载较重的容器。

解决方法 — 增加超时预算:

终端窗口
# 通过环境变量设置(在多次启动之间保持有效):
export OMNIROUTE_READY_TIMEOUT_MS=180000 # 3 分钟
omniroute serve
# 通过 CLI 标志设置(仅本次有效):
omniroute serve --ready-timeout 180000

默认值为 60 000 ms(60 s)。该警告仅供参考;服务器会继续在后台启动,并在启动完成后可供访问。

有关 OMNIROUTE_READY_TIMEOUT_MS 的完整详情,请参阅 docs/reference/ENVIRONMENT.md。



OmniRoute 源码 (a58000c7685f)

HagiCode

HagiCode 是一套智能体编码工作台:结构化工作流、多 Agent 并行执行与 Hero Dungeon 视图,把想法变成真正交付的软件。

让想法更快变成好用的软件,让智能编码更聪明、更高效,也更有趣。

HagiCode 浅色主题主界面截图
  • Smart结构化工作流将意图转化为从想法到交付的可执行路径。
  • Efficient多 Agent 工作流让调研、实现与审阅并行推进。
  • FunHero Dungeon 让长时间编码协作更直观、更有参与感。
访问 HagiCode