本文面向第一次使用 Terminal、第一次配置 OpenCode,或者需要把 OpenCode 接入第三方 AI Gateway 的用户。

完成本文后,你将能够:

  • 安装并确认 OpenCode;
  • 安全输入 AI Gateway 的 Base URL 和 API Key;
  • 查询自己的 API Key 可以看到的模型;
  • 判断模型应使用 OpenAI Chat、OpenAI Responses 还是 Anthropic Messages;
  • 把通过测试的模型写入正确的 OpenCode provider;
  • 用一条真实消息确认 OpenCode 已经连接成功;
  • 根据错误信息判断是网络、认证、模型路由、请求协议还是 OpenCode 配置问题。

本文以 macOS Terminal 为例,示例 AI Gateway Base URL 为:

<https://cn-shanghai-alicloud-aimesh.api.clickzetta.com/gateway/v1>

如果你的 AI Gateway 不同,只需要替换 Base URL、API Key 和模型 ID。本文中的模型名称仅用于演示协议和配置写法,实际模型范围以你的 API Key 和中转站返回结果为准。不要把真实 API Key 发到聊天、工单、截图、Git 仓库或公开网页。

本文配置示例按 OpenCode

1.18.18
1.18.18
编写。OpenCode 的配置格式会随版本变化;如果你的版本不同,请先执行
opencode --version
opencode --version
,不要直接把新旧版本的配置格式混用。


先看结论:模型厂商和请求协议是两件事

OpenCode 不会根据模型名称自动选择请求协议。真正决定请求格式的是 provider 使用的 AI SDK runtime。

本文使用三个容易识别的 provider 名称:

OpenCode providerAI SDK runtimeAI Gateway 端点什么时候使用
my-relay
my-relay
@ai-sdk/openai-compatible
@ai-sdk/openai-compatible
/chat/completions
/chat/completions
模型的 OpenAI Chat 请求成功
my-relay-responses
my-relay-responses
@ai-sdk/openai
@ai-sdk/openai
/responses
/responses
模型的 OpenAI Responses 请求成功
my-relay-anthropic
my-relay-anthropic
@ai-sdk/anthropic
@ai-sdk/anthropic
/messages
/messages
模型的 Anthropic Messages 请求成功

如果你已经有其他 provider 名称,不需要为了匹配本文示例而重命名。继续沿用原名称,并把本文命令中的 provider ID 替换为你的实际名称。provider 名称是本机配置名称,不是模型厂商名称。

按模型厂商选择第一条测试路径

下面的表格用于选择起始路径,不代表某个厂商的所有模型都开放相同协议。具体模型必须以自己的

/models
/models
和对应 curl 结果为准:

模型厂商或系列OpenAI ChatOpenAI ResponsesAnthropic MessagesOpenCode 配置建议
Anthropic Claude通常不是首选需要单独测试原生接入路径,优先测试使用
my-relay-anthropic
my-relay-anthropic
OpenAI GPT、Codex 系列常见兼容路径OpenAI 原生路径,需单独测试通常不是首选Chat 成功使用
my-relay
my-relay
;Responses 成功使用
my-relay-responses
my-relay-responses
DeepSeek 系列网关提供时可用按模型单独测试网关提供时可用按实际成功协议选择 provider
Qwen 系列网关提供时可用按模型单独测试网关提供时可用按实际成功协议选择 provider
其他厂商或自定义模型不能推断不能推断不能推断先查目录,再按协议测试

最重要的规则是:

模型厂商 ≠ 请求协议 模型出现在目录中 ≠ 模型已经可以调用 标准 curl 成功 ≠ OpenCode 已经配置完成

只需要为准备使用的协议配置 provider。只用 Claude 时可以只配置 Anthropic provider;只用 OpenAI Chat 时可以只配置 OpenAI Compatible provider;只有在

/responses
/responses
测试成功且确实需要该接口时,才配置 Responses provider。


0. 完整操作路线

第一次配置时,请按以下顺序操作:

1. 安装或确认 OpenCode 2. 准备 Base URL 和 API Key 3. 查询自己的模型目录 4. 选择模型和目标协议 5. 用对应协议的 curl 得到最终文字 6. 把成功模型写入 OpenCode 7. 校验配置并查看 provider 8. 用 OpenCode 发送第一条消息 9. 需要时再添加其他模型或协议

真正成功必须同时满足:

  1. 当前协议的模型目录能看到模型;
  2. 标准 curl 返回 HTTP 200;
  3. 响应中有实际模型文本;
  4. OpenCode 通过正确的 provider 返回实际模型文本。

只看到模型名称,不能直接说明模型可用。模型目录、协议路由和客户端实际调用必须分别验证。

0.1 如何阅读模型信息

本文中的模型信息分成三层,含义不同:

信息层说明你应采取的动作
API Key 实时目录当前 API Key 通过某种认证头查询
/models
/models
能看到的模型 ID
先作为候选,再继续做请求测试
协议调用结果某个模型在 OpenAI Chat、OpenAI Responses 或 Anthropic Messages 下的实际 HTTP 结果只在对应协议下使用,并记录成功或失败原因
OpenCode 配置结果OpenCode provider、AI SDK runtime 和客户端参数组合后的实际结果按文档中的 provider 写法调用;高级能力需单独确认

因此,请按以下优先级判断:

自己的 API Key 实时目录 ↓ 对应协议的标准 curl ↓ OpenCode 对应 provider 的实际调用 ↓ 才可以判断该模型在自己的环境中可用

本文中的“可以使用”默认指“最小文本请求返回了最终文本”。它不自动包含工具调用、流式、多模态、结构化输出、长上下文或模型专属参数。

你最终能否调用某个模型,取决于四个条件同时成立:

产品是否配置了该模型的上游路由 × API Key 是否拥有该模型权限 × OpenCode 是否使用了正确 provider 和协议 × 本次请求使用的功能是否经过验证 = 本次调用是否真正可用

因此,“中转站可以路由某模型”与“你的 API Key 当前可以调用某模型”是两个不同问题。后者还会受到租户、套餐、权限和实时上游状态影响。

0.2 配置完成后的预期效果

完成本文后,你应能做到:

  • 在 OpenCode 中看到自己 API Key 可用的 provider 和模型;
  • my-relay
    my-relay
    调用 OpenAI Compatible Chat 模型;
  • 在模型的
    /responses
    /responses
    请求成功时,用
    my-relay-responses
    my-relay-responses
    调用该模型;
  • my-relay-anthropic
    my-relay-anthropic
    调用 Anthropic Messages 模型,包括 Claude;
  • 根据厂商和协议规则选择正确的 provider,不再把 Claude 放入 OpenAI provider;
  • 用最小文本请求确认模型确实返回最终文本;
  • 遇到认证、网络、协议、路由或客户端参数错误时,判断问题属于哪一层。

完成第 8 步后,你已经具备基础文本对话能力。工具调用、图片、文件、结构化输出和其他高级能力的适用范围见第 11.6 节和第 12 节。

如果只完成 JSON 编辑但没有完成 curl 和 OpenCode 实际调用,配置还没有完成验证。


1. 准备信息

开始前准备三项内容。

1.1 Base URL

Base URL 是 AI Gateway 接口地址。本示例使用:

<https://cn-shanghai-alicloud-aimesh.api.clickzetta.com/gateway/v1>

地址已经包含

/v1
/v1
。不要手动拼成
/v1/v1
/v1/v1
,也不要把它写成具体端点,例如
/chat/completions
/chat/completions
/messages
/messages
。OpenCode 的 provider runtime 会自动追加端点。

1.2 API Key

请到 AI Gateway 后台创建 API Key,并确认:

  • API Key 没有过期;
  • API Key 有模型调用权限;
  • 复制时没有多余空格或换行;
  • API Key 与 Base URL 属于同一个环境;
  • 如果中转站按协议区分权限,API Key 拥有你准备使用的 OpenAI、Responses 或 Anthropic 路由权限。

API Key 的权限可能比产品目录更窄。不同用户、不同套餐或不同租户看到的模型范围可能不同,所以请先查询自己的 OpenAI 和 Anthropic 两个认证视图,再把实际使用的模型加入配置。

1.3 是否需要 VPN

OpenCode 请求的是你配置的 AI Gateway,不是直接请求 Anthropic 或 OpenAI。只要本机能访问中转站,一般不需要 VPN。

先执行第 6 节的

/models
/models
和第 7 节的 curl:

  • 能建立 TLS 连接但返回
    401
    401
    No upstream candidates
    No upstream candidates
    502
    502
    :通常是 API Key、模型 ID、协议或上游路由问题,不是 VPN 问题;
  • 出现 DNS 失败、连接超时、TLS 握手失败:才优先检查网络、公司代理、防火墙或 VPN。

