OpenAI API Python实战教程:如何稳定获取结构化 JSON 输出(简易/复杂 双示例)
痛点:为什么我拿不到想要的 JSON?
在开发 AI 应用时,我们经常需要从非结构化文本中提取信息并转换为 JSON 格式,以便程序处理。传统方法是在提示(Prompt)中要求模型返回 JSON,但你可能遇到过这些问题:
- 模型返回的 JSON 前后被包裹在多余的解释性文本中(例如
"好的,这是您要的 JSON:..."
)。 - 在复杂场景下,模型生成的 JSON 可能存在语法错误(如缺少逗号、括号不匹配)。
- 输出格式不稳定,每次请求的结果都可能需要做不同的字符串清理,增加了处理成本。
解决方案:强制启用 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
中,防止将敏感信息泄露到代码仓库。
步骤 2:编写 Python 脚本
我们将所有逻辑都放在一个名为 extract_info.py
的文件中。
2.1 完整代码概览
对于希望快速上手的开发者,这里是完整的脚本。后续我们将对每个部分进行深度剖析。
import os
import json
from openai import OpenAI
from dotenv import load_dotenvdef 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 文件中设置。")returnprint(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
异常,使代码更具韧性。
步骤 3:进阶技巧:处理复杂 JSON,完整代码概览。
现实世界的需求往往更复杂。假设我们需要从一段文本中提取一个包含嵌套对象和列表的 JSON。
示例场景:从用户反馈中提取用户信息、评分和标签。
import os
import json
from openai import OpenAI
from dotenv import load_dotenvdef 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.contentprint("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.contentprint("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 文件中设置。")returnprint(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 模式来获取高质量结构化数据的核心技术。
- 安全永远第一:始终通过
.env
文件管理你的密钥。 - 提示决定内容:
response_format
保证格式,而精心设计的提示保证内容的准确性。在提示中清晰描述你想要的 JSON 结构。 - 强制优于请求:与其在提示中“请求”JSON,不如用
response_format={"type": "json_object"}
来“强制”它。 - 代码要稳健:总是为 API 调用和数据解析添加错误处理。
这项技术是构建可靠、可预测的 AI 应用的基石,能广泛应用于数据抓取、自然语言理解、智能客服等多种场景。现在,就开始在你的项目中应用它吧!
版权信息: 本文由界智通(jieagi)团队编写,保留所有权利。未经授权,不得转载或用于商业用途。