大模型 API 报 400、401、404 或流式输出为空,怎么排查?OpenAI、Claude、Gemini 接口对照与 Python 示例
TL;DR:换模型或换 Base URL 后报错,多数是请求格式与厂商接口定义不一致,模型本身通常没有问题。按 Base URL、鉴权头、请求体、流式事件的顺序核对,大部分问题在一两次请求内能定位。
同时调用多家模型时,可以交给统一网关处理差异,例如 灵眸 AI同时提供 Anthropic 与 OpenAI Compatible 两种协议入口。使用网关时,协议与 Base URL 的对应关系同样要核对。
一、报 400、401、404 时,常见原因是什么?
每种报错通常对应地址、鉴权头或请求体字段中的一类不一致。
下表是按接口定义归纳的常见组合,不是某家厂商的完整错误码表。具体错误以返回体中的 error 字段为准。
| 现象 | 常见原因 | 查看位置 |
|---|---|---|
| 404,地址出现 /v1/v1/ | Base URL 带了 /v1,Anthropic SDK 又会拼接 /v1/messages | 第三节第 1 步 |
| 401,鉴权失败 | 密钥不匹配,或鉴权头与协议不对应 | 第三节第 2 步 |
| 400,缺少 max_tokens | Anthropic Messages 要求传入 max_tokens | 第三节第 3 步 |
| 400,messages 角色不合法 | 系统提示放进了 messages,应放在顶层 system | 第三节第 3 步 |
| 400 或 404,模型不存在 | 模型名拼错,或密钥所属分组里没有该模型 | 第三节第 3 步 |
| 流式输出为空 | 读取了其他厂商的事件名或增量字段 | 第三节第 4 步 |
二、OpenAI、Anthropic、Gemini 的接口差在哪里?
三家的路径、鉴权头、请求字段和读取位置各不相同,换一个 Base URL 无法直接通用。下表在本地模拟服务上抓包核对过请求路径和请求头。
| 接口 | 请求路径 | 鉴权头 | 请求体关键字段 | 读取文本的位置 |
|---|---|---|---|---|
| OpenAI Chat Completions | POST /v1/chat/completions | Authorization: Bearer | messages | choices[0].message.content |
| OpenAI Responses | POST /v1/responses | Authorization: Bearer | input | response.output_text |
| Anthropic Messages | POST /v1/messages | Authorization: Bearer(SDK 的 api_key 参数) | model、max_tokens(必填)、messages、顶层 system | type 为 text 的内容块 |
| Gemini Interactions | POST /v1beta/interactions | x-goog-api-key | model、input | interaction.output_text |
来源:anthropic 2.5.0、openai 3.46.0、google-genai 2.34.0 的 SDK 源码。
三、排查时按哪四步核对?
按 Base URL、鉴权头、请求体、流式事件的顺序逐项核对。
第 1 步:Base URL 写对了吗?
Anthropic SDK 把 base_url 当作主机地址,自己拼接 /v1/messages,所以 base_url 不能带 /v1。本地模拟服务的测试结果如下,服务只返回固定 JSON:
base_url = http://127.0.0.1:8777/v1 -> 请求 /v1/v1/messages -> 404
base_url = http://127.0.0.1:8777 -> 请求 /v1/messages -> 200
两行结果说明,base_url 多写一个 /v1,请求路径就多出一段,模拟服务随之返回 404。
【建议补上 EEAT|经验:放一个你实际遇到此报错的案例,写明时间、模型、接口和错误原文】
OpenAI SDK 则要求 base_url 带 /v1,测试中请求路径为 /v1/chat/completions 和 /v1/responses。Google SDK 默认主机为 https://generativelanguage.googleapis.com/,路径由 SDK 拼出。
第 2 步:鉴权头发出去了吗?
用 curl -v 或抓包确认请求头确实发出。anthropic 2.5.0、openai 3.46.0 发送 Authorization: Bearer,google-genai 2.34.0 发送 x-goog-api-key。经网关转发时,以网关文档为准。
第 3 步:请求体和模型名填对了吗?
请求体的字段名和位置必须与接口定义一致。
- Anthropic 的
max_tokens是必填参数(来源:anthropic 2.5.0resources/messages/messages.py)。 - 系统提示放在顶层
system,不放进messages。 - OpenAI Responses 用
input,Chat Completions 用messages,不能混用。 - 模型名必须是当前密钥可用的名字,网关通常按分组限制模型。
第 4 步:流式输出为什么为空?
流式输出为空时,先确认读取的事件名和增量字段与该厂商一致。
| 接口 | 文本增量的位置 |
|---|---|
| OpenAI Chat Completions | choices[0].delta.content |
| OpenAI Responses | 事件类型 response.output_text.delta |
| Anthropic Messages | content_block_delta 中 delta.type 为 text_delta 时读取 delta.text |
| Gemini Interactions | step.delta 事件 |
流式调用本文未实测,示例只做非流式。
四、三家的 Python 示例怎么写?
三个函数各调用一家接口,密钥、模型名和 Base URL 都从环境变量读取。
pip install openai==3.46.0 anthropic==2.5.0 google-genai==2.34.0
环境变量为 ANTHROPIC_API_KEY、ANTHROPIC_MODEL、ANTHROPIC_BASE_URL(不带 /v1)、OPENAI_API_KEY、OPENAI_MODEL、OPENAI_BASE_URL(带 /v1)、GEMINI_API_KEY、GEMINI_MODEL、GEMINI_BASE_URL(主机地址)。Base URL 未设置时,SDK 使用官方默认地址。
import os
from anthropic import Anthropic
from openai import OpenAI
from google import genai
from google.genai import types
PROMPT = "请用 Python 解释 HTTP API 和 REST API 的区别。"
def ask_claude() -> str:
client = Anthropic(
api_key=os.environ["ANTHROPIC_API_KEY"],
base_url=os.environ.get("ANTHROPIC_BASE_URL"),
)
message = client.messages.create(
model=os.environ["ANTHROPIC_MODEL"],
max_tokens=512,
system="你是一名 Python 讲师。",
messages=[{"role": "user", "content": PROMPT}],
)
return "".join(block.text for block in message.content if block.type == "text")
def ask_openai() -> str:
client = OpenAI(
api_key=os.environ["OPENAI_API_KEY"],
base_url=os.environ.get("OPENAI_BASE_URL"),
)
response = client.responses.create(
model=os.environ["OPENAI_MODEL"],
input=PROMPT,
)
return response.output_text
def ask_gemini() -> str:
client = genai.Client(
api_key=os.environ["GEMINI_API_KEY"],
http_options=types.HttpOptions(base_url=os.environ.get("GEMINI_BASE_URL")),
)
interaction = client.interactions.create(
model=os.environ["GEMINI_MODEL"],
input=PROMPT,
)
return interaction.output_text
if __name__ == "__main__":
print("Claude:", ask_claude())
print("OpenAI:", ask_openai())
print("Gemini:", ask_gemini())
代码在本地模拟服务上运行过,请求路径、鉴权头和响应解析已核对。未用真实 Key 调用,模型可用性、费用和真实错误码未验证。
五、上线后要处理哪些问题?
排查通过后,线上调用还要做三件事:只对 429 限流和 5xx 做指数退避,额度类 429 不重试;为客户端设置 timeout,超时后不无限重试;记录厂商、路径、模型名、状态码和请求 ID,不记录密钥。
六、只改 Base URL 就能接入其他模型吗?
不能完整接入。只改 Base URL 不等于接口兼容,工具调用、流式和多模态要逐项测试。
- OpenAI SDK 指向 Claude 或 Gemini 的兼容入口时,只覆盖部分字段。
- Anthropic 和 Google 的 OpenAI 兼容页本次未能在本机打开,兼容范围和状态未核对。
【建议补上 EEAT|权威:引用官方兼容说明时附上链接与核验日期,并附第三方的提及】
七、上线前要检查哪些项?
- Base URL 与协议对应:Anthropic 不带 /v1,OpenAI 带 /v1,Gemini 写主机地址。
- Anthropic 请求带 max_tokens,系统提示放在顶层 system。
- 429 与 5xx 退避重试,额度类错误不重试。
八、常见问题
改了 Base URL 为什么还是报 400?
400 表示请求格式不合法,重试通常无效。先查模型名、max_tokens 和 system 的位置。
只换 Base URL,能直接切换到另一家模型吗?
不能完整切换。兼容入口只覆盖部分字段,工具调用、流式和多模态要逐项测试。
参考资料
- anthropic-sdk-python:https://github.com/anthropics/anthropic-sdk-python
- openai-python:https://github.com/openai/openai-python
- python-genai:https://github.com/googleapis/python-genai
核验日期:2026-11-05。依据 anthropic 2.5.0、openai 3.46.0、google-genai 2.34.0 的 PyPI 发布源码。
【建议补上 EEAT|可信度:文末标注本文核对的范围和未能打开的官方页面】
更多推荐



所有评论(0)