6. LangChain 解析器

LangChain 解析器:驯服 LLM 的输出,实现结构化数据交互

LLM 的强大在于其自然语言能力,但当我们想将其结果用于后续的代码处理数据库存储系统输入时,问题出现了。LLM 的输出常常包含冗余文本、不一致的格式、或遗漏的标点。

  • LangChain 的解决方案: Output Parser(解析器)模块专为解决此问题而设计。它充当了 LLM 的“翻译官”和“守门员”,强制 LLM 以指定的格式输出,并在接收到输出后将其准确地转换成 Python(或其他语言)程序可以理解的结构化对象(如字典、列表或 Pydantic 对象)。

6.1 解析器的三大任务

解析器在 LangChain 工作流中扮演着关键的角色,它在两个阶段发挥作用:

  1. 指导 (Instruction): 在调用 LLM 之前,解析器将所需的输出格式要求格式恢复指令注入到提示词(Prompt)中。
    • 例如: 如果需要 JSON 格式,解析器会告诉 LLM:“请严格按照以下 JSON Schema 输出,不要包含任何解释性文字。”
  2. 验证与转换 (Validation & Transformation): 在接收到 LLM 的原始文本输出之后,解析器会:
    • 验证: 检查输出是否符合期望的格式(如 JSON 语法是否正确)。
    • 转换: 将符合格式的文本反序列化为 Python 对象(如字典或 Pydantic 模型实例)。

6.2 LLM Schema 生成结构化结果

在 LangChain 中,结构化输出意味着让语言模型以清晰、定义好的格式(如 JSON)进行响应,而不仅仅是自由格式的文本。这使得以编程方式处理结果变得容易得多,特别是当你需要提取特定字段或将输出馈送到另一个系统时。

在 LangChain 中使用结构化输出时,尤其是当你期望 LLM 以特定格式(如产品目录、用户档案或知识卡片)响应时,仅仅说“返回 JSON”是不够的。

你需要一个明确定义的模式(Schema)来告诉模型要返回什么样的 JSON。这就是 TypedDict、Pydantic 和 JSON Schema 发挥作用的地方。

这张图展示了 “LLM(大语言模型)绑定输出 Schema 并生成结构化结果” 的流程 ,核心是让 LLM 按照指定格式输出内容,避免自由文本的不确定性。下面分步骤拆解:

1. 输入部分

  • 左侧输入 1:Natural language(用户输入)**即用户用自然语言提出的问题 / 需求(比如 “提取这条评论的评分和关键词”)。
  • 左侧输入 2:Output Schema(输出模板)这是提前定义好的结构化格式规则(通常是 JSON Schema 或 Pydantic 模型),比如要求输出包含foobar两个字段(对应图中的foo: ... bar: ...)。

2. 核心流程:Bind schema to LLM(将 Schema 绑定到 LLM)

这个粉色模块是流程的核心,包含两个关键操作:

  • Tool(工具 / 绑定):把 “Output Schema” 注入到 LLM 的上下文 / 提示中,告诉模型 “必须按照这个格式输出结果”。(类似给模型发一份 “答卷模板”,要求它必须填在指定位置)
  • LLM(大语言模型):接收 “用户输入” 和 “绑定好的 Schema”,生成符合格式要求的 “Answer string”(通常是 JSON 字符串)。

3. 输出部分:Parse(解析)

把 LLM 生成的 “Answer string”(比如 JSON 文本)解析成结构化数据(对应右侧的 “Output Schema”),最终得到包含foobar的结构化结果,方便后续程序 / 系统直接使用。

举个实际例子(对应流程)

比如要让 LLM 提取 “苹果手机的价格和颜色”:

  1. 用户输入:“iPhone 15 Pro 的价格和颜色有哪些?”
  2. Output Schema:提前定义格式{ "price": "价格", "color": "颜色列表" }
  3. Bind schema to LLM:告诉 LLM “必须按这个 Schema 输出”,模型生成字符串{"price": "6999元起", "color": ["黑色", "白色", "蓝色"]}
  4. Parse:把字符串解析成结构化数据,得到最终的pricecolor字段。

6.3 输出解析器

LangChain 解析器(parser),主要是指 输出解析器(Output Parser)

在 LangChain 中,输出解析器的作用 就是:把大模型返回的原始文本结果,转化为你需要的结构化数据(如 JSON、列表、字典、Pydantic 对象等),方便程序后续使用。

