【Python】OpenAI API

【Python 与 OpenAI API 深度探索:从基础到未来】

第一章:OpenAI API 概览与核心概念

1.1 OpenAI API 是什么?能做什么?

OpenAI API (Application Programming Interface,应用程序编程接口) 是一套允许开发者通过编程方式访问和使用 OpenAI 开发的各种先进人工智能模型的服务。这些模型经过海量数据的训练,能够在多种任务上达到甚至超越人类水平。通过 API,开发者可以将这些强大的 AI 能力集成到自己的应用程序、网站或工作流程中,而无需自行承担训练和部署这些复杂模型的巨大成本和技术挑战。

OpenAI API 的核心价值在于其提供的多样化模型,每种模型都有其擅长的领域:

  • 1.1.1 GPT (Generative Pre-trained Transformer) 模型家族

    • 概述:GPT 系列模型是 OpenAI 最著名的成果之一,它们是基于 Transformer 架构的大型语言模型 (LLM)。这些模型擅长理解和生成自然语言文本,能够执行广泛的文本相关任务。
    • 主要模型及其特点
      • gpt-4o (Omni): OpenAI 当前最先进的多模态模型,能够处理和生成文本、音频和图像。它在理解和生成方面达到了新的高度,速度更快,成本更低(相对于 gpt-4-turbo)。它是处理跨文本、视觉和音频输入的复杂任务的首选。
      • gpt-4-turbo: gpt-4 的增强版,拥有更大的上下文窗口 (128k tokens),更新的知识库 (截至2023年4月),并且在某些任务上性能更优,成本也相对较低。支持 JSON mode 和并行函数调用。
      • gpt-4: 比 gpt-3.5 更强大,具有更强的推理能力、更广泛的知识和更长的上下文窗口 (通常有 8k 和 32k 版本)。适用于需要深度理解和复杂推理的任务。
      • gpt-3.5-turbo: gpt-3 系列的优化版本,广泛应用于聊天机器人和各种文本生成任务。性价比高,响应速度快,是许多应用的理想选择。支持多种上下文窗口大小 (如 4k, 16k)。它是 InstructGPT 系列的继承者。
      • (旧版) text-davinci-003, text-curie-001, text-babbage-001, text-ada-001: 这些是旧版的 Completions API 模型,虽然仍然可用,但 OpenAI 强烈建议新应用使用更新的 Chat Completions API 模型 (如 gpt-3.5-turbo, gpt-4),因为它们更强大、更灵活且通常更具成本效益。
    • 应用场景
      • 内容创作 (文章、博客、营销文案、剧本、诗歌)
      • 代码生成与解释
      • 问答系统
      • 文本摘要
      • 文本翻译
      • 情感分析
      • 聊天机器人与虚拟助手
      • 教育辅导
      • 数据分析与洞察提取
  • 1.1.2 DALL·E 模型 (图像生成)

    • 概述:DALL·E 模型能够根据文本描述生成全新的、富有创意的图像和艺术作品。它们将自然语言处理与计算机视觉相结合。
    • 主要模型及其特点
      • dall-e-3: 最新一代图像生成模型,对自然语言提示的理解能力更强,生成的图像质量更高、更符合细节要求,尤其擅长处理复杂的场景和细致的描述。它通常与 ChatGPT 集成,可以帮助用户优化提示词。
      • dall-e-2: 上一代图像模型,仍然非常强大。除了从文本生成图像,它还支持图像编辑 (in-painting, out-painting) 和生成图像变体。
    • 应用场景
      • 艺术创作与设计
      • 广告与营销素材生成
      • 产品概念可视化
      • 游戏与虚拟世界素材创建
      • 教育与娱乐内容配图
  • 1.1.3 Whisper 模型 (语音转文本)

    • 概述:Whisper 是一种通用的语音识别模型,可以将音频内容转换为文本。它在多种语言、口音和嘈杂环境下都表现出卓越的准确性。
    • 主要模型及其特点
      • whisper-1: 当前 API 提供的 Whisper 模型。
    • 应用场景
      • 会议记录与访谈转录
      • 语音助手与语音控制
      • 视频字幕生成
      • 语音邮件转文本
      • 数据分析 (从音频中提取信息)
      • 多语言语音内容的翻译 (可以转录并翻译成英文)
  • 1.1.4 Embeddings 模型 (文本向量化)

    • 概述:Embeddings 模型可以将文本转换为高维度的数字向量 (numerical vectors)。这些向量捕捉了文本的语义信息,使得机器可以更容易地理解文本之间的关系和相似性。
    • 主要模型及其特点
      • text-embedding-3-large: 最新、性能最好的嵌入模型,支持高达 3072 维。
      • text-embedding-3-small: 最新一代中更小、更高效的模型,支持高达 1536 维。这两个新模型支持通过 dimensions 参数缩短输出向量的维度,而不会显著损失概念表示能力。
      • text-embedding-ada-002: 上一代广泛使用的嵌入模型,输出 1536 维向量。性价比高。
    • 应用场景
      • 语义搜索 (根据意义而非关键词查找文本)
      • 文本聚类与分类
      • 推荐系统
      • 异常检测
      • 问答系统 (查找与问题最相关的文档片段)
      • 衡量文本相似度
  • 1.1.5 Moderation 模型 (内容审核)

    • 概述:Moderation 模型用于检测文本内容是否违反 OpenAI 的使用政策,例如是否包含仇恨言论、自残内容、色情内容、暴力内容等。
    • 主要模型及其特点
      • text-moderation-latest: 指向当前最新的审核模型。
      • text-moderation-stable: 指向一个相对稳定,不经常更新的审核模型版本。
    • 应用场景
      • 保护在线社区免受有害内容的侵害
      • 确保用户生成的内容符合规范
      • 过滤 AI 生成内容的潜在不当输出
  • 1.1.6 Fine-tuning (模型微调)

    • 概述:Fine-tuning 允许开发者使用自己的数据集来进一步训练 OpenAI 的基础模型,使其在特定任务上表现更好或学习特定的知识、风格。
    • 支持微调的模型:包括 gpt-3.5-turbo, babbage-002, davinci-002 等 (具体列表请查阅最新 OpenAI 文档)。
    • 应用场景
      • 提升特定行业或领域术语的理解能力
      • 定制化模型输出的风格和语气
      • 在模型原有知识库之外教授新知识 (有限度)
      • 优化特定任务的性能,如特定类型的分类或摘要
  • 1.1.7 Assistants API (构建AI助手)

    • 概述:Assistants API 是一个更高级别的抽象,旨在帮助开发者构建复杂的 AI 助手。它简化了许多常见任务,如管理持久对话状态 (Threads)、调用模型定义的工具 (如 Code Interpreter, Retrieval, Function calling) 以及处理文件。
    • 核心组件:Assistant (助手配置), Thread (对话线程), Message (消息), Run (执行任务), Tool (工具)。
    • 应用场景
      • 构建具有记忆能力和上下文感知的高级聊天机器人
      • 创建能够执行代码、分析数据、从文档中检索信息的 AI 代理
      • 自动化复杂的工作流程,如客户支持、数据分析报告生成等

