LangChain学习——结构化输出和数据解析

LangChain

本指南全面介绍LangChain中结构化输出生成和数据解析的核心功能,包括Pydantic BaseModel构造、各种输出解析器的使用,以及高级错误处理机制。

详细测试样例和代码可参考如下两个链接:

  • test_output_parsers
  • test_pydantic_base_model

结构化输出概述

概念定义

结构化输出是指将大语言模型(LLM)的自然语言输出转换为具有明确数据类型和格式的结构化数据。这种转换使得AI应用能够可靠地处理和使用LLM的输出结果。

核心优势

  • 🎯 类型安全:确保数据符合预定义的结构和类型约束
  • 🔄 一致性:保证输出格式的稳定性和可预测性
  • ⚡ 可靠性:通过验证和错误处理提高系统鲁棒性
  • 🔧 易集成:直接获得可在应用中使用的数据对象

技术实现方式

LangChain提供两种主要的结构化输出实现方式:

  1. 结构化输出模式(Structured Output):基于约束解码技术,确保100%格式正确
  2. 函数调用模式(Function Calling):基于工具调用机制,支持更复杂的数据结构

相关链接

  • 结构化输出概念
  • 输出解析器概念

Pydantic BaseModel 集成

概念定义

Pydantic BaseModel是Python中最强大的数据验证和序列化库,LangChain深度集成了Pydantic来定义和验证结构化输出的数据模型。

with_structured_output 方法

输入:Pydantic模型类或JSON Schema
输出:符合指定结构的数据对象
原理:将LLM输出约束到预定义的数据结构中

from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAIclass UserProfile(BaseModel):"""用户档案数据模型"""name: str = Field(description="用户姓名")age: int = Field(description="用户年龄", ge=0, le=150)email: str = Field(description="邮箱地址")skills: List[str] = Field(description="技能列表")# 创建结构化输出模型
model = ChatOpenAI(model="gpt-4o-mini")
structured_llm = model.with_structured_output(UserProfile)# 使用结构化输出
result = structured_llm.invoke("提取用户信息:张三,25岁,邮箱zhang@example.com,擅长Python和数据分析")
# result 是 UserProfile 类型的对象
print(f"姓名: {result.name}, 年龄: {result.age}")

复杂数据结构支持

嵌套模型:支持模型之间的嵌套关系

class Address(BaseModel):"""地址信息"""street: str = Field(description="街道地址")city: str = Field(description="城市")country: str = Field(description="国家")class Company(BaseModel):"""公司信息"""name: str = Field(description="公司名称")address: Address = Field(description="公司地址")employees: List[UserProfile] = Field(description="员工列表")# 处理复杂嵌套结构
company_llm = model.with_structured_output(Company)

枚举类型支持

from enum import Enumclass TaskStatus(str, Enum):"""任务状态枚举"""PENDING = "pending"IN_PROGRESS = "in_progress"COMPLETED = "completed"CANCELLED = "cancelled"class Task(BaseModel):"""任务信息"""title: str = Field(description="任务标题")status: TaskStatus = Field(description="任务状态")priority: int = Field(description="优先级", ge=1, le=5)task_llm = model.with_structured_output(Task)

Function Calling vs Structured Output

技术选择指南

特性Structured OutputFunction Calling
动态字段支持❌ 不支持 Dict[str, Any]✅ 完全支持
复杂嵌套受限无限制
格式可靠性100%正确高度可靠
首次延迟有预处理开销无额外开销
# 包含动态字段的模型需要使用 function_calling
class FlexibleResponse(BaseModel):core_data: str = Field(description="核心数据")metadata: Dict[str, Any] = Field(description="动态元数据")# 必须指定 method="function_calling"
flexible_llm = model.with_structured_output(FlexibleResponse,method="function_calling"
)

相关链接

  • 如何返回结构化数据
  • Pydantic模型验证

输出解析器系统

概念定义

**输出解析器(Output Parsers)**是LangChain中负责将LLM的文本输出转换为特定数据类型的组件。它们提供了比结构化输出更灵活的数据处理能力。

基础解析器类型

StrOutputParser

功能:提取AI消息中的纯文本内容
输入:AIMessage对象
输出:字符串
适用场景:简单的文本提取和处理

from langchain_core.output_parsers import StrOutputParser# 文本提取链
text_chain = model | StrOutputParser()
result = text_chain.invoke("介绍一下人工智能")
# result 是纯字符串
JsonOutputParser

功能:解析JSON格式的模型输出
输入:包含JSON的文本
输出:Python字典或列表
适用场景:结构化数据提取

