OpenAI-compatible API 调用教程:Python 与 Postman 从零接入
用 Python 和 Postman 调用 OpenAI-compatible Chat Completions,掌握 Base URL、Bearer 认证、模型 ID、响应解析与流式输出的关键细节。

第一次调用 AI API 时,最常见的障碍往往不是提示词,而是地址拼错、密钥没有进入运行环境,或者把模型展示名称当成了模型 ID。本文用同一条文本请求,分别演示 Postman 与 Python 的接入方法。
示例使用 OpenAI-compatible Chat Completions 格式。它适合学习兼容接口的基本结构;服务商是否支持对应路径、参数和流式协议,需要查阅其文档。OpenAI 官方也提供其他 API,本文不将它们混为同一个接口。
一、先理解兼容范围
“OpenAI-compatible”通常表示服务采用了某些相似的请求或响应结构,并不是对全部 API 功能的统一认证。一个服务可能支持文本聊天,却不支持 Responses、图片生成或工具调用。
本文只要求最小文本请求具有以下结构:请求指定 model 和 messages,响应中可以读取 choices[0].message.content。这个消息式结构可对照 Chat Completions 官方参考理解;第三方差异仍以各自文档为准。
二、准备配置:地址、凭证、模型
| 变量 | 示例或含义 |
|---|---|
AI_BASE_URL |
例如 https://api.example.com/v1,必须换成服务商实际地址 |
AI_API_KEY |
有效密钥,不能使用文章里的演示占位值 |
AI_MODEL |
当前账户有权限调用的精确模型 ID |
本文的 example.com 地址不会作为可用 AI 服务使用。你应先在服务文档中找到真实配置,再运行示例。
若 Base URL 已经带有 /v1,不要再手动添加一层 /v1。Python SDK 的 base_url 使用 API 根路径;Postman 则需要完整请求地址。对于本文的示例路径,完整 URL 是 {{base_url}}/chat/completions。
三、先用 Postman 验证请求
1. 建立环境变量
创建一个测试环境,配置 base_url、api_key、model 三个变量。base_url 末尾不带斜线。发送请求前选中该环境,确认变量已解析,而不是原样发送 {{model}}。
Postman 用双花括号引用变量。变量可以存在于不同作用域,同名值可能覆盖彼此;具体行为可查看 Postman 变量文档。排错时先减少同名变量。密钥避免同步或导出到共享环境,分享集合前检查是否包含敏感值。
2. 配置 URL 与认证
新建 POST 请求,URL 填写:
{{base_url}}/chat/completions
在 Authorization 中选择 Bearer Token,Token 填写 {{api_key}}。它通常会生成 Authorization: Bearer ... 请求头,不要在 Token 输入框中再重复写 Bearer。
Body 选择 raw 和 JSON,确保 Content-Type 是 application/json。
3. 添加最小请求体
{
"model": "{{model}}",
"messages": [
{
"role": "user",
"content": "请用三句话解释 HTTP API,每句话不超过四十个字。"
}
]
}
点击 Send 后,先观察 HTTP 状态码,再查看响应体。不要只判断界面是否出现了一段文本:如果返回的是网页 HTML,可能请求到了网页路由或被网关拦截,并未得到 API JSON。
成功响应通常含有 choices。文本位于第一个 choice 的 message.content。返回内容的具体措辞不是固定答案;你要验证的是接口能成功认证、接受指定模型并返回预期结构。
可以在 Post-response 脚本中添加一个基础检查:
pm.test("返回成功状态和文本回答", function () {
pm.expect(pm.response.code).to.eql(200);
const body = pm.response.json();
pm.expect(body.choices).to.be.an("array").that.is.not.empty;
pm.expect(body.choices[0].message.content).to.be.a("string").and.not.empty;
});
这个检查用于本文的纯文本请求。工具调用或其他类型响应不应套用同一断言。
四、使用 Python 发送相同请求
1. 安装与配置
建议使用 Python 3.10 或更新版本,在项目虚拟环境中安装依赖:
python -m pip install openai
Windows PowerShell 的环境变量写法如下。请将三个占位值换成自己的配置;这些变量作用于当前终端及其启动的进程。
$env:AI_BASE_URL = "https://api.example.com/v1"
$env:AI_API_KEY = "替换为真实密钥"
$env:AI_MODEL = "替换为可用模型ID"
macOS 或 Linux 的常见 shell 写法:
export AI_BASE_URL="https://api.example.com/v1"
export AI_API_KEY="替换为真实密钥"
export AI_MODEL="替换为可用模型ID"
不要把带真实密钥的命令复制到工单或公开截图中。使用 .env 时还需要显式加载它;Python 不会自动读取该文件。
2. 保存并运行代码
将下列代码保存为 chat_demo.py,在已配置环境变量的终端运行 python chat_demo.py。
import os
from openai import OpenAI, APIConnectionError, APIStatusError, APITimeoutError
def required(name):
value = os.getenv(name, "").strip()
if not value:
raise RuntimeError(f"请先设置环境变量 {name}")
return value
def main():
client = OpenAI(
api_key=required("AI_API_KEY"),
base_url=required("AI_BASE_URL").rstrip("/"),
timeout=30.0,
max_retries=0,
)
try:
result = client.chat.completions.create(
model=required("AI_MODEL"),
messages=[{
"role": "user",
"content": "请用三句话解释 HTTP API,每句话不超过四十个字。",
}],
)
except APITimeoutError:
raise SystemExit("请求超时;先检查链路,不要立即连续重发。")
except APIConnectionError:
raise SystemExit("连接失败;检查地址、DNS、代理与证书。")
except APIStatusError as exc:
request_id = getattr(exc, "request_id", None)
raise SystemExit(
f"API 返回 HTTP {exc.status_code},request_id={request_id}"
)
if not result.choices:
raise SystemExit("响应中没有 choices,请核对接口兼容性。")
choice = result.choices[0]
if not choice.message.content:
raise SystemExit(
f"没有文本回答,finish_reason={choice.finish_reason}"
)
print(choice.message.content)
print(f"finish_reason={choice.finish_reason}")
if __name__ == "__main__":
main()
首次调试关闭自动重试,有助于观察一次请求的真实结果。超时值是演示配置,不能解释为服务响应时间承诺。代码不直接输出完整错误体,是为了减少日志泄露输入或凭证的机会;进一步排错时可以在本机查看经过脱敏的错误信息。
官方 Python SDK 的安装和基础用法可参考 OpenAI SDK 文档。固定项目依赖版本后再做回归验证,能减少环境变化造成的差异。
五、需要逐字显示时,再加入流式输出
非流式请求拿到完整结果后再显示。流式请求会陆续收到片段,适合降低用户等待完整回答的感知时间,但它不会保证总耗时更短。
服务确认支持 Chat Completions 流式输出后,可用下列独立示例:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["AI_API_KEY"],
base_url=os.environ["AI_BASE_URL"].rstrip("/"),
timeout=60.0,
max_retries=0,
)
with client.chat.completions.create(
model=os.environ["AI_MODEL"],
messages=[{"role": "user", "content": "用一个生活例子解释缓存。"}],
stream=True,
) as stream:
for chunk in stream:
if not chunk.choices:
continue
text = chunk.choices[0].delta.content
if text:
print(text, end="", flush=True)
print()
注意读取的是 delta.content,而不是非流式的 message.content。某些片段没有文本,不能把每个 chunk 都当作一个完整回答。生产应用还要处理流中断:已经展示给用户的内容不能在重试后无提示地重复追加。
六、调用成功后的三个检查
检查输出是否完整。 如果结束原因显示长度限制,应查阅模型支持的输出上限参数,并检查输入上下文;不要盲目复制其他模型的参数。
检查业务格式。 要求模型输出 JSON 不等于获得有效 JSON。需要解析、校验必要字段,支持结构化输出时再按实际文档启用。
检查凭证边界。 网页应用应通过自己的后端调用 API。浏览器可见的配置、前端打包变量和网络请求都可能暴露密钥,不能把“用户看不到源码”当作保护手段。
七、常见问题
Postman 能调用,Python 为什么不行?
对比实际 Base URL、模型 ID 和运行环境,而不是只对比代码。Python 可能从另一个终端启动,没有继承密钥;也可能使用了不同代理。先让两者发送同一条最小请求,再检查依赖版本。
为什么收到 404?
检查完整请求路径,尤其是重复的版本前缀。404 也可能表示模型或资源不可用,应结合脱敏错误体判断,不能只归因于网址。
为什么不一开始就加入 temperature 等参数?
不同模型对参数的支持范围可能不同。最小请求先验证连接,然后每次只增加一个参数,便于区分基础接入问题和能力兼容问题。
完成这条最小调用后,你就获得了一条可复现的基线。接下来无论加入多轮对话、流式显示还是业务校验,都应从这条基线逐步扩展。

