loading

Loading

首页 📂开发编程✍代码示例

OpenAI API Python实战教程:如何稳定获取结构化 JSON 输出(简易/复杂 双示例)

字数: (8046)
阅读: (70)
0

痛点:为什么我拿不到想要的 JSON?

在开发 AI 应用时,我们经常需要从非结构化文本中提取信息并转换为 JSON 格式,以便程序处理。传统方法是在提示(Prompt)中要求模型返回 JSON,但你可能遇到过这些问题:

  • 模型返回的 JSON 前后被包裹在多余的解释性文本中(例如 "好的,这是您要的 JSON:...")。
  • 在复杂场景下,模型生成的 JSON 可能存在语法错误(如缺少逗号、括号不匹配)。
  • 输出格式不稳定,每次请求的结果都可能需要做不同的字符串清理,增加了处理成本。

jeiagi-openai5946dsd

解决方案:强制启用 JSON 模式

幸运的是,OpenAI API 提供了一个强大的功能——JSON 模式(JSON Mode)。通过一个简单的参数,我们就能强制模型输出一个语法绝对正确的 JSON 对象,彻底解决上述所有问题。

本教程将通过一个实用的 Python 示例,带你一步步掌握如何安全、可靠地调用 API 并获得100%稳定的 JSON 输出。

你将学到:

  • 使用 .env 文件安全管理 API 密钥的最佳实践。
  • 构建有效的系统提示(System Prompt)来精确指导模型行为。
  • 利用 response_format 参数启用 JSON 模式,确保输出的可靠性。
  • 处理更复杂的嵌套 JSON 和列表。

步骤 1:准备工作

在开始之前,请确保你已准备好:

  • Python 3.7+ 环境。
  • 一个 OpenAI API 密钥
  • 对 API 和 JSON 的基本了解。

1.1 安装必要的库

我们需要 openai 库来与 API 交互,以及 python-dotenv 库来优雅地管理环境变量。

pip install openai python-dotenv

1.2 创建 .env 文件管理密钥

在代码中硬编码密钥是严重的安全隐患。我们将在项目根目录下创建一个名为 .env 的文件来存放配置。

# .env 文件
# 输入你在 uiuiapi.com 获取的 API 密钥或官方API秘钥
API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# API 的基础 URL (例如 OpenAI 官方地址或uiuiAPI地址)
BASE_URL="https://uiuiapi地址/v1"

# 你希望使用的模型名称 (可选)
MODEL_NAME="gpt-4o"

💡 安全提示: 务必将 .env 文件添加到你的 .gitignore 中,防止将敏感信息泄露到代码仓库。

jeiagi-openai594dsd

步骤 2:编写 Python 脚本

我们将所有逻辑都放在一个名为 extract_info.py 的文件中。

2.1 完整代码概览

对于希望快速上手的开发者,这里是完整的脚本。后续我们将对每个部分进行深度剖析。

import os
import json
from openai import OpenAI
from dotenv import load_dotenv

