大型语言模型(LLM),例如Google Gemini和OpenAI GPT-4o,在文本生成方面表现出了惊人的能力。然而,在许多实际应用场景中,我们需要的不仅仅是自由格式的文本,而是可以直接嵌入应用程序的结构化数据。本文将深入探讨如何利用Python,通过Gemini API和OpenAI API,从LLM中获取结构化JSON输出,并利用Pydantic模型自动验证数据,从而提升AI应用的可靠性和可维护性。

结构化输出:告别繁琐解析

传统的LLM应用往往返回非结构化的文本,需要开发者自行编写代码进行解析,这不仅耗时耗力,而且容易出错。结构化输出 则改变了这一现状。它允许我们预先定义数据的Schema,让LLM直接返回符合该Schema的JSON格式数据。

举个例子,如果我们想从LLM获取一个菜谱信息,传统的LLM可能会返回类似这样的文本:

这里是一个曲奇饼干的菜谱:...

而使用结构化输出,我们可以让LLM直接返回如下JSON数据:

{
  "recipe_name": "巧克力曲奇",
  "ingredients": [
    "2 杯面粉",
    "1 杯糖",
    "1 杯巧克力豆"
  ]
}

这种方法的优势显而易见:

  • 避免手动解析:无需编写复杂的正则表达式或字符串处理代码。
  • 数据格式可预测:保证数据的一致性,方便后续处理。
  • 易于验证:可以使用Pydantic等库进行自动验证,确保数据的质量。

Gemini API:Pydantic加持的结构化JSON输出

Google Gemini API 提供了强大的结构化输出能力,允许开发者通过指定 response_schema 来获得经过 Pydantic 验证的 JSON 输出。这极大地简化了从LLM获取结构化数据的流程。

以下是一个使用 Gemini API 获取曲奇饼干菜谱的示例代码:

from google import genai
from pydantic import BaseModel
from dotenv import load_dotenv
import os

load_dotenv()

api_key = os.getenv("GEMINI_APIKEY")
if not api_key:
    raise ValueError("GEMINI_APIKEY environment variable not set")

client = genai.Client(api_key=api_key)

class Recipe(BaseModel):
    recipe_name: str
    ingredients: list[str]

response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="给我一个流行的曲奇饼干菜谱,并包括配料的用量。",
    config={
        "response_mime_type": "application/json",
        "response_schema": Recipe,
    },
)

recipe: Recipe = response.parsed

print(f"菜谱名称: {recipe.recipe_name}")
print("配料:")
for ingredient in recipe.ingredients:
    print(f"- {ingredient}")

代码解析:

  1. 定义 Pydantic 模型: 首先,我们使用 Pydantic 定义了一个 Recipe 模型,明确了菜谱的 recipe_nameingredients 字段,并指定了各自的数据类型。这为 Gemini API 提供了明确的数据结构定义。
  2. 调用 generate_content() 方法: 在调用 generate_content() 方法时,我们将 response_mime_type 设置为 "application/json",并将 response_schema 设置为我们定义的 Recipe 模型。这告诉 Gemini API 我们期望返回 JSON 格式的数据,并且数据应该符合 Recipe 模型的结构。
  3. 访问 response.parsed Gemini API 会自动将返回的 JSON 数据解析为 Recipe 类的实例,并赋值给 response.parsed。我们可以直接通过 response.parsed 访问结构化数据,无需手动解析。

实际应用案例:

假设你需要构建一个美食推荐App,用户可以输入关键词,App会返回相关的菜谱信息。使用 Gemini API 的 结构化输出 功能,你可以轻松地从LLM获取菜谱名称、配料、制作步骤等信息,并将这些信息直接展示在App界面上,而无需编写复杂的解析代码。

数据案例:

以下是一个可能的返回结果:

{
  "recipe_name": "花生酱曲奇",
  "ingredients": [
    "1 杯奶油花生酱",
    "1 杯砂糖",
    "1 个鸡蛋"
  ]
}

OpenAI GPT-4o:新一代结构化输出解析方案

OpenAI 近期也加入了 结构化输出 解析的行列,为开发者提供了另一种便捷的方式来获取结构化数据。与 Gemini API 类似,OpenAI 也支持使用 Pydantic 模型进行数据验证。

以下是使用 OpenAI GPT-4o 获取曲奇饼干菜谱的示例代码:

from openai import OpenAI
from pydantic import BaseModel
from dotenv import load_dotenv
import os

load_dotenv()

api_key = os.getenv("OPENAI_APIKEY")
if not api_key:
    raise ValueError("OPENAI_APIKEY environment variable not set")

client = OpenAI(api_key=api_key)

class Recipe(BaseModel):
    recipe_name: str
    ingredients: list[str]