通过组合使用这些模型和功能,开发者可以构建出功能强大且多样化的 AI 应用。接下来的章节将详细介绍如何使用 Python 与这些 API 进行交互。

1.2 API 密钥管理与安全性

在使用 OpenAI API 之前,您首先需要获取一个 API 密钥。这个密钥是您访问 API 服务的凭证,因此必须妥善保管。

  • 1.2.1 获取 API 密钥

    1. 注册 OpenAI 账户:如果您还没有 OpenAI 账户,请访问 OpenAI 官网 并注册。
    2. 访问 API Keys 页面:登录后,导航到您的账户设置中的 “API keys” 部分。通常可以在个人头像下拉菜单中找到 “View API keys” 或类似的选项。
    3. 创建新的密钥:点击 “Create new secret key” 按钮。您可以选择为密钥命名,以便区分其用途 (例如 “my-python-app-key”)。
    4. 复制并保存密钥:创建成功后,API 密钥会显示出来。请立即复制这个密钥并将其保存在一个安全的地方。一旦关闭该对话框,您将无法再次看到完整的密钥。 如果丢失,您需要创建一个新的密钥。
    # 这是一个注释,提醒您API密钥的重要性
    # API密钥示例格式 (请勿在代码中硬编码您的真实密钥):
    # sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    # (上面的 x 代表随机字母和数字)
    
    # 您的真实API密钥应该像这样:
    # "sk-proj-YourUniqueCharactersAndNumbers" (对于项目密钥)
    # 或者传统的 "sk-YourUniqueCharactersAndNumbers"
    
    print("请访问 https://platform.openai.com/api-keys 获取您的API密钥。") # 打印提示信息
    
  • 1.2.2 安全存储和使用密钥
    将 API 密钥直接硬编码到您的 Python 脚本中是一种非常不安全的做法,尤其当代码需要共享或提交到版本控制系统 (如 Git) 时。以下是更安全的密钥管理方法:

    1. 环境变量 (推荐):

      • 原理:将 API 密钥存储在操作系统的环境变量中。您的应用程序在运行时从环境中读取该密钥。
      • 设置方法
        • Linux/macOS: 在您的 shell 配置文件 (如 .bashrc, .zshrc) 中添加:
          export OPENAI_API_KEY='你的真实API密钥'
          
          然后执行 source ~/.bashrc (或对应的配置文件) 使其生效。
        • Windows:
          • 通过系统属性 (搜索 “环境变量”) -> “高级” -> “环境变量…” 设置。
          • 或者在 PowerShell 中临时设置 (仅当前会话有效):
            $Env:OPENAI_API_KEY = "你的真实API密钥"
            
      • Python 中读取:
        import os # 导入os模块,用于访问操作系统功能
        
        # 从环境变量中获取OpenAI API密钥
        api_key = os.getenv("OPENAI_API_KEY") 
        
        if api_key:
            # print(f"成功获取到API密钥: {api_key[:5]}...{api_key[-4:]}") # 打印部分密钥用于验证,注意不要完整打印
            pass # 如果获取到密钥,则执行后续操作
        else:
            print("错误:未在环境变量中找到 OPENAI_API_KEY。") # 如果未获取到,打印错误信息
            print("请确保您已正确设置了 OPENAI_API_KEY 环境变量。")
        
        # OpenAI Python 客户端库默认会自动查找名为 OPENAI_API_KEY 的环境变量
        # 所以如果设置了环境变量,初始化客户端时通常不需要显式传递密钥
        
        中文解释:
        import os: 导入 Python 内置的 os 模块,它提供了与操作系统交互的功能。
        api_key = os.getenv("OPENAI_API_KEY"): 调用 os.getenv() 函数,尝试从环境变量中读取名为 “OPENAI_API_KEY” 的变量值。如果该环境变量存在,则返回其值;否则返回 None
        if api_key:: 判断 api_key 是否成功获取到值 (不是 None 或空字符串)。
        else:: 如果未获取到密钥,则打印提示信息。
    2. 配置文件 (例如 .env 文件):

      • 原理:将密钥存储在一个单独的、不受版本控制的配置文件中 (例如 .env 文件),然后使用库 (如 python-dotenv) 来加载这些配置。
      • 步骤:
        1. 安装 python-dotenv:
          pip install python-dotenv
          
        2. 创建 .env 文件 (与您的 Python 脚本在同一目录或项目根目录):
          OPENAI_API_KEY="你的真实API密钥"
          ANOTHER_CONFIG_VAR="some_value"
          
        3. 重要: 将 .env 文件添加到您的 .gitignore 文件中,以防止其被提交到 Git 仓库。
          .gitignore 文件中添加一行:
          .env
          
        4. Python 中读取:
          import os # 导入os模块
          from dotenv import load_dotenv # 从dotenv库导入load_dotenv函数
          
          # 加载 .env 文件中的环境变量
          # 这会查找当前目录或父目录中的 .env 文件,并将其中的键值对加载到环境变量中
          load_dotenv() 
          
          api_key = os.getenv("OPENAI_API_KEY") # 从已加载的环境变量中获取API密钥
          
          if api_key:
              # print(f"成功从.env文件加载API密钥: {api_key[:5]}...{api_key[-4:]}") # 验证密钥
              pass
          else:
              print("错误:未能从 .env 文件加载 OPENAI_API_KEY。") # 错误提示
              print("请确保 .env 文件存在且包含 OPENAI_API_KEY。")
          
          中文解释:
          from dotenv import load_dotenv: 从 python-dotenv 库中导入 load_dotenv 函数。
          load_dotenv(): 执行此函数会查找项目中的 .env 文件,并将其中的每一行 KEY=VALUE 解析为环境变量,加载到当前的运行环境中。这样 os.getenv() 就能读取到它们了。
    3. 密钥管理服务 (适用于生产环境和团队协作):

      • 原理:使用专门的密钥管理服务,如 HashiCorp Vault, AWS Secrets Manager, Google Cloud Secret Manager, Azure Key Vault 等。这些服务提供了更高级的安全特性,如访问控制、审计日志、密钥轮换等。
      • 集成方式:通常通过这些服务提供的 SDK 或客户端库在应用程序中安全地获取密钥。
      • 示例概念 (AWS Secrets Manager):
        # import boto3 # 导入AWS SDK for Python
        # from botocore.exceptions import ClientError # 导入boto3客户端错误
        
        # def get_secret(secret_name, region_name="your-aws-region"):
        #     """从AWS Secrets Manager获取密钥"""
        #     session = boto3.session.Session() # 创建一个boto3会话
        #     client = session.client(
        #         service_name='secretsmanager',
        #         region_name=region_name
        #     ) # 创建Secrets Manager客户端
        
        #     try:
        #         get_secret_value_response = client.get_secret_value(
        #             SecretId=secret_name
        #         ) # 调用API获取密钥值
        #     except ClientError as e:
        #         print(f"获取密钥 {secret_name} 失败: {e}") # 打印错误
        #         raise e # 重新抛出异常
        #     else:
        #         # Secrets Manager 可以存储字符串或二进制,这里假设是字符串
        #         # 如果密钥是JSON字符串,可能需要进一步解析
        #         if 'SecretString' in get_secret_value_response:
        #             secret = get_secret_value_response['SecretString'] # 获取密钥字符串
        #             # 通常密钥会以JSON格式存储,例如 {"OPENAI_API_KEY": "your_key"}
        #             # import json
        #             # return json.loads(secret).get("OPENAI_API_KEY")
        #             return secret # 返回获取到的密钥(或解析后的密钥)
        #         else:
        #             # decoded_binary_secret = base64.b64decode(get_secret_value_response['SecretBinary'])
        #             # return decoded_binary_secret
        #             print(f"密钥 {secret_name} 的格式非SecretString")
        #             return None
        
        # if __name__ == "__main__":
        #     # 假设你在AWS Secrets Manager中存储的密钥名为 "openai/api_key"
        #     # 并且该密钥的值就是你的OpenAI API密钥字符串或一个包含它的JSON
        #     try:
        #         # openai_api_key = get_secret("your_secret_name_in_aws", "your_aws_region")
        #         # if openai_api_key:
        #         #     print(f"成功从AWS Secrets Manager获取API密钥: {openai_api_key[:5]}...")
        #         # else:
        #         #     print("未能从AWS Secrets Manager获取到API密钥。")
        #         print("AWS Secrets Manager 示例代码已注释掉,请根据实际情况取消注释并配置。")
        #     except Exception as e:
        #         # print(f"调用AWS Secrets Manager出错: {e}")
        #         pass
        
        中文解释 (AWS Secrets Manager 示例):
        此示例代码展示了如何使用 boto3 (AWS SDK for Python) 从 AWS Secrets Manager 服务中检索预先存储的密钥。实际使用时需要正确配置 AWS凭证、区域以及密钥名称。这种方法将密钥管理中心化,提高了安全性,尤其适用于云环境中的生产应用。
  • 1.2.3 API 密钥的最佳实践

    • 不要在客户端代码中嵌入密钥:例如,不要在公开的 JavaScript 或移动应用代码中包含 API 密钥。应该通过后端服务代理 API 请求。
    • 不要将密钥提交到版本控制系统:如前所述,使用 .gitignore 忽略包含密钥的文件。
    • 为不同应用使用不同的密钥:这样可以方便地撤销某个应用的访问权限,而不会影响其他应用。也可以更好地追踪不同应用的用量。
    • 定期轮换密钥:虽然 OpenAI 目前不强制密钥轮换,但在安全策略中考虑定期更换密钥是一个好习惯,尤其是在密钥可能已泄露的情况下。
    • 限制密钥权限 (如果平台支持):有些 API 平台允许创建具有特定权限范围或访问特定资源的密钥。OpenAI 目前的 API 密钥通常具有对账户下所有服务的访问权限,但组织管理员可以进行一些成员和权限管理。对于项目密钥 (Project API Keys),可以实现更细致的权限控制。
    • 监控 API 使用情况:定期检查 OpenAI 账户中的用量仪表盘,注意是否有异常的 API 调用,这可能表明密钥已泄露。
    • 使用组织和项目功能:如果在一个团队或组织内工作,利用 OpenAI 的组织 (Organization) 和项目 (Project) 功能来管理访问和计费。项目 API 密钥可以被限定在特定项目内,提供更好的隔离和控制。