def main():
    """主函数,从 .env 文件加载配置并执行API调用。"""
    # 1. 安全加载配置
    load_dotenv()
    api_key = os.getenv("API_KEY")
    base_url = os.getenv("BASE_URL")
    model_name = os.getenv("MODEL_NAME", "gpt-4o")

    if not api_key or not base_url:
        print("错误:API_KEY 或 BASE_URL 未在 .env 文件中设置。")
        return

    print(f"--- 配置加载成功,使用模型: {model_name} ---")

    # 2. 初始化客户端
    try:
        client = OpenAI(api_key=api_key, base_url=base_url)
    except Exception as e:
        print(f"初始化OpenAI客户端时出错: {e}")
        return

    # 3. 构造精准的提示
    source_text = "user email is test@example.com, and the user id is 12345."
    messages = [
        {"role": "system", "content": "You are a helpful assistant designed to output JSON. Your task is to extract structured data from the user's text."},
        {"role": "user", "content": f"From the text '{source_text}', extract the email and user ID. The JSON keys must be exactly 'email' and 'user_id'."}
    ]

    # 4. 调用 API 并强制启用 JSON 模式
    print("\n--- 正在调用 API 并请求 JSON 输出... ---")
    try:
        response = client.chat.completions.create(
            model=model_name,
            messages=messages,
            # 这是启用 JSON 模式的关键!
            response_format={"type": "json_object"},
        )
        json_content_string = response.choices[0].message.content

        # 5. 解析并使用结果
        print("API 调用成功,返回纯净的 JSON 字符串:")
        print(json_content_string)

        parsed_json = json.loads(json_content_string)

        print("\n解析为 Python 字典:")
        print(parsed_json)

        email = parsed_json.get('email')
        user_id = parsed_json.get('user_id')

        print("\n--- 提取结果 ---")
        print(f"Email: {email or '未找到'}")
        print(f"ID: {user_id or '未找到'}")

    except json.JSONDecodeError:
        print("\n错误:无法解析返回的字符串为 JSON。")
    except Exception as e:
        print(f"\n调用API时发生错误: {e}")

if __name__ == "__main__":
    main()

2.2 代码深度剖析

第 1-2 部分:配置与初始化

这部分代码负责安全地加载环境变量并初始化 API 客户端。将配置与代码分离是现代软件开发的标准实践。

第 3 部分:提示工程的艺术

即使在 JSON 模式下,一个清晰的提示也至关重要,因为它决定了 JSON 的内容和结构

  • 系统消息 (**role: "system"**): 为模型设定一个高级角色和任务。我们明确告诉它,它的核心职责就是输出 JSON。
  • 用户消息 (**role: "user"**): 给出具体指令。我们不仅提供了待提取的文本,还严格规定了 JSON 的键名 ('email''user_id')。这种精确性是获得理想输出的关键。
第 4 部分:**response_format - 终极武器**

response_format={"type": "json_object"} 是本教程的核心。它向 API 发出一个强制指令,要求返回的内容必须是一个语法有效的 JSON 对象。这消除了所有格式不一致的风险,让你得到的 response.choices[0].message.content 是一个可以直接被解析的、纯净的 JSON 字符串。

第 5 部分:稳健地处理结果
  • 我们使用 try...except 块来捕获潜在的错误,如网络问题或 API 密钥无效。
  • 特别地,我们还捕获 json.JSONDecodeError,尽管在 JSON 模式下这几乎不可能发生,但这是一种良好的防御性编程习惯。
  • 使用字典的 .get() 方法来访问键值。相比 parsed_json['email'],如果键不存在,.get() 会返回 None 而不是抛出 KeyError 异常,使代码更具韧性。

jeiagi-openai59445f56d

步骤 3:进阶技巧:处理复杂 JSON,完整代码概览。

现实世界的需求往往更复杂。假设我们需要从一段文本中提取一个包含嵌套对象和列表的 JSON。

示例场景:从用户反馈中提取用户信息、评分和标签。

import os
import json
from openai import OpenAI
from dotenv import load_dotenv

def run_simple_example(client: OpenAI, model_name: str):
    """运行一个简单的信息提取示例。"""
    print("\n--- 运行简单示例 ---")
    source_text = "user email is test@example.com, and the user id is 12345."
    messages = [
        {"role": "system", "content": "You are a helpful assistant designed to output JSON. Your task is to extract structured data from the user's text."},
        {"role": "user", "content": f"From the text '{source_text}', extract the email and user ID. The JSON keys must be exactly 'email' and 'user_id'."}
    ]

    response = client.chat.completions.create(
        model=model_name,
        messages=messages,
        response_format={"type": "json_object"},
    )

    json_content_string = response.choices[0].message.content
    print("API 调用成功,返回纯净的 JSON 字符串:")
    print(json_content_string)

    parsed_json = json.loads(json_content_string)
    print("\n解析为 Python 字典:")
    print(parsed_json)

    email = parsed_json.get('email')
    user_id = parsed_json.get('user_id')

    print("\n--- 提取结果 ---")
    print(f"Email: {email or '未找到'}")
    print(f"ID: {user_id or '未找到'}")

