4、API 调用与SDK入门:OpenAI API、文心一言API、通义千问API的调用方式与鉴权

好,咱们进入第四讲。API 调用,说白了就是让我们的代码去跟大模型「对话」。

我刚开始接触大模型时,觉得这东西很神秘。后来发现,本质上就是发一个 HTTP 请求,拿回一个 JSON 响应。嗯,就这么简单。

但不同厂商的 API,鉴权方式、参数格式、返回结构,各有各的脾气。今天我就带你一次性搞定三家主流 API:OpenAI、文心一言、通义千问。

4.1 鉴权:你的「通行证」

调用任何大模型 API,第一步都是鉴权。说白了,就是告诉服务器「我是谁,我有权限调用」。

每家厂商的鉴权方式不太一样,我整理了一张表,你一看就明白:

厂商 鉴权方式 关键参数 有效期
OpenAI API Key(Bearer Token) Authorization: Bearer sk-xxx 永久(可撤销)
文心一言 Access Token(通过 API Key + Secret Key 获取) grant_type, client_id, client_secret 默认 30 天
通义千问 API Key(Header 或 Query 参数) X-DashScope-SSE: enable / disable 永久(可撤销)

核心要点:OpenAI 和通义千问是「一次鉴权,永久使用」。文心一言需要先拿 API Key 和 Secret Key 去换一个临时 Access Token,过期了得重新换。

4.2 OpenAI API:最经典的调用方式

OpenAI 的 API 设计,可以说是行业标杆。我建议你从它入手,一通百通。

先看一个最简单的例子——用 Python 调用 GPT-3.5-turbo:

import openai

# 设置 API Key
openai.api_key = "sk-your-api-key-here"

# 调用 Chat Completion
response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "system", "content": "你是一个资深的编程导师。"},
        {"role": "user", "content": "请用 Python 写一个快速排序。"}
    ],
    temperature=0.7,
    max_tokens=500
)

# 提取回复内容
reply = response.choices[0].message.content
print(reply)

这里有几个关键点,我当年踩过坑:

  • messages 数组:这是核心。system 角色设定 AI 的行为,user 是用户输入,assistant 是 AI 回复。多轮对话就是不断往这个数组里追加消息。
  • temperature:控制随机性。0 表示完全确定,1 表示天马行空。我个人习惯用 0.7,既有创意又不至于跑偏。
  • max_tokens:限制回复长度。注意,这是输入+输出的总 token 数,不是只限制输出。

我的经验:我曾经在项目中把 max_tokens 设得太小,结果 AI 话说到一半被截断了,返回的内容不完整。后来我改成动态计算:先估算输入 token 数,再用总限制减去输入,剩下的给输出。

4.3 文心一言 API:先换令牌再说话

文心一言的鉴权流程,说白了就是「两步走」。

第一步,用 API Key 和 Secret Key 换 Access Token:

import requests

# 你的 API Key 和 Secret Key
API_KEY = "your-api-key"
SECRET_KEY = "your-secret-key"

# 获取 Access Token
url = "https://aip.baidubce.com/oauth/2.0/token"
params = {
    "grant_type": "client_credentials",
    "client_id": API_KEY,
    "client_secret": SECRET_KEY
}
response = requests.post(url, params=params)
access_token = response.json().get("access_token")

print(f"Access Token: {access_token}")

第二步,拿着 Access Token 去调用对话接口:

# 调用文心一言对话 API
url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions"
headers = {
    "Content-Type": "application/json"
}
params = {
    "access_token": access_token
}
data = {
    "messages": [
        {"role": "user", "content": "请用 Python 写一个快速排序。"}
    ],
    "temperature": 0.7
}

response = requests.post(url, headers=headers, params=params, json=data)
result = response.json()
reply = result.get("result")
print(reply)

注意:Access Token 默认有效期是 30 天。我曾经在生产环境中忘记刷新 Token,结果凌晨三点服务挂了。建议写个定时任务,每 25 天自动刷新一次。

文心一言的返回结构跟 OpenAI 不太一样。OpenAI 用 choices[0].message.content,文心一言直接用 result 字段。嗯,这个细节容易搞混。

4.4 通义千问 API:阿里系的简洁风格

