上周有个朋友问我:「你平时用 Python 调 GPT-4 的 API,到底怎么弄的?网上教程一堆,但跑起来全报错。」
说实话,我第一次调 GPT-4 API 的时候也是这种状态——官方文档写得挺好,但实际跑的时候各种幺蛾子。Key 的权限不对、请求超时、返回格式解析出错……折腾了大半天才跑通第一个请求。
这篇文章就把我的完整流程和踩坑经历写出来,保证你复制代码就能跑。
先说结论
| 步骤 | 耗时 | 难度 |
|---|---|---|
| 安装 openai 库 | 1 分钟 | ⭐ |
| 获取 API Key | 5 分钟 | ⭐ |
| 跑通第一个请求 | 10 分钟 | ⭐⭐ |
| 流式输出 | 5 分钟 | ⭐⭐ |
| 多轮对话 | 10 分钟 | ⭐⭐ |
| Function Calling | 20 分钟 | ⭐⭐⭐ |
整套流程如果不踩坑,半小时内搞定。但你大概率会踩坑,所以我把坑也写了。
为什么现在还要学调 GPT-4 API?
我知道很多人会说:「ChatGPT 网页版不就行了吗?干嘛费劲调 API?」
几个真实场景:
- 自动化工作流:我有个脚本每天自动把 GitHub Issues 丢给 GPT-4 做分类打标签,这事儿你总不能每天手动复制粘贴吧
- 嵌入自己的产品:做独立开发的话,用户端的 AI 功能肯定得走 API
- 批量处理:上周帮朋友处理 2000 条客服记录做情感分析,网页版点到手抽筋都搞不完
- 成本控制:API 按 token 计费,比 Plus 会员划算得多(前提是你不是重度聊天用户)
好,废话不多说,直接开干。
第一步:环境准备
安装 openai 库
pip install openai>=1.0.0
这里有个坑我先提一嘴:openai 库在 1.0 版本做了一次大改,网上很多教程还在用 openai.ChatCompletion.create() 这种旧写法,你照着抄会直接报 AttributeError。
现在的新版写法是面向对象的,用 OpenAI() 实例化一个 client,后面全用 client 调方法。如果你之前装过旧版,先升级:
pip install --upgrade openai
确认版本:
import openai
print(openai.__version__) # 确保 >= 1.0.0
获取 API Key
去 OpenAI 官网的 API Keys 页面 创建一个。
不过说实话,如果你在国内,直接访问 OpenAI 的 API 可能会遇到网络问题。我之前试过好几种方案,最后发现最省事的办法是用一个兼容 OpenAI 协议的聚合接口。我现在用的是 ofox.ai,改一下 base_url 就行,不用折腾别的,国内直连延迟也还可以。
后面的代码示例我会同时给出两种配置方式,你根据自己的情况选。
第二步:跑通第一个请求
这是最基础的单轮对话:
from openai import OpenAI
# 方式一:直连 OpenAI 官方
client = OpenAI(
api_key="sk-your-openai-key"
)
# 方式二:用聚合接口,国内直连
# client = OpenAI(
# api_key="your-ofox-key",
# base_url="https://api.ofox.ai/v1" # 兼容 OpenAI 协议,一个 Key 调多个模型
# )
response = client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "你是一个有用的助手。"},
{"role": "user", "content": "用一句话解释什么是 API"}
],
temperature=0.7,
max_tokens=500
)
print(response.choices[0].message.content)
跑通之后你会拿到类似这样的输出:
API(应用程序编程接口)是一组定义了不同软件组件之间如何交互的规则和协议,让程序之间可以互相通信和共享数据。
几个参数说一下:
- model:
gpt-4是基础版,gpt-4-turbo更快更便宜,gpt-4o是最新的多模态版本。根据你的需求选 - temperature:0-2 之间,越高越有创意(越放飞自我),写代码建议 0-0.3,写文案可以 0.7-1.0
- max_tokens:限制回复长度,避免烧钱。GPT-4 的输出 token 不便宜
第三步:流式输出(打字机效果)
正常请求要等模型把整个回复生成完才返回,如果回复很长,用户要干等好几秒。流式输出就是一个字一个字蹦出来,体验好很多:
from openai import OpenAI
client = OpenAI(api_key="sk-your-key")
stream = client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "user", "content": "写一首关于 Python 的打油诗"}
],
stream=True # 就加这一个参数
)
for chunk in stream:
content = chunk.choices[0].delta.content
if content is not None:
print(content, end="", flush=True)
print() # 最后换个行
注意 flush=True,不加的话 Python 的 print 会缓冲输出,你看不到打字机效果。
第四步:多轮对话
GPT 的 API 是无状态的,它不会「记住」你之前说了什么。想要多轮对话,你得自己把历史消息全部塞进 messages 里:
from openai import OpenAI
client = OpenAI(api_key="sk-your-key")
conversation_history = [
{"role": "system", "content": "你是一个 Python 编程助手,回复简洁。"}
]
def chat(user_input: str) -> str:
conversation_history.append({"role": "user", "content": user_input})
response = client.chat.completions.create(
model="gpt-4",
messages=conversation_history,
temperature=0.3,
max_tokens=1000
)
assistant_message = response.choices[0].message.content
conversation_history.append({"role": "assistant", "content": assistant_message})
return assistant_message
# 模拟多轮对话
print(chat("Python 里怎么读取 JSON 文件?"))
print("---")
print(chat("如果文件很大,有什么优化方案?")) # 它会记住上下文
print("---")
print(chat("给我写个完整的示例代码")) # 继续基于前面的对话
这里有个实际问题:对话越长,token 消耗越大。因为每次请求你都要把所有历史消息发过去。
我的处理方式是加一个简单的窗口限制:
MAX_HISTORY = 20 # 最多保留最近 20 条消息
def chat_with_limit(user_input: str) -> str:
conversation_history.append({"role": "user", "content": user_input})
# 保留 system prompt + 最近的 N 条
messages_to_send = [conversation_history[0]] + conversation_history[-MAX_HISTORY:]
response = client.chat.completions.create(
model="gpt-4",
messages=messages_to_send,
temperature=0.3,
max_tokens=1000
)
assistant_message = response.choices[0].message.content
conversation_history.append({"role": "assistant", "content": assistant_message})
return assistant_message
第五步:Function Calling(进阶)
这个功能是我觉得 GPT-4 API 最实用的特性之一。简单说就是让模型决定什么时候调用你定义的函数,并且帮你提取出结构化的参数。
举个例子,做一个能查天气的助手:
import json
from openai import OpenAI
client = OpenAI(api_key="sk-your-key")
# 定义可用的工具
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的当前天气",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如 北京、上海"
}
},
"required": ["city"]
}
}
}
]
# 模拟天气查询函数
def get_weather(city: str) -> str:
# 实际项目里这里调真实的天气 API
fake_data = {"北京": "晴,26°C", "上海": "多云,28°C", "深圳": "雷阵雨,31°C"}
return fake_data.get(city, f"{city}:暂无数据")
# 发起请求
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "北京今天天气怎么样?"}],
tools=tools,
tool_choice="auto" # 让模型自己决定是否调用函数
)
message = response.choices[0].message
# 检查模型是否想调用函数
if message.tool_calls:
tool_call = message.tool_calls[0]
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
# 执行对应的函数
if function_name == "get_weather":
result = get_weather(**function_args)
# 把函数结果传回给模型,让它生成自然语言回复
final_response = client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "user", "content": "北京今天天气怎么样?"},
message, # 模型的 tool_call 消息
{
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
}
]
)
print(final_response.choices[0].message.content)
else:
print(message.content)
输出大概是:「北京今天天气晴,气温 26°C,适合出门走走。」
模型不会自己查天气,但它能判断用户意图、提取参数、然后用你给的函数结果来组织回复。这个模式在做 AI Agent 的时候非常有用。
踩坑记录
这几个坑我都亲自踩过,记录一下:
坑一:用了旧版 API 写法
网上搜到的很多教程还在用这种写法:
# ❌ 旧版写法,openai >= 1.0 会报错
import openai
openai.api_key = "sk-xxx"
response = openai.ChatCompletion.create(...)
新版必须用 OpenAI() 客户端实例。如果你看到哪个教程还在用上面的写法,直接关掉换下一篇。
坑二:gpt-4 和 gpt-4-turbo 的区别没搞清
我一开始全用 gpt-4,后来看账单发现贵得离谱。查了一下:
| 模型 | 输入价格 (1M tokens) | 输出价格 (1M tokens) | 上下文长度 |
|---|---|---|---|
| gpt-4 | $30 | $60 | 8K |
| gpt-4-turbo | $10 | $30 | 128K |
| gpt-4o | $2.5 | $10 | 128K |
价格差了好几倍……大部分场景用 gpt-4o 就够了,又快又便宜。只有对推理质量有极高要求的时候才上 gpt-4。
坑三:超时和重试没做
生产环境一定要加超时和重试,不然 API 偶尔抽风你的程序就直接挂了:
from openai import OpenAI
import httpx
client = OpenAI(
api_key="sk-your-key",
timeout=httpx.Timeout(60.0, connect=10.0), # 总超时 60s,连接超时 10s
max_retries=3 # 自动重试 3 次
)
openai 库内置了重试机制,加上这两行就行,不用自己写 retry 逻辑。
小结
整个流程其实不复杂:装库 → 拿 Key → 构造 messages → 发请求。核心就是理解 messages 这个数组的结构,system、user、assistant 三种角色,多轮对话就是不断往里 append。
几个建议:
- 开发阶段用 gpt-4o,别一上来就用 gpt-4,钱包会感谢你
- 一定要加 max_tokens,不然模型有时候会疯狂输出,一个请求烧好几毛
- 流式输出不是必须的,但如果你做面向用户的产品,体验差距非常大
- Function Calling 值得花时间学,这是做 AI 应用和做 AI 玩具的分水岭
有问题评论区聊,我看到都会回。