OpenCode 模型与 Provider:多模型自由切换

Posted on Sat 03 October 2026 in AI 编程 • Sucre Liu

模型引用长什么样

OpenCode 里模型的标准引用是:

provider/model
openai/gpt-5.2
openai/gpt-5.2#high
openrouter/anthropic/claude-sonnet-4.5#high

规则要记清,否则会配出莫名其妙的值:

部分 规则
provider 到第一个 / 为止,不能含 / 或 #
model 可以再含 /,不能含 #
variant 跟在 # 后面
大小写 provider 和 model ID 区分大小写

用目录里的 ID,不要用 provider 的展示名。会话里用 /models 选,会把它列出来:

/models

选择只作用于当前会话,不会改配置文件。这一点和很多工具不同,意味着你随手试一个贵模型,不会不小心把它变成默认。

连接与默认值

大多数 provider 先连账号:

/connect
/models

设默认模型写在项目或全局配置里:

{
  "$schema": "https://opencode.ai/config.json",
  "model": "anthropic/claude-sonnet-4-5"
}

几个行为要知道:

  • 配置的默认模型只在"已启用且 provider 可用"时生效,否则回退到最新的可用模型;
  • 会话里已经选过的模型优先于配置默认;
  • 切换会话模型不会回写配置文件;
  • 根级 model 只保留 provider 和 model,不保留 variant。

最后一条是个坑:你写 "model": "openai/gpt-5.2#high" 到根级,variant 可能不生效。要变体,就在会话、run、agent、command 上指定。

变体:控成本最直接的杠杆

变体(variant)是同一个模型上的命名选项,通常对应推理强度或 token 预算:

opencode run --model openai/gpt-5.2#high "Review this migration plan"

变体名来自模型当前目录的元数据。low、high、max 这类名字不是每个模型都有,写了不存在的变体会直接报模型解析错误。

你也可以自己定义或覆盖同 ID 的变体:

{
  "providers": {
    "openai": {
      "models": {
        "gpt-5.2": {
          "variants": [
            { "id": "fast", "settings": { "reasoningEffort": "low" } },
            { "id": "deep", "settings": { "reasoningEffort": "high", "reasoningSummary": "auto" } }
          ]
        }
      }
    }
  }
}

实践里,把"日常改动用低推理、复杂决策用高推理"固化成两个变体,比每次手动切模型更省事,也更省钱。

请求覆盖:settings / headers / body

provider、model、variant 三层都可以加请求设置,应用顺序是 provider → model → variant:

{
  "providers": {
    "openai": {
      "settings": { "baseURL": "https://api.example.com/v1" },
      "headers": { "X-Team": "platform" },
      "models": {
        "gpt-5.2": {
          "settings": { "reasoningEffort": "high" },
          "body": { "store": false }
        }
      }
    }
  }
}
  • settings:provider 包选项,如 baseURL、reasoningEffort;
  • headers:附加 HTTP 头(大小写不敏感);
  • body:合并进请求体的字段。

嵌套对象合并,数组和标量后者覆盖前者。选项是 provider 特定的,换一个 provider 包可能被忽略或拒绝。

modelID 和 model:别搞反

这里有个命名陷阱,值得单独拎出来:

  • 在选择器里(会话、agent、command 的 model)用 model;
  • 在 provider 的 models 映射里,键是 OpenCode 用的 ID,modelID 才是发给 provider 的真实 ID。
{
  "model": "openai/coding-default",
  "providers": {
    "openai": {
      "models": {
        "coding-default": {
          "modelID": "gpt-5.2",
          "name": "Coding default"
        }
      }
    }
  }
}

这里 openai/coding-default 是你选的,gpt-5.2 是发给 provider 的。报错 Model unavailable 时,先核对映射的键,而不是 modelID。

本地模型:开箱发现

Ollama、LM Studio、vLLM 在默认地址上会被自动发现,不需要连接账号:

{
  "model": "ollama/gemma3:4b"
}

各自默认端点和注意点:

运行时 默认地址 注意
Ollama http://127.0.0.1:11434 只收录带 completion 能力的模型,嵌入模型不出现
LM Studio http://127.0.0.1:1234 排除嵌入模型
vLLM http://127.0.0.1:8000 先查 /health;工具调用能力无法探测,默认关闭

vLLM 那条尤其重要:工具调用要靠服务端开关(如 --enable-auto-tool-choice 和对应的 parser),而发现过程拿不到这些信息,所以发现出来的模型 tools 是关的。需要就手动在配置里声明能力。

换地址就设 settings.baseURL,并且带上 /v1(否则发现路径会对不上)。要关掉某个自动发现:

{ "plugins": ["-opencode.provider.ollama"] }

自定义 OpenAI 兼容端点

不在目录里的服务,手写一个 provider。至少给包、端点和一个模型:

{
  "model": "local/coder",
  "providers": {
    "local": {
      "name": "Local server",
      "package": "@opencode/ai/providers/openai-compatible",
      "settings": { "baseURL": "http://127.0.0.1:1234/v1" },
      "models": {
        "coder": {
          "modelID": "model-name-on-server",
          "capabilities": { "tools": true, "input": ["text"], "output": ["text"] },
          "limit": { "context": 32768, "output": 8192 }
        }
      }
    }
  }
}

能力与上限要你手填准确值。 OpenCode 对目录外的模型有一组兜底假设(如 200k 上下文、32k 输出、支持工具),那只是假设,不是探测结果。填错会导致截断或工具调用失败。

网关与几家特殊 provider

  • OpenRouter 用原生运行时和目录,模型引用带完整 OpenRouter ID;走兼容网关时保留原生包,才能保住它的请求与推理行为。
  • Azure 需要 settings.resourceName(或环境变量),且不会查询管理 API 或自动发现部署;部署名和目录名不一致时用 modelID 映射。
  • Bedrock 走 AWS 默认凭据链,profile 或凭据是必需项,只设区域不会激活。
  • Vertex 用 ADC,且必须有可解析的 project,光有 ADC 不会激活。

这些"看起来配了却没出现"的情况,多半就卡在上面这几条。

WebSocket:长会话的省流

OpenAI、xAI 和部分 Azure Responses 模型可以每个会话保持一条 WebSocket,连续步骤只发增量:

{ "providers": { "openai": { "settings": { "transport": "websocket" } } } }

找不到通道会降级回 HTTP;连接断开下一步重连。装了 http.request/http.response 钩子的 provider 插件会留在 HTTP,保证每个请求可观测。

配错时先看这张表

现象 先查
No model is available for session 当前没有可选模型,先完成连接再选
Model unavailable: provider/model provider 未激活、ID 不存在/被禁用,或发现不再返回;自定义别名核对映射键
Cannot initialize ... NAME is required baseURL 里还有未替换的 ${NAME} 占位
Azure 报资源名缺失 配 resourceName 或对应环境变量
Vertex 不出现 缺 project(ADC 不够)
Bedrock 不出现 缺 profile 或凭据(区域不够)
Ollama 无模型 检查 /api/tags、/api/show 与 completion 能力

小结

  • 引用格式 provider/model#variant,provider 到第一个 / 为止,大小写敏感。
  • 根级 model 不保留变体;变体在会话/run/agent/command 上指定。
  • modelID 是"发给 provider 的 ID",别和选择器的 model 搞混。
  • 本地模型自动发现,但 vLLM 的工具能力探测不到,要手配。
  • 目录外模型的能力/上限要手填准确,别信兜底假设。

下一篇讲怎么把这套能力组织成你自己的工具:自定义 agent、技能与命令。