OpenAI API 入门:Chat Completions、函数调用和流式输出怎么写

整理兼容 OpenAI 的 Chat Completions API 基本用法:如何配置 BASE_URL 和 OPENAI_API_KEY,如何组织 messages、tools、tool_choice 与 stream,以及如何理解非流式和流式响应。

很多大模型服务都会提供“兼容 OpenAI”的接口。实际接入时,最重要的是先确认两件事:

  1. BASE_URL:服务商提供的 API 地址。
  2. OPENAI_API_KEY:你的访问密钥。

如果服务商兼容的是 Chat Completions API,那么请求形态通常接近 OpenAI 的 /v1/chat/completions。不过要注意,OpenAI 当前也在推动 Responses API。Chat Completions 仍然常见,尤其是在第三方兼容接口里,但新项目如果直接使用 OpenAI 官方能力,也应该同时关注 Responses API。

官方参考:

最小请求示例

一个最小的 Chat Completions 请求大概长这样:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [
      {
        "role": "system",
        "content": "You are a helpful assistant."
      },
      {
        "role": "user",
        "content": "Hello!"
      }
    ]
  }'

如果你使用的是第三方兼容服务,通常只需要把第一行替换为对方的 BASE_URL

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
curl $BASE_URL/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "your-model-id",
    "messages": [
      {
        "role": "user",
        "content": "Hello!"
      }
    ]
  }'

这里最容易出错的地方有三个:

  • BASE_URL 不要多写或少写 /v1
  • Authorization 要使用 Bearer
  • model 必须是服务商实际支持的模型 ID。

请求体里最重要的字段

Chat Completions 的请求体是一个 JSON 对象。最基础、最常用的字段如下。

model

model 是必填字段,表示要调用的模型 ID。

1
2
3
{
  "model": "gpt-4o-mini"
}

在兼容 OpenAI 的第三方服务里,模型 ID 不一定叫 gpt-4o-mini。有的服务会使用自己的模型名称,比如 deepseek-chatqwen-plusllama-3.1-70b 等。这里要以服务商文档或模型列表为准。

messages

messages 是必填字段,表示从头到尾的对话历史。它是一个数组,每个元素是一条消息。

常见角色包括:

  • system:系统指令,用来定义助手行为;
  • user:用户消息;
  • assistant:模型上一轮回复;
  • tool:工具调用结果。

一个简单多轮对话可以写成:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "model": "gpt-4o-mini",
  "messages": [
    {
      "role": "system",
      "content": "You are a concise technical assistant."
    },
    {
      "role": "user",
      "content": "什么是 API?"
    },
    {
      "role": "assistant",
      "content": "API 是应用程序之间约定好的调用接口。"
    },
    {
      "role": "user",
      "content": "用一句话解释给非技术人员听。"
    }
  ]
}

system message

system 消息通常放在最前面,用来告诉模型应该扮演什么角色、遵守什么规则。

1
2
3
4
{
  "role": "system",
  "content": "You are a helpful assistant."
}

常见字段:

  • role:固定为 system
  • content:系统提示词内容;
  • name:可选,用来标记参与者名称。

不是所有兼容服务都会完全支持同样的 system 行为。如果发现系统提示词不生效,先检查服务商是否改写了角色规则。

user message

user 消息表示用户输入。最常见的是纯文本:

1
2
3
4
{
  "role": "user",
  "content": "Hello!"
}

在支持多模态输入的模型里,content 也可以是数组,用来同时传文本和图片:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4o",
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "text",
            "text": "What is in this image?"
          },
          {
            "type": "image_url",
            "image_url": {
              "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
            }
          }
        ]
      }
    ],
    "max_completion_tokens": 300
  }'

兼容接口是否支持图片,要看具体模型。不要只因为接口路径兼容 OpenAI,就默认它一定支持多模态。

assistant message

assistant 消息通常出现在多轮对话历史里,表示模型之前说过什么。

1
2
3
4
{
  "role": "assistant",
  "content": "Hello, how can I help you today?"
}

当模型决定调用工具时,assistant 消息里可能没有普通文本,而是包含 tool_calls

tool message

tool 消息用于把工具执行结果反馈给模型。它必须对应上一轮 assistant 消息里的某个 tool_calls.id

1
2
3
4
5
{
  "role": "tool",
  "tool_call_id": "call_abc123",
  "content": "{\"temperature\": 22, \"unit\": \"celsius\"}"
}

这一步常用于 Agent 场景:模型先决定要调用哪个函数,应用程序真正执行函数,然后把执行结果作为 tool 消息发回模型,让模型生成最终回答。