1.4 在哪里操作

所有命令都在 macOS Terminal 执行。按 Command + Space,输入 Terminal,按回车打开。

终端提示符可能类似:

a123@Mac ~ %

不要复制提示符本身,只复制代码框中的命令。

**下一步:**执行第 2 节,检查基础工具和 OpenCode。


2. 确认基础工具和 OpenCode

2.1 检查 curl、jq、Node.js

在 Terminal 执行:

command -v curl command -v jq node --version npm --version

看到

curl
curl
jq
jq
的文件路径,并且 Node.js、npm 能返回版本号,就可以继续。

如果 jq 不存在:

command -v brew

如果 brew 存在:

brew install jq jq --version

如果 brew 也不存在,请先安装 Homebrew,再安装 jq。后面的模型目录和响应解析命令需要 jq。

**下一步:**确认 OpenCode 命令是否已经安装。

2.2 安装或确认 OpenCode

先执行:

command -v opencode opencode --version type -a opencode

如果已经返回路径和版本号,可以直接进入第 3 节。

type -a opencode
type -a opencode
如果显示多个路径,后续排查时要确认 Terminal 使用的是哪一个版本。

如果还没有安装,可以使用 npm:

npm install -g opencode-ai opencode --version

也可以使用 OpenCode 官方安装脚本:

curl -fsSL --proto '=https' --tlsv1.2 https://opencode.ai/install | bash opencode --version

正常返回版本号即可,例如:

1.18.18

如果显示

opencode: command not found
opencode: command not found
,先确认 npm 的全局 bin 是否在 PATH 中:

NPM_GLOBAL_BIN="$(npm prefix -g)/bin" printf 'npm global bin: %s\n' "$NPM_GLOBAL_BIN" test -x "$NPM_GLOBAL_BIN/opencode" && echo 'opencode 已安装但当前 PATH 未包含该目录' command -v opencode

如果命令已经安装但当前 Terminal 找不到,请把实际 npm 全局 bin 目录加入

~/.zshrc
~/.zshrc
,重新打开 Terminal,再执行
opencode --version
opencode --version
。不要为了绕过 PATH 直接重复安装很多次。

**下一步:**确认 OpenCode 版本后,进入第 3 节保存 API Key。


3. 在当前 Terminal 安全输入 API Key

不要把 API Key 直接写在命令行参数中,因为它可能进入 Terminal history。在同一个 Terminal 执行:

export RELAY_BASE_URL='https://cn-shanghai-alicloud-aimesh.api.clickzetta.com/gateway/v1' RELAY_BASE_URL="${RELAY_BASE_URL%/}" read -s "RELAY_API_KEY?请粘贴 AI Gateway API Key,然后按回车:" echo export CLICKZETTA_API_KEY="$RELAY_API_KEY"

粘贴 API Key 时屏幕不会显示字符,这是正常的。

export
export
只对当前 Terminal 会话有效,关闭窗口后变量会消失。

检查变量是否存在时不要打印实际内容:

if [ -n "$CLICKZETTA_API_KEY" ]; then echo 'CLICKZETTA_API_KEY 已加载' else echo 'CLICKZETTA_API_KEY 未加载' fi

3.1 新 Terminal 为什么需要重新加载

上面的变量只在当前 Terminal 窗口有效。关闭窗口或重启电脑后,如果看到

API Key: missing
API Key: missing
,通常不是 OpenCode 配置失效,而是新 Terminal 尚未加载环境变量。

临时使用时,在每个新 Terminal 中重新执行本节的

read -s
read -s
命令即可。

3.2 长期使用:保存到 macOS Keychain(推荐)

完成前面的

read -s
read -s
后,可以把当前变量保存到 macOS Keychain。下面命令中的 API Key 仍然通过变量传入,不要把真实值直接写进命令:

security add-generic-password \ -U \ -a "$USER" \ -s 'opencode-clickzetta-api-key' \ -w "$CLICKZETTA_API_KEY"

以后打开新 Terminal,执行下面命令加载,不会在屏幕上打印 API Key:

export RELAY_BASE_URL='https://cn-shanghai-alicloud-aimesh.api.clickzetta.com/gateway/v1' export CLICKZETTA_API_KEY="$(security find-generic-password \ -a "$USER" \ -s 'opencode-clickzetta-api-key' \ -w)" test -n "$CLICKZETTA_API_KEY" && echo 'API Key 已从 macOS Keychain 加载'

首次读取时 macOS 可能要求确认 Keychain 访问,这是正常现象。如果不再使用,可以删除该条目:

security delete-generic-password \ -a "$USER" \ -s 'opencode-clickzetta-api-key'

如果不是 macOS,请使用系统密码管理器或权限受限的本地密钥方案。不要把真实值写进本文、Git 仓库、截图、项目目录、公开的

opencode.json
opencode.json
或可同步到云端的 shell 配置文件。

**下一步:**先不要打开 OpenCode,按照协议分别查看模型目录。


4. OpenCode 配置文件在哪里

本节只确认配置文件位置并做好备份。先不要把未测试的模型全部写进去;模型目录和 curl 测试在第 6、7 节完成,真正写入配置在第 8 节。

macOS 默认配置文件为:

~/.config/opencode/opencode.json

也就是:

/Users/你的用户名/.config/opencode/opencode.json

先检查目录和文件:

mkdir -p "$HOME/.config/opencode" ls -la "$HOME/.config/opencode"

第一次修改已有配置前先备份:

if [ -f "$HOME/.config/opencode/opencode.json" ]; then cp -p "$HOME/.config/opencode/opencode.json" "$HOME/.config/opencode/opencode.json.bak" fi

4.1 重要:OpenCode 版本格式差异

本文基于 OpenCode

1.18.18
1.18.18
,使用下面这些字段:

provider 单数 npm provider 使用的 AI SDK runtime options baseURL 等运行参数 models provider 下的模型字典

OpenCode 新版文档可能使用

providers
providers
package
package
settings
settings
等字段。不要把两套格式拼在同一个文件中。最可靠的做法是:先看本机
opencode --version
opencode --version
,再按本版本的 schema 写配置。

如果你使用的版本不是

1.18.18
1.18.18
,先执行:

opencode debug config

如果报配置 schema 错误,先按该版本的配置格式迁移,不能简单地把

provider
provider
改成
providers
providers
或反过来。

**下一步:**先理解第 5 节的 provider 与协议对应关系,再查询模型目录。


5. 先理解 OpenCode 的三个 provider

OpenCode 不会根据模型 ID 自动选择请求协议。协议由 provider 的 runtime package 决定。

本指南使用三个 provider:

my-relay → @ai-sdk/openai-compatible → POST /v1/chat/completions → Authorization: Bearer API_KEY my-relay-responses → @ai-sdk/openai → POST /v1/responses → Authorization: Bearer API_KEY my-relay-anthropic → @ai-sdk/anthropic → POST /v1/messages → x-api-key: API_KEY → anthropic-version: 2023-06-01

模型引用格式是:

<provider-id>/<model-id>

例如:

my-relay/openai/gpt-5.5 my-relay-anthropic/anthropic/claude-opus-5

这里的

my-relay-anthropic
my-relay-anthropic
是 OpenCode 的 provider ID,
anthropic/claude-opus-5
anthropic/claude-opus-5
是中转站的模型 ID。模型 ID 中出现
anthropic/
anthropic/
,不会自动把
my-relay
my-relay
切换为 Anthropic 协议。

以下写法协议不匹配:

my-relay/anthropic/claude-opus-5 my-relay-anthropic/openai/gpt-5.5

**下一步:**执行第 6 节,按认证方式分别查询模型目录。


6. 获取实时模型目录

模型目录必须按协议分别查询。不能只执行一次

/models
/models
,然后认为返回结果就是中转站全部模型。

6.1 OpenAI 视图

OpenAI Compatible 使用 Bearer 认证:

curl -sS -o /tmp/opencode-gateway-models-openai.json \ --max-time 30 \ -w 'HTTP %{http_code}\n' \ "$RELAY_BASE_URL/models" \ -H "Authorization: Bearer $CLICKZETTA_API_KEY" \ -H 'Accept: application/json'

HTTP 200 后执行:

jq -r ' if (.data | type) == "array" then .data[].id else .error.message // .message // "没有读取到模型目录" end ' /tmp/opencode-gateway-models-openai.json

返回含义:

