Qwen Code 接入自定义 OpenAI 兼容 API 实战指南

实测 Qwen Code 接入 OpenAI 兼容端点的配置陷阱与请求成本。
作者用可模拟 401、429、503 的本地 mock 服务器,逐请求实测了 Qwen Code 0.25.2 接入 OpenAI 兼容端点的行为。结论包括:base URL 必须保留 `/v1`,否则 SDK 追加路径后多数网关 404;默认 `max_tokens` 为 32000,易超模型上限或占用配额;provider 条目的 `generationConfig` 整体替换顶层配置,导致顶层设置静默失效;一次 `qwen -p` 调用会发出两个请求,系统提示词约 41500 字符,托管自动记忆默认开启;SDK 与 CLI 两层重试相乘,宕机端点可在数分钟内产生 40 多个请求。文章给出配置清单,并说明循环检测是常开保护。
Qwen Code 是通义团队推出的终端编码智能体,最初从 Gemini CLI 分叉而来,但改用 OpenAI Chat Completions 协议,因此可以对接 vLLM、Ollama 的 /v1 端点、LiteLLM 或任意托管网关。这给了开发者很大的自由度——但默认配置里有不少不那么显眼的细节。一位开发者用本地 mock 服务器(可模拟 401、429、503)实测了 Qwen Code 0.25.2 的每个网络请求,以下是实测结果与值得注意的配置陷阱。