tools 和 tool_choice

tools 用来告诉模型:你可以调用哪些工具。目前最常见的是函数工具。

下面是一个查询天气的例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [
      {
        "role": "user",
        "content": "What is the weather like in Boston today?"
      }
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_current_weather",
          "description": "Get the current weather in a given location",
          "parameters": {
            "type": "object",
            "properties": {
              "location": {
                "type": "string",
                "description": "The city and state, e.g. San Francisco, CA"
              },
              "unit": {
                "type": "string",
                "enum": ["celsius", "fahrenheit"]
              }
            },
            "required": ["location"]
          }
        }
      }
    ],
    "tool_choice": "auto"
  }'

如果模型认为需要调用工具,响应里可能出现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "tool_calls": [
          {
            "id": "call_abc123",
            "type": "function",
            "function": {
              "name": "get_current_weather",
              "arguments": "{\"location\":\"Boston, MA\"}"
            }
          }
        ]
      },
      "finish_reason": "tool_calls"
    }
  ]
}

这里要注意两件事:

  1. 模型只是在“建议调用函数”,不会替你的程序真正执行函数。
  2. arguments 是模型生成的 JSON 字符串,使用前必须校验,不要直接信任。

tool_choice 用来控制模型是否调用工具:

  • "none":不调用工具,只生成文本;
  • "auto":模型自己决定生成文本还是调用工具;
  • "required":要求模型调用一个或多个工具;
  • 指定某个函数:强制调用具体工具。

旧接口里的 functionsfunction_call 已经被 toolstool_choice 取代。维护旧项目时可能还会看到这些字段,新项目建议优先使用新写法。

stream 流式输出

stream 是可选布尔值。设置为 true 后,接口会用 SSE 方式逐段返回内容,适合实时聊天界面。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "model": "gpt-4o-mini",
  "messages": [
    {
      "role": "user",
      "content": "写一句欢迎语"
    }
  ],
  "stream": true
}

非流式响应会等模型完整生成后一次性返回;流式响应会不断返回 chunk。典型片段类似:

1
2
3
4
5
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}

data: {"id":"chatcmpl-123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}

data: [DONE]

前端或后端需要不断读取 data: 行,把每次 delta.content 拼起来,直到收到 [DONE]

非流式响应怎么看

非流式 Chat Completions 响应通常包含这些字段:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "created": 1677652288,
  "model": "gpt-4o-mini",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Hello there, how may I assist you today?"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 12,
    "total_tokens": 21
  }
}

最常用的是:

  • choices[0].message.content:模型最终回复;
  • choices[0].message.tool_calls:模型想调用的工具;
  • choices[0].finish_reason:停止原因;
  • usage:token 使用量。

finish_reason 常见值包括:

  • stop:自然停止;
  • length:达到 token 上限;
  • tool_calls:模型请求调用工具;
  • content_filter:内容被过滤。

兼容接口接入时的检查清单

接入第三方兼容 OpenAI 的服务时,不要只看接口路径一样。建议按这个清单检查:

  1. BASE_URL 是否包含 /v1
  2. OPENAI_API_KEY 是否真的对应当前服务商。
  3. model 是否是可用模型 ID。
  4. 是否支持 system 消息。
  5. 是否支持多模态 image_url
  6. 是否支持 toolstool_choice
  7. 是否支持 stream: true
  8. token 限制字段使用 max_completion_tokens 还是旧的 max_tokens
  9. 错误响应格式是否和 OpenAI 完全一致。
  10. 是否有额外的速率限制、并发限制或区域限制。

“兼容 OpenAI”通常意味着调用方式相似,不等于所有模型能力、字段语义和错误格式都完全相同。

结论

如果只是做最基础的聊天,对 Chat Completions 来说,核心字段其实只有三个:

1
2
3
4
5
{
  "model": "your-model-id",
  "messages": [],
  "stream": false
}

如果要做 Agent 或业务自动化,就需要进一步理解:

  • tools:告诉模型有哪些函数可以用;
  • tool_choice:控制模型是否调用工具;
  • tool_calls:读取模型想调用什么;
  • tool message:把真实工具结果反馈给模型;
  • stream:把回复变成实时输出。

对于兼容 OpenAI 的 API,最稳妥的接入方式是:先用最小文本请求跑通,再加流式输出,最后再接工具调用。每加一层能力,都用真实模型和真实服务商验证一次,不要只按字段名猜兼容程度。

记录并分享
使用 Hugo 构建
主题 StackJimmy 设计