返回含义下一步
HTTP 200网络和 Bearer 认证正常查看目录并测试具体模型
HTTP 401/403API Key 错误、失效或权限不足检查 API Key、租户和权限
HTTP 404Base URL 或
/v1
/v1
路径错误
检查地址,避免重复
/v1
/v1
HTTP 429限流、额度或并发限制等待后重试,或检查额度
HTTP 5xx网关或上游暂时异常稍后重试并保存脱敏错误
没有 HTTP 状态、DNS 或超时请求没有正常到达网关检查网络、代理、防火墙或 VPN

模型出现在目录中,只表示当前 API Key 能看到该 ID;它不代表该模型在 Chat、Responses 和 Anthropic 三种协议下都可用。继续执行第 7 节的具体请求测试。

6.2 Anthropic 视图

Anthropic Messages 使用不同认证头:

curl -sS -o /tmp/opencode-gateway-models-anthropic.json \ --max-time 30 \ -w 'HTTP %{http_code}\n' \ "$RELAY_BASE_URL/models" \ -H "x-api-key: $CLICKZETTA_API_KEY" \ -H 'anthropic-version: 2023-06-01' \ -H 'Accept: application/json'

HTTP 200 后执行:

jq -r ' if (.data | type) == "array" then .data[].id else .error.message // .message // "没有读取到 Anthropic 模型目录" end ' /tmp/opencode-gateway-models-anthropic.json

如果 OpenAI 视图和 Anthropic 视图不同,这是正常现象。请求头和协议上下文不同,AI Gateway 可以返回不同的模型目录。请使用自己的 API Key 重新查询两个视图,不要复制某一份静态清单。

6.3 OpenCode 自带模型目录的含义

直接执行:

opencode models

会看到 OpenCode 内置目录中的许多 provider,例如

amazon-bedrock/anthropic.claude-*
amazon-bedrock/anthropic.claude-*
。这些条目属于 AWS Bedrock provider,不是本中转站模型,不代表你已经获得了 AWS 凭据,也不代表 OpenCode 会自动通过中转站调用它们。

OpenCode 的内置目录与中转站目录是两套目录。只有写入

opencode.json
opencode.json
的 provider 才会通过本中转站请求。

6.4 如何使用自己的模型目录

你不需要把本文示例中的模型全部复制到配置文件。推荐按下面规则处理:

  1. 保存自己 API Key 的 OpenAI 和 Anthropic
    /models
    /models
    输出;
  2. 只把自己目录中存在的模型 ID 放入对应 provider;
  3. 对每个准备使用的模型执行第 7 节对应协议的最小文本请求;
  4. 只有返回 HTTP 200 且包含最终文本的模型,才进入 OpenCode 实际调用;
  5. 如果模型在目录中但请求返回
    No upstream candidates
    No upstream candidates
    502
    502
    ,保留记录但不要标记为可用;
  6. 如果自己的目录与预期不一致,先以实时目录为准,再联系中转站支持人员确认权限或路由。

模型目录是权限和路由的实时快照,不是需要手工维护的“模型总表”。能否使用某个模型,必须同时看模型 ID、协议、provider 和实际调用结果。

**下一步:**从对应目录复制一个完整模型 ID,执行第 7 节的协议请求。


7. 用标准 curl 验证协议和模型

7.1 OpenAI Chat Completions

请求端点:

POST /v1/chat/completions Authorization: Bearer API_KEY

从第 6.1 节的结果中复制一个完整模型 ID:

read "CHAT_MODEL_ID?请粘贴准备使用 Chat 协议的完整模型 ID:"

执行:

curl -sS -o /tmp/opencode-test-chat.json \ --max-time 60 \ -w 'HTTP %{http_code}\n' \ "$RELAY_BASE_URL/chat/completions" \ -H "Authorization: Bearer $CLICKZETTA_API_KEY" \ -H 'Content-Type: application/json' \ -d "$(jq -cn \ --arg model "$CHAT_MODEL_ID" \ '{ model: $model, max_tokens: 512, messages: [{role: "user", content: "请只回复:Chat连接成功"}] }')"

提取最终文字:

jq -r ' .choices[0].message.content // .error.message // .message // "HTTP 已返回,但没有找到最终文字" ' /tmp/opencode-test-chat.json

成功时应看到:

HTTP 200 Chat连接成功

如果成功,可以在第 8 节只配置

my-relay
my-relay

7.2 OpenAI Responses

请求端点:

POST /v1/responses Authorization: Bearer API_KEY

从第 6.1 节的结果中复制一个完整模型 ID:

read "RESPONSES_MODEL_ID?请粘贴准备使用 Responses 协议的完整模型 ID:"

执行。Responses 使用

input
input
max_output_tokens
max_output_tokens
,不能直接复制 Chat Completions 的
messages
messages
请求体:

curl -sS -o /tmp/opencode-test-responses.json \ --max-time 60 \ -w 'HTTP %{http_code}\n' \ "$RELAY_BASE_URL/responses" \ -H "Authorization: Bearer $CLICKZETTA_API_KEY" \ -H 'Content-Type: application/json' \ -d "$(jq -cn \ --arg model "$RESPONSES_MODEL_ID" \ '{ model: $model, input: "请只回复:Responses连接成功", max_output_tokens: 512 }')"

提取最终文字:

jq -r ' ([.output[]?.content[]? | select(.type == "output_text" or .type == "text") | .text] | join("\n")) as $text | if ($text | length) > 0 then $text else .error.message // .message // "HTTP 已返回,但没有找到最终文字" end ' /tmp/opencode-test-responses.json

不同网关或 SDK 的 Responses 响应结构可能不同,通常从

output[].content[].text
output[].content[].text
output_text
output_text
读取。

成功时应看到:

HTTP 200 Responses连接成功

Responses 结果不能由 Chat 结果推断:同一个模型在两个端点的上游路由可能不同。OpenCode 本指南的

my-relay
my-relay
没有配置 Responses runtime,因此不要把 curl 的 Responses 成功当成 OpenCode 已启用 Responses。

Responses 是可选接入路径。只有同一模型先通过本节的

/responses
/responses
标准 curl,再按第 8.4 节配置
my-relay-responses
my-relay-responses
,并通过第 10.2 节的
opencode run
opencode run
返回最终文本,才能判断 Responses 在你的环境中可用。文档提供配置模板,不代表你的 API Key 或上游路由已经开放该协议。

7.3 Anthropic Messages

请求端点:

POST /v1/messages x-api-key: API_KEY anthropic-version: 2023-06-01

从第 6.2 节的结果中复制一个完整模型 ID:

read "ANTHROPIC_MODEL_ID?请粘贴准备使用 Anthropic 协议的完整模型 ID:"

对本文示例 AI Gateway,Claude 当前优先且已经验证的接入路径是 Anthropic Messages,因此使用下面的请求结构:

curl -sS -o /tmp/opencode-test-anthropic.json \ --max-time 60 \ -w 'HTTP %{http_code}\n' \ "$RELAY_BASE_URL/messages" \ -H "x-api-key: $CLICKZETTA_API_KEY" \ -H 'anthropic-version: 2023-06-01' \ -H 'content-type: application/json' \ -d "$(jq -cn \ --arg model "$ANTHROPIC_MODEL_ID" \ '{ model: $model, max_tokens: 1024, messages: [{role: "user", content: "请只回复:Anthropic连接成功"}] }')"

提取最终文字:

jq -r ' ([.content[]? | select(.type == "text") | .text] | join("\n")) as $text | if ($text | length) > 0 then $text else .error.message // .message // "HTTP 已返回,但没有找到最终文字" end ' /tmp/opencode-test-anthropic.json

成功时应看到:

HTTP 200 Anthropic连接成功

测试时不要把

max_tokens
max_tokens
设得过小;某些带思考过程的响应可能只返回思考内容,导致误判为没有最终文本。建议从
1024
1024
开始进行最小文本测试。

下面是模型 ID 写法示例。实际使用时,只把模型 ID 换成自己的 Anthropic 目录中存在、并且请求验证成功的 ID:

anthropic/claude-haiku-4.5 anthropic/claude-opus-4.8 anthropic/claude-opus-5 anthropic/claude-sonnet-4.6 anthropic/claude-sonnet-5

如果成功,可以在第 8 节只配置

my-relay-anthropic
my-relay-anthropic

7.4 HTTP 200 但没有最终文字

部分推理模型可能先生成 thinking 或 reasoning 内容。输出预算太小时,请求可能返回 HTTP 200,但没有最终文字。

可以把对应请求中的:

max_tokens: 512 max_output_tokens: 512

先提高到