快速配置:三个环境变量
最轻量的接法是三个环境变量:OPENAI_API_KEY、OPENAI_BASE_URL、OPENAI_MODEL,然后直接 qwen -p "..." 运行。无需任何配置文件,Qwen Code 就会选择 OpenAI 兼容路径,发送带 Bearer 鉴权、stream: true 和工具列表的请求。
实测中有两个容易踩的坑。
base URL 必须保留 /v1。 Qwen Code 使用官方 OpenAI Node SDK,它会在你给的地址后追加 /chat/completions。如果 OPENAI_BASE_URL=https://host(不带 /v1),请求会发到 /chat/completions,多数网关直接回 404。
max_tokens 默认是 32000。 每次仅用环境变量的请求都携带 "max_tokens": 32000。部分服务器会拒绝超过模型输出上限的值,另一些则会按这个额度预留配额。如果你的模型输出上限更低,需要手动设置。
密钥错误时的行为倒是很干净:一次请求,报 [API Error: 401 Invalid API key],退出码 1,不重试。
OpenAI Chat Completions 协议 是目前事实上的 LLM 推理接入标准,主流自托管框架都实现了它:vLLM 提供高性能生产推理,Ollama 面向本地轻量部署,LiteLLM 则做多供应商统一代理与密钥管理。它们的共同点是暴露 /v1/chat/completions 端点并接受 Bearer 鉴权,因此任何按此协议实现的客户端都能无缝切换后端。Qwen Code 之所以从 Gemini CLI 分叉后改写网络层,正是为了放弃 Gemini 私有协议而获得这种可替换性。理解这一点很关键:下文所有路径、鉴权、重试行为都来自官方 OpenAI Node SDK 的默认实现,而非 Qwen Code 自己发明的约定。
环境变量优先级 也值得留意。Qwen Code 同时支持 OPENAI_API_KEY 这类通用变量和 OPENAI_BASE_URL 这类网关地址,它们构成一个临时性的“运行时模型”。这种方式适合快速验证,但不支持多 provider 并存、超时、重试次数等细粒度控制,所以官方文档把 settings.json 作为日常方案。两者同时存在时,需要明确哪一方最终决定请求参数,否则容易出现改了配置却不见生效的情况。
日常推荐:settings.json 中的 modelProviders
环境变量创建的是文档所称的“运行时模型”。日常使用更推荐在 ~/.qwen/settings.json 里配置 provider 条目,结构更清晰、也更容易管理。关键字段包括 id、name、envKey(环境变量的名称,不是密钥本身)、baseUrl,以及嵌套的 generationConfig(含 timeout、maxRetries、contextWindowSize 和 samplingParams)。另需在 security.auth.selectedType 指定 openai,并在顶层 model.name 指向同一模型 ID。
modelProviders 下的键必须是真实的协议名(openai、anthropic、gemini、vertex-ai)。自造一个 "apiclaw" 这样的键会被跳过并给出警告,除非你在顶层 providerProtocol 块里做映射。
envKey 指向的密钥有三个可放位置:项目目录的 .env 文件(有效)、~/.qwen/.env(有效)、或都没有(Qwen Code 在发送前即停止,提示缺少 API 密钥)。如果用项目 .env,务必加入 .gitignore——编码代理就在你的仓库里运行,密钥被误提交的风险真实存在。
配置生效后,请求体变为 temperature: 0.2、max_tokens: 4096,32000 的默认值消失。
会静默失效的设置
实测还发现一个隐蔽行为:同一文件里顶层的 model.generationConfig.samplingParams.top_p 从未被发送。这符合文档规则——一旦选中某个 modelProviders 条目,它的 generationConfig 会整体替换,顶层同名配置对该模型被忽略。samplingParams、customHeaders、extra_body 都是整对象替换而非合并。如果某项设置似乎没生效,先检查它是不是放错了层级。
generationConfig 的整对象替换 是 Qwen Code 配置模型的核心语义。它把采样参数(temperature、top_p、max_tokens)、超时、重试、上下文窗口等打包成一个单元,选中某个 provider 条目时整块生效,不与顶层或其他 provider 的同名字段合并。这与多数工具“就近覆盖单个键”的做法相反,因此从顶层的某个参数迁移到 provider 内部时,容易误以为设了却没生效。排查方法是把最终请求体打印出来核对,而不是反复修改配置文件。
envKey 与密钥托管 的设计意图是避免把密钥写进 JSON。envKey 只存变量名,真实值由 .env 文件或 shell 环境注入。项目级 .env 会被编码代理读取并在仓库内工作,一旦误提交就等于把密钥连同代码一起泄露;放到 ~/.qwen/.env 则可跨项目复用且不入库。多环境场景下,还可以用 shell 变量按会话覆盖,避免长期凭证散落在磁盘上。
一句“Say hi”的真实成本
非交互式运行 qwen -p "Say hi" 会发送两个请求,而不是一个。
第一个是回答请求,系统提示词达 30,553 字符,另有一个 10,963 字符的块列出可用技能和记忆路径,再加六个工具定义(glob、grep_search、read_file、skill、tool_call、tool_search)。这意味着在你输入提示词之前,已有约 41,500 字符,按每 token 四字符粗算约 1 万输入 token。
第二个请求在回答打印之后发出,系统提示词以“You are now acting as the managed memory extraction subagent”开头,重放对话并提供 write_file 和 edit 工具,用于更新 ~/.qwen/ 下的记忆文件。这是默认开启的托管自动记忆功能。
按 token 计费的计划,这个基线对短提示词影响明显;按请求数或每分钟限流计费的计划,记忆轮次会让一次性运行翻倍。可以通过 "memory": {"enableManagedAutoMemory": false, "enableManagedAutoDream": false} 关闭,之后 qwen -p "Say hi" 只发一个请求。
重试:两层机制相乘
这是 CI 或慢速端点部署前最该配置的部分。
快速恢复的 429 处理得当。mock 两次返回 Retry-After: 2 的 429 时,Qwen Code 每次等待约 2 秒,第三次请求成功。
持续宕机的服务器则是另一回事。默认设置下,mock 始终返回 503 时:OpenAI SDK 每次尝试重试三次,退避约 0.4 秒、0.9 秒、1.8 秒,请求四个一组到达;Qwen Code 自身的重试循环以逐渐增大的间隔(约 2、3、7、14、30、30 秒)重复这些组,七组共 28 个请求、约 107 秒;随后 CLI 打印 Retrying in 60s (attempt 1/10) 开始新一轮。实测在 200 秒、44 个请求时手动停止,仍在重试。
把 generationConfig 里的 maxRetries 设为 0 可去掉 SDK 层。同样宕机的端点随后只收到 7 个请求(约 74 秒),CLI 以 [API Error: 503 upstream busy] 和退出码 1 结束。脚本和 CI 任务建议将 maxRetries 设为 0 或 1,并在外层包自己的 timeout,让供应商故障在一分钟内失败而非挂起。
指数退避与 Retry-After 是理解重试放大的基础。OpenAI SDK 默认在遇到 429、5xx 和网络错误时重试,间隔按指数增长并带抖动,同时尊重服务器返回的 Retry-After 头。Qwen Code 在 SDK 之外又包了一层自己的重试循环,用于处理会话级失败。两层独立计数意味着实际请求数约为两者乘积:SDK 的 3 次尝试乘以 CLI 的 7 轮,再乘以每轮可能的多请求,就能在几分钟内累积到数十个请求。对按请求计费或严格限流的端点,这既浪费配额也可能触发封禁。把 maxRetries 调低只关闭 SDK 层,外层循环仍会继续,所以 CI 中务必同时设置进程级超时作为兜底。
一个令人欣慰的保护机制
mock 设有持续请求同一工具调用、参数不变的重复模式。Qwen Code 在三次请求后停止:Loop detection halted the run (global_tool_call_duplicate...)。这是常开保护,对有时会卡在重复步骤上的小模型或廉价模型尤其有用。
循环检测(loop detection) 针对的是智能体常见的失败模式:模型反复调用同一工具、参数完全相同,既消耗 token 又无法推进任务。Qwen Code 在连续三次相同调用后以 global_tool_call_duplicate 中止,属于无需配置的常开保护。它对能力较弱或量化程度较高的模型尤其有价值,因为这些模型更容易陷入重复步骤。需要注意的是,合法的批处理式重复调用也可能被误判,此时应调整提示词或拆分任务,而不是依赖关闭检测来绕过。
配置清单
OPENAI_BASE_URL(或baseUrl)以/v1结尾,不要带/chat/completions- 使用
modelProviders配envKey,密钥放~/.qwen/.env或被 git 忽略的项目.env - 将
samplingParams.max_tokens设为模型真实输出上限,而非 32000 默认值 - provider 模型的所有设置放在它自己的
generationConfig里,顶层配置对该模型无效 - 按请求计费或跑一次性
-p任务时关闭托管自动记忆 - CI 中把
maxRetries设低并加外层超时
需要说明的是,原文作者是 OpenAI 兼容网关 APIClaw 的开发者,示例指向其服务,观点需相应权衡;但上述行为对任何兼容端点均适用。
相关推荐

WorkBuddy智能体实战:从AI问答到自动办公的跨越
WorkBuddy是腾讯推出的AI智能体桌面工作台,能读取本地文件、操作办公软件、执行多步骤任务并定时自动运行。本文详解其核心功能、与传统AI工具的本质区别及适用场景。

Anthropic研究:LLM让形式化软件验证规模化成为可能
Anthropic Frontier Red Team研究显示,LLM已能在上百个真实开源库的RISC-V汇编级别批量生成形式化证明,覆盖123个OSS-Fuzz库、239个入口点,合计约1.8亿行Rocq证明,并在过程中发现数百量级Bug。文章解析其规格生成、证明流水线、信任边界与成本下降路径。

提示词工程入门:从写提示词到构建AI协作能力
从提示词的四大作用到提示词工程的六步流程,系统梳理AI提示词工程的核心概念、商业价值与三层局限性,帮助初学者建立对提示词工程的完整认知框架。