如今,兼容 OpenAI 的 API 主要有两种请求格式:长期使用的 /v1/chat/completions,以及较新的 /v1/responses。GetVibe API 使用同一个密钥和基础 URL https://getvibeapi.com/v1 同时支持这两种格式。下面介绍它们在实际使用中的区别、该如何选择,以及在两者之间切换时需要注意的一个陷阱。
简要结论
| Chat Completions | Responses | |
|---|---|---|
| 端点 | POST /v1/chat/completions | POST /v1/responses |
| 输入 | 一个 messages 数组 | input:字符串或项目数组 |
| 系统提示词 | 使用 system 角色的消息 | instructions 字段 |
| 回答 | choices[0].message | 一个 output 数组:推理、消息、函数调用 |
| 输出限制 | max_tokens | max_output_tokens |
| 使用者 | 大多数 SDK、框架和聊天应用 | Codex CLI 和较新的智能体 SDK |
格式不会改变模型、价格或 token 数量:无论使用哪种格式,都会按照模型的输入和输出 token 计费。
两种格式中的相同请求
Chat Completions:
curl https://getvibeapi.com/v1/chat/completions \
-H "Authorization: Bearer $GETVIBE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-luna",
"messages": [
{"role": "system", "content": "用一句话回答。"},
{"role": "user", "content": "HTTP 429 表示什么?"}
],
"max_tokens": 300
}'
Responses:
curl https://getvibeapi.com/v1/responses \
-H "Authorization: Bearer $GETVIBE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-luna",
"instructions": "用一句话回答。",
"input": "HTTP 429 表示什么?",
"max_output_tokens": 300
}'
在 Chat Completions 中,文本位于 choices[0].message.content。在 Responses 中,文本位于 output 内:对于推理模型,第一个项目是 reasoning 项,回答则是类型为 message 的项目。你不必手动遍历数组;Python SDK 提供了 output_text 属性。
import os
from openai import OpenAI
client = OpenAI(base_url="https://getvibeapi.com/v1", api_key=os.environ["GETVIBE_API_KEY"])
chat = client.chat.completions.create(
model="gpt-6-luna",
messages=[{"role": "system", "content": "用一句话回答。"},
{"role": "user", "content": "HTTP 429 表示什么?"}],
)
print(chat.choices[0].message.content)
resp = client.responses.create(
model="gpt-6-luna",
instructions="用一句话回答。",
input="HTTP 429 表示什么?",
)
print(resp.output_text)
Responses 并不局限于 OpenAI 模型。在发布前,我们将相同的 Responses 请求分别发送给 gpt-6-luna、claude-sonnet-5.5 和 deepseek-v4.1-flash,三个模型都给出了回答。DeepSeek 在其 message 之前返回了一个 reasoning 项,与上面的说明完全一致。
对话历史:需要自行发送
这是切换前需要了解的唯一事项。OpenAI 自己的 Responses API 可以在服务器上保存对话,因此下一次请求可以通过 previous_response_id 指向上一次请求。GetVibe API 不会存储你的对话,因此不支持 previous_response_id,而 store 会被忽略。我们尝试使用它时,请求因 400 错误而被拒绝。
可行的模式与 Chat Completions 相同:将完整历史记录放入 input 中发送。
history = [{"role": "user", "content": "我叫 Ana。记住这个名字。"}]
first = client.responses.create(model="gpt-6-luna", input=history)
history.append({"role": "assistant", "content": first.output_text})
history.append({"role": "user", "content": "我叫什么名字?用一个词回答。"})
second = client.responses.create(model="gpt-6-luna", input=history)
print(second.output_text) # Ana
工具:形状有所不同
两种格式都支持函数调用,但工具定义的形式不同。在 Chat Completions 中,函数字段嵌套在 function 对象内;在 Responses 中,这些字段直接位于工具上。调用会作为单独的 function_call 项返回,而你需要使用具有相同 call_id 的 function_call_output 项返回结果。
import json
tools = [{
"type": "function",
"name": "get_weather",
"description": "某个城市的当前天气",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
"additionalProperties": False,
},
}]
items = [{"role": "user", "content": "丹佛的天气怎么样?"}]
resp = client.responses.create(model="gpt-6-luna", input=items, tools=tools)
for item in resp.output:
if item.type == "function_call":
result = {"city": "Denver", "temp_f": 54, "sky": "overcast"} # 你的函数
items.append({"type": "function_call", "call_id": item.call_id,
"name": item.name, "arguments": item.arguments})
items.append({"type": "function_call_output", "call_id": item.call_id,
"output": json.dumps(result)})
final = client.responses.create(model="gpt-6-luna", input=items, tools=tools)
print(final.output_text)
在我们的运行中,模型使用 {"city":"Denver"} 调用了 get_weather,第二个请求回答丹佛的气温为 54°F,天气阴天。相同循环的 Chat Completions 版本请参阅我们的函数调用指南。
流式传输
两种格式都支持 "stream": true,但事件有所不同。Chat Completions 发送统一的 data: 行,每一段新增文本位于 choices[0].delta.content 中。Responses 发送带名称的事件:首先是 response.created,然后是包含文本片段的 response.output_text.delta,最后是 response.completed。如果你不是通过 SDK,而是自行解析流,就需要针对具体格式编写解析器。
该如何选择
- 如果你已经在使用 Chat Completions,或者使用某个框架、聊天应用或无代码平台,就选择它。几乎所有工具都支持这种格式,没有必要仅仅为了更换格式而重写可正常运行的代码。
- 如果某个工具要求使用 Responses,就选择它。主要例子是 Codex CLI,它通过
/v1/responses进行通信;配置方法请参阅 Codex CLI 文档和我们的 Codex CLI 指南。