1024
1024
,仍然不足时再提高到
4096
4096
。如果提高后仍然只有 thinking 或 reasoning、没有最终文字,请只在本机查看完整 JSON,确认响应结构是否与当前协议一致;此时不能把该模型标记为这个协议下可用,也不要把未经脱敏的完整 JSON 粘贴到聊天或工单。

**下一步:**只把刚才 curl 成功的模型写入对应 OpenCode provider,执行第 8 节。


8. 写入 OpenCode 配置

下面是 OpenCode

1.18.18
1.18.18
的基础配置模板。它使用
my-relay
my-relay
对应 OpenAI Compatible Chat,
my-relay-anthropic
my-relay-anthropic
对应 Anthropic Messages;只有
/responses
/responses
测试成功时才按第 8.4 节加入
my-relay-responses
my-relay-responses
。配置文件中不保存 API Key,API Key 通过环境变量
CLICKZETTA_API_KEY
CLICKZETTA_API_KEY
注入。

8.1 复制配置前先区分“固定部分”和“可变部分”

配置内容是否可以直接沿用说明
provider
provider
的对象结构
可以OpenCode
1.18.18
1.18.18
使用单数
provider
provider
;不要与新版格式混用
@ai-sdk/openai-compatible
@ai-sdk/openai-compatible
可以只用于 OpenAI Compatible Chat,不代表启用 Responses
@ai-sdk/openai
@ai-sdk/openai
按需使用只用于已通过
/responses
/responses
测试的模型;配置在独立 provider 中
@ai-sdk/anthropic
@ai-sdk/anthropic
可以用于 Anthropic Messages;本文示例网关的 Claude 使用此 provider
baseURL
baseURL
必须替换使用你自己的中转站 Base URL,并确保只包含一个
/v1
/v1
CLICKZETTA_API_KEY
CLICKZETTA_API_KEY
必须替换使用自己的 API Key,不写入 JSON
根级别的
model
model
按需替换必须指向你已验证成功的
<provider>/<model-id>
<provider>/<model-id>
models
models
下的模型 ID
按需替换只保留自己
/models
/models
能看到且通过最小请求验证的模型
limit.context
limit.context
limit.output
limit.output
按需调整是 OpenCode 客户端预算,不是中转站永久承诺

8.2 方案 A:用 Terminal 写入 OpenAI Chat provider

这是推荐方式。它只修改

my-relay
my-relay
provider,保留配置文件中的其他内容。必须先完成第 7.1 节,并且当前 Terminal 中仍然存在
CHAT_MODEL_ID
CHAT_MODEL_ID

如果你已有其他 provider 名称,可在执行前设置

OPENAI_PROVIDER_ID
OPENAI_PROVIDER_ID
;不设置时默认使用
my-relay
my-relay

set -e OPENAI_PROVIDER_ID="${OPENAI_PROVIDER_ID:-my-relay}" test -n "$CHAT_MODEL_ID" || read "CHAT_MODEL_ID?请粘贴已测试成功的 Chat 模型 ID:" CONFIG_FILE="$HOME/.config/opencode/opencode.json" mkdir -p "$(dirname "$CONFIG_FILE")" if [ -f "$CONFIG_FILE" ]; then cp -p "$CONFIG_FILE" "$CONFIG_FILE.backup-$(date +%Y%m%d-%H%M%S)" else printf '%s\n' '{"$schema":"https://opencode.ai/config.json","provider":{}}' > "$CONFIG_FILE" fi CHAT_PROVIDER=$(jq -cn \ --arg base "$RELAY_BASE_URL" \ --arg model "$CHAT_MODEL_ID" \ '{ name: "AI Gateway (OpenAI Chat)", env: ["CLICKZETTA_API_KEY"], npm: "@ai-sdk/openai-compatible", options: {baseURL: $base}, models: {($model): {name: $model}} }') TMP_FILE=$(mktemp) jq \ --argjson provider "$CHAT_PROVIDER" \ --arg provider_id "$OPENAI_PROVIDER_ID" \ --arg model "$CHAT_MODEL_ID" \ '.provider = (.provider // {}) | .provider[$provider_id] as $existing | .provider[$provider_id] = (($existing // {}) * $provider) | .provider[$provider_id].models = (($existing.models? // {}) + $provider.models) | .model = ($provider_id + "/" + $model)' \ "$CONFIG_FILE" > "$TMP_FILE" && mv "$TMP_FILE" "$CONFIG_FILE" jq empty "$CONFIG_FILE" opencode debug config >/dev/null && echo 'OpenAI Chat provider 配置成功'

8.3 方案 B:用 Terminal 写入 Anthropic provider

这是 Claude 的推荐方式。必须先完成第 7.3 节,并且当前 Terminal 中仍然存在

ANTHROPIC_MODEL_ID
ANTHROPIC_MODEL_ID

如果你已有其他 provider 名称,可在执行前设置

ANTHROPIC_PROVIDER_ID
ANTHROPIC_PROVIDER_ID
;不设置时默认使用
my-relay-anthropic
my-relay-anthropic

set -e ANTHROPIC_PROVIDER_ID="${ANTHROPIC_PROVIDER_ID:-my-relay-anthropic}" test -n "$ANTHROPIC_MODEL_ID" || read "ANTHROPIC_MODEL_ID?请粘贴已测试成功的 Anthropic 模型 ID:" CONFIG_FILE="$HOME/.config/opencode/opencode.json" mkdir -p "$(dirname "$CONFIG_FILE")" if [ -f "$CONFIG_FILE" ]; then cp -p "$CONFIG_FILE" "$CONFIG_FILE.backup-$(date +%Y%m%d-%H%M%S)" else printf '%s\n' '{"$schema":"https://opencode.ai/config.json","provider":{}}' > "$CONFIG_FILE" fi ANTHROPIC_PROVIDER=$(jq -cn \ --arg base "$RELAY_BASE_URL" \ --arg model "$ANTHROPIC_MODEL_ID" \ '{ name: "AI Gateway (Anthropic Messages)", env: ["CLICKZETTA_API_KEY"], npm: "@ai-sdk/anthropic", options: {baseURL: $base}, models: {($model): {name: $model}} }') TMP_FILE=$(mktemp) jq \ --argjson provider "$ANTHROPIC_PROVIDER" \ --arg provider_id "$ANTHROPIC_PROVIDER_ID" \ --arg model "$ANTHROPIC_MODEL_ID" \ '.provider = (.provider // {}) | .provider[$provider_id] as $existing | .provider[$provider_id] = (($existing // {}) * $provider) | .provider[$provider_id].models = (($existing.models? // {}) + $provider.models) | .model = ($provider_id + "/" + $model)' \ "$CONFIG_FILE" > "$TMP_FILE" && mv "$TMP_FILE" "$CONFIG_FILE" jq empty "$CONFIG_FILE" opencode debug config >/dev/null && echo 'Anthropic provider 配置成功'

如果需要多个协议,分别执行已通过 curl 测试的方案。每段命令会写入独立 provider,不会把 Claude 放进 OpenAI provider,也不会把 Responses 模型误当成 Chat 模型;最后执行的方案会把对应模型设置为默认模型,之后仍可使用

--model
--model
临时切换。

8.4 方案 C:用 Terminal 写入 OpenAI Responses provider(按需)

只有第 7.2 节返回 HTTP

200
200
且提取到最终文字时,才需要执行本节。不要因为模型名称中带有
openai
openai
gpt
gpt
,就跳过 Responses 测试。

如果你已有其他 provider 名称,可在执行前设置

RESPONSES_PROVIDER_ID
RESPONSES_PROVIDER_ID
;不设置时默认使用
my-relay-responses
my-relay-responses

set -e RESPONSES_PROVIDER_ID="${RESPONSES_PROVIDER_ID:-my-relay-responses}" test -n "$RESPONSES_MODEL_ID" || read "RESPONSES_MODEL_ID?请粘贴已测试成功的 Responses 模型 ID:" CONFIG_FILE="$HOME/.config/opencode/opencode.json" mkdir -p "$(dirname "$CONFIG_FILE")" if [ -f "$CONFIG_FILE" ]; then cp -p "$CONFIG_FILE" "$CONFIG_FILE.backup-$(date +%Y%m%d-%H%M%S)" else printf '%s\n' '{"$schema":"https://opencode.ai/config.json","provider":{}}' > "$CONFIG_FILE" fi RESPONSES_PROVIDER=$(jq -cn \ --arg base "$RELAY_BASE_URL" \ --arg model "$RESPONSES_MODEL_ID" \ '{ name: "AI Gateway (OpenAI Responses)", env: ["CLICKZETTA_API_KEY"], npm: "@ai-sdk/openai", options: {baseURL: $base}, models: {($model): {name: $model}} }') TMP_FILE=$(mktemp) jq \ --argjson provider "$RESPONSES_PROVIDER" \ --arg provider_id "$RESPONSES_PROVIDER_ID" \ --arg model "$RESPONSES_MODEL_ID" \ '.provider = (.provider // {}) | .provider[$provider_id] as $existing | .provider[$provider_id] = (($existing // {}) * $provider) | .provider[$provider_id].models = (($existing.models? // {}) + $provider.models) | .model = ($provider_id + "/" + $model)' \ "$CONFIG_FILE" > "$TMP_FILE" && mv "$TMP_FILE" "$CONFIG_FILE" jq empty "$CONFIG_FILE" opencode debug config >/dev/null && echo 'OpenAI Responses provider 配置成功'

