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_tokensAnthropic Messages 要求传入 max_tokens第三节第 3 步
400,messages 角色不合法系统提示放进了 messages,应放在顶层 system第三节第 3 步
400 或 404,模型不存在模型名拼错,或密钥所属分组里没有该模型第三节第 3 步
流式输出为空读取了其他厂商的事件名或增量字段第三节第 4 步

二、OpenAI、Anthropic、Gemini 的接口差在哪里?

三家的路径、鉴权头、请求字段和读取位置各不相同,换一个 Base URL 无法直接通用。下表在本地模拟服务上抓包核对过请求路径和请求头。

接口请求路径鉴权头请求体关键字段读取文本的位置
OpenAI Chat CompletionsPOST /v1/chat/completionsAuthorization: Bearermessageschoices[0].message.content
OpenAI ResponsesPOST /v1/responsesAuthorization: Bearerinputresponse.output_text
Anthropic MessagesPOST /v1/messagesAuthorization: Bearer(SDK 的 api_key 参数)model、max_tokens(必填)、messages、顶层 systemtype 为 text 的内容块
Gemini InteractionsPOST /v1beta/interactionsx-goog-api-keymodel、inputinteraction.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.0 resources/messages/messages.py)。
  • 系统提示放在顶层 system,不放进 messages。
  • OpenAI Responses 用 input,Chat Completions 用 messages,不能混用。
  • 模型名必须是当前密钥可用的名字,网关通常按分组限制模型。

第 4 步:流式输出为什么为空?

流式输出为空时,先确认读取的事件名和增量字段与该厂商一致。

接口文本增量的位置
OpenAI Chat Completionschoices[0].delta.content
OpenAI Responses事件类型 response.output_text.delta
Anthropic Messagescontent_block_delta 中 delta.type 为 text_delta 时读取 delta.text
Gemini Interactionsstep.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,能直接切换到另一家模型吗?

不能完整切换。兼容入口只覆盖部分字段,工具调用、流式和多模态要逐项测试。

参考资料

  1. anthropic-sdk-python:https://github.com/anthropics/anthropic-sdk-python
  2. openai-python:https://github.com/openai/openai-python
  3. 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|可信度:文末标注本文核对的范围和未能打开的官方页面】

Logo

更多推荐