from langchain_core.output_parsers import JsonOutputParserjson_parser = JsonOutputParser()# 创建JSON解析链
json_chain = model | json_parser
result = json_chain.invoke("用JSON格式返回用户信息:姓名张三,年龄25")
# result 是 Python 字典
XMLOutputParser

功能:解析XML格式的结构化数据
输入:XML格式文本
输出:解析后的数据结构
适用场景:处理层次化数据

from langchain_core.output_parsers import XMLOutputParserxml_parser = XMLOutputParser()
xml_chain = model | xml_parser
YAMLOutputParser

功能:解析YAML格式的配置数据
输入:YAML格式文本
输出:Python数据结构
适用场景:配置文件处理

from langchain_core.output_parsers import YamlOutputParseryaml_parser = YamlOutputParser()
yaml_chain = model | yaml_parser

PydanticOutputParser

功能:将文本输出解析为Pydantic模型实例
输入:符合模型格式的文本
输出:Pydantic模型对象
原理:结合格式指令和数据验证

from langchain_core.output_parsers import PydanticOutputParser# 创建解析器
parser = PydanticOutputParser(pydantic_object=UserProfile)# 获取格式指令
format_instructions = parser.get_format_instructions()# 构建提示模板
from langchain_core.prompts import ChatPromptTemplateprompt = ChatPromptTemplate.from_template("提取用户信息:{query}\n{format_instructions}"
).partial(format_instructions=format_instructions)# 创建完整链
chain = prompt | model | parser
result = chain.invoke({"query": "张三,工程师,28岁"})
# result 是 UserProfile 对象

流式解析支持

概念:支持实时处理模型的流式输出
优势:提供更好的用户体验和响应性

# 流式JSON解析
from langchain_core.output_parsers import SimpleJsonOutputParserstreaming_parser = SimpleJsonOutputParser()# 流式处理
for chunk in (model | streaming_parser).stream("生成用户数据"):print(chunk, end="", flush=True)

相关链接

  • 如何解析字符串输出
  • 如何解析JSON输出
  • 如何解析XML输出
  • 如何解析YAML输出

智能错误处理

概念定义

智能错误处理是LangChain提供的高级功能,能够自动检测、修复和重试解析错误,大幅提升系统的鲁棒性和可靠性。

OutputFixingParser

功能:自动修复格式错误的LLM输出
输入:可能包含格式错误的文本
输出:修复后的正确数据结构
原理:使用另一个LLM理解并修复格式问题

from langchain_core.output_parsers import OutputFixingParser# 基础解析器
base_parser = JsonOutputParser()# 包装为自动修复解析器
fixing_parser = OutputFixingParser.from_llm(parser=base_parser,llm=ChatOpenAI(temperature=0.1)  # 使用低温度提高修复准确性
)# 自动处理格式错误
broken_json = '{"name": "张三", "age": 25'  # 缺少闭合括号
fixed_result = fixing_parser.parse(broken_json)  # 自动修复成功

应用场景

  • JSON格式错误(缺少括号、多余逗号)
  • XML标签不匹配
  • YAML缩进问题
  • Pydantic字段类型错误

RetryWithErrorOutputParser

功能:解析失败时的智能重试机制
输入:原始提示和错误信息
输出:重新生成的正确格式数据
原理:将错误反馈给LLM,指导重新生成

from langchain_core.output_parsers import RetryWithErrorOutputParser# 创建重试解析器
retry_parser = RetryWithErrorOutputParser.from_llm(parser=PydanticOutputParser(pydantic_object=UserProfile),llm=ChatOpenAI(temperature=0.1),max_retries=3  # 最多重试3次
)# 自动处理解析失败并重试
chain = prompt | model | retry_parser
result = chain.invoke({"query": "用户信息提取"})

重试流程

  1. 初始解析尝试失败
  2. 将错误信息反馈给LLM
  3. LLM重新生成符合格式的输出
  4. 重复直到成功或达到最大重试次数

组合错误处理策略

组合使用:将多种错误处理机制结合,实现最高可靠性

# 构建三层错误处理
base_parser = PydanticOutputParser(pydantic_object=ComplexModel)# 第一层:格式修复
fixing_parser = OutputFixingParser.from_llm(parser=base_parser,llm=ChatOpenAI(temperature=0.1)
)# 第二层:重试机制
ultimate_parser = RetryWithErrorOutputParser.from_llm(parser=fixing_parser,llm=ChatOpenAI(temperature=0.1),max_retries=2
)ultimate_chain = prompt | model | ultimate_parser