@ai-sdk/openai
@ai-sdk/openai
@ai-sdk/openai-compatible
@ai-sdk/openai-compatible
的模型 ID 可以相同,但它们不是同一个 runtime。Responses provider 不会替代 Chat provider;如果同一模型在两种协议下都成功,可以同时保留两个 provider。

8.5 手动编辑配置文件

如果你不希望使用 Terminal 写入命令,也可以用编辑器打开配置文件:

open -e "$HOME/.config/opencode/opencode.json"

下面 JSON 是最小手动编辑示例。保存前,将示例模型 ID 换成第 7 节已经测试成功的模型;不要把不存在于自己目录的模型直接复制进去。

{ "$schema": "https://opencode.ai/config.json", "model": "my-relay/openai/gpt-5.5", "provider": { "my-relay": { "name": "AI Gateway (OpenAI Chat)", "env": ["CLICKZETTA_API_KEY"], "npm": "@ai-sdk/openai-compatible", "options": { "baseURL": "https://cn-shanghai-alicloud-aimesh.api.clickzetta.com/gateway/v1" }, "models": { "openai/gpt-5.5": { "name": "OpenAI model example" } } }, "my-relay-anthropic": { "name": "AI Gateway (Anthropic Messages)", "env": ["CLICKZETTA_API_KEY"], "npm": "@ai-sdk/anthropic", "options": { "baseURL": "https://cn-shanghai-alicloud-aimesh.api.clickzetta.com/gateway/v1" }, "models": { "anthropic/claude-opus-5": { "name": "Anthropic model example" } } } } }

配置文件中不保存 API Key,OpenCode 会从环境变量

CLICKZETTA_API_KEY
CLICKZETTA_API_KEY
读取令牌。

如果需要手动加入 Responses provider,请以第 8.4 节的

my-relay-responses
my-relay-responses
对象为准,作为第三个
provider
provider
条目加入;不要把已有
my-relay
my-relay
npm
npm
改成
@ai-sdk/openai
@ai-sdk/openai

8.6 目录中出现但请求失败的模型

有些模型会出现在

/models
/models
,但实际请求仍可能返回
No upstream candidates
No upstream candidates
model_not_found
model_not_found
或 HTTP
502
502
。这通常表示模型权限、协议路由或上游状态还没有准备好,不是 OpenCode 配置文件语法错误。

遇到这种情况,不要为了让模型出现在 OpenCode 列表中而继续保留它。先记录模型 ID、请求协议、HTTP 状态码和脱敏错误,联系中转站确认路由;只有对应协议返回最终文本后,再加入配置。

8.7 按自己的目录调整模型

当自己的模型目录与本文示例配置不同,只调整

models
models
对象,不要随意修改 provider runtime:

  1. OpenAI 目录没有的模型,从
    my-relay.models
    my-relay.models
    删除;
  2. Anthropic 目录没有的模型,从
    my-relay-anthropic.models
    my-relay-anthropic.models
    删除;
  3. 同一个 Qwen 或 DeepSeek ID 如果多个协议都验证成功,可以分别放入对应 provider;
  4. 对本文示例网关,Claude 放入
    my-relay-anthropic.models
    my-relay-anthropic.models
    ,不要因为 ID 中有
    anthropic/
    anthropic/
    就直接放进
    my-relay
    my-relay
    ;只有 Claude 同时出现在 OpenAI 认证视图,并且 Chat curl 与 OpenCode 调用都返回最终文本时,才可以额外配置 OpenAI Chat 路径;
  5. 新增模型前必须先执行对应协议的 curl,并确认响应中有最终文本;
  6. 不要为了让模型出现在 OpenCode 列表中而伪造模型 ID,列表显示不等于实际可用。

**下一步:**保存 JSON 后,先做语法和 OpenCode 配置校验。


9. 校验 OpenCode 配置

9.1 校验 JSON 语法

jq empty "$HOME/.config/opencode/opencode.json"

没有任何输出且退出码为 0,表示 JSON 语法正确。

9.2 校验 OpenCode schema

opencode debug config

正常情况下会输出解析后的配置,不能出现

Config validation failed
Config validation failed
expected object
expected object
unknown key
unknown key
等错误。

如果出现:

Invalid input: expected object, received string

通常是把 provider 对象写成了字符串,或者把新版本

providers
providers
格式和本版本
provider
provider
格式混用。请检查
provider.my-relay
provider.my-relay
provider.my-relay-anthropic
provider.my-relay-anthropic
是否都是 JSON 对象。

9.3 查看已配置 provider 的模型

如果你在第 8 节使用了自定义 provider ID,请把下面命令中的名称替换为实际 ID。

opencode models my-relay opencode models my-relay-anthropic # 仅在第 8.4 节配置了 Responses provider 时执行: # opencode models my-relay-responses

如果配置了 Responses provider,请删除最后一行开头的

# 
#
后单独执行。

这些命令会列出你写入配置文件的模型。这里列出模型只代表配置已登记,不代表每个请求都成功,还要执行第 10 节的实际调用。

**下一步:**使用第 10 节的

opencode run
opencode run
发送第一条消息。


10. 在 OpenCode 中实际调用

首次验证建议使用独立临时目录,避免 OpenCode 读取当前项目的代码、指令文件或会话上下文。在 Terminal 执行:

TEST_DIR="$(mktemp -d "${TMPDIR:-/tmp}/opencode-gateway-test.XXXXXX")" printf '本次测试目录:%s\n' "$TEST_DIR"

后面的首次测试命令都使用

--dir "$TEST_DIR"
--dir "$TEST_DIR"
。这只改变测试工作目录,不会改变 OpenCode 的全局 provider 配置。

10.1 调用 OpenAI Chat provider

如果你使用了自定义 provider ID,请把命令中的

my-relay
my-relay
替换为实际 ID。

下面使用

openai/gpt-5.5
openai/gpt-5.5
作为示例。如果你的 API Key 的 OpenAI 目录没有这个 ID,请替换成自己目录中存在、并在第 7 节验证成功的 OpenAI Chat 模型;provider 写法不变。

opencode run \ --dir "$TEST_DIR" \ --model my-relay/openai/gpt-5.5 \ --format json \ '请只回复:OK'

成功时 JSON 中应有模型输出文本。

如果需要测试 DeepSeek,并且自己的目录中存在该模型,先把它加入

my-relay.models
my-relay.models
,再使用同样的 provider 写法:

opencode run \ --dir "$TEST_DIR" \ --model my-relay/deepseek/deepseek-v4-pro \ --format json \ '请只回复:OK'

10.2 调用 OpenAI Responses provider(按需)

只有已经执行第 7.2 节和第 8.4 节时,才运行此命令。把示例 ID 替换成你在

/responses
/responses
下得到最终文字的模型 ID。

opencode run \ --dir "$TEST_DIR" \ --model my-relay-responses/openai/gpt-5.5 \ --format json \ '请只回复:OK'

如果这条命令成功,说明 OpenCode 已用

@ai-sdk/openai
@ai-sdk/openai
通过
/responses
/responses
调用模型。若 curl 成功而此处失败,请回到第 12.2 节确认没有误用 Chat provider。

10.3 调用 Anthropic provider

如果你使用了自定义 provider ID,请把命令中的

my-relay-anthropic
my-relay-anthropic
替换为实际 ID。

下面使用

anthropic/claude-opus-5
anthropic/claude-opus-5
作为示例。如果你的 API Key 没有该 Claude 权限,请替换成自己 Anthropic 目录中存在、并在第 7 节验证成功的 Claude ID;按照本文已经验证的路径,继续使用
my-relay-anthropic
my-relay-anthropic

opencode run \ --dir "$TEST_DIR" \ --model my-relay-anthropic/anthropic/claude-opus-5 \ --format json \ '请只回复:OK'

