LangChain结构化输出:Pydantic与JSON解析器实战

发布时间:2026/7/27 8:21:36
LangChain结构化输出:Pydantic与JSON解析器实战 1. 为什么需要模型返回结构化数据在自然语言处理的实际应用中我们经常会遇到这样的场景模型输出的文本内容需要被后续程序解析和处理。比如你问模型明天北京的天气如何理想的回答可能是{ city: 北京, date: 2023-11-20, weather: 晴, temperature: { high: 15, low: 5 } }而不是一段自由文本明天北京天气晴朗最高气温15度最低气温5度。后者虽然对人类友好但程序需要额外编写复杂的解析逻辑才能提取关键信息。1.1 结构化数据的优势结构化数据相比自由文本有几个显著优势程序可读性JSON/YAML等格式可以直接被各种编程语言解析数据一致性固定字段确保每次返回的数据结构相同接口标准化便于不同系统间的数据交换类型安全可以定义字段的数据类型减少错误1.2 LangChain中的结构化输出LangChain提供了几种实现结构化输出的方式Pydantic输出解析器利用Python的类型提示系统JSON输出解析器直接返回JSON格式自定义解析器针对特定需求定制提示选择哪种方式取决于你的具体需求。Pydantic适合Python项目JSON更通用自定义解析器灵活性最高但开发成本也最高。2. 使用Pydantic实现结构化输出Pydantic是Python中用于数据验证和设置管理的库LangChain内置了对Pydantic的支持。2.1 定义输出模型首先需要定义一个Pydantic模型来描述你期望的数据结构from pydantic import BaseModel, Field class WeatherInfo(BaseModel): city: str Field(description城市名称) date: str Field(description日期格式为YYYY-MM-DD) weather: str Field(description天气状况) temperature: dict Field(description温度信息包含最高和最低温度) class Config: schema_extra { example: { city: 北京, date: 2023-11-20, weather: 晴, temperature: {high: 15, low: 5} } }2.2 创建解析器并绑定到链from langchain.output_parsers import PydanticOutputParser from langchain.prompts import PromptTemplate from langchain.llms import OpenAI # 创建解析器 parser PydanticOutputParser(pydantic_objectWeatherInfo) # 创建提示模板 prompt PromptTemplate( template回答用户问题。\n{format_instructions}\n问题{query}\n, input_variables[query], partial_variables{format_instructions: parser.get_format_instructions()} ) # 创建链 model OpenAI(temperature0) chain prompt | model | parser # 执行查询 result chain.invoke({query: 明天北京的天气如何}) print(result)2.3 关键参数解析temperature0设置为0确保输出确定性高适合结构化数据get_format_instructions()自动生成模型的结构描述partial_variables将格式指令作为固定部分加入提示注意Pydantic模型中的Field描述很重要它们会被转换为模型的结构说明影响LLM的输出。3. JSON输出解析器实战如果你不需要Pydantic的验证功能或者需要与非Python系统交互JSON格式是更好的选择。3.1 基本使用from langchain.output_parsers import StructuredOutputParser, ResponseSchema from langchain.prompts import ChatPromptTemplate # 定义响应模式 response_schemas [ ResponseSchema(namecity, description城市名称), ResponseSchema(namedate, description日期), ResponseSchema(nameweather, description天气状况), ResponseSchema(nametemperature, description温度范围) ] # 创建解析器 parser StructuredOutputParser.from_response_schemas(response_schemas) # 创建提示 prompt ChatPromptTemplate.from_template( 回答关于天气的问题返回JSON格式。 {format_instructions} 问题{query} ) # 创建链 chain prompt | model | parser # 执行 result chain.invoke({ query: 明天上海的天气怎么样, format_instructions: parser.get_format_instructions() })3.2 高级配置# 自定义JSON格式 custom_parser StructuredOutputParser.from_response_schemas( response_schemas, json_pattern{ 回答: { 城市: ..., 日期: ..., 天气: ..., 温度: {最高: xx, 最低: xx} } } )3.3 处理复杂结构对于嵌套结构可以这样定义response_schemas [ ResponseSchema(namecity, description城市名称), ResponseSchema(namedate, description日期), ResponseSchema(nameweather, description天气状况), ResponseSchema( nametemperature, description温度信息, typeobject, schema{ high: {type: number, description: 最高温度}, low: {type: number, description: 最低温度} } ) ]4. 常见问题与解决方案4.1 模型不遵循格式现象返回自由文本而非指定格式解决方案加强提示词中的格式要求在示例中展示正确格式降低temperature值使用更强大的模型如GPT-4改进后的提示模板prompt PromptTemplate( template请严格按照指定格式回答问题。 格式要求 {format_instructions} 示例 问题明天北京的天气如何 回答 {{ city: 北京, date: 2023-11-20, weather: 晴, temperature: {{high: 15, low: 5}} }} 现在请回答 问题{query} 回答, input_variables[query], partial_variables{format_instructions: parser.get_format_instructions()} )4.2 字段缺失或错误现象缺少某些字段或字段值不符合预期解决方案在Pydantic模型中设置必填字段为字段添加更详细的描述使用try-catch处理解析错误from pydantic import validator class WeatherInfo(BaseModel): city: str date: str weather: str temperature: dict validator(date) def date_format(cls, v): if not re.match(r\d{4}-\d{2}-\d{2}, v): raise ValueError(日期格式必须是YYYY-MM-DD) return v4.3 处理多值返回有时一个问题需要返回多个结构化结果class WeatherInfoList(BaseModel): items: List[WeatherInfo] # 提示词中明确说明 prompt 返回以下城市未来三天的天气 {cities} 每个城市每天一个记录共{count}条记录。 {format_instructions}5. 性能优化技巧5.1 批量处理当需要处理多个相似查询时可以使用批量模式queries [北京天气, 上海天气, 广州天气] results chain.batch([{query: q} for q in queries])5.2 缓存结果对相同查询缓存结果from langchain.cache import InMemoryCache from langchain.globals import set_llm_cache set_llm_cache(InMemoryCache())5.3 流式处理对于大结构数据可以分段处理class ChunkedOutputParser(BaseOutputParser): def parse(self, text: str): # 实现分段解析逻辑 pass6. 高级应用场景6.1 动态结构根据输入动态确定输出结构def dynamic_schema(query): if 天气 in query: return WeatherInfo elif 股票 in query: return StockInfo else: return BaseModel parser PydanticOutputParser(pydantic_objectdynamic_schema(query))6.2 多模型协作让一个模型决定结构另一个模型填充内容# 第一步确定结构 schema_chain prompt | model | SchemaParser() # 第二步填充数据 data_chain prompt | model | DataParser()6.3 结合其他LangChain组件from langchain.chains import LLMChain from langchain.agents import Tool weather_tool Tool( nameWeather, funclambda x: chain.run(queryx), description获取天气信息输入格式城市名 天气 )在实际项目中我发现结构化输出特别适合以下场景构建问答系统API数据提取和标准化多步骤工作流中的数据传递需要精确解析的自动化任务一个实用的技巧是先让模型用自由文本回答再让另一个模型将其转换为结构化格式。这种方法结合了两种方式的优点在复杂场景下效果更好。