如果你已经拿到了 API Key,却卡在 Base URL、模型名或者 401/404,这篇从一个普通文本请求开始排查。先不接 Agent,不加知识库,也不一次塞进十几个参数。
本文用通用的 Chat Completions 请求格式说明排查方法,不评测或推荐具体服务。兼容 Chat Completions,不代表每个模型都支持所有参数或所有客户端。
先分清三个地址
下表中的 example.com 和 api.example.com 只表示地址结构,不是真实可调用的模型服务。运行脚本前,必须换成你有权使用的服务在官方文档中给出的地址;不要向陌生域名发送 Key。
| 名称 | 本文示例 | 用途 |
|---|---|---|
| 网站地址 | https://example.com |
浏览网页和控制台 |
| Base URL | https://api.example.com/v1 |
作为程序拼接接口路径的前缀 |
| 完整请求地址 | https://api.example.com/v1/chat/completions |
本文实际发送 POST 请求的位置 |
下面的脚本会自行追加 /chat/completions。因此,AI_BASE_URL 不要再填完整接口地址,否则路径会重复。其他客户端是否自动补 /v1,要看它自己的说明,不能把这里的值机械照搬。
还需要两样东西:
- 你自己账户的 API 令牌,不是网站登录密码,也不是其他服务的 Key。
- 账户实际可用、支持 Chat Completions 的文本模型 ID。从控制台或模型列表核对,别把模型展示名称直接当 ID,也别照搬过时文章里的型号。
模型、权限、余额或配额都可能影响调用结果,请以账户当前状态为准。真实 API 调用可能产生费用;先确认所选模型的计费说明,只做少量测试。
一个不依赖第三方 SDK 的 Python 示例
脚本只用 Python 3 标准库。先把下面代码保存为 chat_smoke.py。
它不把 Key 写进源码;没有设置 AI_API_KEY 时,会在终端里询问,输入不回显。诊断请求不会自动跟随重定向,也不会在失败后自动重试。
python
import getpass
import json
import os
import time
from urllib.error import HTTPError, URLError
from urllib.request import HTTPRedirectHandler, Request, build_opener
class NoRedirect(HTTPRedirectHandler):
def redirect_request(self, req, fp, code, msg, headers, newurl):
return None # 带密钥的诊断请求不自动跟随重定向
def main():
base = os.environ.get("AI_BASE_URL", "").strip().rstrip("/")
model = os.environ.get("AI_MODEL", "").strip()
if not base.startswith("https://") or not model:
raise SystemExit("请设置 HTTPS 的 AI_BASE_URL 和实际可用的 AI_MODEL。")
key = (os.environ.get("AI_API_KEY") or getpass.getpass("API Key(不回显): ")).strip()
if not key:
raise SystemExit("API Key 不能为空。")
payload = {
"model": model,
"messages": [{"role": "user", "content": "请用一句话解释 HTTP 状态码 401。"}],
"stream": False,
}
request = Request(
base + "/chat/completions",
data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
headers={
"Authorization": "Bearer " + key,
"Content-Type": "application/json",
},
method="POST",
)
start = time.monotonic()
try:
with build_opener(NoRedirect()).open(request, timeout=60) as response:
result = json.load(response)
content = result["choices"][0]["message"]["content"]
if not isinstance(content, str) or not content.strip():
raise ValueError("没有普通文本回复")
print(content)
print(f"请求完成,用时 {time.monotonic() - start:.2f} 秒")
return 0
except HTTPError as error:
print(f"HTTP {error.code}:先核对地址、令牌、模型权限和服务端错误说明。")
print("未自动重试,也未输出请求头或原始错误正文。")
except (URLError, TimeoutError):
print("连接或读取失败:检查网络、代理、证书和超时;不要关闭证书校验。")
except (ValueError, KeyError, IndexError, TypeError):
print("响应不是预期的 Chat Completions 文本格式,请核对接口协议。")
return 1
if __name__ == "__main__":
raise SystemExit(main())
在 macOS / Linux 的终端里设置两个非秘密参数后运行。下方的地址和模型 ID 都是占位符,请先替换;脚本没有预设服务地址:
bash
export AI_BASE_URL='https://api.example.com/v1'
export AI_MODEL='替换成账户实际可用的文本模型ID'
python3 chat_smoke.py
Windows PowerShell 可这样设置,再用自己安装的 Python 启动脚本:
powershell
$env:AI_BASE_URL = 'https://api.example.com/v1'
$env:AI_MODEL = '替换成账户实际可用的文本模型ID'
python chat_smoke.py
AI_BASE_URL、AI_MODEL、AI_API_KEY 是本文脚本使用的变量名,不是每个客户端都认识的通用设置。请在自己的本地终端输入 Key,不要把真实 Key 粘贴进评论、截图、Git 仓库或陌生调试网站。
代码中的 timeout=60 用于限制相关阻塞操作,不是整个任务严格的 60 秒总时限。页面上打印的是这一次请求的耗时,不是模型的稳定性评测。
按现象排查,别同时改三个变量
| 现象 | 优先检查 |
|---|---|
| HTTP 401 | 是否把登录密码当成令牌、Key 是否属于当前站点、复制是否完整 |
| HTTP 403 | 令牌权限、模型访问限制或服务端访问策略 |
| HTTP 404 | 最终请求路径是否重复;也可能是模型不存在,继续看服务端具体错误说明 |
| HTTP 429 | 限流或配额相关错误;先核对错误信息,不要立即开启无限重试 |
| HTTP 5xx | 网关或上游异常;保留发生时间和脱敏后的错误信息 |
| 连接、证书或读取失败 | 网络、代理、证书链、超时设置;不要用关闭证书校验来"修复" |
| HTTP 成功但格式不对 | 是否调到了网页地址、其他协议接口,或响应中没有预期的普通文本 |
状态码只能帮你缩小范围,具体含义仍要结合服务商的错误码和文档。这个诊断脚本刻意不打印原始错误正文,避免把服务端回显的数据直接带进日志;需要进一步排查时,在可信环境查看详情,分享前先脱敏。
推荐顺序是:固定模型,确认完整 URL;固定 URL,确认令牌;最小文本请求通过后,再逐项加入流式、工具调用或图片。
如果纯文本正常,而某个客户端仍报错,下一步应核对客户端真正发送的接口与参数。不要仅凭一次 Chat Completions 成功,就认定 Responses、原生 Messages 或所有 Agent 功能都已兼容。
排查时保留哪些信息
如果你卡住了,评论里留下客户端/版本、接口路径、HTTP 状态码和脱敏后的报错就比较容易定位。不要发送完整令牌、私人对话或业务数据。
参考:Python 官方 urllib.request 文档、OpenAI 官方 Chat Completions 接口说明。
创作说明:本文含 AI 辅助生成内容。示例做了本地 mock 检查,未用真实 Key 执行线上模型调用;mock 通过不代表具体模型或上游服务已经验收。