通义千问的 API 设计,我个人觉得介于 OpenAI 和文心一言之间。鉴权简单,但参数命名有点不一样。

先看代码:

import dashscope

# 设置 API Key
dashscope.api_key = "sk-your-dashscope-api-key"

# 调用通义千问
response = dashscope.Generation.call(
    model="qwen-turbo",
    prompt="请用 Python 写一个快速排序。",
    temperature=0.7,
    max_tokens=500
)

# 提取回复
reply = response.output.text
print(reply)

你看,跟 OpenAI 很像,但有两个关键区别:

  • 参数名不同:OpenAI 用 messages,通义千问用 prompt(单轮对话)或 messages(多轮)。
  • 返回结构不同:OpenAI 用 choices[0].message.content,通义千问用 output.text

避坑指南:我曾经在切换模型时,直接把 OpenAI 的代码复制过来改个 endpoint 就跑了。结果通义千问返回的字段名不一样,程序直接报 KeyError。后来我养成了一个习惯——每次换 API,先打印一次完整的 response 看看结构。

4.5 流式输出:让 AI 边想边说

上面讲的都是「一次性返回」。但实际产品中,用户更希望看到 AI 一个字一个字地往外蹦。这就是流式输出(Streaming)。

以 OpenAI 为例,开启流式输出只需要加一个参数:

import openai

openai.api_key = "sk-your-api-key"

response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[{"role": "user", "content": "讲一个冷笑话。"}],
    stream=True  # 开启流式输出
)

# 逐块读取
for chunk in response:
    if chunk.choices[0].delta.get("content"):
        print(chunk.choices[0].delta.content, end="")

流式输出的核心是 stream=True。返回的不再是一个完整的 JSON,而是一个生成器,每次吐出一小块数据。

文心一言和通义千问也支持流式,但参数名略有不同:

  • 文心一言:在请求体中加 "stream": true
  • 通义千问:在 Header 中加 X-DashScope-SSE: enable

我的建议:流式输出在用户体验上提升巨大。但要注意,前端需要处理 SSE(Server-Sent Events)协议。如果你用 React,可以用 EventSourcefetchReadableStream 来接收。

4.6 错误处理:别让用户看到 500

API 调用一定会遇到错误。我总结了几种常见情况:

错误类型 HTTP 状态码 常见原因 处理方式
鉴权失败 401 API Key 错误或过期 提示用户重新配置
频率限制 429 请求太快太多 等待后重试(指数退避)
模型不可用 503 服务过载或维护 切换备用模型或提示稍后重试
参数错误 400 messages 格式不对 检查请求体结构

我建议你封装一个统一的调用函数,把错误处理逻辑写进去:

def call_llm(messages, model="gpt-3.5-turbo", max_retries=3):
    for attempt in range(max_retries):
        try:
            response = openai.ChatCompletion.create(
                model=model,
                messages=messages,
                timeout=30
            )
            return response.choices[0].message.content
        except openai.error.RateLimitError:
            wait_time = 2 ** attempt
            print(f"频率限制,等待 {wait_time} 秒...")
            time.sleep(wait_time)
        except openai.error.AuthenticationError:
            raise Exception("API Key 无效,请检查配置")
        except Exception as e:
            print(f"未知错误:{e}")
            if attempt == max_retries - 1:
                raise
    return None

注意:千万不要把 API Key 硬编码在代码里。我见过有人把 Key 提交到 GitHub 公开仓库,结果几分钟内就被盗刷了几千美元。建议用环境变量或密钥管理服务。

4.7 小结:选哪家?

说实话,没有绝对的「最好」。我个人的选择标准是这样的:

  • OpenAI:生态最成熟,文档最清晰,适合快速原型验证。但国内访问需要代理,延迟较高。
  • 文心一言:中文理解能力强,对国内场景优化好。但鉴权流程稍繁琐,需要定期刷新 Token。
  • 通义千问:阿里系产品,跟阿里云生态集成好。API 设计简洁,但模型种类不如 OpenAI 丰富。

我的建议是:原型阶段用 OpenAI 快速验证,产品化阶段根据部署环境选择国内模型。嗯,灵活切换才是王道。

下一讲,我们会深入 Prompt Engineering,教你如何「调教」大模型,让它输出你想要的内容。