遵循这些安全实践,可以最大限度地降低 API 密钥泄露的风险及其潜在的不良后果。

1.3 理解 Token 与计费

OpenAI API 的使用并非免费 (通常新用户会有少量免费额度),其计费方式与一个核心概念紧密相关:Token

  • 1.3.1 Token 是什么?如何计算?

    • 定义:在自然语言处理中,Token 是模型处理文本的基本单位。对于英文文本,一个 Token 通常可以是一个单词、一个单词的一部分 (如 “eating” 中的 “eat” 和 “ing”),或者一个标点符号。对于中文等其他语言,一个 Token 可能对应一个汉字,也可能对应一个词的一部分。
    • 粗略估计:
      • 对于英文:1 个 Token 大约是 4 个字符或 0.75 个单词。
      • 对于中文:1 个 Token 大约是 0.5 - 0.7 个汉字 (具体取决于模型和编码)。一个汉字通常算作1到2个token。
    • Token 包含的内容:输入给模型的文本 (Prompt) 和模型生成的文本 (Completion/Response) 都会被计算 Token 数量。
    • 计算工具:
      • OpenAI 的 Tokenizer 工具:OpenAI 提供了一个在线的 Tokenizer 工具,您可以在上面粘贴文本,查看其被特定模型(如 gpt-3.5-turbogpt-4)分解后的 Token 数量和具体的 Token 形式。
      • tiktoken 库 (Python):OpenAI 开源了 tiktoken 库,允许开发者在代码中精确计算文本会被特定模型计为多少 Token。这对于成本预估和防止超出模型上下文长度限制非常有用。
    import tiktoken # 导入tiktoken库
    
    def count_tokens(text: str, model_name: str = "gpt-3.5-turbo") -> int:
        """
        使用tiktoken计算给定文本在特定模型下的token数量。
        
        参数:
            text (str): 需要计算token的文本。
            model_name (str): OpenAI模型的名称,例如 "gpt-3.5-turbo", "gpt-4", "text-embedding-ada-002"。
                               不同模型可能使用不同的编码方式。
        
        返回:
            int: 文本对应的token数量。
        """
        try:
            # 获取模型对应的编码器
            # tiktoken.encoding_for_model() 会根据模型名称返回正确的编码器实例
            encoding = tiktoken.encoding_for_model(model_name) 
        except KeyError:
            # 如果模型名称未知,则尝试使用一个通用的编码器 (例如cl100k_base,gpt-4和gpt-3.5-turbo使用)
            print(f"警告: 模型 '{
           
           model_name}' 未找到特定编码,将使用 'cl100k_base'。")
            encoding = tiktoken.get_encoding("cl100k_base") 
        
        # 使用编码器的encode方法将文本转换为token ID列表
        token_ids = encoding.encode(text) 
        # token ID列表的长度即为token数量
        return len(token_ids) 
    
    # 示例用法
    sample_text_en = "Hello, world! This is a test sentence."
    sample_text_zh = "你好,世界!这是一个测试句子。"
    
    # 针对 gpt-3.5-turbo 模型计算token
    tokens_en_gpt35 = count_tokens(sample_text_en, "gpt-3.5-turbo")
    tokens_zh_gpt35 = count_tokens(sample_text_zh, "gpt-3.5-turbo")
    
    print(f"英文文本: '{
           
           sample_text_en}'") # 打印英文示例文本
    print(f"使用 gpt-3.5-turbo 计算的Token数量: {
           
           tokens_en_gpt35}") # 打印英文Token数
    
    print(f"中文文本: '{
           
           sample_text_zh}'") # 打印中文示例文本
    print(f"使用 gpt-3.5-turbo 计算的Token数量: {
           
           tokens_zh_gpt35}") # 打印中文Token数
    
    # 针对 gpt-4 模型计算token
    tokens_en_gpt4 = count_tokens(sample_text_en, "gpt-4")
    tokens_zh_gpt4 = count_tokens(sample_text_zh, "gpt-4")
    
    print(f"使用 gpt-4 计算的英文Token数量: {
           
           tokens_en_gpt4}") # 打印英文Token数 (GPT-4)
    print(f"使用 gpt-4 计算的中文Token数量: {
           
           tokens_zh_gpt4}") # 打印中文Token数 (GPT-4)
    
    # 演示编码和解码
    encoding_gpt35 = tiktoken.encoding_for_model("gpt-3.5-turbo")
    encoded_tokens_zh = encoding_gpt35.encode(sample_text_zh)
    print(f"中文文本 '{
           
           sample_text_zh}' 被编码为 Token IDs: {
           
           encoded_tokens_zh}") # 打印编码后的Token ID
    
    decoded_text_zh = encoding_gpt35.decode(encoded_tokens_zh)
    print(f"Token IDs 解码回文本: '{
           
           decoded_text_zh}'") # 打印解码后的文本
    

    中文解释:
    import tiktoken: 导入 OpenAI 官方提供的 tiktoken 库。
    tiktoken.encoding_for_model(model_name): 这个函数会根据你指定的 model_name (例如 “gpt-3.5-turbo”) 返回一个该模型使用的特定编码器对象。不同的模型族可能使用不同的编码方案 (BPE - Byte Pair Encoding)。
    encoding = tiktoken.get_encoding("cl100k_base"): 如果 encoding_for_model 找不到特定模型,我们回退到获取一个已知的编码器,例如 “cl100k_base”,它是 gpt-4, gpt-3.5-turbotext-embedding-ada-002 等模型使用的编码。
    token_ids = encoding.encode(text): 编码器的 encode 方法接收一个字符串,并返回一个由整数组成的列表,这些整数是文本被分解成的各个 Token 的 ID。
    len(token_ids): 这个列表的长度就是文本所包含的 Token 数量。
    decoded_text_zh = encoding_gpt35.decode(encoded_tokens_zh): 编码器的 decode 方法可以将 Token ID 列表转换回原始文本字符串。

  • 1.3.2 不同模型的 Token 限制与成本

    • Token 限制 (Context Window):

      • 每个 OpenAI 模型都有一个最大的 Token 数量限制,称为“上下文窗口” (Context Window)。这个限制包括了输入 Prompt 的 Token 和模型生成响应的 Token 的总和 (对于 Chat Models,是整个对话历史 + 生成的新消息)。
      • 如果您的输入+预期输出超过了这个限制,API 请求可能会失败,或者输出会被截断。
      • 示例模型及其典型上下文窗口大小 (请务必查阅 OpenAI 官方文档获取最新和最准确的信息):
        • gpt-4o: 128,000 tokens
        • gpt-4-turbo (如 gpt-4-1106-preview, gpt-4-0125-preview): 128,000 tokens
        • gpt-4: 8,192 tokens (gpt-4) 或 32,768 tokens (gpt-4-32k)
        • gpt-3.5-turbo (如 gpt-3.5-turbo-0125): 16,385 tokens (输入), 4,096 tokens (输出)
        • gpt-3.5-turbo (旧版如 gpt-3.5-turbo-0613): 4,096 tokens 或 16,385 tokens (gpt-3.5-turbo-16k)
        • text-embedding-ada-002: 8,191 tokens
      • 重要: 选择模型时,需要考虑其上下文窗口是否能容纳您的任务所需的输入和预期输出。对于需要处理长文档或长对话历史的应用,具有更大上下文窗口的模型 (如 gpt-4-turbo, gpt-4o) 更为合适。
    • 成本:

      • OpenAI API 的价格根据所使用的模型、输入 Token 的数量和输出 Token 的数量来计算。
      • 通常,更强大的模型 (如 gpt-4 系列) 比能力稍弱的模型 (如 gpt-3.5-turbo) 价格更高。
      • 输入 Token 和输出 Token 的价格可能不同。例如,对于某些模型,输入 Token 的价格可能比输出 Token 的价格便宜。
      • 价格单位:通常以每 1,000 Tokens (1k Tokens) 或每 1,000,000 Tokens (1M Tokens) 美元计价。
      • 查看最新价格: 请务必访问 OpenAI 官方定价页面 获取最新的、针对不同模型的详细价格信息。价格会随时间和模型更新而调整。
      • Fine-tuning 的成本: Fine-tuning 模型会涉及训练成本 (按训练数据中的 Token 总数和训练时长/轮数计算) 和之后使用微调模型的推理成本 (通常与基础模型类似或略高)。
      • DALL·E 成本: 按生成的图像数量、尺寸和质量 (如 DALL·E 3 的 hd 模式) 计费。
      • Whisper 成本: 按音频时长 (例如,每分钟) 计费。
      • Assistants API 成本: 涉及多个方面,包括底层模型调用 (如 GPT-4)、Code Interpreter 的使用 (按会话时长)、Retrieval (按存储和查询量)。
    # 假设的费率 (美元/1k tokens) - 这些数字仅为示例,请务必查阅官方文档!
    MOCK_RATES = {
         
         
        "gpt-3.5-turbo": {
         
         "input": 0.0005, "output": 0.0015}, # 假设每1k输入token $0.0005, 每1k输出token $0.0015
        "gpt-4": {
         
         "input": 0.03, "output": 0.06},          # 假设每1k输入token $0.03, 每1k输出token $0.06
        "gpt-4o": {
         
         "input": 0.005, "output": 0.015},       # 假设每1k输入token $0.005, 每1k输出token $0.015
    }
    
    def estimate_cost(input_tokens: int, output_tokens: int, model_name: str) -> float:
        """
        估算API调用的成本。
        
        参数:
            input_tokens (int): 输入的token数量。
            output_tokens (int): 输出的token数量。
            model_name (str): 使用的模型名称。
            
        返回:
            float: 估算的成本 (美元)。
        """
        if model_name not in MOCK_RATES:
            print(f"警告: 模型 '{
           
           model_name}' 的费率未知,无法估算成本。")
            return 0.0
            
        rate = MOCK_RATES[model_name] # 获取对应模型的费率
        cost = (input_tokens / 1000) * rate["input"] + \
               (output_tokens / 1000) * rate["output"] # 计算总成本
        return cost
    
    # 示例:估算一次调用的成本
    prompt = "请帮我写一首关于春天的诗,大约100字。"
    # 假设模型生成了包含150个token的响应
    # (这些token数是随意假设的,实际中需要用tiktoken精确计算)
    
    # 使用 gpt-3.5-turbo
    input_tokens_gpt35 = count_tokens(prompt, "gpt-3.5-turbo") # 计算输入token
    # 假设输出 token 数,实际应从 API 响应的 usage 字段获取
    # 或在请求中通过 max_tokens 限制,然后根据实际输出来计算
    output_tokens_gpt35 = count_tokens("春天的风,轻拂杨柳岸。桃花笑靥,燕儿呢喃。", "gpt-3.5-turbo") # 假设这是模型的输出
    
    cost_gpt35 = estimate_cost(input_tokens_gpt35, output_tokens_gpt35, "gpt-3.5-turbo")
    print(f"使用 gpt-3.5-turbo (输入: {
           
           input_tokens_gpt35} tokens, 输出: {
           
           output_tokens_gpt35} tokens) 的估算成本: ${
           
           cost_gpt35:.6f}")
    
    # 使用 gpt-4o
    input_tokens_gpt4o = count_tokens(prompt, "gpt-4o")
    output_tokens_gpt4o = count_tokens("春风拂绿柳,桃花逐水流。莺歌燕舞时,万象更新柔。", "gpt-4o") # 假设这是模型的输出
    
    cost_gpt4o = estimate_cost(input_tokens_gpt4o, output_tokens_gpt4o, "gpt-4o")
    print(f"使用 gpt-4o (输入: {
           
           input_tokens_gpt4o} tokens, 输出: {
           
           output_tokens_gpt4o} tokens) 的估算成本: ${
           
           cost_gpt4o:.6f}")
    
    # 注意:上述成本估算使用的是假设的费率MOCK_RATES。
    # 实际成本请务必参考OpenAI官方最新的定价页面。
    # API响应中通常会包含 `usage` 字段,明确告知了该次调用的确切token消耗。
    

    中文解释:
    MOCK_RATES: 这是一个字典,模拟存储了不同模型的输入和输出 Token 的单价 (每千 Token)。再次强调,这里的费率是假设的,实际费率会变化,请务必查阅 OpenAI 官方文档。
    estimate_cost(...): 这个函数接收输入 Token 数、输出 Token 数和模型名称,然后根据 MOCK_RATES 中的费率计算总成本。计算方法是:(输入Token数 / 1000) * 输入单价 + (输出Token数 / 1000) * 输出单价
    这个示例清晰地展示了不同模型以及输入/输出 Token 数量对成本的直接影响。

  • 1.3.3 成本控制与优化策略
    管理和优化 OpenAI API 的使用成本对于任何规模的应用都至关重要。

    1. 选择合适的模型
      • 并非所有任务都需要最强大的模型。对于简单任务 (如简单分类、格式转换),gpt-3.5-turbo 可能已经足够,并且成本远低于 gpt-4gpt-4o
      • 在满足性能要求的前提下,优先选择成本效益更高的模型。
    2. 优化 Prompt 长度
      • Prompt 越长,消耗的输入 Token 就越多,成本也越高。
      • 尽量使 Prompt 简洁明了,只包含必要的信息。
      • 移除不相关的上下文或示例。
      • 使用更高效的 Prompt Engineering 技巧 (例如,few-shot learning 时提供简短但信息量大的示例)。
    3. 限制输出长度 (max_tokens):
      • 在 API 请求中设置 max_tokens 参数,可以限制模型生成响应的最大 Token 数量。这不仅可以防止意外生成过长的文本,也能直接控制输出 Token 的成本。
      • 需要注意的是,如果 max_tokens 设置得太小,可能会导致输出不完整 (finish_reason 会是 length)。
    4. 使用 tiktoken 预估成本:
      • 在发送 API 请求前,使用 tiktoken 计算 Prompt 的 Token 数量,可以提前预估输入成本。
    5. 监控 API usage 字段:
      • OpenAI API 的响应中通常会包含一个 usage 对象,其中详细说明了该次请求消耗的 prompt_tokens (输入Token)、completion_tokens (输出Token) 和 total_tokens (总Token)。
      • 记录和分析这些数据,可以帮助您了解应用的实际 Token 消耗情况。
      // API 响应中 usage 字段示例
      {
             
             
        // ... 其他响应内容 ...
        "usage": {
             
             
          "prompt_tokens": 56,
          "completion_tokens": 150,
          "total_tokens": 206
        }
      }
      
    6. 设置预算与告警 (OpenAI Platform):
      • 在 OpenAI 平台的账户设置中,您可以设置每月的使用量上限 (硬限制或软限制) 和消费预警。当支出接近或达到设定的阈值时,您会收到通知。
    7. 批处理请求 (Batching):
      • 对于某些 API (如 Embeddings API),可以一次性提交多个输入项进行处理,这通常比逐个发送请求更高效,并可能在某些情况下降低总体开销 (例如,减少了 HTTP 请求的次数)。
    8. 缓存 API 响应:
      • 对于那些输入相同、预期输出也基本不变的请求 (例如,对特定文档的摘要、常见问题的回答),可以考虑缓存 API 的响应结果。
      • 使用 Redis 或其他缓存系统存储结果,当再次遇到相同请求时,直接从缓存返回,避免重复调用 API,从而节省成本和提高响应速度。
      • 需要注意缓存的有效期和更新策略。
    9. 流式响应 (stream=True):
      • 对于 Chat Completions,使用流式响应本身不直接降低 Token 成本 (因为总 Token 数不变),但它可以改善用户体验,让用户更快看到结果。在某些交互场景下,用户可能在看到部分结果后就中止请求,从而间接节省了未生成部分的 Token 成本。
    10. 针对特定任务使用专用模型:
      • 例如,如果只需要语音转文本,直接使用 Whisper API;如果只需要文本向量化,使用 Embeddings API。这些专用模型通常比使用通用的大型语言模型 (如 GPT-4) 来模拟这些功能更具成本效益和性能优势。
    11. 对于 Fine-tuning:
      • 仔细准备和清洗训练数据,高质量的数据比大量低质量数据更重要。
      • 监控微调过程中的指标,避免不必要的训练轮次。
      • 评估微调后的模型是否真的比使用 Prompt Engineering 的基础模型有显著优势,以证明其成本合理性。
    12. 利用更低成本的 Embedding 模型和维度裁剪:
      • text-embedding-3-smalltext-embedding-3-large 便宜。
      • 对于新的 text-embedding-3 系列模型,可以使用 dimensions 参数来获取更短的嵌入向量,这不仅可以减少存储和计算成本(例如在向量数据库中),而且 OpenAI 对这些缩短维度的嵌入有更低的定价。

