配置 OpenCode 的 Router One provider 与模型 ID
OpenCode 是 Anomaly 出品的开源终端编程 Agent,另有桌面应用和 IDE 扩展,自定义模型 provider 直接写进 opencode.json。一段基于 @ai-sdk/openai-compatible、指向 https://api.router.one/v1 的 provider 配置,就能把 Claude、GPT、Gemini、Grok 与 DeepSeek 聊天模型放进它的 /models 选择器,共用一把 Key。之后每一轮模型调用、子 Agent 任务和会话标题都会以 POST /v1/chat/completions 发到 Router One,并出现在控制台 → 日志里;Agent 会话无人值守时,Key 上的 maxSpend 上限就是硬性止损。网关在大陆可直连,支付宝或银行卡即可充值。自定义 provider 的模型在 OpenCode 的 models.dev 目录里都找不到,所以配置里还要写明每个模型的能力:上下文与输出上限、图片输入,以及由哪个模型生成标题。按 OpenCode 1.18.33(2026 年 9 月 28 日发布,npm 默认安装的版本)的 opencode.ai 文档与源码核对(2026-09-29);2026-10-09 按 1.18.35(2026 年 10 月 6 日发布,npm latest)复核,provider 与配置相关源码没有变化;最后一节介绍 2.0 预发布线。
安装 OpenCode,用 /connect 保存 Key
npm install -g opencode-ai 安装的是 1.18.35,即 2026-10-09 时 npm latest 标签对应的版本。请为 OpenCode 单独创建一把 Router One Key,并设置 maxSpend 消费上限:Agent 会话的每一轮模型调用都是一次计费请求,包括只把工具结果交回模型的轮次。然后保存 Key:在 TUI 里运行 /connect,拉到 Other,输入 router-one 之类的 provider ID,再粘贴 Key。OpenCode 会把它写进 ~/.local/share/opencode/auth.json,并提示这一步只保存凭证,provider 本身仍要在 opencode.json 里用同一个 ID 定义。opencode auth list 会列出已保存的凭证。如果更想把 Key 放在环境变量里,可以跳过 /connect,改用下面配置中的 {env:ROUTER_ONE_API_KEY}。
npm install -g opencode-ai # 2026-10-09 时 npm latest 为 1.18.35 opencode # 在 TUI 里:/connect → Other → router-one → 粘贴 Key opencode auth list # 查看已保存的凭证
把 OpenCode 配置到 Router One base URL
在 opencode.json 的 provider 下定义 provider:写在 ~/.config/opencode/opencode.json 对所有项目生效,也可以写在项目的 opencode.json 里,OpenCode 会把它合并到全局配置之上。provider 下的键名就是 provider ID,必须与 /connect 时填的一致。npm 指定协议包:文档把 @ai-sdk/openai-compatible 对应到 /v1/chat/completions,把 @ai-sdk/openai 对应到 /v1/responses,所以用前者。options.baseURL 填带 /v1 的地址,models 下的每个键都是精确的目录 ID。Key 来自 /connect 时,不写 options.apiKey;改用 {env:ROUTER_ONE_API_KEY} 则从环境变量读取,变量不存在时会被替换成空字符串,而不是报错。选模型时在 /models 里选 router-one/<目录 ID>,或写进顶层的 model 字段固定下来:
{
"$schema": "https://opencode.ai/config.json",
"model": "router-one/anthropic/claude-sonnet-5",
"small_model": "router-one/anthropic/claude-haiku-4.5",
"provider": {
"router-one": {
"npm": "@ai-sdk/openai-compatible",
"name": "Router One",
"options": {
"baseURL": "https://api.router.one/v1",
"apiKey": "{env:ROUTER_ONE_API_KEY}"
},
"models": {
"anthropic/claude-sonnet-5": {
"name": "Claude Sonnet 5",
"attachment": true,
"modalities": { "input": ["text", "image"], "output": ["text"] },
"limit": { "context": 1000000, "output": 32000 }
},
"anthropic/claude-haiku-4.5": {
"name": "Claude Haiku 4.5",
"limit": { "context": 200000, "output": 16000 }
}
}
}
}
}告诉 OpenCode 每个 Router One 模型能做 什么
对于只在你的配置里定义的模型,OpenCode 1.18.33 的源码会填入这些默认值:limit.context 和 limit.output 都是 0,只支持文本输入、不带附件,开启工具调用,不发送 temperature 参数。context 为 0 会关闭自动压缩,因为 OpenCode 只在知道窗口大小时才检查是否溢出,于是会话会一直增长,直到某次请求因为太长被拒绝。output 为 0 时退回 OpenCode 的 32,000 tokens 上限;设置了数值时,OpenCode 取 limit.output 与 32,000 中较小的一个,作为 max_tokens 发送,Router One 的 Chat Completions 接受它作为输出上限。limit.context 按 /models 上该模型详情页的窗口填写;详情页显示的是取整后的缩写(1.05M、200K),请换算成整数并往小取:anthropic/claude-sonnet-5、openai/gpt-5.6-sol 与 deepseek-v4-flash 填 1000000,anthropic/claude-haiku-4.5 填 200000。想发截图,就加上 attachment: true 和 input 含 image 的 modalities,并且只对详情页标明支持图片输入的 ID 这样做;deepseek-v4-flash 这类只支持文本的 ID 会收到 HTTP 400,错误信息含 has no chat candidate that supports requested capabilities: vision。窗口越大,OpenCode 能发出的提示词越长:在套餐下,单次请求的输入超过模型的长上下文门槛时会多扣套餐次数(见 /pricing)。
用 small_model 指定 生成 标题的 模型
OpenCode 文档说明 small_model 用于生成标题这类轻量任务:不设置时,OpenCode 会在同一个 provider 上找更便宜的模型,找不到就用主模型。自定义 provider 的模型没有可供查找的系列信息(按 1.18.33 源码),所以每个会话标题都会落回主模型,而主模型往往是你用的最贵的 ID。请把 small_model 设为同一 provider 上更便宜的目录 ID,例如 router-one/anthropic/claude-haiku-4.5,标题请求就会在控制台 → 日志里记在这个 ID 下。
Claude ID 走 /v1/messages、GPT ID 走 /v1/responses(可选)
OpenAI 兼容的配置已经覆盖全部聊天模型。想让 Claude ID 走原生 Messages API,就用另一个 ID 再加一条 provider:npm 填 @ai-sdk/anthropic,options.baseURL 填 https://api.router.one/v1;这个包会自己拼上 /messages,并用 x-api-key 请求头发送 Key,Router One 接受这种写法。Router One 在 /v1/messages 上服务 Claude 系列与 DeepSeek V4 的 ID。想让某个模型改走 Responses API,OpenCode 文档允许用 provider.npm 按模型覆盖协议包,例如给 openai/gpt-5.6-sol 设为 @ai-sdk/openai;只对模型详情页列出 /v1/responses 的 ID(GPT 系列、DeepSeek 与 Grok 对话模型)这样做。Claude 系列 ID 发到那里会收到 HTTP 400 model '<id>' must be called via /v1/messages or /v1/chat/completions,Gemini 的 ID 在那里同样不提供。
跑一条 提示词,到日志里 核对
opencode models router-one 会列出 OpenCode 在这个 provider 下看到的模型,是确认配置已加载的最快办法。opencode run -m router-one/anthropic/claude-sonnet-5 "Reply with OK" 以非交互方式发送一条提示词,模型按 provider/model 的格式指定。在控制台 → 日志里,这一轮会记在对应的目录 ID 下,显示 tokens、费用、状态、总耗时,以及产生过输出的流式请求的首字延迟(TTFT);之后可能还有一条记在 small_model ID 下的标题请求。401 通常说明 Key 没有发出:{env:…} 背后的环境变量没有设置,或者 /connect 用的 provider ID 与 provider 下的键名不一致。OpenCode 提示模型未知,说明它不在该 provider 的 models 里。provider 的 options 还可以设置 timeout(默认 300000 毫秒)和 chunkTimeout,后者是流式响应两个数据块之间允许的最长间隔(默认同样是 300000 毫秒),超时后 OpenCode 会中止请求。
opencode models router-one opencode run -m router-one/anthropic/claude-sonnet-5 "Reply with OK"
OpenCode 2.0 预发布线:配置有 哪些 变化
2026 年 9 月 21 日至 10 月 8 日,OpenCode 打出了 v2.0.12 到 v2.0.26 的标签,而 npm 的默认安装仍停在 1.18.x(2026-10-09 为 1.18.35),所以 2.x 仍是预发布线;下面的字段来自它当前的文档,等它成为默认安装版本时值得再核对一遍。按 2.0 迁移指南,1.x 与 2.x 都使用 opencode 命令,默认不会并存安装;2.x 读取相同的配置位置,并在内存中兼容受支持的 V1 字段,所以本页的配置块照常可用。2.0 的原生写法把 provider 改为 providers,npm 改为 package(aisdk:@ai-sdk/openai-compatible,或原生的 @opencode/ai/providers/openai-compatible),options.baseURL 改为 settings.baseURL,模型的 id 改为 modelID,tool_call 和 modalities 改为 capabilities;env 列出可以提供 Key 的环境变量,small_model 改为 agents.title.model,V1 的 attachment 字段在 2.x 里会被忽略。对于不认识的模型,2.x 默认假定支持工具、文本与图片输入,并按 200,000 上下文与 32,000 输出 tokens 处理,所以请显式写出 capabilities 和 limit。每条 provider 配置要么全用 V1 写法、要么全用 2.0 写法,测试期间请保留一份 V1 配置,因为 1.x 读不了改成 2.0 原生写法的文件。
{
"$schema": "https://opencode.ai/config.json",
"model": "router-one/anthropic/claude-sonnet-5",
"providers": {
"router-one": {
"name": "Router One",
"env": ["ROUTER_ONE_API_KEY"],
"package": "aisdk:@ai-sdk/openai-compatible",
"settings": { "baseURL": "https://api.router.one/v1" },
"models": {
"anthropic/claude-sonnet-5": {
"capabilities": { "tools": true, "input": ["text", "image"], "output": ["text"] },
"limit": { "context": 1000000, "output": 32000 }
}
}
}
}
}OpenCode 该填 哪个 模型 ID?
从 /models 页复制精确的模型 ID,保留大小写、连字符和版本后缀,不要用展示名称代替。打开该模型的详情页,核对支持的 API 端点、上下文窗口和工具调用等能力,再与 OpenCode 当前选择的 provider 和功能对应。模型出现在目录里,不等于当前客户端能调用它的所有功能。建议为每个客户端或应用单独建 API Key,并设置 maxSpend 消费上限。
OpenCode 用的是哪种 API 协议?
OpenAI 兼容描述的是接口格式,不能据此推断 Chat Completions(/v1/chat/completions)、Responses(/v1/responses)和 Anthropic Messages(/v1/messages)可以互换。先核对工具当前版本、provider 配置和实际请求路径,再查模型详情与 API 兼容性事实页。一次普通对话成功,也不能证明服务端工具、历史状态或文件编辑功能都受支持。
在请求日志里 核对 OpenCode 的调用
先在 OpenCode 发出一次简单文本请求,再到控制台 → 日志按时间、模型和 request_id 找到这条记录,核对 Token、花费、总耗时和状态码。成功后再分别验证流式输出、工具调用和多轮历史。失败时保留实际请求路径、完整错误消息及 request_id;没有对应日志时,要么请求没到达网关(客户端配置或网络问题),要么网关在调用模型之前就拒绝了它——Key 问题的 401、余额不足或 Key 达到 maxSpend 上限的 402、Key 或账户自身限额触发的 429,或模型 ID、端点不对的 400 / 404;在输出任何内容之前就失败的流式请求也可能没有日志。看客户端收到的状态码和错误消息就能区分是哪一种;先确认这一点,再判断是不是网关或上游故障。
常见 问题
OpenCode 提示 模型 未知或 认证 失败,怎么 排查?
按顺序查三处:model 字符串里的 provider ID 必须和 provider 下的键名一致(router-one/<模型 ID>);每个模型都要出现在该 provider 的 models 里,ID 与 /models 页完全一致;Key 必须能解析——要么由 /connect 以同一个 provider ID 保存,要么用 {env:ROUTER_ONE_API_KEY} 从启动 opencode 的那个 shell 里已导出的变量读取,变量不存在时会被替换成空字符串,而不是报错。
为什么长 会话 从不 压缩,最后 因为 太长而 失败?
因为模型没有设置 limit.context。对于只在配置里定义的模型,OpenCode 1.18.33 把上下文记为 0,而 0 意味着它从不检查溢出,于是会话一直增长到某次请求被拒绝。给每个模型加上 limit.context(详情页窗口换算成整数并往小取)和 limit.output。
为什么 会话 标题都跑在我 最贵的 模型上?
因为没有设置 small_model,而自定义 provider 让 OpenCode 找不到更便宜的模型,标题只能落回主模型。把 small_model 设为同一 provider 上更便宜的目录 ID,例如 router-one/anthropic/claude-haiku-4.5。
Claude 系列能走 Router One 的 Anthropic 兼容 端点吗?
可以,属于可选项。上面的 OpenAI 兼容配置已经覆盖 Claude 系列;如果想让这些模型走原生 Messages API,再加一条 provider:npm 填 @ai-sdk/anthropic,options.baseURL 填 https://api.router.one/v1——网关在 /v1/messages 上原生服务 Claude 系列,该包发送的 x-api-key 头里放同一把 Key 即可。两条 provider 用不同的 ID,模型列表互不干扰。
这份 配置能 用于 OpenCode 2.0 吗?
按 2.0 迁移指南,可以:2.x 读取相同位置的 opencode.json,并兼容 V1 的 provider 配置,不会改写文件。截至 2026-10-09,2.x 仍是预发布线;如果改成原生写法(providers、package、settings.baseURL、capabilities),请保留一份 V1 配置,因为 1.x 读不了改写后的文件。
本指南 对应哪个 OpenCode 版本?
OpenCode 1.18.33(2026 年 9 月 28 日发布),核对日期为 2026-09-29,依据 opencode.ai 文档与 1.18.33 源码;最后一节依据 2.0 预发布文档。2026-10-09 按 1.18.35 复核。文中的模型默认值来自 1.18.33 源码,升级后值得再检查一遍。
OpenCode 能通过 网关用 哪些 模型?
选用当前目录中同时支持 OpenCode 所用端点和所需功能的模型。精确 ID、当前单价与能力以 /models 及模型详情为准;不要仅按 GPT、Claude 等系列名判断兼容性。客户端能列出模型,只说明它从自身配置或 GET /v1/models 读到了这个 ID,仍需验证实际调用。
能列出 模型,但调用报 400 或 404,怎么办?
先记录实际请求路径和错误消息,再核对精确模型 ID。400 可能是参数、工具类型或模型与端点不匹配;404 可能是请求路径或资源不存在,不能直接判定模型下线。若错误提示 must be called via,按它指明的端点调整客户端 provider,或换用支持当前端点的模型。不要在所有工具里统一增删 /v1 或 /chat/completions。
中国 大陆能 直连吗?
能。网关在大陆可直连、无需 VPN,配置与全球环境完全一致。
报 401/402/403/429 怎么 排查?
先看客户端收到的响应:状态码、错误消息和 X-Request-ID 响应头。401(Key 缺失、不存在、已吊销或已过期)、402(钱包余额不足,或这把 Key 达到 maxSpend 上限)以及 Key 或账户自身限额触发的 429,都在调用任何模型之前被拒绝,不会出现在控制台 → 日志里;模型 ID 或端点写错导致的 400 / 404 也一样。401 查 Key 是否完整传入、在控制台 → API 密钥里是否仍有效;402 充值或调高这把 Key 的 maxSpend;403 请保留完整错误消息。429 请退避后重试;日志里能查到的 429 是网关重试之后上游仍返回的。保留 request_id,再按错误码速查页逐项排查。