Python 调用 GPT-4 API 完整教程:从 0 到能跑通,含 3 个我踩过的坑

6 阅读1分钟

上周有个朋友问我:「你平时用 Python 调 GPT-4 的 API,到底怎么弄的?网上教程一堆,但跑起来全报错。」

说实话,我第一次调 GPT-4 API 的时候也是这种状态——官方文档写得挺好,但实际跑的时候各种幺蛾子。Key 的权限不对、请求超时、返回格式解析出错……折腾了大半天才跑通第一个请求。

这篇文章就把我的完整流程和踩坑经历写出来,保证你复制代码就能跑。

先说结论

步骤耗时难度
安装 openai 库1 分钟
获取 API Key5 分钟
跑通第一个请求10 分钟⭐⭐
流式输出5 分钟⭐⭐
多轮对话10 分钟⭐⭐
Function Calling20 分钟⭐⭐⭐

整套流程如果不踩坑,半小时内搞定。但你大概率会踩坑,所以我把坑也写了。

为什么现在还要学调 GPT-4 API?

我知道很多人会说:「ChatGPT 网页版不就行了吗?干嘛费劲调 API?」

几个真实场景:

  1. 自动化工作流:我有个脚本每天自动把 GitHub Issues 丢给 GPT-4 做分类打标签,这事儿你总不能每天手动复制粘贴吧
  2. 嵌入自己的产品:做独立开发的话,用户端的 AI 功能肯定得走 API
  3. 批量处理:上周帮朋友处理 2000 条客服记录做情感分析,网页版点到手抽筋都搞不完
  4. 成本控制: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(应用程序编程接口)是一组定义了不同软件组件之间如何交互的规则和协议,让程序之间可以互相通信和共享数据。

几个参数说一下:

  • modelgpt-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$608K
gpt-4-turbo$10$30128K
gpt-4o$2.5$10128K

价格差了好几倍……大部分场景用 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 这个数组的结构,systemuserassistant 三种角色,多轮对话就是不断往里 append。

几个建议:

  1. 开发阶段用 gpt-4o,别一上来就用 gpt-4,钱包会感谢你
  2. 一定要加 max_tokens,不然模型有时候会疯狂输出,一个请求烧好几毛
  3. 流式输出不是必须的,但如果你做面向用户的产品,体验差距非常大
  4. Function Calling 值得花时间学,这是做 AI 应用和做 AI 玩具的分水岭

有问题评论区聊,我看到都会回。