相关链接

  • 如何处理解析重试
  • 如何修复解析错误

高级应用模式

自定义解析器开发

概念:基于BaseOutputParser创建专用的解析逻辑
原理:继承基类并实现parse和get_format_instructions方法

from langchain_core.output_parsers import BaseOutputParser
from typing import Listclass ListOutputParser(BaseOutputParser[List[str]]):"""列表解析器 - 分隔符解析"""def __init__(self, separator: str = ","):self.separator = separatordef parse(self, text: str) -> List[str]:"""解析分隔符分隔的列表"""return [item.strip() for item in text.split(self.separator)]def get_format_instructions(self) -> str:"""返回格式指令"""return f"请用{self.separator}分隔列表项目"# 使用自定义解析器
list_parser = ListOutputParser(separator="|")
list_chain = model | list_parser

条件解析器

功能:根据内容特征自动选择解析策略

class ConditionalOutputParser(BaseOutputParser):"""条件解析器 - 智能格式识别"""def parse(self, text: str) -> Union[str, Dict, List]:"""根据内容特征选择解析策略"""text = text.strip()if text.startswith('{') and text.endswith('}'):# JSON对象格式return json.loads(text)elif text.startswith('[') and text.endswith(']'):# JSON数组格式  return json.loads(text)elif ',' in text:# 逗号分隔的列表return [item.strip() for item in text.split(',')]else:# 纯文本return textdef get_format_instructions(self) -> str:return "可以返回JSON、列表或纯文本格式"

链式解析器

概念:组合多个解析器,实现复杂的数据处理流程

class ChainedOutputParser(BaseOutputParser[Dict[str, Any]]):"""链式解析器 - 多策略组合"""def __init__(self, parsers: List[Tuple[str, BaseOutputParser]]):self.parsers = parsersdef parse(self, text: str) -> Dict[str, Any]:"""依次应用多个解析器"""results = {"original": text}for name, parser in self.parsers:try:results[name] = parser.parse(text)except Exception as e:results[f"{name}_error"] = str(e)return results# 创建链式解析器
chained_parser = ChainedOutputParser([("json", JsonOutputParser()),("list", ListOutputParser()),("yaml", YamlOutputParser())
])

验证解析器

功能:在解析后进行额外的数据验证和清理

class ValidatingOutputParser(BaseOutputParser[Dict]):"""验证解析器 - 数据质量保证"""def __init__(self, base_parser: BaseOutputParser, validators: List[callable]):self.base_parser = base_parserself.validators = validatorsdef parse(self, text: str) -> Dict:"""解析并验证数据"""result = self.base_parser.parse(text)# 应用验证规则for validator in self.validators:result = validator(result)return resultdef validate_user_age(data: Dict) -> Dict:"""验证用户年龄合理性"""if 'age' in data and not (0 <= data['age'] <= 150):data['age'] = max(0, min(data['age'], 150))return data# 使用验证解析器
validating_parser = ValidatingOutputParser(base_parser=JsonOutputParser(),validators=[validate_user_age]
)

相关链接

  • 如何创建自定义解析器

最佳实践指南

选择合适的方法

决策流程图

需要结构化输出?
├─ 是 → 数据结构复杂(包含动态字段)?
│   ├─ 是 → 使用 with_structured_output(method="function_calling")
│   └─ 否 → 使用 with_structured_output() (默认模式)
└─ 否 → 需要格式转换?├─ 是 → 使用合适的OutputParser (Json/XML/YAML)└─ 否 → 使用 StrOutputParser

错误处理最佳实践

分层错误处理

  1. 预防:使用清晰的格式指令
  2. 检测:实现数据验证逻辑
  3. 修复:使用OutputFixingParser
  4. 重试:使用RetryWithErrorOutputParser
  5. 降级:提供备用解析策略
def robust_structured_output(query: str, model_class: BaseModel, fallback_parser=None):"""鲁棒的结构化输出处理"""try:# 主要方法:结构化输出structured_llm = model.with_structured_output(model_class)return structured_llm.invoke(query)except Exception as e:if fallback_parser:# 降级方法:使用解析器return fallback_parser.parse(model.invoke(query).content)else:raise e

监控和调试

性能监控

import time
from typing import Anydef monitored_parse(parser: BaseOutputParser, text: str) -> Dict[str, Any]:"""监控解析性能"""start_time = time.time()try:result = parser.parse(text)success = Trueerror = Noneexcept Exception as e:result = Nonesuccess = Falseerror = str(e)end_time = time.time()return {"result": result,"success": success,"error": error,"parse_time": end_time - start_time,"input_length": len(text)}

