现象
上篇接好了 CommandCode GOAT 套餐,模型能正常对话,但我一直没细看一个细节:deepseek-v4-flash 切不出思考深度。
在 opencode go 套餐里同一批模型明明可以切思考档位,换到 goat 上全没了。第一反应是”goat 套餐不支持”——但排查下来根本不是套餐的事,是配置漏了一环。
太长不看的结论
配置文件再改一下,需要能选思考深度的模型,都给加一句配置:"reasoning": true
就行了。
比如
"deepseek/deepseek-v4-flash": {
"name": "DeepSeek V4 Flash (latest)",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
啊顺便,今天把GOAT套餐的用量测算也做成实时表格了:

项目在: https://github.com/mousebomb/opencode-go-limits
精简了一下配置
{
"$schema": "https://opencode.ai/config.json",
"permission": {
},
"mcp": {
},
"provider": {
"goat": {
"npm": "@ai-sdk/openai-compatible",
"name": "goat",
"options": {
"baseURL": "https://api.commandcode.ai/provider/v1",
"headers": {}
},
"models": {
"deepseek/deepseek-v4-flash-vision-exp": {
"name": "DeepSeek V4 Flash Vision (exp)",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"Qwen/Qwen3.8-Flash": {
"name": "Qwen 3.8 Flash",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"stepfun/Step-3.7-Flash": {
"name": "Step 3.7 Flash",
"limit": {
"context": 256000,
"output": 262144
},
"reasoning": true
},
"poolside/laguna-s-2.1-free": {
"name": "Laguna S 2.1",
"limit": {
"context": 256000,
"output": 262144
},
"reasoning": true
},
"meta/muse-spark-1.2": {
"name": "Muse Spark 1.2",
"limit": {
"context": 1048576,
"output": 262144
},
"reasoning": true
},
"meta/muse-spark-1.2-contributor": {
"name": "Muse Spark 1.2 Contributor",
"limit": {
"context": 1048576,
"output": 262144
},
"reasoning": true
},
"xai/grok-4.5": {
"name": "Grok 4.5",
"limit": {
"context": 500000,
"output": 262144
},
"reasoning": true
},
"xai/grok-4.6": {
"name": "Grok 4.6",
"limit": {
"context": 500000,
"output": 262144
},
"reasoning": true
}
}
},
"goat-zdr": {
"npm": "@ai-sdk/openai-compatible",
"name": "goat-zdr",
"options": {
"baseURL": "https://api.commandcode.ai/provider/v1",
"headers": {
"x-cmd-zdr": "1"
}
},
"models": {
"deepseek/deepseek-v4-pro": {
"name": "DeepSeek V4 Pro (latest)",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"deepseek/deepseek-v4-flash": {
"name": "DeepSeek V4 Flash (latest)",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"deepseek/deepseek-v4-flash-fast": {
"name": "DeepSeek V4 Flash Fast",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"moonshotai/Kimi-K3": {
"name": "Kimi K3",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"moonshotai/Kimi-K2.7-Code": {
"name": "Kimi K2.7 Code",
"limit": {
"context": 256000,
"output": 262144
},
"reasoning": true
},
"moonshotai/Kimi-K2.7-Code-Highspeed": {
"name": "Kimi K2.7 Code HighSpeed",
"limit": {
"context": 262000,
"output": 262144
},
"reasoning": true
},
"moonshotai/Kimi-K2.6": {
"name": "Kimi K2.6",
"limit": {
"context": 256000,
"output": 262144
},
"reasoning": true
},
"moonshotai/Kimi-K2.5": {
"name": "Kimi K2.5",
"limit": {
"context": 256000,
"output": 262144
},
"reasoning": true
},
"z-ai/glm-5.3-flash": {
"name": "GLM-5.3 Flash",
"limit": {
"context": 1048576,
"output": 262144
},
"reasoning": true
},
"zai-org/GLM-5.3": {
"name": "GLM-5.3",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"zai-org/GLM-5.2": {
"name": "GLM-5.2",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"zai-org/GLM-5.2-Fast": {
"name": "GLM-5.2 Fast",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"zai-org/GLM-5.1": {
"name": "GLM-5.1",
"limit": {
"context": 200000,
"output": 262144
},
"reasoning": true
},
"zai-org/GLM-5": {
"name": "GLM-5",
"limit": {
"context": 200000,
"output": 262144
},
"reasoning": true
},
"MiniMaxAI/MiniMax-M3": {
"name": "MiniMax M3",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"MiniMaxAI/MiniMax-M2.7": {
"name": "MiniMax M2.7",
"limit": {
"context": 200000,
"output": 262144
},
"reasoning": true
},
"MiniMaxAI/MiniMax-M2.5": {
"name": "MiniMax M2.5",
"limit": {
"context": 200000,
"output": 262144
},
"reasoning": true
},
"xiaomi/mimo-v2.5-pro": {
"name": "MiMo V2.5 Pro",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"xiaomi/mimo-v2.5": {
"name": "MiMo V2.5",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"Qwen/Qwen3.8-Max": {
"name": "Qwen 3.8 Max",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"Qwen/Qwen3.8-27B": {
"name": "Qwen 3.8 27B",
"limit": {
"context": 262144,
"output": 262144
},
"reasoning": true
},
"Qwen/Qwen3.7-Max": {
"name": "Qwen 3.7 Max",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"Qwen/Qwen3.7-Plus": {
"name": "Qwen 3.7 Plus",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"Qwen/Qwen3.7-Flash": {
"name": "Qwen 3.7 Flash",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"Qwen/Qwen3.6-Max-Preview": {
"name": "Qwen 3.6 Max Preview",
"limit": {
"context": 200000,
"output": 262144
},
"reasoning": true
},
"Qwen/Qwen3.6-Plus": {
"name": "Qwen 3.6 Plus",
"limit": {
"context": 200000,
"output": 262144
},
"reasoning": true
},
"stepfun/Step-3.5-Flash": {
"name": "Step 3.5 Flash",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"tencent/hy3-paid": {
"name": "Tencent Hy3",
"limit": {
"context": 262144,
"output": 262144
},
"reasoning": true
},
"tencent/hy4-preview": {
"name": "Tencent Hy4 Preview",
"limit": {
"context": 1048576,
"output": 262144
},
"reasoning": true
},
"nvidia/nemotron-3-ultra-550b-a55b": {
"name": "Nemotron 3 Ultra",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"thinkingmachines/inkling": {
"name": "Inkling",
"limit": {
"context": 256000,
"output": 262144
},
"reasoning": true
},
"thinkingmachines/inkling-small": {
"name": "Inkling Small",
"limit": {
"context": 1000000,
"output": 262144
},
"reasoning": true
},
"gpt-5.6-sol": {
"name": "GPT-5.6 Sol",
"limit": {
"context": 1050000,
"output": 262144
},
"reasoning": true
}
}
}
},
"plugin": [
]
}
根因:自定义 provider 缺 reasoning 能力声明
opencode 给模型生成”思考档位”(variants)的入口是 variants() 函数,开头第一道门卫就是:
if (!model.capabilities.reasoning) return {} // 没声明推理能力 → 直接不给档位
内置 provider(opencode-go、官方 deepseek 等)的模型元数据来自 models.dev,天生带 reasoning: true 和 reasoning_options,所以能出思考档位。
而 goat 是自定义 provider(@ai-sdk/openai-compatible),模型全是我在 opencode.json 里手写的。当时只写了 name 和 limit,没写 reasoning: true → 能力声明默认 false → variants() 直接返回空,TUI 自然不显示思考档位。
对照代码看得很清楚(packages/opencode/src/provider/transform.ts):
case "@ai-sdk/openai-compatible":
const efforts = [...WIDELY_SUPPORTED_EFFORTS] // ["low","medium","high"]
if (model.api.id.toLowerCase().includes("deepseek-v4")) {
efforts.push("max") // deepseek-v4 额外加 max
}
return Object.fromEntries(efforts.map(e => [e, { reasoningEffort: e }]))
也就是说:@ai-sdk/openai-compatible 的模型,只要 reasoning: true 声明到位,opencode 会按模型 ID 自动分配思考档位——deepseek-v4 系列给 low/medium/high/max。
GOAT 网关本身是支持 effort 的
顺手验证了网关层:reasoning_effort 参数被真实接受并转发,实测 deepseek-v4-flash 在不同 effort 下 reasoning tokens 数量确实有差异。档位枚举是 low|medium|high|xhigh(none 会报错),max 也能过。
结论锁定:能力在,只是 opencode 侧没被告知这个模型能推理。
修复:给模型补上 reasoning: true
在 goat 和 goat-zdr 两个 provider 的模型条目里补声明即可:
"deepseek/deepseek-v4-flash": {
"name": "DeepSeek V4 Flash (latest)",
"limit": { "context": 1000000, "output": 262144 },
"reasoning": true
}
补完重启,opencode run -m goat/deepseek/deepseek-v4-flash --variant max 实测通过,档位真实生效。
进阶疑问:给所有模型都标 reasoning:true 安全吗?
修好 deepseek 后我冒出个念头:与其逐个判断哪些模型该标,不如全部标 true,把最终裁决权交给 opencode 内置的模型判定逻辑(它内部有”哪些模型该给档位”的黑名单)。但这是否安全?
查源码发现:variants() 在给档位前有一份硬编码黑名单,命中的模型直接 return {}:
if (
id.includes("deepseek-chat") || id.includes("deepseek-r1") ||
id.includes("deepseek-v3") ||
id.includes("minimax") || (id.includes("glm") && !glm52) ||
id.includes("kimi") || id.includes("qwen")
) return {}
也就是说 kimi、qwen、glm(非5.2)、minimax(非M3) 这些即使标了 reasoning:true 也不会出思考档位——上游本来就不吃 effort 控制(实测 Kimi-K3 发 high 档 reasoning tokens 几乎无变化,印证了黑名单的合理性)。
剩下的疑问是:标了 true 但被黑名单挡下的模型,opencode 会不会偷偷往请求体塞默认 effort?用抓包实测打消了这个顾虑——给 Qwen3.8-Flash(黑名单)标 reasoning:true 后,发出的请求体里 reasoning_effort 字段完全不存在,对话行为跟没标之前一模一样。对照非黑名单的 deepseek-v4-flash,--variant high 时请求体确实带 reasoning_effort: high。
于是放心地把 goat、goat-zdr 下全部 74 个模型都标了 reasoning: true,交给 opencode 的机制去兜底。重构配置后 /models 正常、各模型实测对话正常。
最终效果对照
| 模型 | 标 reasoning:true 后 TUI 出现的思考档位 |
|---|---|
| deepseek-v4 系列(pro/flash/fast/vision) | low / medium / high / max |
| mimo-v2.5、stepfun、tencent、nemotron、inkling、gpt-5.6-sol、muse、grok 等 | low / medium / high |
| GLM-5.2 | high / max(单独特判) |
| MiniMax-M3 | 思考 开 / 关(toggle 特判) |
| Kimi 系列、Qwen 系列、GLM-5/5.1/5.3、MiniMax-M2.x | 无档位(硬编码黑名单,上游不支持 effort) |
经验小结
- 自定义 provider(openai-compatible)的模型档位全靠自己声明,
reasoning: true是给档位的必要不充分条件——能不能给、给哪些,由 opencode 内置模型判定逻辑(含黑名单)二次裁决。 - 黑名单模型标 reasoning:true 没有副作用:只影响”能否出现思考档位”这个 UI 开关,请求体不会被注入任何默认 effort 参数。放心全标。
- 修完配置记得重启 opencode(配置只在启动时加载,不热更新),然后
/models选中模型按 Tab 循环即可切档位。