Files
zend-token/docs/china-providers.md
2026-08-23 02:12:08 +08:00

20 KiB
Raw Permalink Blame History

国产 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_code0 = 成功)。

{"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_type17 的违规分类),还有 mask_sensitive_info 参数

finish_reason: "sensitive" 会直接打破 OpenAI 客户端的枚举校验——严格的 SDK(尤其是 Go/Rust 这类强类型的)会反序列化失败。中转站必须把它映射成 content_filter,同时用扩展字段保留原值。

0.3 鉴权方式没有一个统一的

方式 厂商
Authorization: Bearer <key> 智谱(现行)、Kimi 、豆包/火山方舟 、腾讯混元兼容端点 、DeepSeek
Bearer + 额外 header 百度千帆 v2Bearer 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-apihttps://help.aliyun.com/zh/model-studio/qwen-api-via-dashscopehttps://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 原生接口是嵌套结构

// 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/v1region 含 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_thinkingthinking_budgettop_krepetition_penalty0.012.0)、enable_search / search_optionspreserve_thinking / clear_thinkingenable_code_interpretertool_streamvl_high_resolution_images
  • QwQ 等思考模型需要流式输出 ,非流式体验会因长推理阶段而劣化。
  • seed 范围 [0, 2³¹-1],与 OpenAI 的 int64 范围不同 ⚠️

2. 智谱 GLMBigModel

来源: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 下界不是 0top_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 <api_key>历史 JWT 方式仍支持 ⚠️——API Key 形如 {id}.{secret},需按点号拆分后签发含 api_key/exp/timestamp 的 JWT

默认模型为 glm-5.2。流式同样以 data: [DONE] 结束。


3. 月之暗面 KimiMoonshot

已拆分为独立文件:kimi.md2026-08-13 全量重采集,并用真实 API key 实测校验)。本节仅保留跨厂商对比时用得上的摘要,细节以那边为准——尤其 §14 列出了 10 条被实测推翻的官方文档结论。

⚠️ 域名分层:文档站/控制台 platform.moonshot.cnplatform.kimi.com301),但 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、上限是 1OpenAI 是 2),且 n>1 要求 temperature>0(隐藏耦合,文档未提)
同参数两入口行为相反(实测) 同一个 temperature=0.7OpenAI 入口 400,自家 Anthropic 入口 200 静默忽略。但 tool_choice 的限制两边一致——是选择性的不一致,不能"打不通就换入口"
流式 usage 位置可控(实测) 不传 stream_options.include_usage 时藏在 choices[0].usageOpenAI SDK 的 chunk.usage 恒为 None,会漏计费);include_usage:true 则回到顶层 + choices:[],与 OpenAI 一致。中转站补这个参数即可,无需改写响应
Partial Mode(前缀续写) 在 messages 末尾加 {"role": "assistant", "content": "...", "partial": true},模型从该前缀继续。字段名是 partialDeepSeek 叫 prefix —— 同一能力三家三个名字(另见 Anthropic 的 prefill,且 Claude 4.6+ 已禁用)
n 最多 5 仅 Moonshot V1 系列支持,新模型固定为 1
思考模型分裂成两套参数 K3 用顶层 reasoning_effortlow/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://<file_id>。与 OpenAI/Anthropic 的硬性差异
动态工具加载 工具可声明在 {"role":"system","tools":[...]}content 字段)里,位置决定可见轮次。仅 K3 支持,其他模型报 tokenization failed
finish_reason stop / length / tool_calls,与 OpenAI 一致,没有 sensitive——内容安全走 400 content_filter,比多数国产厂商干净
错误体缺字段 + 三种格式 OpenAI 入口只有 error.type/error.messagecode/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<ak-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(同一信息重复三份)。成功时无法得知剩余配额,配额管理只能本地计数

| 两个产品两套栈 | platformapi.moonshot.cnkey sk-)与 Kimi For Codingapi.kimi.com/codingkey sk-kimi-key 互不通用,模型名(kimi-k3 vs k3)、Anthropic 入口路径、限流、错误语义、tool_call id 格式全不同。⚠️ coding 侧几乎不校验 model:传 gpt-4/空字符串都返回 200 并原样回显,只有带方括号的名字被拒(且返回 401 而非 404)。详见 kimi.md §17 |

无状态 API,多轮需自行拼接历史。

context caching 已查证(原"需另行查证"结论作废):早期的独立 cache 对象 API 已被移除,现行是全自动前缀缓存——无需创建或引用 cache id。⚠️ 文档称"prompt > 256 token 才命中"实测 21 token 也完整命中。命中量同时报在 usage.cached_tokensKimi 私有)和 usage.prompt_tokens_details.cached_tokensOpenAI 兼容,中转站直接用后者即可);未命中时字段不出现而非返回 0。K3 命中 ¥2/1M、未命中 ¥20/1M,10 倍价差意味着中转站任何对 prompt 前缀的改写都会带来 10 倍成本。


4. 字节 · 豆包 / 火山方舟(Ark)

来源:https://doubao.apifox.cn/265892759e0 、搜索结果

  • Base URLhttps://ark.cn-beijing.volces.com/api/v3OpenAI 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/0m2vwrjwsv2 通告,+ 搜索结果(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 TokenAuthorization: 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 URLhttps://api.hunyuan.cloud.tencent.com/v1
  • 直接用 API Key + Authorization: BearerOpenAI 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_code0 = 成功)
业务状态码 1002 限流 / 1004 鉴权失败 / 1008 余额不足 / 1039 token 超限 / 2013 参数无效
内容安全字段 input_sensitiveoutput_sensitiveinput_sensitive_type / output_sensitive_type17 分类)、mask_sensitive_info
temperature 范围 01,非 OpenAI 的 02
top_p 默认 0.95
response_format JSON schema 仅 MiniMax-Text-01 支持
特有响应字段 reasoning_contentaudio_contentcorrect_rateJSON 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 枚举映射sensitivecontent_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 §10。Kimi 的其余待验证项已转入 kimi.md §14。
  • 百度 v2 是否仍保留 messages 奇数/交替约束 — 通告未明说,必须实测
  • 所有标 ⚠️ 的条目 — 来自搜索结果聚合,建议用真实请求逐条验证后再固化进代码。