# 国产 AI Provider 的怪癖 > 采集于 2026-08-12。 > > **可信度标注**:本文件里 ✅ 表示来自厂商官方文档页面;⚠️ 表示来自搜索结果聚合或第三方资料,**落地前需要用真实请求验证**。国产厂商文档改版频繁(本次采集就遇到 moonshot.cn → kimi.com、volcengine.com → docs.volcengine.com 两处 301),且很多"历史怪癖"在新版本里已被修掉,不要照抄老博客。 国产 API 的怪癖**和欧美三家不是一个类型**。OpenAI/Anthropic/DeepSeek 的坑主要在**语义层**(thinking 怎么回传、tool_result 放哪);国产的坑主要在**协议层和运维层**:鉴权方式五花八门、HTTP 200 里藏业务错误、流式默认全量返回、内容安全是一等公民。 --- ## 0. 跨厂商的共性怪癖(最重要) 这五条是中转站架构里必须提前留出的抽象层,逐个厂商去补会很痛苦。 ### 0.1 HTTP 200 内嵌业务错误 ⚠️→✅ **MiniMax 是典型**:无论成功失败都返回 **HTTP 200**,真正的状态在 body 的 `base_resp.status_code`(0 = 成功)。 ```json {"base_resp": {"status_code": 1002, "status_msg": "rate limit"}} ``` 对中转站的直接后果:**只看 HTTP 状态码的限流检测会完全失效**——限流返回的是 200 而不是 429。重试逻辑、熔断器、计费统计全都要能读 body。 建议:网关的上游响应处理层做成"HTTP 状态码 + body 业务码"双通道判定,而不是假设 HTTP 语义可靠。 ### 0.2 内容安全是一等公民 欧美三家只有 `content_filter` / `refusal` 一个笼统信号,国产普遍把内容安全做成结构化字段: | 厂商 | 表现形式 | | --- | --- | | 智谱 GLM ✅ | `finish_reason: "sensitive"`(OpenAI 枚举里没有这个值) | | MiniMax ✅ | `input_sensitive` / `output_sensitive` 布尔,外加 `input_sensitive_type` / `output_sensitive_type`(1–7 的违规分类),还有 `mask_sensitive_info` 参数 | `finish_reason: "sensitive"` 会直接**打破 OpenAI 客户端的枚举校验**——严格的 SDK(尤其是 Go/Rust 这类强类型的)会反序列化失败。中转站必须把它映射成 `content_filter`,同时用扩展字段保留原值。 ### 0.3 鉴权方式没有一个统一的 | 方式 | 厂商 | | --- | --- | | `Authorization: Bearer ` | 智谱(现行)✅、Kimi ✅、豆包/火山方舟 ✅、腾讯混元兼容端点 ✅、DeepSeek | | Bearer + 额外 header | 百度千帆 v2(`Bearer bce-v3/ALTAK-...` + `appid` header)⚠️ | | JWT 签名(key 形如 `{id}.{secret}`,需自行签发带 exp 的 token) | 智谱(历史方式,现在仍支持)⚠️ | | `access_token` 放 query string(用 API Key + Secret Key 先换取) | 百度千帆 v1 ⚠️ | | TC3-HMAC-SHA256 云厂商签名 | 腾讯混元原生接口 ✅ | | HMAC-SHA256 签名拼进 **WebSocket URL** | 讯飞星火原生接口 ✅ | | `AK:SK` 拼接格式 | 讯飞星火 OpenAI 兼容端点 ⚠️ | 中转站的凭据存储不能假设"一个 key 一个字符串"——至少要支持 (key, secret, appid, region) 四元组,且签名逻辑要能按 provider 插拔。 ### 0.4 流式默认可能是全量累积 见 §1.2 的阿里 `incremental_output`。这是**最容易在生产上炸**的一条:不设参数时每个 SSE chunk 返回的是**从头累积的完整文本**,直接按 OpenAI 语义拼接会得到指数级重复的内容。 ### 0.5 非标参数塞 `extra_body` 国产厂商的 OpenAI 兼容模式普遍保留一批自有参数(思考开关、联网搜索、重复惩罚),官方推荐用 OpenAI SDK 的 `extra_body` 透传。中转站需要一个**参数白名单 + 透传通道**,而不是严格按 OpenAI schema 校验后丢弃未知字段。 --- ## 1. 阿里 · 通义千问 / 百炼(DashScope)✅ > 来源:https://help.aliyun.com/zh/model-studio/use-qwen-by-calling-api 、https://help.aliyun.com/zh/model-studio/qwen-api-via-dashscope 、https://www.alibabacloud.com/help/zh/model-studio/qwen-api-via-openai-chat-completions ### 1.1 四套接口并存 百炼同时提供**四种**入口,这本身就是中转站的最佳参考: 1. **OpenAI 兼容 Chat Completions** — 迁移成本最低 2. **OpenAI 兼容 Responses** — 内置联网搜索、代码解释器、网页提取,自动管理对话历史 3. **Anthropic 兼容 Messages** — 支持 thinking 和工具调用 4. **DashScope 原生** — "提供最完整的功能集和参数支持" **功能集不等价**:原生接口是超集。做中转站时若只对接 OpenAI 兼容模式,会拿不到部分能力。 ### 1.2 `incremental_output`:最大的坑 ⚠️ DashScope 原生流式下: | 取值 | 行为 | | --- | --- | | `true` | 每个 chunk 只含**新增**内容(OpenAI 语义) | | `false`(部分场景默认) | 每个 chunk 返回**从头累积的完整文本** | 如果按 OpenAI 的"delta 累加"逻辑处理 `incremental_output=false` 的流,输出会变成 `我我是我是通我是通义…` 这样的雪球。 **中转站务必显式传 `incremental_output=true`,不要依赖默认值。** ### 1.3 原生接口是嵌套结构 ```jsonc // DashScope 原生 POST /api/v1/services/aigc/text-generation/generation { "model": "qwen-plus", "input": { "messages": [...] }, // ← 嵌套 "parameters": { "temperature": 0.7, "result_format": "message" } } // 响应:output.choices[].message ← 比 OpenAI 多一层 output ``` `result_format` 取值 `text` / `message`——**取 `text` 时响应结构完全不同**(不是 choices 数组)。中转站应固定用 `message`。 ### 1.4 其他 - **原生 HTTP 流式必须加 header `X-DashScope-SSE: enable`** ⚠️,只设 `stream` 参数不生效。 - **base_url 按地域 + workspace 分片** ✅:`https://{WorkspaceId}.{region}.maas.aliyuncs.com/compatible-mode/v1`,region 含 cn-beijing / ap-southeast-1 / cn-hongkong / eu-central-1 / ap-northeast-1,另有 `https://dashscope-us.aliyuncs.com/compatible-mode/v1`。中转站的上游配置不能是单一 URL 常量。 - OpenAI 兼容模式下需走 `extra_body` 的非标参数 ✅:`enable_thinking`、`thinking_budget`、`top_k`、`repetition_penalty`(0.01–2.0)、`enable_search` / `search_options`、`preserve_thinking` / `clear_thinking`、`enable_code_interpreter`、`tool_stream`、`vl_high_resolution_images`。 - **QwQ 等思考模型需要流式输出** ✅,非流式体验会因长推理阶段而劣化。 - `seed` 范围 `[0, 2³¹-1]`,与 OpenAI 的 int64 范围不同 ⚠️。 --- ## 2. 智谱 GLM(BigModel)✅ > 来源:https://docs.bigmodel.cn/api-reference/模型-api/对话补全 端点:`POST https://open.bigmodel.cn/api/paas/v4/chat/completions`(注意路径是 `/api/paas/v4/`,不是 `/v1/`) | 怪癖 | 详情 | | --- | --- | | **`do_sample`** | 布尔,默认 `true`。为 `false` 时走贪心解码,**`temperature` / `top_p` 全部失效**。OpenAI 无此参数——中转站收到 `temperature: 0` 时应考虑翻译成 `do_sample: false` 而不是直接透传 | | **`temperature` 范围 `[0.0, 1.0]`** | 不是 OpenAI 的 0~2,超出需 clamp | | **`top_p` 范围 `[0.01, 1.0]`,默认 0.95** | 下界不是 0,`top_p: 0` 会被拒 | | **`finish_reason: "sensitive"`** | 内容被安全拦截。**不在 OpenAI 枚举内**,会打破严格客户端 | | `thinking` | `{"type": "enabled"\|"disabled", "clear_thinking": bool}`,仅 GLM-4.5+ | | `reasoning_content` | 思维链输出字段(DeepSeek 风格的事实标准) | | 工具上限 | 最多 128 个 function,另支持 web_search / 知识库检索 / MCP 工具 | | 鉴权 | 现行推荐 `Authorization: Bearer `;**历史 JWT 方式仍支持** ⚠️——API Key 形如 `{id}.{secret}`,需按点号拆分后签发含 `api_key`/`exp`/`timestamp` 的 JWT | 默认模型为 `glm-5.2`。流式同样以 `data: [DONE]` 结束。 --- ## 3. 月之暗面 Kimi(Moonshot)✅ > **已拆分为独立文件:[kimi.md](./kimi.md)**(2026-08-13 全量重采集,**并用真实 API key 实测校验**)。本节仅保留跨厂商对比时用得上的摘要,细节以那边为准——尤其 §14 列出了 10 条被实测推翻的官方文档结论。 > > ⚠️ **域名分层**:文档站/控制台 `platform.moonshot.cn` → `platform.kimi.com`(301),但 **API 数据面仍是 `api.moonshot.cn`**,没有迁到 `api.kimi.com`。另有国际站 `platform.kimi.ai` / `api.moonshot.ai`,**账号与 key 与国内站完全隔离**。 | 怪癖 | 详情 | | --- | --- | | **采样参数硬 400**(实测) | K3 / K2.7-code 把 `temperature`(1.0) / `top_p`(0.95) / `n`(1) / 两个 penalty 写死,**传其他值 400 而不是静默忽略**(实测 `invalid temperature: only 1 is allowed for this model`)。而 moonshot-v1 的 `temperature` 默认是 **0**、上限是 **1**(OpenAI 是 2),且 **`n>1` 要求 temperature>0**(隐藏耦合,文档未提) | | **同参数两入口行为相反**(实测) | 同一个 `temperature=0.7`:OpenAI 入口 **400**,自家 Anthropic 入口 **200 静默忽略**。但 `tool_choice` 的限制两边一致——**是选择性的不一致**,不能"打不通就换入口" | | **流式 `usage` 位置可控**(实测) | 不传 `stream_options.include_usage` 时藏在 **`choices[0].usage`**(OpenAI SDK 的 `chunk.usage` 恒为 `None`,会漏计费);**传 `include_usage:true` 则回到顶层 + `choices:[]`,与 OpenAI 一致**。中转站补这个参数即可,无需改写响应 | | **Partial Mode(前缀续写)** | 在 messages 末尾加 `{"role": "assistant", "content": "...", "partial": true}`,模型从该前缀继续。**字段名是 `partial`,DeepSeek 叫 `prefix`** —— 同一能力三家三个名字(另见 Anthropic 的 prefill,且 Claude 4.6+ 已禁用) | | **`n` 最多 5** | 且**仅 Moonshot V1 系列支持**,新模型固定为 1 | | 思考模型分裂成两套参数 | K3 用顶层 `reasoning_effort`(`low`/`high`/`max`,默认最贵的 `max`);K2.6/K2.5 用 `thinking` 对象;K2.7-code 用 `thinking` 但只接受 `"enabled"`(实测关闭 → 400)。⚠️ **文档称 K3 恒开不可关,实测 `thinking:{"type":"disabled"}` 有效**(`prompt_tokens` 88→21,思考模式带约 67 token 隐藏 system prompt)。⚠️ `reasoning_effort` 传 `"banana"` 也返回 200——**枚举校验形同虚设,非法值静默跑默认的 max 档** | | `reasoning_content` 明文回传 | 明文(非 Anthropic 那种加密 signature)。⚠️ **文档称 K3/K2.7-code 多轮缺失会报错,实测不报错**(200 正常继续) | | `tool_choice` 与思考互斥 | 指定具体函数 + 思考开启 → **400 `tool_choice 'specified' is incompatible with thinking enabled`**(两个入口一致)。⚠️ **但关闭思考后再指定函数 → 200 且模型不调用工具、直接幻觉出假数据**——静默错误比 400 更危险,不要把关思考当变通方案 | | tool_call id 可预测 | 格式是 **`{函数名}_{序号}`**(如 `get_weather_0`),不是 OpenAI 的随机串。多轮同名函数会**重复 id**,用它做去重键会误判 | | 多模态**不收 http URL** | 只接受 base64 data URI 和 `ms://`。与 OpenAI/Anthropic 的硬性差异 | | 动态工具加载 | 工具可声明在 `{"role":"system","tools":[...]}`(**无 `content` 字段**)里,位置决定可见轮次。仅 K3 支持,其他模型报 `tokenization failed` | | `finish_reason` | `stop` / `length` / `tool_calls`,与 OpenAI 一致,**没有 `sensitive`**——内容安全走 400 `content_filter`,比多数国产厂商干净 | | 错误体缺字段 + 三种格式 | OpenAI 入口只有 `error.type`/`error.message`(**无 `code`/`param`**);Anthropic 入口多 `request_id` 和顶层 `type`;**路径写错会掉到网关层**,返回 `{"code":5,"error":"url.not_found","message":"没找到对象","ua":"curl/8.7.1",...}`——连 `error` 字段的类型都从 object 变成 string | | 三种 429 语义相反 | `engine_overloaded_error`(退避重试)/ `exceeded_current_quota_error`(欠费,重试无用)/ `rate_limit_reached_error`(降并发)。只看状态码的通用重试会在欠费时打爆上游 | | **错误信息泄漏账号标识** | 429 的 message 原文含 `Your account org-xxx request reached organization max RPM: 3`——**org id 和 key 标识直接暴露**。响应头另有 `msh-org-id`/`msh-uid`/`msh-project-id`。中转站原样透传 = 把自己的账号广播给所有下游用户 | | 无 `x-ratelimit-*` 头 | 只在 429 时给 `retry-after` / `x-retry-after` / `msh-cooldown-seconds`(同一信息重复三份)。**成功时无法得知剩余配额**,配额管理只能本地计数 | | **两个产品两套栈** | `platform`(`api.moonshot.cn`,key `sk-`)与 **Kimi For Coding**(`api.kimi.com/coding`,key `sk-kimi-`)**key 互不通用**,模型名(`kimi-k3` vs `k3`)、Anthropic 入口路径、限流、错误语义、tool_call id 格式全不同。⚠️ **coding 侧几乎不校验 `model`**:传 `gpt-4`/空字符串都返回 200 并原样回显,只有带方括号的名字被拒(且返回 **401** 而非 404)。详见 [kimi.md](./kimi.md) §17 | 无状态 API,多轮需自行拼接历史。 ✅ **context caching 已查证(原"需另行查证"结论作废)**:早期的独立 cache 对象 API 已被移除,**现行是全自动前缀缓存**——无需创建或引用 cache id。⚠️ 文档称"prompt > 256 token 才命中",**实测 21 token 也完整命中**。命中量同时报在 `usage.cached_tokens`(Kimi 私有)和 `usage.prompt_tokens_details.cached_tokens`(OpenAI 兼容,**中转站直接用后者即可**);未命中时字段不出现而非返回 0。K3 命中 ¥2/1M、未命中 ¥20/1M,**10 倍价差**意味着中转站任何对 prompt 前缀的改写都会带来 10 倍成本。 --- ## 4. 字节 · 豆包 / 火山方舟(Ark)✅ > 来源:https://doubao.apifox.cn/265892759e0 、搜索结果 - Base URL:`https://ark.cn-beijing.volces.com/api/v3`,OpenAI SDK 直接可用。 - **`model` 字段的历史怪癖** ⚠️:早期必须先在控制台创建"推理接入点"拿到 **Endpoint ID(形如 `ep-2024...`)** 填进 `model`,而不是模型名。现在也支持直接填模型名(如 `doubao-pro-32k-240615`)。 中转站的模型别名表必须允许"一个逻辑模型名 → 一个 ep-xxx 字符串"的映射,且**不同用户的 ep id 不同**(接入点是账号级资源)。这意味着模型路由表可能需要**按租户隔离**,而不是全局共享一张表。 - usage 中含缓存相关明细字段。 - ⚠️ 抓取到的 OpenAPI 规范页**未列出 thinking 参数和完整限制**,深度思考模型(doubao-1.5-thinking 等)的参数需另查。 --- ## 5. 百度 · 文心 / 千帆 ⚠️ > 来源:https://ai.baidu.com/ai-doc/WENXINWORKSHOP/0m2vwrjws(v2 通告,✅)+ 搜索结果(v1 约束,⚠️) 百度是"新旧两代差异最大"的一家。 ### v1(历史,仍在运行)的经典怪癖 ⚠️ - **每个模型一个独立 URL**,模型名在路径里,没有 `model` 参数。 - **鉴权用 `access_token` 放 query string**:先用 API Key + Secret Key 调 `grant_type=client_credentials` 换取。 - **`messages` 必须是奇数条**。 - **role 必须 user / assistant 严格交替**:奇数位是 `user`(或 `function`),偶数位是 `assistant`,且**第一条不能是 `function`**。 - `system` 是**独立顶层字段**,不能放进 messages(和 Anthropic 一样)。 这套约束意味着**任何带连续同角色消息的 OpenAI 请求都无法直通 v1**,中转站必须做消息合并(连续 user 合并成一条)。 ### v2(现行,已 OpenAI 兼容)✅ - 端点统一为 `https://qianfan.baidubce.com/v2/chat/completions`,用 `model` 参数选模型。 - 鉴权改为 **IAM Bearer Token**:`Authorization: Bearer bce-v3/ALTAK-...`,并需要额外的 `appid` header ⚠️。 - 官方称"完全兼容 OpenAI SDK"。 - v1 在过渡期内继续可用,TPM 配额在两个版本间共享。 **中转站建议直接对接 v2**,但要注意 v2 是否仍保留 messages 交替约束——通告未明确说明,需实测验证。 --- ## 6. 腾讯混元 ✅ > 来源:https://cloud.tencent.com/document/product/1729/111007 两套接口差异极大: ### 原生接口 - **腾讯云 TC3-HMAC-SHA256 签名**(云厂商通用签名 v3),需要多步 HMAC 派生密钥(SecretDate → SecretService → SecretSigning)。POST 支持最大 10MB。 - ⚠️ 字段命名是 **PascalCase 大驼峰**(`Messages` / `Role` / `Content`),不是 OpenAI 的 snake_case。这是腾讯云全平台 API 的统一风格。 ### OpenAI 兼容接口(推荐) - Base URL:`https://api.hunyuan.cloud.tencent.com/v1` - 直接用 API Key + `Authorization: Bearer`,OpenAI SDK 无需改代码。 **中转站结论**:走兼容端点,不要碰 TC3 签名——那套签名实现成本高且容易在时钟偏移、URL 编码细节上出错。 --- ## 7. MiniMax ✅ > 来源:https://platform.minimax.io/docs/api-reference/text-post | 怪癖 | 详情 | | --- | --- | | **端点路径非标** | `https://api.minimax.io/v1/text/chatcompletion_v2`,**不是** `/v1/chat/completions` | | **HTTP 200 + `base_resp`** | 业务错误也返回 200,状态在 `base_resp.status_code`(0 = 成功) | | 业务状态码 | `1002` 限流 / `1004` 鉴权失败 / `1008` 余额不足 / `1039` token 超限 / `2013` 参数无效 | | 内容安全字段 | `input_sensitive`、`output_sensitive`、`input_sensitive_type` / `output_sensitive_type`(1–7 分类)、`mask_sensitive_info` | | `temperature` 范围 | 0–1,非 OpenAI 的 0–2 | | `top_p` 默认 | 0.95 | | `response_format` | JSON schema **仅 MiniMax-Text-01 支持** | | 特有响应字段 | `reasoning_content`、`audio_content`、`correct_rate`(JSON schema 模式下的置信度) | | usage | 单独统计 `reasoning_tokens` | `base_resp` 这一条值得再强调:**限流不返回 429**,任何依赖 HTTP 状态码的重试/熔断中间件在 MiniMax 上都是失效的。 --- ## 8. 讯飞星火 ✅ > 来源:https://www.xfyun.cn/doc/spark/ 系列页面 - **原生接口是 WebSocket,不是 HTTP** ✅。鉴权方式是用 APPID + APIKey + APISecret 做 HMAC-SHA256,把签名**拼进 WebSocket 连接 URL** 里。这在中转站架构里是完全异类——需要独立的连接管理、心跳、重连逻辑,无法复用 HTTP 连接池。 - **OpenAI 兼容 HTTP 端点**:`https://spark-api-open.xf-yun.com/v1`,用 APIPassword 认证;最新的 Spark-X2 还支持 `AK:SK` 拼接格式 ⚠️。 **中转站结论**:只对接 OpenAI 兼容 HTTP 端点。WebSocket 原生接口的接入成本远高于收益,除非需要它独有的能力(如实时语音)。 --- ## 9. 给中转站的设计清单 从上面这些怪癖倒推,网关需要的抽象层: 1. **双通道错误判定** — HTTP 状态码 + body 业务码(MiniMax `base_resp`)。不能假设 HTTP 语义可靠。 2. **可插拔签名器** — Bearer / JWT 自签 / query token / TC3-HMAC / WebSocket 签名 URL 至少五种。凭据模型要支持 (key, secret, appid, region) 而非单字符串。 3. **流式规范化层** — 统一处理"全量累积 vs 增量"(阿里 `incremental_output`)、`[DONE]` 有无、SSE header 要求(`X-DashScope-SSE`)。**这一层是国产接入的核心价值**。 4. **finish_reason 枚举映射** — `sensitive` → `content_filter`,并用扩展字段保留原值,避免打破强类型客户端。 5. **非标参数透传白名单** — `extra_body` 风格的旁路通道,而不是按 OpenAI schema 严格校验后丢弃。 6. **租户级模型路由表** — 火山方舟的 Endpoint ID 是账号级资源,模型别名映射不能全局共享。 7. **多地域 base_url** — 阿里按 region + workspace 分片,上游地址不能是常量。 8. **消息结构归一化** — 连续同角色消息合并(百度 v1 交替约束、Anthropic 单 system),作为通用前置处理。 --- ## 10. 未覆盖 / 待验证 - **零一万物 Yi、百川 Baichuan、阶跃星辰 StepFun、商汤日日新** — 未收集。 - **火山方舟深度思考模型的 thinking 参数** — 官方 OpenAPI 页未列出,需另查。 - ~~**Kimi 的 context caching**~~ — ✅ 已查证(2026-08-13):早期的独立 cache 对象 API 已移除,现为全自动前缀缓存,见 [kimi.md](./kimi.md) §10。Kimi 的其余待验证项已转入 [kimi.md](./kimi.md) §14。 - **百度 v2 是否仍保留 messages 奇数/交替约束** — 通告未明说,**必须实测**。 - 所有标 ⚠️ 的条目 — 来自搜索结果聚合,建议用真实请求逐条验证后再固化进代码。