如果自己的 Anthropic 目录中有 Sonnet 或 Haiku,先把对应 ID 加入

my-relay-anthropic.models
my-relay-anthropic.models
,再分别测试:

opencode run --dir "$TEST_DIR" --model my-relay-anthropic/anthropic/claude-sonnet-5 --format json '请只回复:OK' opencode run --dir "$TEST_DIR" --model my-relay-anthropic/anthropic/claude-haiku-4.5 --format json '请只回复:OK'

10.4 默认模型

配置文件中的:

{ "model": "my-relay/openai/gpt-5.5" }

表示未指定

--model
--model
时使用 GPT-5.5。如果希望默认使用 Claude,改成:

{ "model": "my-relay-anthropic/anthropic/claude-sonnet-5" }

修改后重新执行

opencode debug config
opencode debug config
,再重新运行命令。

10.5 配置完成后的效果和判断标准

完成配置后,你至少应看到一个自己有权限的模型返回最终文本。如果 API Key 同时有 OpenAI 和 Anthropic 模型权限,再分别检查下面两类结果:

OpenAI Chat provider:返回 OK my-relay/openai/gpt-5.5 Anthropic Messages provider:返回 OK my-relay-anthropic/anthropic/claude-opus-5

如果两类调用都成功,说明:

  • OpenCode 能读取配置文件;
  • API Key 已通过环境变量传入;
  • OpenAI Compatible Chat 路由可用;
  • Anthropic Messages 路由可用;
  • 至少一个 OpenAI 模型和一个 Claude 模型完成了端到端调用。

如果 API Key 没有 Claude 权限,只检查 OpenAI Chat;如果没有 OpenAI 模型,则只检查 Anthropic provider。不要为了满足示例而添加自己目录中不存在的模型。

这不说明所有模型都可用,也不说明所有高级能力都可用。其他模型必须按照第 11 节的厂商和协议规则选择 provider,并按第 7 节和本节命令单独检查。

**下一步:**按第 11 节的厂商和协议规则选择模型,不要只根据模型名称猜测协议。


11. 按厂商和协议选择模型

模型 ID 由中转站返回,厂商名称或 ID 前缀不能单独决定请求协议。配置时先确认模型属于哪类厂商,再根据该模型在你的目录和测试结果选择 provider。

下面的说明用于帮助你完成配置,不是固定模型清单。模型数量、版本和权限可能随 API Key、套餐和上游路由变化。

11.1 目录和请求结果怎么理解

状态含义下一步
✅ 成功HTTP 200,并且响应中有最终模型文本可以在这个协议下配置
❌ 无上游HTTP 400,返回
No upstream candidates
No upstream candidates
检查模型 ID、协议、权限和路由
⚠️ 上游失败HTTP 502,返回
UPSTREAM_ALL_FAILED
UPSTREAM_ALL_FAILED
Upstream failed
Upstream failed
稍后重试,仍失败时联系中转站
⏳ 客户端等待OpenCode 持续等待或重试,没有返回最终模型文本先用 curl 复现,再检查 provider
— 不在目录当前认证方式对应的
/models
/models
中没有该模型
不要在这个协议下配置

“成功”必须同时满足 HTTP 200 和有最终文本。HTTP 200 但只有思考块、没有最终文本时,仍应继续检查输出预算和响应解析。

11.2 厂商类型与协议选择

厂商或模型类型OpenAI ChatOpenAI ResponsesAnthropic MessagesOpenCode provider配置原则
OpenAI、Codex 等 OpenAI 系列通常使用只有该模型和网关明确提供时使用通常不使用Chat 用
my-relay
my-relay
;Responses 用
my-relay-responses
my-relay-responses
先按实际成功端点选择,不要把 OpenAI 模型放入 Anthropic provider
Anthropic Claude 系列只有网关明确提供兼容路由且实测成功时使用需要单独测试本文示例网关的优先且已验证路径
my-relay-anthropic
my-relay-anthropic
先测试 Anthropic Messages;ID 中的
anthropic/
anthropic/
不会自动切换协议
DeepSeek 系列可能使用按模型和网关路由确认可能使用按实际成功协议选择Chat 成功不代表 Responses 成功;如果两个协议都成功,可以分别配置
Qwen 系列可能使用按模型和网关路由确认可能使用按实际成功协议选择以自己的
/models
/models
和最小请求结果为准
其他厂商或自定义模型不能推断不能推断不能推断按协议单独配置不要根据厂商名称或模型前缀猜测协议

这里的“通常”表示常见适配方式,不是自动路由规则。每个模型仍需以自己的目录、协议请求和 OpenCode 调用结果为准。

11.3 OpenCode 配置写法

模型引用始终使用下面的格式:

<provider-id>/<model-id>

常见写法:

my-relay/openai/gpt-5.5 my-relay-responses/openai/gpt-5.5 my-relay-anthropic/anthropic/claude-opus-5 my-relay/deepseek/deepseek-v4-pro my-relay-anthropic/deepseek/deepseek-v4-pro

最后两个示例只有在 DeepSeek 分别通过 OpenAI Chat 和 Anthropic Messages 成功时才同时成立。以下写法不会自动改变协议:

my-relay/anthropic/claude-opus-5 my-relay-anthropic/openai/gpt-5.5

11.4 选择模型的实际步骤

对每个准备使用的模型,按以下顺序操作:

  1. 确认模型 ID 出现在对应认证方式的
    /models
    /models
    中;
  2. 用第 7 节的 OpenAI Chat、Responses 或 Anthropic Messages 请求测试;
  3. 只有 HTTP 200 且有最终文本时,才把模型放入对应 provider;
  4. 使用第 10 节的
    opencode run
    opencode run
    进行实际调用;
  5. OpenCode 失败时,先用同一模型、同一协议的 curl 对照,判断是网关问题还是客户端配置问题。

11.5 Claude 模型 ID 的写法

Claude 版本号和标点是路由键的一部分,必须原样复制:

下面只展示写法示例,不代表 Claude 只有这些版本。请以自己的 Anthropic

/models
/models
返回值为准。

正确:anthropic/claude-opus-4.8 错误:anthropic/claude-opus-4-8 正确:anthropic/claude-sonnet-4.6 错误:anthropic/claude-sonnet-4-6 正确:anthropic/claude-haiku-4.5 错误:anthropic/claude-haiku-4-5

错误的连字符版本会返回

No upstream candidates
No upstream candidates
,不是 OpenCode 的 Claude 功能缺失。

11.6 OpenCode 能力边界

本文配置覆盖三种请求方式,其中 Responses 是按需配置:

能力配置方式说明
OpenAI Compatible Chat
my-relay
my-relay
+
@ai-sdk/openai-compatible
@ai-sdk/openai-compatible
请求
/v1/chat/completions
/v1/chat/completions
OpenAI Responses
my-relay-responses
my-relay-responses
+
@ai-sdk/openai
@ai-sdk/openai
请求
/v1/responses
/v1/responses
,仅在第 7.2 节和第 8.4 节均完成后使用
Anthropic Messages
my-relay-anthropic
my-relay-anthropic
+
@ai-sdk/anthropic
@ai-sdk/anthropic
请求
/v1/messages
/v1/messages
,Claude 使用此方式

模型能否调用,应该这样理解:

  1. “目录中出现”表示 API Key 能看到模型 ID;
  2. “协议调用成功”表示该模型在某一个协议下返回最终文本;
  3. “OpenCode 调用成功”表示对应 provider、模型 ID 和客户端参数组合可以工作;
  4. 以上结论只适用于对应协议,不会自动推广到其他协议;
  5. 文本调用成功,不代表工具调用、流式、多模态、结构化输出、缓存、长上下文或思考参数都可用。

因此,对本文示例网关,Claude 优先使用

my-relay-anthropic
my-relay-anthropic
;配置 OpenAI 系列时,Chat 用
my-relay
my-relay
、Responses 用
my-relay-responses
my-relay-responses
;DeepSeek、Qwen 或其他模型则根据第 11.2 节和实际测试结果选择 provider。未来如果网关为 Claude 增加其他协议路由,也必须重新完成目录、curl 和 OpenCode 三层验证。

**下一步:**需要进一步了解协议字段时,阅读第 12 节;遇到错误时进入第 13 节。


12. OpenCode 的请求协议限制

12.1 三种协议的硬性差异

协议不能只修改 URL 后继续沿用另一种请求体。客户端必须同时匹配端点、认证头、请求结构和响应解析方式。

