【LangChain Output Parser 输出解析器】输出篇

LangChain Output Parser 输出解析器完全指南

目录

  • [什么是 Output Parser](#什么是 Output Parser)

  • [为什么需要 Output Parser](#为什么需要 Output Parser)

  • [StrOutputParser 字符串解析器](#StrOutputParser 字符串解析器)

  • [JsonOutputParser JSON解析器](#JsonOutputParser JSON解析器)

  • [PydanticOutputParser Pydantic解析器](#PydanticOutputParser Pydantic解析器)

  • [with_structured_output 结构化输出](#with_structured_output 结构化输出)

  • [Annotated 类型注解](#Annotated 类型注解)

  • [get_format_instructions 格式化指令](#get_format_instructions 格式化指令)


什么是 Output Parser

Output Parser 是 LangChain 中用于将大模型自由文本输出转换为结构化数据的工具。

问题

大模型输出的是自由文本

复制代码
"好的,我给你返回一个JSON:{"name": "华为", "price": 9999}"

但程序需要的是结构化数据

复制代码
{"name": "华为", "price": 9999}  # dict 类型,可以直接使用

解决方案

复制代码
大模型自由文本  →  Output Parser  →  结构化数据

Output Parser 就像一个"翻译器",把 AI 说的话转成程序能理解的数据格式。


为什么需要 Output Parser

场景对比

场景 没有 Parser 有 Parser
获取用户名 "用户名为:张三" {"name": "张三"}
获取商品信息 "商品:电脑,价格:5999元" {"product": "电脑", "price": 5999}
获取列表 "1. 苹果 2. 香蕉 3. 橙子" ["苹果", "香蕉", "橙子"]

优势

  1. 程序化处理 :直接用 .name.price 访问数据

  2. 减少错误:不用手动解析字符串

  3. 类型安全:Pydantic 等支持数据校验

  4. API对接:直接返回 JSON 给前端或 API


StrOutputParser 字符串解析器

什么是 StrOutputParser

最简单、最基础的输出解析器。从结果中提取 content 字段转换为字符串输出

复制代码
from langchain_core.output_parsers import StrOutputParser
​
parser = StrOutputParser()
result = parser.invoke(ai_message)
# result 现在是字符串类型

工作原理

复制代码
AIMessage 对象
├── content: "这是AI的回答内容"
├── additional_kwargs: {}
└── ...
        ↓ StrOutputParser.invoke()
"这是AI的回答内容"  # 字符串

完整示例

复制代码
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain.chat_models import init_chat_model
import os
from dotenv import load_dotenv
​
load_dotenv(encoding='utf-8')
​
# 创建提示模板
chat_prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个{role},请简短回答我的问题"),
    ("human", "请回答:{question}")
])
​
# 初始化模型
model = init_chat_model(
    model="qwen-plus",
    model_provider="openai",
    api_key=os.getenv("aliQwen-api"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
​
# 调用模型
prompt = chat_prompt.invoke({"role": "AI助手", "question": "什么是LangChain?"})
result = model.invoke(prompt)
​
print(f"原始输出类型: {type(result)}")  # AIMessage
print(f"原始输出: {result}")
​
# 使用 StrOutputParser 解析
parser = StrOutputParser()
response = parser.invoke(result)
​
print(f"解析后类型: {type(response)}")  # str
print(f"解析后内容: {response}")

使用场景

  • 简单问答,直接获取文本回答

  • 不需要结构化数据时

  • 作为其他 Parser 的基础


JsonOutputParser JSON解析器

什么是 JsonOutputParser

将大模型的自由文本输出转换为结构化 JSON 数据(dict 类型)。

基本用法

复制代码
from langchain_core.output_parsers import JsonOutputParser
​
parser = JsonOutputParser()
result = parser.invoke(ai_message)
# result 现在是 dict 类型

方法1:提示词指定格式

在提示词中直接指定返回 JSON 格式:

复制代码
chat_prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个{role},请简短回答我的问题,结果返回json格式,q字段表示问题,a字段表示答案。"),
    ("human", "请回答:{question}")
])
​
prompt = chat_prompt.invoke({"role": "AI助手", "question": "什么是LangChain?"})
result = model.invoke(prompt)
​
parser = JsonOutputParser()
response = parser.invoke(result)
print(response)  # {'q': '什么是LangChain?', 'a': 'LangChain是一个...'}

方法2:使用 Pydantic 模型 + get_format_instructions(推荐)

复制代码
from langchain_core.output_parsers import JsonOutputParser
from pydantic import BaseModel, Field

# 定义数据结构
class Person(BaseModel):
    time: str = Field(description="时间")
    person: str = Field(description="人物")
    event: str = Field(description="事件")

# 创建解析器
parser = JsonOutputParser(pydantic_object=Person)

# 获取格式化指令(让模型知道如何输出)
format_instructions = parser.get_format_instructions()
print(format_instructions)
# The output format must be a JSON object...
# {"time": "...", "person": "...", "event": "..."}

# 在提示词中使用
chat_prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个AI助手,你只能输出结构化JSON数据。"),
    ("human", "请生成一个关于{topic}的新闻。{format_instructions}")
])

prompt = chat_prompt.format_messages(
    topic="小米SU7发布",
    format_instructions=format_instructions
)

result = model.invoke(prompt)
response = parser.invoke(result)
print(response)  # {'time': '2024年', 'person': '雷军', 'event': '发布小米SU7...'}

get_format_instructions 的作用

这个方法生成格式说明,告诉大模型应该如何输出 JSON:

复制代码
The output format must be a JSON object...
Parrot must adhere to the following schema:
{"time": "<time>", "person": "<person>", "event": "<event>"}

模型会根据这个指令来格式化输出,确保能被正确解析。


PydanticOutputParser Pydantic解析器

什么是 PydanticOutputParser

基于 Pydantic 模型的结构化输出解析器,功能最强,支持:

  • 类型校验

  • 数据转换

  • 复杂嵌套结构

  • 运行时验证

Pydantic 模型基础

复制代码
from pydantic import BaseModel, Field

class Product(BaseModel):
    name: str = Field(description="产品名称")
    price: float = Field(description="产品价格")
    description: str = Field(description="产品描述")

完整示例

复制代码
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain.chat_models import init_chat_model
from pydantic import BaseModel, Field, field_validator
import os
from dotenv import load_dotenv

load_dotenv(encoding='utf-8')

# 定义数据结构
class Product(BaseModel):
    name: str = Field(description="产品名称")
    category: str = Field(description="产品类别")
    description: str = Field(description="产品简介")

    @field_validator("description")
    def validate_description(cls, value):
        """验证产品简介长度必须 >= 10"""
        if len(value) < 10:
            raise ValueError('产品简介长度必须大于等于10')
        return value

# 创建解析器
parser = PydanticOutputParser(pydantic_object=Product)

# 获取格式化指令
format_instructions = parser.get_format_instructions()

# 创建提示模板
prompt_template = ChatPromptTemplate.from_messages([
    ("system", "你是一个AI助手,你只能输出结构化的json数据\n{format_instructions}"),
    ("human", "请你输出标题为:{topic}的新闻内容")
])

# 格式化提示词
prompt = prompt_template.format_messages(
    topic="华为Mate X7",
    format_instructions=format_instructions
)

# 调用模型
model = init_chat_model(
    model="qwen-plus",
    model_provider="openai",
    api_key=os.getenv("aliQwen-api"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

result = model.invoke(prompt)

# 解析结果
response = parser.invoke(result)

# 访问结构化数据
print(response.name)        # 产品名称
print(response.category)    # 产品类别
print(response.description)  # 产品描述

Pydantic 字段验证器

复制代码
from pydantic import BaseModel, Field, field_validator

class Product(BaseModel):
    name: str = Field(description="产品名称")
    price: float = Field(description="价格,必须大于0")
    description: str = Field(description="描述,长度10-100")

    @field_validator("price")
    def validate_price(cls, value):
        if value <= 0:
            raise ValueError("价格必须大于0")
        return value

    @field_validator("description")
    def validate_description(cls, value):
        if len(value) < 10 or len(value) > 100:
            raise ValueError("描述长度必须在10-100之间")
        return value

JsonOutputParser vs PydanticOutputParser

特性 JsonOutputParser PydanticOutputParser
返回类型 dict Pydantic Model 实例
类型校验 有(运行时验证)
嵌套结构 支持 支持(更强大)
自定义验证 不支持 支持(@field_validator)
使用难度 简单 中等
推荐场景 简单结构 复杂结构、强类型需求

with_structured_output 结构化输出

什么是 with_structured_output

直接让模型输出结构化数据,不需要 Parser,更简洁:

复制代码
# 使用 with_structured_output
llm_with_structured_output = llm.with_structured_output(Schema)
result = llm_with_structured_output.invoke(messages)

TypedDict 版本

复制代码
from typing import TypedDict, Annotated
from langchain.chat_models import init_chat_model
import os
from dotenv import load_dotenv

load_dotenv(encoding='utf-8')

llm = init_chat_model(
    model="qwen-plus",
    model_provider="openai",
    api_key=os.getenv("aliQwen-api"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

# 定义数据结构
class Animal(TypedDict):
    animal: Annotated[str, "动物名称"]
    emoji: Annotated[str, "动物表情"]

class AnimalList(TypedDict):
    animals: Annotated[list[Animal], "动物与表情列表"]

# 使用 with_structured_output
llm_with_structured = llm.with_structured_output(AnimalList)

messages = [{"role": "user", "content": "任意生成三种动物,以及他们的emoji表情"}]
result = llm_with_structured.invoke(messages)

print(result)
# {'animals': [{'animal': '猫', 'emoji': '🐱'}, {'animal': '狗', 'emoji': '🐶'}, {'animal': '兔子', 'emoji': '🐰'}]}

Pydantic 版本

复制代码
from pydantic import BaseModel
from typing import List

class Animal(BaseModel):
    animal: str
    emoji: str

class AnimalList(BaseModel):
    animals: List[Animal]

llm_with_structured = llm.with_structured_output(AnimalList)
result = llm_with_structured.invoke(messages)
print(result.animals[0].animal)  # 猫

对比

方式 优点 缺点
with_structured_output 代码简洁,不需要Parser 只能用于结构化输出
OutputParser 灵活,可组合 代码较多

Annotated 类型注解

什么是 Annotated

Annotated[T, metadata] 是 Python 的类型注解扩展,用于给类型添加元数据(描述信息)

复制代码
from typing import Annotated

Age = Annotated[int, "年龄,范围0-150"]
  • int - 基础类型

  • "年龄,范围0-150" - 元数据/描述

Annotated + Field

复制代码
from typing import Annotated
from pydantic import Field

# 用 Annotated 结合 Field 设置范围约束
Age = Annotated[int, Field(ge=0, le=150, description="年龄,范围0-150")]

class Person(BaseModel):
    name: str
    age: Age

Annotated 在 LangChain 中的作用

with_structured_outputTypedDict 中,Annotated 用于给模型提供字段描述

复制代码
class Animal(TypedDict):
    animal: Annotated[str, "动物名称"]      # 告诉模型这个字段的含义
    emoji: Annotated[str, "动物表情"]       # 描述越详细,模型理解越准确

Annotated vs 普通类型

复制代码
# 普通类型 - 无描述
class Animal(TypedDict):
    animal: str
    emoji: str

# Annotated - 有描述
class Animal(TypedDict):
    animal: Annotated[str, "动物名称"]
    emoji: Annotated[str, "动物表情"]

描述信息会帮助模型更准确地理解需要输出什么内容。

注意事项

Annotated 本身不具备运行时校验能力

复制代码
from typing import Annotated, TypedDict

Age = Annotated[int, "年龄,范围0-150"]

class Person(TypedDict):
    name: str
    age: Age

# 这不会报错!Annotated 只是描述,Python 不会校验范围
p = Person(name="z3", age=188)

如果需要运行时校验,必须使用 Pydantic:

复制代码
from pydantic import BaseModel, Field, ValidationError
from typing import Annotated

# Pydantic + Field 才能真正校验
Age = Annotated[int, Field(ge=0, le=150, description="年龄,范围0-150")]

class Person(BaseModel):
    name: str
    age: Age

try:
    p = Person(name="z3", age=188)  # 会报错!
except ValidationError as e:
    print("数据校验失败:", e)

get_format_instructions 格式化指令

什么是格式化指令

告诉大模型应该如何格式化输出的指令字符串。

复制代码
parser = JsonOutputParser(pydantic_object=Person)
format_instructions = parser.get_format_instructions()

输出示例

复制代码
The output format must conform to the following schema:
{"name": "<name>", "age": "<age>"}

Parrot must adhere to the following strict JSON format and return ONLY the JSON object.

在提示词中使用

复制代码
chat_prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个AI助手,你只能输出JSON格式。"),
    ("human", "请生成用户信息:{format_instructions}")
])

prompt = chat_prompt.format_messages(
    format_instructions=format_instructions
)

工作流程

复制代码
1. 定义 Pydantic 模型
       ↓
2. 创建 Parser,传入模型
       ↓
3. get_format_instructions() 生成格式化指令
       ↓
4. 将指令嵌入提示词
       ↓
5. 模型根据指令输出 JSON
       ↓
6. Parser 解析 JSON 为程序数据

总结

Output Parser 分类

Parser 返回类型 特点 使用场景
StrOutputParser str 最简单 纯文本提取
JsonOutputParser dict JSON转换 简单JSON结构
PydanticOutputParser Model 强类型校验 复杂结构验证

选择指南

复制代码
简单文本输出 → StrOutputParser
JSON结构(简单) → JsonOutputParser
JSON结构(复杂/需验证) → PydanticOutputParser
不想用Parser → with_structured_output

完整调用链

复制代码
PromptTemplate
    ↓ format_messages()
Messages
    ↓ model.invoke()
AIMessage
    ↓ parser.invoke()
结构化数据(dict / Pydantic Model)
相关推荐
金智维科技官方1 小时前
AI智能体在7×24客服场景中的真实表现评估
大数据·人工智能·ai·rpa·智能体
liliangcsdn2 小时前
LLM如何辅助RAG从大量文档中筛选目标文档
开发语言·人工智能
Magic-Yuan2 小时前
泰勒制的崩塌 - 上
人工智能·管理
咚咚王者2 小时前
人工智能之提示词工程 第七章 行业场景深度落地案例
人工智能
feasibility.2 小时前
量化:LLM与CV模型的极致压缩艺术
人工智能·科技·llm·边缘计算·量化·cv·压缩
β添砖java2 小时前
深度学习(15)卷积层
人工智能·深度学习·计算机视觉
β添砖java2 小时前
深度学习(14)确认GPU
人工智能·深度学习
浔川python社2 小时前
浔川社团第一次福利数据公布
人工智能·python·deepseek
薛定e的猫咪2 小时前
强化学习中的OOD检测:从状态异常到分布偏移
论文阅读·人工智能·深度学习