通过综合运用这些策略,开发者可以有效地控制和优化 OpenAI API 的使用成本,确保项目的可持续性。

1.4 API 请求与响应结构

与 OpenAI API 交互本质上是进行 HTTP 网络请求。理解其通用的请求和响应结构有助于更好地使用和调试 API。

  • 1.4.1 通用请求头 (HTTP Headers)
    当您通过 HTTP 直接调用 API (例如使用 curlrequests 库,而不是 OpenAI 官方 Python 客户端库) 时,通常需要设置以下请求头:

    • Authorization: 用于身份验证。
      • 值格式: Bearer YOUR_OPENAI_API_KEY
      • 示例: Authorization: Bearer sk-xxxxxxxxxxxxxxxxxxxx
    • Content-Type: 指定请求体的格式。
      • 对于发送 JSON 数据的 POST 请求 (大部分 OpenAI API 都如此),其值为 application/json
      • 示例: Content-Type: application/json
    • OpenAI-Organization (可选): 如果您的账户属于多个组织,您可以使用此头部指定请求应归属于哪个组织。值为您的组织 ID (Organization ID)。
      • 示例: OpenAI-Organization: org-xxxxxxxxxxxxxxxx
    • OpenAI-Project (可选): 如果您使用了项目功能并希望将请求与特定项目关联,可以指定项目 ID。
      • 示例: OpenAI-Project: proj_xxxxxxxxxxxxxxxx

    当使用 OpenAI 官方 Python 客户端库 (openai) 时,库会自动处理这些请求头的设置,您通常只需要在初始化客户端时提供 API 密钥。

  • 1.4.2 基本 API 端点 (Endpoints)
    OpenAI API 的所有端点都以一个基础 URL 开始,通常是 https://api.openai.com/v1/
    不同的功能对应不同的路径:

    • Chat Completions: POST /v1/chat/completions
    • Embeddings: POST /v1/embeddings
    • Image Generation (DALL·E): POST /v1/images/generations
    • Audio Transcriptions (Whisper): POST /v1/audio/transcriptions (这是一个 multipart/form-data 请求,因为需要上传文件)
    • Fine-tuning Jobs: POST /v1/fine_tuning/jobs
    • Files: POST /v1/files (用于上传文件)
    • Assistants: POST /v1/assistants
    • Threads: POST /v1/threads
    • Moderations: POST /v1/moderations

    完整的 API 端点列表和各端点的具体参数可以在 OpenAI API 参考文档 中找到。

  • 1.4.3 理解 JSON 响应格式
    OpenAI API 的绝大多数成功响应都会返回 JSON 格式的数据。JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写,也易于机器解析和生成。

    一个典型的 JSON 响应结构可能包含以下部分:

    • id: 唯一标识该次 API 响应的 ID (例如,Chat Completion ID)。
    • object: 响应对象的类型 (例如,chat.completion, embedding, list)。
    • created: API 响应创建的 Unix 时间戳。
    • model: 本次请求使用的模型名称 (例如,gpt-3.5-turbo-0125)。
    • choices (常用于 Chat Completions, Completions): 一个数组,包含了模型生成的候选项。
      • 每个 choice 对象通常包含:
        • index: 候选项的索引。
        • message (Chat Completions): 包含 role (assistant) 和 content (模型生成的文本) 的对象。
        • text (旧版 Completions): 模型生成的文本。
        • finish_reason: 模型停止生成的原因 (如 stop - 自然停止, length - 达到 max_tokens, tool_calls - 需要调用工具, content_filter - 内容被过滤)。
        • logprobs (如果请求了): Token 的对数概率信息。
    • data (常用于 Embeddings, Files list, Models list): 一个数组,包含请求的数据列表 (例如,嵌入向量列表,文件对象列表)。
    • usage (常用于 Chat Completions, Completions, Embeddings): 包含 Token 使用信息的对象,如 prompt_tokens, completion_tokens, total_tokens
    • 其他特定于 API 的字段。

    示例 JSON 响应 (Chat Completion):

    {
         
         
      "id": "chatcmpl-xxxxxxxxxxxxxxxxxxxxxxxxx",
      "object": "chat.completion",
      "created": 1700000000,
      "model": "gpt-3.5-turbo-0125",
      "choices": [
        {
         
         
          "index": 0,
          "message": {
         
         
            "role": "assistant",
            "content": "你好!我能为你做些什么?"
          },
          "logprobs": null,
          "finish_reason": "stop"
        }
      ],
      "usage": {
         
         
        "prompt_tokens": 10,
        "completion_tokens": 12,
        "total_tokens": 22
      },
      "system_fingerprint": "fp_xxxxxxxxxx" // 用于追踪模型变动的系统指纹
    }
    

    在 Python 中,可以使用 json 模块或 requests 库内置的 .json() 方法来轻松解析这些 JSON 响应。

  • 1.4.4 错误处理与状态码
    当 API 请求出现问题时,OpenAI API 会返回一个非 200 OK 的 HTTP 状态码,并且响应体通常也是 JSON 格式,包含一个 error 对象,其中描述了错误信息。

    常见的 HTTP 状态码及其含义:

    • 200 OK: 请求成功。
    • 400 Bad Request: 请求无效。通常是由于请求参数错误、格式不正确等。错误响应中会包含具体原因。
      • 示例错误: 模型不支持的参数, max_tokens 超出模型限制等。
    • 401 Unauthorized: 身份验证失败。通常是 API 密钥不正确、缺失或已过期/被撤销。
      • error.type: invalid_request_error
      • error.code: invalid_api_key
    • 403 Forbidden: 请求被拒绝,通常与权限或内容策略有关(例如,触发了内容安全过滤器)。
    • 404 Not Found: 请求的资源不存在 (例如,错误的端点,或尝试检索不存在的文件/模型)。
    • 429 Too Many Requests: 超出速率限制 (Rate Limit)。OpenAI 对 API 的调用频率和 Token 处理速率都有限制,以保证服务的稳定性。
      • error.type: tokensrequests
      • 响应头中可能包含 Retry-After 字段,建议等待一段时间后再重试。
    • 500 Internal Server Error: OpenAI 服务器端发生内部错误。这种情况通常是暂时的,可以稍后重试。
    • 502 Bad Gateway: OpenAI 服务器作为网关或代理,从上游服务器收到了无效的响应。
    • 503 Service Unavailable: OpenAI 服务器当前不可用 (例如,过载或正在进行维护)。通常也是暂时的,可以稍后重试。

    示例错误 JSON 响应:

    {
         
         
      "error": {
         
         
        "message": "You exceeded your current quota, please check your plan and billing details. For more information on usage limits, please visit: https://platform.openai.com/account/billing/limits.",
        "type": "insufficient_quota", // 错误类型
        "param": null,               // 导致错误的参数 (如果适用)
        "code": "insufficient_quota" // 错误码
      }
    }
    

    或者对于速率限制:

    {
         
         
      "error": {
         
         
        "message": "Rate limit reached for requests to gpt-4 in organization org-xxxx on tokens per min (TPM): Limit 10000, Used 9500, Requested 1000. Please try again in 3s. Visit https://platform.openai.com/account/rate-limits to learn more.",
        "type": "tokens",
        "param": null,
        "code": "rate_limit_exceeded"
      }
    }
    

    健壮的应用程序应该能够正确处理这些错误情况,例如通过记录错误、通知用户、实现重试机制 (特别是对于 429, 500, 503 错误) 等。OpenAI Python 客户端库会将这些错误封装为特定的异常类。