项目OpenAI Chat CompletionsOpenAI ResponsesAnthropic Messages
端点
POST /v1/chat/completions
POST /v1/chat/completions
POST /v1/responses
POST /v1/responses
POST /v1/messages
POST /v1/messages
认证头
Authorization: Bearer API_KEY
Authorization: Bearer API_KEY
Authorization: Bearer API_KEY
Authorization: Bearer API_KEY
x-api-key: API_KEY
x-api-key: API_KEY
必要版本头
anthropic-version: 2023-06-01
anthropic-version: 2023-06-01
输入字段
messages
messages
max_tokens
max_tokens
input
input
max_output_tokens
max_output_tokens
messages
messages
max_tokens
max_tokens
,系统提示通常放顶层
system
system
常见最终文本
choices[0].message.content
choices[0].message.content
output[].content[].text
output[].content[].text
output_text
output_text
content[]
content[]
type=text
type=text
text
text
本文 OpenCode provider
my-relay
my-relay
my-relay-responses
my-relay-responses
,按第 8.4 节配置
my-relay-anthropic
my-relay-anthropic
使用 Messages

必须遵守:

  1. anthropic/claude-opus-5
    anthropic/claude-opus-5
    中的
    anthropic/
    anthropic/
    只是模型 ID 的一部分,不会自动选择 Anthropic runtime;
  2. my-relay/anthropic/claude-opus-5
    my-relay/anthropic/claude-opus-5
    仍走 OpenAI Chat;如果该模型没有通过 Chat 验证,不应使用此写法;
  3. my-relay-anthropic/anthropic/claude-opus-5
    my-relay-anthropic/anthropic/claude-opus-5
    会走本文已经验证的 Anthropic Messages 路径;
  4. Authorization: Bearer
    Authorization: Bearer
    x-api-key + anthropic-version
    x-api-key + anthropic-version
    会得到不同模型视图,不能只查询一次
    /models
    /models
  5. Chat 成功不代表 Responses 成功;同一个模型需要分别测试;
  6. Anthropic Messages 成功不代表 OpenAI Chat 成功;Claude 通常应使用 Anthropic provider;
  7. AI Gateway 不保证自动把 OpenAI
    tool_calls
    tool_calls
    转成 Anthropic
    tool_use
    tool_use
    ,也不保证反向转换。

12.2 Responses 必须使用独立 provider

my-relay
my-relay
使用的是:

@ai-sdk/openai-compatible → OpenAI Compatible Chat Completions

它不会因为某个模型在

/v1/responses
/v1/responses
成功,就自动改变为 Responses。若需要使用 Responses,必须先完成第 7.2 节的标准 curl,再按第 8.4 节配置
my-relay-responses
my-relay-responses
@ai-sdk/openai
@ai-sdk/openai
。不能把现有
my-relay
my-relay
当作 Responses provider。

12.3 OpenCode 不自动回退

一次调用选定 provider 后,请求协议固定:

Chat 失败 ≠ 自动改用 Responses ≠ 自动改用 Anthropic Messages ≠ 自动换成另一个模型

需要切换协议时,必须显式选择另一个 provider;需要切换模型时,必须显式填写另一个精确 ID。

12.4 SDK 可能改变请求参数

OpenCode 通过 AI SDK runtime 组装请求。即使裸 curl 成功,客户端仍可能因为自动添加思考、工具、结构化输出或流式相关字段而出现差异。

本文只要求最小文本请求成功,不等于以下能力都已确认:

  • streaming 流式输出;
  • tool calling / function calling;
  • JSON schema 或严格结构化输出;
  • 图像、文件和多模态输入;
  • prompt caching;
  • 长上下文接近上限时的行为;
  • 模型特定的思考预算字段。

例如某些客户端给请求加入不被中转站接受的

thinking_budget
thinking_budget
,可能返回参数校验错误。遇到此类问题,先用第 7 节的最小 curl 复现,再逐个减少客户端高级参数。

12.5 配置上限不是服务端承诺

示例中的:

{ "limit": { "context": 200000, "output": 8192 } }

只是告诉 OpenCode 如何估算上下文和输出预算。它不能扩大模型实际能力、账号额度或中转站限制,也不能保证所有模型都支持相同的工具、图像或思考能力。

**下一步:**如果请求失败,按第 13 节从网络、认证、协议、模型和 provider 逐层排查。


13. 常见错误与定位顺序

13.1 先看错误属于哪一层

建议按以下顺序定位:

网络连接 ↓ 认证头和 API Key ↓ 端点和请求协议 ↓ 模型 ID 与协议路由 ↓ OpenCode provider runtime ↓ 高级参数、工具或流式能力

13.2 错误对照表

现象常见原因处理方式
Could not resolve host
Could not resolve host
、连接超时
DNS、网络、代理或 VPN先访问 Base URL,检查公司网络和 VPN;这不是模型路由结论
HTTP
401
401
403
403
API Key 错误、过期或无权限重新生成 Key,确认当前 Terminal 使用的是同一 Key,不要把 Key 发出来
No upstream candidates
No upstream candidates
模型 ID 不存在、协议不匹配、账号无该上游权限重新执行对应协议的
/models
/models
,核对 provider 和精确 ID
model_not_found
model_not_found
ID 拼写或点号/连字符错误复制实时目录的完整 ID;Claude 使用
4.8
4.8
4.6
4.6
,不要改成
4-8
4-8
4-6
4-6
HTTP
502
502
503
503
upstream failed
upstream failed
上游暂时故障、网关没有候选或模型未路由先用另一个已知成功模型重试,再将错误时间和请求 ID 提供给中转站
OpenAI Chat 成功、Responses 失败两个端点的上游路由不同不要在 OpenCode 中把 Chat provider 当 Responses provider;单独验证和配置
Anthropic 成功、OpenAI 失败当前模型只开放或只验证了 Anthropic 路由使用
my-relay-anthropic
my-relay-anthropic
;不要在 Chat 未验证时使用
my-relay
my-relay
配置报
expected object, received string
expected object, received string
provider 被写成字符串或格式混用检查
provider
provider
是对象;OpenCode
1.18.18
1.18.18
使用单数
provider
provider
OpenCode 列表有模型但调用失败列表只是注册信息,或 provider/runtime 不匹配先做标准 curl,再用相同 provider 做最小 OpenCode 调用
HTTP 200 但看不到最终文本输出预算过小、只返回思考块或解析字段不对先提高到
1024
1024
,必要时提高到
4096
4096
;仍无最终文本时不能标记为可用
database is locked
database is locked
多个 OpenCode 进程同时访问本地状态数据库等待正在运行的 OpenCode 命令结束,再串行重试;这不是网关或模型错误

13.3
No upstream candidates
No upstream candidates
的判断方法

按以下顺序执行:

opencode models my-relay opencode models my-relay-anthropic

然后分别用第 7 节的请求测试同一个模型:

OpenAI 模型 → /chat/completions + Bearer Claude 模型 → /messages + x-api-key + anthropic-version

如果正确的模型 ID 在正确协议下仍然失败,才需要让中转站检查上游候选、账号权限和路由配置。不要通过不断修改 provider 名称或在模型 ID 中添加后缀来“碰运气”。

13.4 如何区分 VPN 问题和模型问题

连接不上域名 / TLS 超时 → 网络、代理、防火墙或 VPN HTTP 401 / 403 → API Key 或权限 HTTP 400 No upstream candidates → 模型、协议或上游路由 HTTP 502 upstream failed → 上游暂时故障或模型未路由 HTTP 200 有文本 → 该协议、该模型、该 API Key 的最小调用成功

**下一步:**确认问题层级后,阅读第 14 节了解使用边界和提交问题所需信息。


14. 如何判断产品支持范围

模型是否能在 OpenCode 中使用,不只取决于模型名称,还取决于 API Key 权限、请求协议、provider 配置和上游路由。遇到不同模型时,可以用下面的方式判断:

14.1 四种结果分别代表什么

看到的结果表示什么下一步
/models
/models
中没有模型
当前 API Key 或协议视图没有提供该模型检查认证头、权限和模型 ID,不要强行加入配置
/models
/models
中有模型
当前 API Key 能看到该模型 ID继续执行对应协议的 curl
curl 返回 HTTP 200 且有最终文本该模型在这个协议下可以进行最小文本调用使用同一协议对应的 OpenCode provider
curl 成功但 OpenCode 失败客户端 provider、SDK 参数或模型登记方式不匹配对照第 12 节检查 provider 和请求参数

