客户端接入与网关差异
本章讲两件事:各客户端怎么连上网关;连上之后,网关的行为和直连上游有什么不同。后者只讲你会观察到什么、怎么应对,不讲背后实现。
客户端接入
通用规则:把客户端的 base_url 指向网关,API key 填你在网关签发的访问密钥,模型名填你在网关配的名字。
OpenAI SDK(Python / Node)
base_url = http://<host>:7890/v1
api_key = <你的访问密钥>curl:
curl http://localhost:7890/v1/chat/completions \
-H "Authorization: Bearer <你的访问密钥>" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o","messages":[{"role":"user","content":"hi"}]}'Embeddings / Images / Audio / Rerank 同理,完整路径见 端点清单。
Anthropic SDK
base_url = http://<host>:7890
api_key = <你的访问密钥> # 通过 x-api-key 头发送curl:
curl http://localhost:7890/v1/messages \
-H "x-api-key: <你的访问密钥>" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{"model":"claude-sonnet","max_tokens":1024,"messages":[{"role":"user","content":"hi"}]}'Anthropic SDK 默认把路径拼成
/v1/messages,所以 base_url 填到根(不带/v1)。
Google Gemini SDK
api_key = <你的访问密钥> # 通过 x-goog-api-key 头发送
base_url = http://<host>:7890curl:
curl "http://localhost:7890/v1beta/models/gemini-2.0-flash:generateContent" \
-H "x-goog-api-key: <你的访问密钥>" \
-H "Content-Type: application/json" \
-d '{"contents":[{"parts":[{"text":"hi"}]}]}'DashScope
两种接法:
- 透传:
POST /v1/services/{*rest},请求体原样发给 DashScope 上游。 - 翻译:
POST /v1/chat/completions,网关把 OpenAI 格式翻译成 DashScope 格式。
任意协议透传
当客户端协议与目标协议相同、你想完全绕过翻译时:
curl http://localhost:7890/v3/<模型名>/<任意后续路径> \
-H "Authorization: Bearer <你的访问密钥>" \
-d '{ ...原样请求体... }'/v3/{model}/{*rest} 把请求体原样转发到该模型配置的目标上游。
Cherry Studio 等第三方客户端
填法:
- API 地址:
http://<host>:7890/v1(OpenAI 兼容) - API Key:网关访问密钥
- 模型:填网关里配的模型名
部分客户端按 model id 推断是否支持 function calling。若工具调用不生效,检查模型名是否落在客户端的能力识别规则内,或在客户端侧手动开启。
网关与原生 API 的差异
直连上游 vs 经网关,调用方会观察到这些不同。
长时间推理时收到 :keep-alive 注释行
流式请求中,如果上游推理时间较长,网关会周期性发送 SSE 注释行 :keep-alive 保持连接活跃,防止中间代理因空闲超时断开。
- 这是 SSE 注释(以
:开头),不是数据事件,SSE 客户端标准实现会自动忽略,无需特殊处理。 - 如果你手写 SSE 解析,跳过以
:开头的行即可。
上游流异常时收到 _gateway_warning 字段
当上游流在传输中途异常中断时,网关不会直接报错打断你的对话,而是:
关闭尚未结束的内容块;
在 SSE 流里插入一个
_gateway_warning扩展字段,告诉你中断原因(含reason/detail/last_finish_reason/timestamp);发送正常的终止序列,让客户端能正常收尾。
_gateway_warning是网关的协议扩展字段(带下划线前缀)。解析流时如果看到它,说明这次响应中途出了问题,可据此记录或告警。设计目的是避免 Claude Code 这类客户端因流异常而中断整段对话。
错误码与重试
经网关时你会遇到这些状态码(完整速查见 错误码):
| 状态码 | 含义 | 你的处理 |
|---|---|---|
| 429 | 被限流(每密钥/每 IP/上游) | 看 Retry-After 头等待后重试;无该头则按响应体提示 |
| 503 | 服务过载/不可用/并发达上限 | 退避后重试 |
| 504 | 超时 | 退避后重试 |
| 502 | 上游故障 | 网关通常已自动故障转移到其他节点;持续 502 检查上游配置 |
429 响应体有两种格式:每密钥限流返回纯文本(
Rate limit exceeded (N requests per Ns). Retry after Ns),每 IP 限流和上游限流返回 JSON。解析 429 时要兼容纯文本与 JSON 两种体。
上游故障时自动转移到其他节点
如果你的模型配了负载均衡(见 负载均衡字段),上游某节点故障时,网关会自动把请求重试到其他节点。你会观察到:
- 响应可能来自不同于上一次的节点(正常现象)。
- 如果所有节点都不可用,返回 503。
单上游(非负载均衡)不会跨节点转移,上游故障直接返回 502。
跨协议工具调用
当客户端协议和上游协议不同、且请求带工具调用时:
- 网关自动翻译
tools/tool_choice/tool_calls等字段。 tool_call_id在跨协议往返中必须保留原值——你在多轮工具对话里回传的tool_call_id要和网关给你的完全一致,否则上游无法匹配。- Anthropic 面向客户端:响应里的
tool_useid 由网关合成为全局唯一的toolu_id(不透传上游原始 id),客户端原样回显即可。 - Anthropic 面向客户端:请求历史里的
tool_useid 必须全局唯一,重复时网关回400 invalid_request_error(tool_use ids must be unique),与 Anthropic 官方 API 一致。 - 流式工具调用期间,网关持续转发增量片段,保证长工具调用时始终有事件流动。
常见问题
Q:客户端报「stream 超时」或连接断开? 检查客户端和网关之间是否有反向代理,其空闲超时是否短于网关 keep-alive 间隔。调大反代超时,或调小 STREAMING_KEEPALIVE_SECONDS(默认 15 秒)。
Q:响应里混进了 _gateway_warning,是上游返回的吗? 不是,是网关加的。说明上游流中途断了。看里面的 reason/detail 判断是否需重试。
Q:流式请求被全局并发限制挡了,返回 503? 网关有全局并发上限。高峰期短暂 503 属正常,退避重试即可。如需调高上限联系管理员。