def run_advanced_example(client: OpenAI, model_name: str):
    """运行一个处理复杂嵌套 JSON 的进阶示例。"""
    print("\n\n--- 运行进阶示例 ---")
    source_text = "User 'John Doe' (ID: 987) left a 5-star review for product 'SuperWidget'. He mentioned it was 'easy to use' and 'reliable'."
    messages = [
        {"role": "system", "content": "You are an expert data extraction assistant. Output valid JSON only."},
        {"role": "user", "content": f"""
        From the text below, extract the user's details, review score, and tags.
        Text: '{source_text}'

        Provide the output in a JSON format with the following structure:
        - A top-level key 'review_details'.
        - Inside it, an object 'user' with string keys 'name' and 'id'.
        - A key 'rating' with an integer value.
        - A key 'tags' with a list of strings.
        """}
    ]

    response = client.chat.completions.create(
        model=model_name,
        messages=messages,
        response_format={"type": "json_object"},
    )

    json_content_string = response.choices[0].message.content
    print("API 调用成功,返回纯净的 JSON 字符串:")
    print(json_content_string)

    parsed_json = json.loads(json_content_string)
    print("\n解析为 Python 字典:")
    print(parsed_json)

    print("\n--- 提取结果 ---")
    review_details = parsed_json.get('review_details', {})
    user_info = review_details.get('user', {})
    print(f"User Name: {user_info.get('name', '未找到')}")
    print(f"User ID: {user_info.get('id', '未找到')}")
    print(f"Rating: {review_details.get('rating', '未找到')}")
    print(f"Tags: {review_details.get('tags', [])}")

def main():
    """主函数,加载配置并运行所有示例。"""
    load_dotenv()
    api_key = os.getenv("API_KEY")
    base_url = os.getenv("BASE_URL")
    model_name = os.getenv("MODEL_NAME", "gpt-4o")

    if not api_key or not base_url:
        print("错误:API_KEY 或 BASE_URL 未在 .env 文件中设置。")
        return

    print(f"--- 配置加载成功,使用模型: {model_name} ---")

    try:
        client = OpenAI(api_key=api_key, base_url=base_url)
        run_simple_example(client, model_name)
        run_advanced_example(client, model_name)
    except Exception as e:
        print(f"\n程序执行时发生错误: {e}")

if __name__ == "__main__":
    main()

预期输出:

{
  "review_details": {
    "user": {
      "name": "John Doe",
      "id": "987"
    },
    "rating": 5,
    "tags": [
      "easy to use",
      "reliable"
    ]
  }
}

关键在于:在用户提示中,我们通过文字清晰地描述了期望的 JSON Schema(数据模式),包括嵌套关系、键名和值类型(字符串、整数、列表)。模型在 JSON 模式下会严格遵循这个结构。

总结与核心要点

通过本教程,你已经掌握了利用 OpenAI API 的 JSON 模式来获取高质量结构化数据的核心技术。

jeiagi-openai594

  • 安全永远第一:始终通过 .env 文件管理你的密钥。
  • 提示决定内容response_format 保证格式,而精心设计的提示保证内容的准确性。在提示中清晰描述你想要的 JSON 结构。
  • 强制优于请求:与其在提示中“请求”JSON,不如用 response_format={"type": "json_object"} 来“强制”它。
  • 代码要稳健:总是为 API 调用和数据解析添加错误处理。

这项技术是构建可靠、可预测的 AI 应用的基石,能广泛应用于数据抓取、自然语言理解、智能客服等多种场景。现在,就开始在你的项目中应用它吧!

版权信息: 本文由界智通(jieagi)团队编写,保留所有权利。未经授权,不得转载或用于商业用途。

转载请注明出处: 界智通

本文的链接地址: https://www.jieagi.com/daimashili/73.html

您可能对以下文章感兴趣
评论列表:
empty

暂无评论

技术博客底部