1.5 OpenAI Python 客户端库 (openai)

虽然可以直接使用 requests 等 HTTP 库与 OpenAI API 交互,但 OpenAI 官方提供了 Python 客户端库 (openai),它极大地简化了 API 调用过程,封装了请求构建、身份验证、错误处理等细节。强烈建议使用官方库进行开发。

  • 1.5.1 安装与基本配置

    1. 安装:
      使用 pip 安装最新版本的 openai 库:

      pip install --upgrade openai
      

      或者,如果您需要异步功能,可以安装带有 httpx 依赖的版本 (尽管最新版 openai 默认包含了 httpx):

      # pip install openai[httpx] # 旧版可能需要,新版通常已包含
      
    2. 基本配置 (API 密钥):
      如 1.2.2 节所述,推荐将 API 密钥设置为环境变量 OPENAI_API_KEYopenai 库会自动检测并使用这个环境变量。

      如果由于某种原因不能使用环境变量,您可以在初始化客户端时显式传递密钥:

      from openai import OpenAI # 导入OpenAI类
      
      # 假设你没有设置环境变量,或者想覆盖环境变量
      # explicit_api_key = "sk-your_actual_api_key_here" # 非常不推荐直接硬编码
      
      # client = OpenAI(api_key=explicit_api_key) # 显式传递API密钥
      
      # 如果设置了环境变量 OPENAI_API_KEY,则可以不传 api_key 参数
      try:
          client = OpenAI() # 客户端会自动查找 OPENAI_API_KEY 环境变量
          # 您可以进行一次简单的调用来测试配置是否成功,例如列出模型
          # models = client.models.list()
          # print("成功初始化OpenAI客户端并连接。可用模型数量:", len(models.data))
          print("OpenAI客户端初始化成功(依赖环境变量OPENAI_API_KEY)。")
      except Exception as e:
          print(f"初始化OpenAI客户端失败: {
               
               e}") # 打印初始化错误
          print("请检查您的OPENAI_API_KEY环境变量是否已正确设置,或者网络连接是否正常。")
      
      # 也可以通过 openai.api_key = "YOUR_KEY" 来全局设置 (已不推荐用于 >=1.0.0 版本)
      # import openai
      # openai.api_key = os.getenv("OPENAI_API_KEY") # 旧版用法示例,新版请使用客户端实例
      

      中文解释:
      from openai import OpenAI: 从 openai 库中导入核心的 OpenAI 类 (用于同步操作) 或 AsyncOpenAI (用于异步操作,稍后介绍)。
      client = OpenAI(): 创建 OpenAI 类的一个实例。如果 OPENAI_API_KEY 环境变量已设置,它会自动被客户端使用。
      client = OpenAI(api_key="sk-..."): 如果需要显式提供 API 密钥,可以在构造函数中通过 api_key 参数传入。

  • 1.5.2 同步与异步客户端
    openai Python 库 (版本 >= 1.0.0) 提供了同步和异步两种方式来调用 API。

    • 同步客户端 (OpenAI):

      • 这是标准的使用方式,API 调用会阻塞当前线程,直到收到响应。
      • 适用于大多数常规脚本、Web 应用的后端请求处理 (在非异步框架中) 等。
      from openai import OpenAI # 导入同步客户端
      
      # 初始化同步客户端
      # 它会自动查找 OPENAI_API_KEY 环境变量
      client = OpenAI() 
      
      # 后续章节将展示如何使用 client 对象调用各种 API
      # 例如: response = client.chat.completions.create(...)
      print("同步OpenAI客户端已准备就绪。")
      
    • 异步客户端 (AsyncOpenAI):

      • 基于 asynciohttpx 实现,允许进行非阻塞的 API 调用。
      • 适用于需要高并发处理大量 API 请求的场景,例如构建高性能的异步 Web 服务 (如 FastAPI, Starlette)、批处理任务等。
      • 使用异步客户端需要在 async def 函数中使用 await 关键字。
      from openai import AsyncOpenAI # 导入异步客户端
      import asyncio # 导入asyncio库
      
      # 初始化异步客户端
      # 它也会自动查找 OPENAI_API_KEY 环境变量
      async_client = AsyncOpenAI()
      
      async def main_async_example(): # 定义一个异步函数
          try:
              # 异步调用示例:列出模型 (这是一个轻量级调用,适合测试)
              models_list = await async_client.models.list() # 使用await进行异步调用
              # print(f"异步获取到 {len(models_list.data)} 个模型。")
              print("异步OpenAI客户端已准备就绪,并成功连接测试。")
          except Exception as e:
              print(f"异步客户端测试失败: {
               
               e}")
          finally:
              await async_client.close() # 异步客户端使用完毕后,建议显式关闭以释放资源
      
      # if __name__ == "__main__":
      #     # 要运行异步代码,需要使用 asyncio.run()
      #     # asyncio.run(main_async_example()) 
      #     print("异步客户端示例代码已注释,如需运行请取消注释并确保在异步上下文中执行。")
      
      # 提示:如果在Jupyter Notebook等已经有事件循环的环境中运行,
      # 可以直接 await async_client.models.list() (在async cell中)
      # 或者使用 get_running_loop().create_task(main_async_example())
      

      中文解释 (异步):
      from openai import AsyncOpenAI: 导入异步版本的客户端 AsyncOpenAI
      async_client = AsyncOpenAI(): 初始化异步客户端。
      async def main_async_example():: 定义一个异步函数。异步操作必须在异步函数内执行。
      models_list = await async_client.models.list(): await 关键字用于等待异步操作 async_client.models.list() 完成。在等待期间,事件循环可以去执行其他任务,从而实现非阻塞。
      await async_client.close(): 在异步操作完成后,调用 close() 方法来妥善关闭底层的 HTTP 连接和资源。这在使用 httpx.AsyncClient 时是一个好习惯。对于脚本结束时会自动清理的简单情况可能不是严格必须,但对于长时间运行的服务是推荐的。

  • 1.5.3 初始化客户端 (OpenAI())
    OpenAIAsyncOpenAI 客户端在初始化时还可以接受其他一些有用的参数,用于自定义其行为:

    from openai import OpenAI, AsyncOpenAI # 导入客户端
    import httpx # 导入httpx库,用于自定义传输配置
    
    # --- 同步客户端的更多初始化选项 ---
    sync_client_custom = OpenAI(
        api_key="sk-your_explicit_key_if_needed",  # 显式设置API密钥 (如果不用环境变量)
        organization="org-your_organization_id", # 指定组织ID (如果账户属于多个组织)
        project="proj_your_project_id",           # 指定项目ID (如果使用了项目功能)
        timeout=httpx.Timeout(30.0, connect=5.0), # 设置超时: 总超时30秒,连接超时5秒
                                                  # 默认总超时是 10 分钟,连接超时是未指定 (通常依赖系统)
                                                  # 对于 stream=True 的请求,默认是无限等待直到流结束
        max_retries=2,                            # 自动重试次数 (针对可重试的错误,如429, 5xx)
                                                  # 默认是 2 次
        # http_client=httpx.Client(proxies="http://localhost:8080"), # 传递自定义的httpx客户端实例,例如用于设置代理
    )
    print("自定义配置的同步OpenAI客户端已创建 (但未使用实际密钥或ID)。")
    
    # --- 异步客户端的更多初始化选项 (类似) ---
    async_client_custom = AsyncOpenAI(
        api_key="sk-your_explicit_key_if_needed",
        organization="org-your_organization_id",
        project="proj_your_project_id",
        timeout=httpx.Timeout(60.0, read=20.0, write=
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宅男很神经

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值