response = client.responses.parse(
    model="gpt-4o-2024-08-06",
    input=[
        {
            "role": "system",
            "content": "你是一个乐于助人的助手,可以从用户查询中提取结构化数据。",
        },
        {
            "role": "user",
            "content": "给我一个流行的曲奇饼干菜谱,并包括配料的用量。",
        },
    ],
    text_format=Recipe,
)

recipe = response.output_parsed

print(f"菜谱名称: {recipe.recipe_name}")
print("配料:")
for ingredient in recipe.ingredients:
    print(f"- {ingredient}")

代码解析:

  1. 定义 Pydantic 模型: 同样,我们首先定义了一个 Recipe 模型,明确了菜谱的结构。
  2. 调用 client.responses.parse() 方法: 使用 client.responses.parse() 方法向 LLM 发送请求,并将 text_format 参数设置为我们定义的 Recipe 模型。这告诉 OpenAI 我们期望返回符合 Recipe 模型的结构化数据。
  3. 访问 response.output_parsed OpenAI 会自动将返回的数据解析为 Recipe 类的实例,并赋值给 response.output_parsed

实际应用案例:

假设你需要构建一个智能客服机器人,它可以回答用户关于电影信息的问题。使用 OpenAI GPT-4o 的 结构化输出 功能,你可以让LLM返回电影名称、导演、演员、上映日期等信息,并将这些信息以结构化的方式展示给用户。

数据案例:

以下是一个可能的返回结果:

{
  "recipe_name": "巧克力燕麦曲奇",
  "ingredients": [
    "1 杯全麦面粉",
    "1/2 杯红糖",
    "1/2 杯燕麦片",
    "1/2 杯巧克力碎片"
  ]
}

结构化输出的应用场景:无限可能

结构化输出 的应用场景非常广泛,以下是一些典型的例子:

  • 构建聊天机器人: 聊天机器人不再局限于简单的文本回复,可以返回结构化的数据,例如产品信息、预订信息等。
  • 自动化工作流: 自动化生成菜谱、任务清单、结构化问答等。例如,可以根据用户的输入,自动生成一份包含详细步骤的旅行计划。
  • 验证 AI 响应: 使用类型化的 Schema 验证 AI 响应,确保数据的准确性和完整性。
  • 减少自定义解析逻辑: 大幅减少编写自定义解析代码的工作量,提高开发效率。

更多实际案例:

  • 金融领域: 从新闻报道中提取公司名称、股票代码、财务数据等,用于构建量化交易模型。
  • 医疗领域: 从病历记录中提取疾病名称、症状、药物信息等,辅助医生进行诊断和治疗。
  • 电商领域: 从商品描述中提取商品名称、品牌、价格、规格等,用于构建商品搜索引擎。

实用技巧:提升结构化输出的质量

在使用 结构化输出 时,以下是一些实用的技巧,可以帮助你提升输出的质量:

  • 定义清晰明确的 Pydantic 模型: 模型的定义越清晰,LLM 就越容易生成符合要求的数据。避免使用模糊的字段名称或数据类型,尽量使用具体的、可枚举的值。
  • 优雅地处理验证错误: 当 LLM 返回的数据不符合 Pydantic 模型的定义时,会抛出验证错误。你需要编写代码来捕获这些错误,并进行相应的处理,例如向用户提示错误信息,或者使用默认值进行填充。
  • 记录原始响应以进行调试: 将 LLM 的原始响应记录下来,可以帮助你分析错误的原因,并改进模型的定义或提示语。
  • 及时更新: Gemini 和 OpenAI 的 API 都在不断发展,及时关注官方文档,了解最新的功能和特性。

具体案例:

假设你的 Pydantic 模型定义了一个 age 字段,数据类型为 int,但是 LLM 返回的 age 值为字符串 "twenty",那么 Pydantic 验证会失败。你需要捕获这个错误,并向用户提示 “年龄必须是数字”。

结论:结构化输出引领AI应用新方向

结构化输出 将自然语言转换为清晰的 JSON 数据,为 AI 应用带来了革命性的变化。无论你选择 Google Gemini 还是 OpenAI GPT-4o,都可以通过简单的 Python 代码,将自然语言转化为干净的 JSON 数据。它不仅提高了开发效率,还增强了 AI 应用的可靠性和可维护性。随着 LLM 技术的不断发展, 结构化输出 将在 AI 应用中发挥越来越重要的作用。拥抱结构化输出,将使你的AI应用更加强大、更加智能。

未来展望:

随着大模型技术的不断进步,我们可以期待 结构化输出 功能将更加完善,支持更复杂的数据结构和更灵活的配置选项。未来的 LLM 可能会具备更强的理解能力和推理能力,能够更好地理解用户的意图,并生成更准确、更符合要求的结构化数据。同时,各种开源工具和框架也将不断涌现,为 结构化输出 的应用提供更便捷的支持。让我们共同期待 结构化输出 在 AI 领域带来的更多惊喜。