提示工程优化

格式指令优化

def enhance_format_instructions(base_instructions: str, examples: List[str] = None) -> str:"""增强格式指令"""enhanced = base_instructionsif examples:enhanced += "\n\n示例格式:\n"for i, example in enumerate(examples, 1):enhanced += f"{i}. {example}\n"enhanced += "\n注意:严格按照上述格式返回,确保数据完整性。"return enhanced

类型安全增强

泛型解析器

from typing import TypeVar, GenericT = TypeVar('T')class TypedOutputParser(BaseOutputParser[T], Generic[T]):"""类型安全的解析器基类"""def __init__(self, target_type: Type[T]):self.target_type = target_typedef parse(self, text: str) -> T:# 实现类型安全的解析逻辑pass

相关资源链接

LangChain 官方文档

  • 输出解析器概述
  • 如何解析结构化输出
  • 如何返回结构化数据
  • 如何创建自定义解析器
  • 如何处理解析重试
  • 如何修复解析错误

数据验证和模型

  • Pydantic 官方文档
  • Python Type Hints 指南

高级功能

  • 异步编程概念
  • 流式输出指南
  • 批处理操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/93181.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/93181.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于华为ENSP的BGP的状态机深入浅出

本篇技术博文摘要 &#x1f31f; 本文章主要探讨BGP状态机如何控制BGP连接的建立与维护&#xff0c;以及BGP协议在运行过程中如何交换路由信息并确保网络的稳定性 引言 &#x1f4d8; 在这个快速发展的技术时代&#xff0c;与时俱进是每个IT人的必修课。我是肾透侧视攻城狮&…

Android 15中的16KB大页有何优势?

deepseek回答&#xff1a; Android 15引入的16KB大内存页是系统性能优化的关键变革&#xff0c;其核心优势体现在以下方面&#xff1a; ⚡ 一、性能全面提升 系统整体加速 配置16KB页面的设备整体性能提升5%-10%&#xff0c;通过减少内存管理开销释放更多资源用于应用运行。…

Gis数据的A*算法规划航线

1.1 用到的技术栈geotools JTSJgrapht1.2 实现思路// 定义栅格网格参数private static final double CELL_SIZE_DEGREES 0.005;private static int gridWidth 0;//格子高度 index 1private static int gridHeight 0;//格子宽度// 1. 读取GeoJSON文件File geoJsonFile new …

Spring Boot 默认使用 CGLIB,但CGLIB 无法代理 final 类或 final 方法

那么当这两件事冲突时&#xff0c;Spring Boot 是怎么“解决”的呢&#xff1f;答案是&#xff1a;它不解决&#xff0c;也无法解决。当这种情况发生时&#xff0c;你的应用程序会直接启动失败。这不是 Spring Boot 的疏忽&#xff0c;而是由 CGLIB 的底层原理和 Java 语言的规…

cuda编程笔记(10)--memory access 优化

全局内存访问优化&#xff08;Coalesced Access&#xff09; 什么是 Coalesced Access&#xff1f; 定义&#xff1a;一个 warp&#xff08;32 个线程&#xff09;在同一指令中访问全局内存时&#xff0c;如果这些访问请求可以合并成尽可能少的内存事务&#xff08;通常是 32…

闲庭信步使用图像验证平台加速FPGA的开发:第三十一课——车牌识别的FPGA实现(3)车牌字符分割预处理

&#xff08;本系列只需要modelsim即可完成数字图像的处理&#xff0c;每个工程都搭建了全自动化的仿真环境&#xff0c;只需要双击top_tb.bat文件就可以完成整个的仿真&#xff0c;大大降低了初学者的门槛&#xff01;&#xff01;&#xff01;&#xff01;如需要该系列的工程…

电子电气架构 --- 汽车软件全生命周期

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…

力扣面试150(41/150)

7.25 56. 合并区间 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 我的思路&#xff1a; 左端点升序…

【隧道篇 / IPsec】(7.6) ❀ 01. 利用向导快速建立IPsec安全隧道 (点对点) ❀ FortiGate 防火墙

【简介】相信很多人已经习惯利用导向快速创建VPN了&#xff0c;而且已经有部分尝鲜者已经用上了FortiOS 7.6&#xff0c;但是会发现FortiOS 7.6下的VPN向导改变了很多&#xff0c;一时无法下手&#xff0c;下面我们来看看最常见的点对点是如何配置的。环境介绍在配置IPsec VPN之…

