很多人拿到中转站或自建服务的 Key 和 Base URL 后,第一个动作就是打开终端敲 curl,结果不是 404 就是 401,或者返回一堆空对象,折腾半天不知道错在哪。这篇不铺概念,直接把最小可用命令、参数该怎么填、返回不对时按什么顺序查列出来,你照着改完就能拿到第一个正常响应。
很多人从中转站或自建服务拿到 Key 和 Base URL 之后,第一反应是打开终端敲 curl。结果要么 404,要么 401,要么返回一个空空的 JSON,折腾半天不知道错在哪。这篇不铺概念,直接把最小可用命令、参数怎么填、返回不对按什么顺序查讲清楚,你照着替换三处就能拿到第一个正常响应。
先明确一点:OpenAI 兼容接口不是一个标准,而是一种「大家照着同一套字段名做」的默契。不同服务商在路径拼接、鉴权头、错误码上会有细节差异,所以下面的命令是通用骨架,具体到你用的那家,最好到 /sites 里对应条目核对它的 Base URL 写法。
最小可用命令:一条 curl 长什么样
一条完整命令就四块:请求方法、地址、请求头、JSON 请求体。方法基本固定 POST;地址由 Base URL 加资源路径拼成,多数是 /chat/completions 或 /v1/chat/completions,取决于你的 Base URL 里有没有带版本段。
curl -sS -X POST "<你的BaseURL>/chat/completions" \
-H "Authorization: Bearer <你的KEY>" \
-H "Content-Type: application/json" \
-d '{
"model": "<你的模型名>",
"messages": [{"role": "user", "content": "你好"}]
}'- Authorization 头里 Bearer 和 Key 之间必须留一个空格,少这个空格是新手最常见的 401 原因;
- Content-Type 必须是 application/json,漏掉时部分服务会直接拒绝,另一部分会把 body 当普通字符串处理;
- 请求体里 model 和 messages 是必填,messages 是对象数组,每项要有 role 和 content,不能直接写成字符串;
- 值都加双引号,JSON 里没有裸标识符,写错一个引号就会返回 400;
- 命令里的模型名要填服务商认的那个字符串,不确定到站内页面查它的模型字段说明。
常用参数与 curl 自身的开关
这里最容易混:一类参数是塞进 JSON 请求体给模型看的,比如温度、最大输出长度、是否流式;另一类是 curl 自己的命令行开关,控制网络行为和输出格式。两者放在同一条命令里,但作用完全不同。
| curl 开关 | 做什么用 | 什么时候用 |
|---|---|---|
| -N | 关闭输出缓冲,边收边打 | 调流式输出时必加,否则终端半天不出字 |
| --max-time | 限制整条请求的总时长 | 脚本里防卡死,秒数按你的场景定 |
| --connect-timeout | 限制建立连接的时间 | 网络不稳或地址写错时,快速失败而不是干等 |
| -i | 把响应头一起打印出来 | 排查 404、502 时,响应头往往比正文有用 |
| -w | 请求结束后打印状态码、耗时等 | 对比不同服务商速度时,比肉眼看快慢靠谱 |
| -v | 打印握手和实际发出的请求头 | 怀疑代理或环境变量改写了地址时用 |
注意一个常见坑:终端里你可能设了代理相关的环境变量,curl 会悄悄带上。地址明明写对了却 404,先加 -v 看一眼实际请求打到了哪。反过来,如果你需要走代理,这个环境变量反而是好事,别急着清掉。
怎么判断返回是对的
正常的返回里至少有 choices 数组,第一条的 message.content 才是模型正文。如果 choices 是空数组,通常意味着请求被上游拦截、被改写,或者模型名对方不认。别只盯着有没有报错,空对象也算失败。
- 401 / 403
- 鉴权问题,先看 Bearer 后有没有空格、Key 有没有复制全
- 404
- 路径拼接错,多半是 Base URL 已经带版本段你还重复加了一次
- 400
- 请求体字段问题,检查 JSON 引号、messages 结构、模型名
- 429
- 被限流,等一会儿或换通道,不是你的命令写错了
- 空 choices
- 请求发出去了但结果被吃掉,查模型名和上游拦截策略
路径重复是 404 的头号原因。判断方法很简单:把 Base URL 和资源路径拼起来,如果中间出现了两段相同的版本标识,就是重复了。拿到正常响应后,建议到 /tools/speed-test 做一次连通性和延迟确认,把网络层问题和参数层问题分开。
调不通时的排查顺序
- 换最简命令只留一个短消息、最少的请求头,跑通说明环境没问题,再逐项把参数加回来,定位到具体哪一项出错。
- 加 -v 看真实请求确认实际发出的地址、请求头和你写的一致,重点看代理或环境变量有没有偷偷改写地址。
- 换通道或换服务商同一条命令发给另一个可用通道,能通说明是原服务侧的问题,不通说明是本机或网络环境问题。
- 一次只改一处不要同时动地址、Key 和请求体,否则就算通了也不知道是哪个改动起的作用。
- 记录能跑通的版本把成功的那条命令存下来当基线,之后所有问题都拿它做对比,省得每次从头猜。
curl 调不通,九成不是接口复杂,而是某个字符多了一个、少了一个,或者路径拼了两遍。
这套顺序不适用于一种情况:你的服务商根本不是 OpenAI 兼容,只是名字像。这时候字段名可能完全不一样,别硬套,先到 /sites 看它到底是哪种接口风格再动手。
下一步把命令跑通只是开始,真正要确认的是这个中转站值不值得长期用。到 /sites 看它的连通性记录和最近状态,比你自己反复试错快得多。→常见问题
curl 返回 404,但我在客户端里明明能连上,是怎么回事?
多半是地址拼接问题。客户端的 Base URL 和请求路径分开填写,curl 里是你手写的完整地址,少一段版本路径或多一层目录都会 404。把客户端里的 Base URL 原样拿出来,后面只接资源名,再拼一次试试。
命令能通,但返回内容一直是空的,怎么查?
先看有没有 choices 字段。有 choices 但 content 为空,通常是提示词被安全策略拦了或者参数设得太极端;连 choices 都没有,就是请求没被正常受理,回头检查请求体是不是合法 JSON,以及 model 名字对方是否认识。
要不要在 curl 里加超时参数?
建议加,尤其是写进脚本或 CI 的时候。不加的话遇到上游挂起会一直等,把整个流程拖死。连接超时和总超时分开设,总超时按你预期的最长响应时间留一点余量,具体数值在站内测速页量一下自己的基线再定。