LangChain 结构化输出:用 Pydantic + PydanticOutputParser 驯服 LLM 的“自由发挥”

目录

一、Pydantic

二、PydanticOutputParser

[1、为什么需要 PydanticOutputParser?](#1、为什么需要 PydanticOutputParser?)

2、Pydantic和PydanticOutputParser核心区别

3、Pydantic的不足

(1)无法直接解析非结构化文本

[(2)缺乏对 LLM 输出的适配性](#(2)缺乏对 LLM 输出的适配性)

(3)缺少格式指导生成

(4)错误处理不够场景化

4、PydanticOutputParser核心功能

5、实现结构化输出

三、为什么需要两者结合?

四、总结


先思考一个问题:为什么要使用结构化输出?

LangChain中,结构化输出就像是**让AI"说话有条理"**。举个生活中的例子:

假设你让朋友推荐电影,普通回答可能是:"《星际穿越》不错,科幻片,诺兰拍的,有黑洞剧情。" 而结构化输出就像朋友递给你一张卡片:

javascript 复制代码
 {
   "电影名": "星际穿越",
   "类型": "科幻",
   "导演": "克里斯托弗·诺兰",
   "关键词": ["黑洞", "时间膨胀", "亲情"]
 }

为什么需要这样?

  1. 机器好处理:就像快递分拣机只认条形码,程序处理这种整齐的数据比从大段文字里"猜"信息容易得多。

  2. 避免遗漏:提前说好要哪些信息(比如必须包含导演),AI就不会忘记回答。

  3. 方便对接:直接塞进数据库、生成图表,或者转发给其他系统,都不用人工整理

一、Pydantic

Pydantic 是一个用于 数据验证和设置 的 Python 库

它通过 类型注解数据模型 的方式,简化了数据校验、转换和序列化的过程

PydanticBaseModel 类允许我们定义数据模型(如 AuthorBookLibrary),并自动处理数据的验证和转换。这确保了输入和输出的数据符合预期的格式和类型要求

主要用于:

  • 确保输入数据符合预定义的结构和约束。
  • 将数据转换为标准化的格式(如字典、JSON)。
  • 与框架(如 FastAPI)深度集成,简化 API 开发。

核心功能

  • 数据验证:基于 Python 的类型注解自动校验数据。
  • 类型转换 :将输入数据转换为定义的类型(如 strint)。
  • 结构化输出:将模型转换为字典或 JSON。
  • 错误处理:提供清晰的错误信息,便于调试

二、PydanticOutputParser

PydanticOutputParser**** 是LangChain库中的一个工具,用于语言模型生成输出解析并转换为结构化的Python数据模型

通过**PydanticOutputParser**,Pydantic 可以直接用于解析来自语言模型的输出,将其转换为预定义的 Pydantic 数据模型。这种集成简化了将自然语言处理结果映射到结构化数据的过程

1、为什么需要 PydanticOutputParser?

既然 Pydantic 已经提供了强大的数据验证和结构化能力,为什么还要引PydanticOutputParser?关键在于 输入源的差异使用场景的特殊性

2、 Pydantic和PydanticOutputParser核心区别

维度 Pydantic PydanticOutputParser
输入类型 结构化数据(如字典、JSON) 非结构化文本(如 LLM 的输出、自然语言)
主要职责 数据校验、类型转换、序列化 解析自由文本为结构化数据
适用场景 API 请求、配置文件加载、数据库交互 处理 LLM 输出、外部系统非标准响应
自动化程度 需手动转换输入数据到模型 自动提取文本中的结构化信息

3、Pydantic的不足

(1)无法直接解析非结构化文本

假设 LLM 输出以下文本:

javascript 复制代码
用户信息:张三,年龄30岁,邮箱[email protected]

Pydantic 无法直接将其转换为结构化模型,需手动编写文本提取和格式转换逻辑

(2)缺乏对 LLM 输出的适配性

问题 :LLM 的输出具有 不确定性和模糊性,例如:

  • 混合自然语言和 JSON(如 答案是:{ "name": "张三" })。
  • 字段名称不匹配(如 user_name vs username)。
  • 格式错误(如未闭合的引号、缺少逗号)

LLM 可能返回以下有问题的 JSON:

javascript 复制代码
{ "name": "张三, "age": "30" }  // 引号未闭合,age 是字符串

Pydantic 会直接抛出错误,无法自动修复或提取有效部分

(3)缺少格式指导生成

问题 :Pydantic 无法生成 针对 LLM 的格式指令,例如在提示(Prompt)中明确要求输出符合特定 JSON 结构。需开发者手动编写格式说明,增加维护成本

PydanticOutputParser 的 **get_format_instructions()**能根据 Pydantic 模型自动生成格式模板,直接嵌入到提示中,确保 LLM 按指定格式输出

(4)错误处理不够场景化

问题:Pydantic 的错误提示面向开发者,但未针对 LLM 输出场景优化。例如:

  • 无法区分"字段缺失"和"LLM 未理解指令"。
  • 缺少对 LLM 常见输出问题(如多余的解释文本)的容错。

若 LLM 返回以下文本:

javascript 复制代码
回答:我不知道用户年龄,但名字是张三。

Pydantic 会直接报错,而无法提取部分有效信息(如 name

4、PydanticOutputParser核心功能

(1) 结构化输出

非结构化文本 (如 LLM 生成的自由格式文本或 JSON 字符串)转换为 结构化的 Pydantic 模型,使其符合预定义的数据格式和规则。

(2) 数据验证

在解析过程中,自动验证输出是否满足 Pydantic 模型定义的约束,例如:

  • 类型校验 (如 intfloatbool)。
  • 范围限制(如数值范围、字符串长度)。
  • 格式要求(如日期格式、邮箱格式)。

(3)错误处理

当输出不符合预期时,提供 详细的错误信息,帮助快速定位问题,例如:

  • 字段缺失。
  • 类型不匹配。
  • 值超出范围。

5、实现结构化输出

这是一个 图书馆信息生成与结构化解析 的案例,目标是通过 LangChain 和 Pydantic 实现以下功能:

  1. 让 LLM 按指定格式生成图书馆信息(包含名称和书籍列表)。
  2. 将 LLM 的非结构化输出自动转换为强类型的 Python 对象。
  3. 确保数据格式正确(如作者年龄在 0-120 之间)。
python 复制代码
from typing import List

from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field


# 定义作者模型:
class Author(BaseModel):
    name: str = Field(description='Name of the author')
    age: int = Field(description='Age of the author',ge=0, le=120)
    

# 定义图书模型:
class Book(BaseModel):
    title: str = Field(description='python')
    author: Author = Field(description='echola')


# 定义图书馆模型:
class Library(BaseModel):
    name: str = Field(description='History Library')
    books: List[Book] = Field(description='List of books')


# 使用PydanticOutputParser解析输出,指定模型为Library
parser = PydanticOutputParser(pydantic_object=Library)

# 定义提示模版,包含图书馆及图书的信息
prompt = PromptTemplate(
    # 提示的文本模版
    template="Provide information about a library an its book,\n{format_instructions}\n{library}",
    # 输入变量为library
    input_variables=["library"],
    # 部分变量为格式说明
    partial_variables={"format_instructions": parser.get_format_instructions()}
)

# 定义LLM
llm = ChatOpenAI(
    model='deepseek-ai/DeepSeek-R1',
    openai_api_key="sk-jcuzvtuophtzgkfhhbanhjgqfxviewqwnwyhkihsvwwoufsu",
    openai_api_base='https://api.siliconflow.cn/v1',
    temperature=0,
    max_tokens=1000
)

# 格式化提示内容,传入查询内容"请描述图书馆的书籍"
message = prompt.format_prompt(library="请描述图书馆的书籍")
# 获取输出
# 解析模型输出为Library对象
result = llm.invoke(message)

# 打印结果
print(result.content)

运行结果输出:

javascript 复制代码
{
  "name": "History Library",
  "books": [
    {
      "title": "python",
      "author": {
        "name": "echola",
        "age": 40
      }
    },
    {
      "title": "The Art of Programming",
      "author": {
        "name": "John Code",
        "age": 45
      }
    },
    {
      "title": "Data Science Essentials",
      "author": {
        "name": "Alice Data",
        "age": 38
      }
    }
  ]
}

PromptTemplate 定义了一个模板,用于生成传递给 LLM 的输入提示。模板包含两个两个占位符变量部分:用户的查询(library)和格式化指令(format_instructions

在实例化**PromptTemplate类时将format_instructions作为partial_variables** 的一部分传入,如此便在原有的提示词模版中追加了**format_instructions**变量,这个变量是输出指令字符串

释义:

  • library:是希望模型产生的列表主题
  • format_instructions:是从输出解析器中获取的预设的输出指令

此处library变量就是"请描述图书馆的书籍",format_instructions的指令模型就是Library类

PydanticOutputParser用于将模型的文本解析为结构化的Library对象

三、为什么需要两者结合?

1. 场景互补

  • Pydantic 解决"数据如何存储和使用"的问题,例如:
    • 确保从数据库读取的数据符合模型。
    • 验证 API 请求参数的合法性。
  • PydanticOutputParser 解决"数据如何从非结构化来源提取"的问题,例如:
    • 将用户自然语言指令(如"帮我订明天北京到上海的机票")解析为结构化的预订请求。
    • 处理外部 API 返回的半结构化文本(如混合了文本和 JSON 的响应)。

2、开发效率

  • 减少胶水代码 :若手动解析 LLM 输出,需编写大量字符串处理、类型转换和错误检查代码。PydanticOutputParser 将这些逻辑封装为通用工具。
  • 统一错误处理Pydantic 的校验错误与 PydanticOutputParser 的解析错误可统一捕获,简化异常处理流程。

3、动态适配

  • 灵活应对 LLM 的不确定性 :LLM 的输出可能不稳定(如偶尔遗漏字段或格式错误)。PydanticOutputParser 的解析逻辑能动态适配,结合重试机制(如 LangChain 的 RetryOutputParser)提高鲁棒性

四、总结

结构化输出的意义

  • 对机器友好:程序无需从自由文本中"猜测"数据,直接按字段提取。
  • 对系统友好:数据格式统一,便于跨模块传递(如存入数据库、生成报表、触发后续流程)。
  • 对开发者友好:减少数据清洗代码,专注业务逻辑。

Pydantic + PydanticOutputParser 的协同价值

  • 从自由到规范:将 LLM 的"自由发挥"转换为严格的结构化数据。
  • 端到端校验:从输入解析到业务使用,全程保障数据质量。
  • 标准化开发范式:为 NLP 任务提供可复用的数据管理方案。

通过两者的结合,开发者能更高效地构建基于 LLM 的智能应用,确保数据从输入到输出的全链路可控、可靠、可维护。

相关推荐
裁二尺秋风1 小时前
Nginx — Nginx处理Web请求机制解析
前端·nginx
一 乐1 小时前
网红酒店|基于java+vue的网红酒店预定系统(源码+数据库+文档)
java·开发语言·数据库·毕业设计·论文·springboot·网红酒店预定系统
excel1 小时前
webpack 核心编译器 第五节
前端
Alfadi联盟 萧瑶2 小时前
Python-用户账户与应用程序样式
数据库·sqlite
曲辒净2 小时前
vue搭建一个树形菜单项目
前端·javascript·vue.js
影子24016 小时前
Navicat导出mysql数据库表结构说明到excel、word,单表导出方式记录
数据库·mysql·excel
java_heartLake6 小时前
PostgreSQL15深度解析(从15.0-15.12)
数据库·postgresql
喝拿铁写前端7 小时前
前端与 AI 结合的 10 个可能路径图谱
前端·人工智能
codingandsleeping7 小时前
浏览器的缓存机制
前端·后端