PLLIP核

。1 号红色框内的速度等级代表着设备的速度 等级&#xff0c;保存默认就好&#xff1b;2 号红色框内设置输入频率&#xff1b;3 号红色框选择 PLL 的工作模式。我们 开发板用的晶振是 50MHz 的&#xff0c;故在 2 号红色框内我们填写 50MHz&#xff1b;我们在 3 号红色框内选正…

1.1 Deep learning?pytorch ?深度学习训练出来的模型通常有效但无法解释合理性? 如何 解释?

DL 是什么&#xff0c;你如何理解DL模型&#xff1f; DL 对于我而言&#xff0c;就是人类试图想通过数学语言描述人类学习过程的一门技术&#xff0c;或者说学科。 因此 DL 模型 相当于 数学 的 一个 funciton &#xff0c;有输入&#xff0c;通过function处理&#xff0c;得…

java实现在工具类中注入其他对象方式

方案1&#xff1a; Slf4j Component public class ChatdocApiClient {Value("${chatdoc.app-id}")private String appId;Value("${chatdoc.secret}")private String secret;Value("${chatdoc.domain}")private String domain;private final Rest…

electron中IPC 渲染进程与主进程通信方法解析

electron中ipcRenderer.invoke、ipcRenderer.on、ipcRenderer.send、ipcRenderer.sendSync作用与区别 IPC 渲染进程与主进程通信方法解析 ipcRenderer 的这几个方法作用不完全相同&#xff0c;它们适用于不同的通信场景&#xff0c;核心区别在于通信方向、是否需要响应以及同步…

epoll_event 事件类型详解

epoll_event 事件类型详解 epoll_event 是 Linux epoll I/O 多路复用机制的核心结构体&#xff0c;其中的事件类型决定了 epoll 监控的行为和触发条件。以下是各种事件类型的详细解析&#xff1a; epoll_event 结构体 #include <sys/epoll.h>typedef union epoll_data {v…

设计自己的小传输协议 导论与概念

设计自己的小传输协议 导论与概念 1&#xff1a;聊一聊协议头设计 ​ 早在《TCP/IP详解》中的第一句话中&#xff0c;我们就知道协议的含义是这样的&#xff1a;协议是通信双方共同遵守的一套规则&#xff0c;提供格式定义、语义解释等&#xff0c;使不同设备或软件能够正确交…

iOS —— 天气预报仿写总结

在iOS中&#xff0c;最常见的网络请求方式是NSURLSession&#xff0c;它是苹果推荐的现代API&#xff0c;简单安全且易于拓展。一次完整的网络请求流程&#xff1a;构造 NSURL 对象创建 NSURLSessionDataTask发起请求&#xff08;resume&#xff09;在回调中解析数据回到主线程…

MySQL 8.4 Windows 版安装记录与步骤参考

导语&#xff1a; MySQL 作为广泛使用的开源数据库管理系统&#xff0c;是许多开发者和学习者的必备工具。最近有朋友询问安装过程&#xff0c;正好整理了 MySQL 8.4 在 Windows 系统下的安装步骤和一些注意事项&#xff0c;分享给有需要的朋友做个参考。关于 MySQL&#xff1a…

七、搭建springCloudAlibaba2021.1版本分布式微服务-skywalking9.0链路追踪

前言链路追踪介绍 对于一个大型的几十个&#xff0c;几百个微服务构成的微服务架构系统&#xff0c;通常会遇到下面的一系列问题。 如何串联整个调用链路&#xff0c;快速定位问题&#xff1f;如何澄清各个微服务之间的依赖关系&#xff1f;如何进行各个微服务接口的性能分析&a…

深入理解大语言模型生成参数:temperature、top\_k、top\_p 等全解析

在使用大语言模型&#xff08;如 GPT-4、LLaMA、ChatGLM 等&#xff09;进行文本生成任务时&#xff0c;很多开发者会面对各种“生成参数”&#xff0c;如 temperature、top_k、top_p、repetition_penalty 等。这些参数虽然看起来抽象&#xff0c;但掌握它们的意义和配置技巧&a…

vulhub Web Machine(N7)靶场攻略

下载地址&#xff1a; https://download.vulnhub.com/webmachine/Web-Machine-N7.ova 使用方法&#xff1a; 靶场下载好以后不用解压&#xff0c;需要使用Oracle VirtualBox虚拟机打开&#xff0c;用VMware会报错。安装Oracle VirtualBox虚拟机时安装地址不能随便选择&#…