Roo Code 接入第三方 API 时,大多数报错不是模型能力问题,而是 Provider 选择、Base URL、Key、限流或网络问题:刚配好就 401、换了地址变 404、长任务跑一半 429、流式卡住直到超时。处理顺序是先看状态码和错误类型,再看 request-id,最后才改提示词。本文按 401、404、429、上下文超限和超时拆开,给出排查步骤、日志清单和示例代码。模型与计费以模型价格为准。
一、先分层:错误发生在哪一层
请求要经过 Roo Code 客户端、VS Code 扩展宿主、网络与代理、网关、上游模型。同一个 401 可能是 Key 错,也可能是 Provider 协议不匹配;同一个 404 可能是路径多了 /v1,也可能是模型 ID 不存在。先分层,避免在错误方向反复改配置。
| 状态码 | 错误类型 | 常见原因 | 怎么处理 |
|---|---|---|---|
| 400 | invalid_request_error | 参数、上下文长度或支出限额 | 改请求或调限额后重试 |
| 401 | authentication_error | Key 缺失、错误、过期、鉴权头不匹配 | 修凭证,不重试 |
| 402 | billing_error | 账单或余额有问题 | 查账单 |
| 403 | permission_error | Key 无模型或项目权限 | 查授权 |
| 404 | not_found_error | 路径或模型 ID 错误 | 查 Base URL 和模型名 |
| 413 | request_too_large | 请求体超过接口限制 | 压缩或拆分请求 |
| 429 | rate_limit_error | 频率、并发或支出上限 | 退避后重试 |
| 500 | api_error | 服务端内部错误 | 退避重试 |
| 504 | timeout_error | 处理超时 | 改流式或分批 |
响应头或错误响应体里的 request-id 要保留。日志至少记录时间、状态码、错误类型、模型 ID 和请求 ID,不要记录完整 Key 和敏感代码。
二、401:Provider、Key 和鉴权头
Roo Code 的 Provider 下拉和 Key 输入框是分开的,最常见的 401 不是 Key 无效,而是组合错了:把 OpenAI 兼容的 Key 填进 Anthropic Provider,或反过来;Base URL 指向 A 环境、Key 属于 B 环境;切换 API 配置档案后还留着旧 Key。
其他常见原因:Key 前后有空格、换行、引号或全角字符;Key 已删除、过期或属于另一个工作区;企业代理改写或剥离 Authorization 头;同一扩展里同时配置了订阅登录和 API Key。
排查顺序:
- 确认 Provider 类型与 Base URL 协议一致:OpenAI 兼容走
/v1/chat/completions,Anthropic 走/v1/messages。 - 用同一 Key 和 Base URL 在终端直连一次最小请求。
- 直连成功而 Roo Code 失败,问题在 Provider 配置、档案或代理;直连也失败,问题在 Key、网关或网络。
- 换一把新 Key 交叉验证,排除复制粘贴问题。
401 不要重试,重试只会放大日志和告警。
三、404:Base URL 路径与模型 ID
404 分两类:路径不存在,或模型不存在。
路径问题:OpenAI 兼容 Provider 的 Base URL 通常填到 /v1 为止,由客户端拼接 /chat/completions。如果填了完整的 /v1/chat/completions,实际路径可能变成重复拼接。末尾斜杠、双斜杠、大小写和多余空格也会造成 404。Anthropic Provider 拼接的是 /v1/messages,把 OpenAI 兼容地址填进去同样会 404。
模型问题:错误消息出现 model not found、invalid model 或 The model does not exist 时,先到网关的模型列表或价格页复制精确 ID。模型别名、日期后缀、大小写都可能不同;有的网关要求带 Provider 前缀。还要确认这把 Key 是否有该模型的权限,权限不足有时返回 403,有时返回 404。
快速确认:调用 /v1/models 看当前 Key 可见的模型列表,再用列表里的 ID 发一条最小请求。
四、429:限流、额度与重试风暴
429 表示请求超过了速率、并发或支出限制。常见原因:
- 每分钟请求数或 Token 数超限;
- 多个工具、多个同事共用一把 Key;
- Roo Code 的 Orchestrator 子任务或并行工具调用抬高瞬时并发;
- 重试没有退避,形成重试风暴;
- 账户余额或工作区支出上限触发限制。
先看响应头 retry-after:有就按它等待;没有就用指数退避加随机抖动,并设置最大次数。部分额度限制触发的 429 不带 retry-after,等待不会自动恢复,需要充值或调整限额。
注意两层重试叠加:Roo Code 自身可能自动重试,SDK 或网关也可能重试,业务层再包一层,实际请求数会成倍增加。把客户端、SDK 和业务重试统一规划。401、403、404、400 不要重试。
五、400 与 413:上下文长度和请求体
上下文超限通常返回 400,错误消息会出现 context length、maximum context、prompt is too long 等字样。原因不是模型坏了,而是输入加输出的预算超过了窗口。
Roo Code 里要特别注意上下文窗口设置:如果手动填的窗口大于模型实际支持值,客户端会按错误预算裁剪或直接发送超长请求,结果就是 400。把窗口改成模型文档标注的值,并开启上下文压缩或 condensing(如果当前版本支持)。
处理顺序:
- 减少一次性读入的文件数量,只给相关片段。
- 压缩终端输出和 MCP 工具返回,只保留必要字段。
- 长文档按章节拆分,分段处理后再汇总。
- 清理早期对话,保留 system、最近几轮和摘要。
- 给输出留空间,
max_tokens只限制输出,不能解决输入超限。
413 request_too_large 是请求体过大,和上下文长度不是一回事。截图、PDF、base64 图片最容易触发;压缩图片、减少附件或拆分请求。
六、超时与断流:流式、代理和长任务
Roo Code 默认使用流式输出。流式请求可能先返回 HTTP 200,再在 SSE 事件流里发一个错误事件;客户端只看状态码,会把失败当成成功。要解析流中的错误事件,确认收到正常结束标记,否则把结果标记为不完整。
超时的常见来源:
- 公司代理、VPN 或 TLS 拦截导致连接不稳定;
- DNS、IPv6、防火墙或 MTU 问题;
- 单次请求过长,空闲连接被断开;
- Agent 长任务持续跑工具,累计时间超过客户端或网关限制;
- 上游模型排队,首字节很慢。
处理上优先用流式;给单次请求设置合理超时;把长任务拆成阶段;减少自动批准的工具范围;换网络或手机热点快速判断是不是本地网络问题。企业 TLS 拦截需要让 VS Code 和系统信任对应 CA,Node 系客户端有时还要配置 NODE_EXTRA_CA_CERTS。
七、日志与支持:怎么把问题说清楚
不要只发一句「报错了」。按下面清单收集信息:
- 发生时间、时区、持续时长。
- Roo Code 版本、VS Code 版本和操作系统。
- Provider 类型、Base URL(只保留域名)、模型 ID。
- 是否流式、请求耗时和重试次数。
- HTTP 状态码、错误类型和完整错误消息。
request-id,响应头和响应体里都可能有。- 影响范围:单机、单项目、单网络还是全团队。
- 最小复现:一条 curl 或一个最小仓库,以及同一请求打官方入口的结果。
日志位置:VS Code 的 Output 面板里找 Roo Code 相关通道;扩展宿主和 MCP 工具的错误可能在 Developer Tools 控制台;网关侧问题把 request-id 发给网关支持。主仓库归档后,GitHub issue 可能只读,先去所用社区分支的支持渠道确认。日志脱敏要具体:Key 只留前四位和后四位,提示词和代码按公司规范处理。
八、示例:按错误类型决定是否重试
下面用 OpenAI 兼容接口演示:401 和 404 直接失败,429、5xx 和超时才退避重试。它既能作为独立脚本复现问题,也能放进自己的批处理任务。
import os
import random
import time
from openai import (
APIConnectionError,
APIStatusError,
APITimeoutError,
AuthenticationError,
NotFoundError,
OpenAI,
RateLimitError,
)
client = OpenAI(
base_url=os.environ["OPENAI_BASE_URL"],
api_key=os.environ["OPENAI_API_KEY"],
)
def ask(prompt: str, retries: int = 4) -> str:
for attempt in range(retries):
try:
resp = client.chat.completions.create(
model=os.environ["OPENAI_MODEL"],
messages=[{"role": "user", "content": prompt}],
timeout=120,
)
return resp.choices[0].message.content or ""
except AuthenticationError as exc:
raise SystemExit(f"401:检查 Provider、Key 与鉴权头,request-id={exc.request_id}") from exc
except NotFoundError as exc:
raise SystemExit(f"404:检查 Base URL 与模型 ID,request-id={exc.request_id}") from exc
except RateLimitError:
wait = min(2 ** attempt, 20) + random.random()
print(f"429:等待 {wait:.1f}s 后重试")
time.sleep(wait)
except (APITimeoutError, APIConnectionError):
wait = min(2 ** attempt, 10) + random.random()
print(f"超时或连接失败:等待 {wait:.1f}s 后重试")
time.sleep(wait)
except APIStatusError as exc:
if exc.status_code >= 500:
wait = min(2 ** attempt, 20) + random.random()
print(f"{exc.status_code}:等待 {wait:.1f}s 后重试")
time.sleep(wait)
continue
raise
raise RuntimeError("重试次数已用完,转降级或告警")
print(ask("只回复 OK"))
示例没有显式设置 SDK 重试次数,生产环境要把 SDK 默认重试和业务重试一起配置。Base URL 一般填 https://ai.zhongshangqihang.com/v1,模型 ID 从模型价格复制。
常见问题
401 一定是 Key 错了吗?
不一定。Provider 类型不匹配、Base URL 指错环境、代理改写鉴权头都会返回 401。先用同一 Key 和 Base URL 直连测试,再检查 Roo Code 的 Provider 和配置档案。
404 提示 model not found,怎么确认模型 ID?
调用 /v1/models 获取当前 Key 可见的列表,复制精确 ID,不要凭记忆手写。再确认 Base URL 是否重复拼接了路径,以及 Provider 协议是否匹配。
429 等一会儿就一定恢复吗?
不一定。速率限制通常会恢复;额度或余额触发的 429 可能不带 retry-after,等待没有意义,需要调整限额或充值。先看错误类型和响应头再决定。
上下文超限是模型问题吗?
通常不是。是输入加输出的预算超过窗口,或 Roo Code 的上下文窗口设置大于模型实际值。减少输入、开启压缩、拆分任务,比换模型更直接。
流式请求返回 200 后中断,算成功吗?
不算。流式响应可能在 200 之后通过 SSE 发送错误事件。客户端要解析事件流并确认正常结束,否则标记为不完整并重试或告警。
下一步
先在中商起航 AI 网关创建一个测试 Key,用上面的 curl 和脚本把 401、404、429、超时各演练一次,再接入生产监控。模型可用性与计费以模型价格为准。
相关阅读:
说明:Roo Code、Cline、Cursor、Claude Code、Anthropic、OpenAI 等名称分别为其权利人的商标或注册商标。本文仅作技术排查说明,与上述公司无隶属或合作关系。错误类型和客户端行为会随版本变化,请以官方文档和仓库公告为准。