解析器名称 功能说明 典型场景 返回类型
StrOutputParser 原样返回模型输出,不做处理 只需要原始文本时 str
RegexParser 使用正则表达式提取结构化数据 提取日期、数字、表格内容等固定格式文本 str / list / dict(取决于正则)
JSONOutputParser 要求模型输出合法 JSON,并自动解析 需要可靠 JSON 结果 dict
StructuredOutputParser 基于 Pydantic Schema 严格定义字段和类型,并做校验 API 响应、表单信息、数据库入库 Pydantic 对象 / dict
CommaSeparatedListOutputParser 把逗号分隔文本解析为列表 关键词提取、分类标签输出 list[str]
EnumOutputParser 限制模型输出在预设枚举值内 多选题、状态值(如 同意/不同意 枚举类型
DatetimeOutputParser 自动解析成 Python 日期时间对象 日程提醒、日志时间戳、时间提取 datetime
XMLOutputParser 解析 XML 格式输出 文档结构化、树状数据 xml.etree.ElementTree 对象
JsonMarkdownOutputParser 从 Markdown 代码块中提取 JSON 当模型喜欢把 JSON 放在 ```json 代码块中 dict
RetryOutputParser 如果解析失败,自动重新请求模型 强制输出格式正确,健壮性要求高 任意(取
  • 简单任务StrOutputParser, RegexParser, CommaSeparatedListOutputParser
  • 需要结构化JSONOutputParser, StructuredOutputParser
  • 格式严格/有限选择EnumOutputParser, DatetimeOutputParser
  • 增强容错RetryOutputParser

6.4 代码应用示例

6.4.1 输出列表

from langchain.output_parsers import CommaSeparatedListOutputParser
from langchain.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from langchain_openai import ChatOpenAI

# 定义输出解析器
output_parser = CommaSeparatedListOutputParser()

# 定义 Prompt 模板
chat_prompt = ChatPromptTemplate.from_messages([
    HumanMessagePromptTemplate.from_template("{request}\\n{format_instructions}")
])

# 填充 Prompt
model_request = chat_prompt.format_messages(
    request="给我20个世界上伟大的程序员,以中文回复",
    format_instructions=output_parser.get_format_instructions()
)

# 定义模型
llm = ChatOpenAI(model_name="gpt-4o-mini")

# 执行请求
result = llm.invoke(model_request)

# 打印原始结果
# print("Raw LLM Response:", result)
print("Response Content:", result.content)

# 使用解析器解析成列表
parsed_output = output_parser.parse(result.content)
print("Parsed Output:", parsed_output)
Response Content: 林纳斯·托瓦兹, 盖瑞·凯茨, 比尔·盖茨, 邓肯·沃尔克, 约翰·卡马克, 艾伦·图灵, 史蒂夫·乔布斯, 洛巴·巴特, 德尼·里奇, 皮埃尔·鲁米耶, 马克·扎克伯格, 约瑟夫·阿尔沃, 瓦尔特·巴哈, 凯瑟琳·约翰逊, 提姆·伯纳斯-李, 高德纳, 拉里·佩奇, 谷歌的谢尔盖·布林, 蒂姆·普特曼, 安德鲁·亨利
Parsed Output: ['林纳斯·托瓦兹', '盖瑞·凯茨', '比尔·盖茨', '邓肯·沃尔克', '约翰·卡马克', '艾伦·图灵', '史蒂夫·乔布斯', '洛巴·巴特', '德尼·里奇', '皮埃尔·鲁米耶', '马克·扎克伯格', '约瑟夫·阿尔沃', '瓦尔特·巴哈', '凯瑟琳·约翰逊', '提姆·伯纳斯-李', '高德纳', '拉里·佩奇', '谷歌的谢尔盖·布林', '蒂姆·普特曼', '安德鲁·亨利']

6.4.2 输出时间格式

from langchain.output_parsers import DatetimeOutputParser
from langchain.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from langchain_openai import ChatOpenAI

# 定义模型
llm = ChatOpenAI(model_name="gpt-3.5-turbo")

# 定义输出解析器
output_parser = DatetimeOutputParser()

# 打印解析器要求的格式说明
print("Parser Instructions:", output_parser.get_format_instructions())

# 定义 Prompt 模板
chat_prompt = ChatPromptTemplate.from_messages([
    HumanMessagePromptTemplate.from_template("{request}\\n{format_instructions}")
])

# 格式化 Prompt
model_request = chat_prompt.format_messages(
    request="中华人民共和国是什么时候成立的?",
    format_instructions=output_parser.get_format_instructions()
)

# 调用模型
result = llm.invoke(model_request)

# 打印模型原始输出
# print("Raw Response:", result)
print("Response Content:", result.content)

# 使用解析器将结果解析成 Python datetime 对象
parsed_date = output_parser.parse(result.content)
print("Parsed Datetime:", parsed_date)
Parser Instructions: Write a datetime string that matches the following pattern: '%Y-%m-%dT%H:%M:%S.%fZ'.

Examples: 2023-07-04T14:30:00.000000Z, 1999-12-31T23:59:59.999999Z, 2025-01-01T00:00:00.000000Z

Return ONLY this string, no other words!
Response Content: 1949-10-01T00:00:00.000000Z
Parsed Datetime: 1949-10-01 00:00:00

6.4.3 输出json格式

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

# 定义 Pydantic 数据模型
class Student(BaseModel):
    name: str = Field(description="学生的姓名")
    age: str = Field(description="学生的年龄")

# 定义请求
student_query = "帮助我生成一个学生的信息,用于测试,根据请求生成JSON格式"

# 定义输出解析器
parser = PydanticOutputParser(pydantic_object=Student)

print("Schema:", parser)
print("Format Instructions:", parser.get_format_instructions())

# 定义 Prompt
prompt = PromptTemplate(
    template="请回答以下问题:\\n{format_instructions}\\n{query}\\n用中文回答",
    input_variables=["query"],
    partial_variables={"format_instructions": parser.get_format_instructions()}
)

# 格式化输入
input = prompt.format_prompt(query=student_query)

# 定义模型
model = ChatOpenAI(model_name="gpt-4o-mini")

# 调用模型
output = model.invoke(input)

# 打印原始输出
# print("Raw Output:", output)
print("Response Content:", output.content)

# 解析输出为 Pydantic 对象
student = parser.parse(output.content)
print("Parsed Student:", student)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