14.2 使用产品时需要遵守的边界

  1. Base URL 必须使用中转站提供的地址,并确认是否已经包含
    /v1
    /v1
  2. OpenAI 和 Anthropic 的认证头不同,不能混用;
  3. my-relay
    my-relay
    代表 OpenAI Compatible Chat,
    my-relay-responses
    my-relay-responses
    代表 OpenAI Responses,
    my-relay-anthropic
    my-relay-anthropic
    代表 Anthropic Messages;
  4. 本文示例网关的 Claude 优先使用 Anthropic Messages;模型 ID 中出现
    anthropic/
    anthropic/
    不会自动切换协议;
  5. Responses 必须按第 8.4 节配置独立 provider,不能把 Chat provider 当成 Responses provider;
  6. 模型在某个协议下成功,不代表在其他协议下也成功;
  7. 最小文本调用成功,不代表工具、流式、多模态、结构化输出、缓存、长上下文或思考参数都可用;
  8. 模型名称、版本号和标点必须与
    /models
    /models
    返回值完全一致。

14.3 提交问题时应提供什么

如果按照本文仍然失败,无需提供 API Key。请提供以下脱敏信息:

  • OpenCode 版本:
    opencode --version
    opencode --version
  • 使用的 provider ID:例如
    my-relay
    my-relay
    my-relay-anthropic
    my-relay-anthropic
  • 模型 ID;
  • 使用的协议:OpenAI Chat、Responses 或 Anthropic Messages;
  • HTTP 状态码;
  • 请求时间和 request ID;
  • 脱敏后的错误摘要;
  • opencode debug config
    opencode debug config
    是否通过。

不要直接粘贴完整的

opencode run --format json
opencode run --format json
错误输出。除完整的
Authorization
Authorization
x-api-key
x-api-key
、Cookie、请求体和真实令牌外,还应删除或替换以下内容:

  • virtualApiKeyAlias
    virtualApiKeyAlias
    tenantId
    tenantId
    等租户信息;
  • 上游供应商名称、上游 Base URL 和账号别名;
  • endpoint_id
    endpoint_id
    、内部路由编号和完整重试历史;
  • 完整
    responseBody
    responseBody
    ,其中可能再次嵌套上述信息。

request ID 通常可以保留,用于支持人员查询服务端日志。支持人员会根据版本、时间、模型、协议、HTTP 状态和 request ID 判断网络、权限或上游路由问题。

**下一步:**完成第 15 节安全检查,再用第 16 节清单逐项确认。


15. 安全与日常运维

15.1 API Key 安全

  • 不要把 Key 写入
    opencode.json
    opencode.json
  • 不要把 Key 写入命令参数、聊天记录、工单、截图或 Git;
  • 不要在排查时执行
    env
    env
    set
    set
    echo "$CLICKZETTA_API_KEY"
    echo "$CLICKZETTA_API_KEY"
  • 分享日志前,删除
    Authorization
    Authorization
    x-api-key
    x-api-key
    、Cookie、租户信息、上游地址、内部端点编号、完整重试历史和请求体中的敏感字段;
  • 不要直接分享
    opencode run --format json
    opencode run --format json
    的完整错误事件,先按第 14.3 节整理为脱敏摘要;
  • 怀疑泄露时立即在中转站后台撤销并重新生成 Key。

**下一步:**完成第 16 节的最终成功检查。

15.2 配置备份和恢复

修改前备份:

cp -p "$HOME/.config/opencode/opencode.json" \ "$HOME/.config/opencode/opencode.json.$(date +%Y%m%d-%H%M%S).bak"

恢复时先确认目标文件路径,再覆盖当前配置。恢复后必须重新执行:

jq empty "$HOME/.config/opencode/opencode.json" opencode debug config

15.3 什么时候需要重新验证

以下情况发生后,应重新执行

/models
/models
、curl 和 OpenCode 最小文本测试:

  • 中转站更换 Base URL 或网关版本;
  • API Key 权限、套餐或上游账号变化;
  • 模型版本号或模型 ID 变化;
  • OpenCode 或 AI SDK runtime 升级;
  • 出现持续的
    502
    502
    No upstream candidates
    No upstream candidates
    或输出格式异常。

16. 最终成功检查表

逐项确认:

  • opencode --version
    opencode --version
    能返回版本;
  • CLICKZETTA_API_KEY
    CLICKZETTA_API_KEY
    已加载,但没有写进配置文件;
  • RELAY_BASE_URL
    RELAY_BASE_URL
    只包含一个
    /v1
    /v1
  • 已查询自己的 OpenAI 和 Anthropic
    /models
    /models
    ,没有盲目复制本文示例模型;
  • OpenAI
    /models
    /models
    已按自己的 API Key 确认 OpenAI/DeepSeek/Qwen 视图;
  • Anthropic
    /models
    /models
    已按自己的 API Key 确认 Qwen、DeepSeek 和 Claude 权限范围;
  • my-relay
    my-relay
    使用
    @ai-sdk/openai-compatible
    @ai-sdk/openai-compatible
  • 如使用 Responses,
    my-relay-responses
    my-relay-responses
    使用
    @ai-sdk/openai
    @ai-sdk/openai
  • my-relay-anthropic
    my-relay-anthropic
    使用
    @ai-sdk/anthropic
    @ai-sdk/anthropic
  • jq empty
    jq empty
    通过;
  • opencode debug config
    opencode debug config
    通过;
  • 每个已配置 provider 都能通过
    opencode models <provider-id>
    opencode models <provider-id>
    列出模型;
  • 首次实际调用使用了独立临时目录,没有在业务项目目录中直接测试;
  • 至少一个自己目录中的 OpenAI Chat 模型实际调用成功;
  • 如使用 Responses,至少一个 Responses 模型通过
    my-relay-responses
    my-relay-responses
    实际调用成功;
  • 如果 API Key 有 Claude 权限,至少一个 Claude 模型通过
    my-relay-anthropic
    my-relay-anthropic
    实际调用成功;
  • 每个准备使用的模型都在自己的对应协议目录中,并完成了最小文本请求;
  • Claude 使用点号版本 ID,而不是连字符版本 ID;
  • 没有把 OpenCode 的 Chat provider 当成 Responses provider;
  • 最小文本测试成功,没有把未确认的工具、流式、多模态能力当成已支持。

17. 一键复查命令

下面命令不会打印 API Key,可在排查时依次执行:

echo "OpenCode: $(opencode --version)" echo "Config: $HOME/.config/opencode/opencode.json" test -n "$CLICKZETTA_API_KEY" && echo 'API Key: loaded' || echo 'API Key: missing' jq empty "$HOME/.config/opencode/opencode.json" && echo 'JSON: valid' opencode debug config >/dev/null && echo 'OpenCode config: valid' opencode models my-relay opencode models my-relay-anthropic # 仅在已配置 Responses provider 时执行: # opencode models my-relay-responses

最小实际调用:

下面命令使用示例模型。如果自己的实时目录没有对应 ID,请替换为同一协议下已经验证成功的模型;不要因为模型 ID 不同,就修改 provider runtime。第三条仅在你已配置并验证 Responses provider 时执行。

if [ -z "${TEST_DIR:-}" ]; then TEST_DIR="$(mktemp -d "${TMPDIR:-/tmp}/opencode-gateway-test.XXXXXX")" fi printf '本次测试目录:%s\n' "$TEST_DIR" opencode run --dir "$TEST_DIR" --model my-relay/openai/gpt-5.5 --format json '请只回复:OK' opencode run --dir "$TEST_DIR" --model my-relay-anthropic/anthropic/claude-opus-5 --format json '请只回复:OK' # opencode run --dir "$TEST_DIR" --model my-relay-responses/openai/gpt-5.5 --format json '请只回复:OK'

如果已配置的模型都返回实际文本,说明 OpenCode 已通过相应协议接入中转站。其他模型仍应按照第 11 节的厂商和协议规则选择 provider。


18. 结论

OpenCode 接入中转站的核心不是“把 Base URL 填进去”,而是同时满足以下关系:

模型 ID + provider ID + AI SDK runtime + 请求端点 + 认证头 + 上游协议路由 = 实际可用调用

配置时可以先记住三条:

OpenAI、DeepSeek、Qwen(Chat) → my-relay/<model-id> OpenAI Responses → my-relay-responses/<model-id> Claude,以及 Anthropic 方式调用的 Qwen/DeepSeek → my-relay-anthropic/<model-id>

Claude 一般使用 Anthropic Messages;OpenAI 系列使用 Chat 或 Responses 时分别使用对应 runtime;DeepSeek、Qwen 和其他厂商模型需要根据自己的目录和协议测试结果选择 provider。任何新模型或新协议都应先经过

/models
/models
、标准 curl、OpenCode 实际调用三层检查,再投入使用。


19. 相关资料

联系我们
预约咨询
微信咨询
电话咨询
邮件咨询