chat-completions-cookbook-languages · ZH · 2026-10-06

用 Python、Node、Go、Java、curl 调 /chat/completions 的复制即用手册

本文提供 Python、Node.js、Go、Java 和 curl 调用 /chat/completions 的最小可运行示例,对比鉴权头的写法与错误处理差异,帮助开发者快速接入。

为什么需要这份手册

许多聚合 API 服务兼容 OpenAI 的 /chat/completions 接口,但不同语言在 HTTP 客户端、鉴权头拼写和错误处理范式上各有习惯。本文用五种最常见的调用方式,给出可直接复制粘贴的最小示例,并指出容易踩坑的细节。

注意:鉴权头通常是 Authorization: Bearer <API_KEY>,但不同语言里字符串拼接方式不同,下文会分别说明。

通用约定

  • 请求方法:POST
  • 端点:/chat/completions(多数服务兼容 OpenAI 风格)
  • 请求体:JSON,包含 model、messages 等字段
  • 成功响应:JSON,通常在 choices[0].message.content 中返回文本
  • 失败响应:HTTP 状态码非 2xx,响应体多为 JSON 错误对象

Python 示例(requests)

import requests

API_KEY = "YOUR_API_KEY"
URL = "https://api.example.com/v1/chat/completions"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

payload = {
    "model": "gpt-3.5-turbo",
    "messages": [
        {"role": "user", "content": "你好,介绍一下你自己"}
    ],
}

try:
    resp = requests.post(URL, headers=headers, json=payload, timeout=30)
    resp.raise_for_status()
    data = resp.json()
    print(data["choices"][0]["message"]["content"])
except requests.HTTPError as e:
    print("HTTP 错误:", e.response.status_code, e.response.text)
except requests.RequestException as e:
    print("请求异常:", str(e))

鉴权头写法:f-string 直接拼接 Bearer 前缀,注意 Bearer 后有一个空格。

错误处理:用 raiseforstatus() 抛出异常,再分别捕获 HTTPError 和网络异常。HTTPError 的 response.text 通常包含服务端错误详情。

Node.js 示例(原生 fetch)

const API_KEY = "YOUR_API_KEY";
const URL = "https://api.example.com/v1/chat/completions";

async function main() {
  const resp = await fetch(URL, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "gpt-3.5-turbo",
      messages: [{ role: "user", content: "你好,介绍一下你自己" }],
    }),
  });

  if (!resp.ok) {
    const text = await resp.text();
    throw new Error(`HTTP ${resp.status}: ${text}`);
  }

  const data = await resp.json();
  console.log(data.choices[0].message.content);
}

main().catch((err) => {
  console.error("请求失败:", err.message);
});

鉴权头写法:模板字符串 ` Bearer ${API_KEY} `,注意保留空格。

错误处理:fetch 只在网络层出错时 reject,HTTP 状态码错误需要手动检查 resp.ok。建议读取 resp.text() 而不是 resp.json(),因为有些错误响应可能不是 JSON。

Go 示例(net/http)

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"
)

func main() {
	apiKey := "YOUR_API_KEY"
	url := "https://api.example.com/v1/chat/completions"

	payload := map[string]interface{}{
		"model": "gpt-3.5-turbo",
		"messages": []map[string]string{
			{"role": "user", "content": "你好,介绍一下你自己"},
		},
	}
	body, _ := json.Marshal(payload)

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+apiKey)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("请求异常:", err)
		return
	}
	defer resp.Body.Close()

	respBody, _ := io.ReadAll(resp.Body)
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		fmt.Printf("HTTP 错误 %d: %s\n", resp.StatusCode, string(respBody))
		return
	}

	var data map[string]interface{}
	json.Unmarshal(respBody, &data)
	choices := data["choices"].([]interface{})
	msg := choices[0].(map[string]interface{})["message"].(map[string]interface{})
	fmt.Println(msg["content"])
}

鉴权头写法:"Bearer " + apiKey,Go 中字符串拼接用 +,注意空格。

错误处理:Go 需要手动检查 resp.StatusCode,网络错误通过 err 返回。读取 resp.Body 后要记得 defer Close()。

Java 示例(HttpClient,Java 11+)

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class ChatDemo {
    public static void main(String[] args) throws Exception {
        String apiKey = "YOUR_API_KEY";
        String url = "https://api.example.com/v1/chat/completions";

        String jsonBody = "{" +
            "\"model\": \"gpt-3.5-turbo\"," +
            "\"messages\": [{\"role\": \"user\", \"content\": \"你好,介绍一下你自己\"}]" +
            "}";

        HttpClient client = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(30))
            .build();

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(url))
            .timeout(Duration.ofSeconds(30))
            .header("Authorization", "Bearer " + apiKey)
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(jsonBody))
            .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

        int status = response.statusCode();
        if (status < 200 || status >= 300) {
            System.out.println("HTTP 错误 " + status + ": " + response.body());
            return;
        }

        System.out.println(response.body());
    }
}

鉴权头写法:"Bearer " + apiKey,Java 中字符串拼接用 +。

错误处理:client.send 可能抛出 IOException 或 InterruptedException,需在方法签名中声明或捕获。状态码需手动判断。

curl 示例

curl -X POST "https://api.example.com/v1/chat/completions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [
      {"role": "user", "content": "你好,介绍一下你自己"}
    ]
  }'

鉴权头写法:使用环境变量 $API_KEY 避免密钥泄露,注意 Bearer 后的空格。

错误处理:curl 默认只输出响应体,需要加 -i 或 -w "%{http_code}" 查看状态码。若返回非 2xx,响应体通常是 JSON 错误信息。

常见差异与避坑

  • 鉴权头空格:Bearer 后面必须有一个空格,否则服务端可能返回 401。
  • Content-Type:必须为 application/json,否则部分服务端会解析失败。
  • 超时设置:LLM 响应可能较慢,建议客户端超时不低于 30 秒。
  • 错误响应格式:不同服务端错误结构可能不同,建议先打印原始响应文本再解析。
  • 重试策略:对 429 或 5xx 错误可做有限次退避重试,但 4xx(如 401、400)通常不应重试。

小结

五种语言的调用骨架高度一致,差异主要集中在鉴权头拼接方式和错误处理习惯上。复制对应示例后,只需替换 API_KEY、URL 和 model 字段即可运行。建议先在 curl 中验证连通性,再移植到项目中。