什么是输出解析器 graph LR
A[输入/指令] --> B[大模型处理]
B --> C[文本]
B --> D[json]
B --> E[xml]
B --> F[...]
大模型本质上是在用概率处理自然语言序列,一般而言输出为文本
然而在现实中我们主要使用机器友好的序列语言来构建应用
让大模型说机器懂的话,而不是人懂的话,就是outputParser的主要任务
LangChain输出解析器(Output Parsers)是将大语言模型(LLM)的原始文本响应转换为结构化、可操作数据的关键组件。输出解析器通过提供格式化指令并解析模型输出,实现文本到结构化数据 的高效转换。
常见的输出解析器一览 LangChain内置多种解析器,如JSON、XML、CSV等结构化数据格式,部分支持流式输出。使用时需注意模型是否支持特定功能,并确保提示词模板包含格式要求,以避免输出错误。不同模型特性差异较大,需测试验证其兼容性与输出质量。
名称
是否支持流
是否有格式要求
输入
输出
str
✅
❌
str|message
string
json
✅
✅
str|message
json object
xml
✅
✅
str|message
dict
csv
✅
✅
str|message
List[str]
pydantic
❌
✅
str|message
Pydantic:Basemodel
yaml
❌
✅
str|message
Pydantic:Basemodel
不同的输出器在输出上都会不同
注意有一些输出器是不支持流式输出的
当解析器有格式要求的时候,需要在提示词模版格式化的时候,将格式要求实例化进去
下游承接输出时,要注意数据格式兼容问题
主流模型的支持情况 Langchain官方对不同模型输出结构化情况说明:https://python.langchain.com/docs/integrations/chat/
以Deepseek举例:https://python.langchain.com/docs/integrations/chat/deepseek/
注意并不是所有的模型都支持结构化的输出
不支持结构化输出的模型只能输出字符串
在使用某个模型前最好先对支持特定进行测试
LangChain支持的主要输出格式(解析器) 在使用langchain框架时,不推荐直接用原生方式获取输出文本,因为会导致数据格式不统一、后续处理复杂。推荐使用框架自带的解析器(如Stream Output Parser、Pydantic Output Parser等),它们能自动提取并标准化输出结构,方便与Agent或Chain等组件协作。特别是Pydantic解析器,它是一个Python数据验证工具,能确保数据符合预期格式、自动转换类型、出错立即报错,常用于生成结构化数据,提升代码清晰度和安全性。同时介绍了JSON和chamr2等常见解析器及其使用场景,并强调使用框架内置解析器可避免重复造轮子、减少错误。
基础解析器 基础解析器处理最简单的数据格式转换:
StrOutputParser :直接提取模型返回的原始文本,不做任何结构化处理。
CommaSeparatedListOutputParser :将逗号分隔的文本转换为Python列表。例如,将”apples, bananas, oranges”解析为[‘apples’, ‘bananas’, ‘oranges’]。
BooleanOutputParser :解析文本为布尔值(True/False)。模型输出必须是”yes”或”no”(不区分大小写),解析器会统一转为大写后判断。
SimpleJsonOutputParser :将文本简单处理后转换为JSON格式,通常用于模型已经正确输出JSON的情况。
这些基础解析器适合处理简单数据结构,但缺乏验证和容错机制,适用于对格式要求不严格的场景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 str_parser = StrOutputParser() comma_parser = CommaSeparatedListOutputParser() comma_parser_instructions = comma_parser.get_format_instructions() boolean_parser = BooleanOutputParser() chain = llm | boolean_parser resp = chain.invoke(""" 要求:仅返回 YES 或者 NO -- 问题:“你好”这句话是否包含敏感信息? """ )print (resp)
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import osfrom langchain_openai import ChatOpenAIapi_base = os.getenv("OPENAI_API_BASE" ) api_key = os.getenv("OPENAI_API_KEY" ) llm = ChatOpenAI( temperature=0.0 , base_url=api_base, api_key=api_key ) from langchain_core.tools import tool@tool def get_weather (location: str ) -> str : """根据location地名返回当地实时天气""" return "天气小雨18度" llm_with_tools = llm.bind_tools([get_weather]) response = llm_with_tools.invoke("北京市当前的天气如何?" ) response.content from langchain_core.output_parsers import StrOutputParserchain = llm_with_tools | StrOutputParser() response = chain.invoke("北京市当前的天气如何?" ) print (response)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import osfrom langchain_openai import ChatOpenAIapi_base = os.getenv("OPENAI_API_BASE" ) api_key = os.getenv("OPENAI_API_KEY" ) llm = ChatOpenAI( temperature=0.0 , base_url=api_base, api_key=api_key ) response = llm.invoke('列出3种适合春季穿搭的颜色,用逗号分隔。' ) print ("原始输出:" , response.content)parser = CommaSeparatedListOutputParser() structured = parser.parse(response.content) print ("结构化列表:" , structured)
Pydantic解析器 Pydantic解析器通过Pydantic模型定义复杂结构,提供更严格的验证和数据校验:
PydanticOutputParser :将模型输出解析为Pydantic定义的模型对象。需要预先定义Pydantic模型,支持嵌套数据结构和类型验证。
PydanticToolsParser :专门处理OpenAI工具调用中的Pydantic对象,将工具调用参数解析为Pydantic模型。
Pydantic解析器适合需要严格验证的数据结构,如用户信息、订单详情等,确保输出的完整性和正确性。
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 import osfrom langchain_openai import ChatOpenAIapi_base = os.getenv("OPENAI_API_BASE" ) api_key = os.getenv("OPENAI_API_KEY" ) llm = ChatOpenAI( temperature=0.0 , base_url=api_base, api_key=api_key ) from pydantic import BaseModel, Field, model_validatorclass Joke (BaseModel ): setup: str = Field(description="笑话中的铺垫问题,必须以?结尾" ) punchline: str = Field(description="笑话中回答铺垫问题的部分,通常是一种抖包袱方式回答铺垫问题,例如谐音、会错意等" ) @model_validator(mode="before" ) @classmethod def question_ends_with_question_mark (cls, values: dict ) -> dict : setup = values.get("setup" ) if setup and setup[-1 ] != "?" : raise ValueError("Badly formed question!" ) return values from langchain_core.output_parsers import PydanticOutputParserfrom langchain_core.prompts import PromptTemplateparser = PydanticOutputParser(pydantic_object=Joke) prompt = PromptTemplate( template="回答用户的查询.\n{format_instructions}\n{query}\n" , input_variables=["query" ], partial_variables={"format_instructions" : parser.get_format_instructions()}, ) print ("pydanticoutparser的格式指令要求为:" )print (parser.get_format_instructions())print ("最终输出结果:" )prompt_and_model = prompt | llm output = prompt_and_model.invoke({"query" : "给我讲一个笑话" }) parser.invoke(output)
扩展:什么是Pydantic
定义:Pydantic是一个Python的数据验证工具,它就像一个“数据把关员”,帮你确保数据符合你预期的格式和规则
作用:
确保所有信息都是按规定填写
自动转换合适数据类型
如果有问题就立即报告
好处:
省心:不用写很多if-else来检查数据
安全:减少因数据格式错误导致的程序崩溃
清晰:代码更容易理解,因为数据结构一目了然
Pydantic In LangChain
V0.1: Pydantic 1
V0.2: Pydantic 1 & Pydantic 2
V0.3: Pydantic 2(Rust重构,语法变化)
JSON解析器
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import osfrom langchain_openai import ChatOpenAIapi_base = os.getenv("OPENAI_API_BASE" ) api_key = os.getenv("OPENAI_API_KEY" ) llm = ChatOpenAI( temperature=0.0 , base_url=api_base, api_key=api_key ) from pydantic import BaseModel, Fieldclass Joke (BaseModel ): setup: str = Field(description="笑话中的铺垫问题,必须以?结尾" ) punchline: str = Field(description="笑话中回答铺垫问题的部分,通常是一种抖包袱方式回答铺垫问题,例如谐音、会错意等" ) from langchain_core.output_parsers import JsonOutputParserfrom langchain_core.prompts import PromptTemplateparser = JsonOutputParser(pydantic_object=Joke) prompt = PromptTemplate( template="回答用户的查询.\n{format_instructions}\n{query}\n" , input_variables=["query" ], partial_variables={"format_instructions" : parser.get_format_instructions()}, ) chain = prompt | llm | parser output = chain.invoke({"query" : "给我讲一个笑话" }) print (output)parser.get_format_instructions() for s in chain.stream({"query" :"给我讲一个关于程序员编程的笑话" }): print (s)
不使用Pydantic生成JSON,缺点是无法控制精准字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from langchain_core.output_parsers import JsonOutputParserfrom langchain_core.prompts import PromptTemplatejoke_query = "Tell me a joke." parser = JsonOutputParser() prompt = PromptTemplate( template="Answer the user query.\n{format_instructions}\n{query}\n" , input_variables=["query" ], partial_variables={"format_instructions" : parser.get_format_instructions()}, ) chain = prompt | llm | parser chain.invoke({"query" : joke_query})
XML解析器
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import osfrom langchain_openai import ChatOpenAIapi_base = os.getenv("OPENAI_API_BASE" ) api_key = os.getenv("OPENAI_API_KEY" ) llm = ChatOpenAI( temperature=0.0 , base_url=api_base, api_key=api_key ) from langchain_core.output_parsers import XMLOutputParserfrom langchain_core.prompts import PromptTemplateactor_query = "Generate the shortened filmography for Tom Hanks." parser = XMLOutputParser(tags=["movies" , "actor" , "film" , "name" , "genre" ]) prompt = PromptTemplate( template="""{query}\n{format_instructions}""" , input_variables=["query" ], partial_variables={"format_instructions" : parser.get_format_instructions()}, ) chain = prompt | llm | parser output = chain.invoke({"query" : actor_query}) print (output)
函数调用解析器 函数调用解析器处理支持OpenAI函数调用的模型(如GPT-4)的响应:
OutputFunctionsParser :解析模型返回的函数调用参数,通常返回JSON格式的函数参数。
JsonOutputFunctionsParser :提取函数调用中的JSON参数。
这些解析器专为需要调用特定函数或工具的场景设计,常见于Agent系统或复杂任务处理。
时间/枚举解析器 处理特定类型的数据:
这些解析器针对特定数据类型进行了优化,提供更精准的解析结果。
正则解析器 通过正则表达式提取特定模式的数据:
RegexParser :单字段正则匹配。
RegexDictParser :多字段正则提取为字典。
正则解析器适合需要灵活匹配文本模式的场景,如提取电话号码、邮箱地址等。
复合解析器 处理复杂或多部分的输出:
CombiningOutputParser :组合多个解析器,将文本通过分隔符拆分后分别解析。
RetryWithErrorOutputParser :在解析失败时重试并尝试修复输出。
复合解析器提供了更强大的处理能力,可以应对复杂或多任务的输出场景。
强校验解析器 提供更严格的输出验证:
GuardrailsOutputParser :基于Guardrails库,对输出进行强校验,支持自定义规则(如过滤不当内容、校验数据格式)。
Guardrails解析器特别适合安全敏感场景,确保输出内容符合预设规则和标准。
输出阶段的容错处理 是在使用大模型时,由于其输出存在不确定性,可能会导致错误,为此Langchain提供了两种容错机制:一种是“重试”,即当解析器输出错误时,重新调用模型进行修正;另一种是“修复”,通过特定方法直接修复错误输出,确保最终结果符合预期格式和要求。
错误重试 使用RetryOutputParser 进行自动重试,示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 import osfrom langchain_openai import ChatOpenAIapi_base = os.getenv("OPENAI_API_BASE" ) api_key = os.getenv("OPENAI_API_KEY" ) llm = ChatOpenAI( temperature=0.0 , base_url=api_base, api_key=api_key ) from pydantic import BaseModel, Fieldclass Action (BaseModel ): action: str = Field(description="action to take" ) action_input: str = Field(description="input to the action" ) from langchain.output_parsers import RetryOutputParserfrom langchain_core.exceptions import OutputParserExceptionfrom langchain_core.output_parsers import PydanticOutputParserfrom langchain_core.prompts import PromptTemplatetemplate = """Based on the user question, provide an Action and Action Input for what step should be taken. {format_instructions} Question: {query} Response:""" parser = PydanticOutputParser(pydantic_object=Action) prompt = PromptTemplate( template="Answer the user query.\n{format_instructions}\n{query}\n" , input_variables=["query" ], partial_variables={"format_instructions" : parser.get_format_instructions()}, ) prompt_value = prompt.format_prompt(query="北京今天天气如何?" ) bad_response = '{"action": "search"}' try : parser.parse(bad_response) except OutputParserException as e: print (e) retry_parser = RetryOutputParser.from_llm(parser=parser, llm=llm) retry_parser.parse_with_prompt(bad_response, prompt_value)
错误修复 使用OutputFixingParser 进行错误修复,示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import osfrom langchain_openai import ChatOpenAIapi_base = os.getenv("OPENAI_API_BASE" ) api_key = os.getenv("OPENAI_API_KEY" ) llm = ChatOpenAI( temperature=0.0 , base_url=api_base, api_key=api_key ) from typing import List from pydantic import BaseModel, Fieldclass Actor (BaseModel ): name: str = Field(description="name of an actor" ) film_names: List [str ] = Field(description="list of names of films they starred in" ) actor_query = "Generate the filmography for a random actor." parser = PydanticOutputParser(pydantic_object=Actor) misformatted = "{'name': 'Tom Hanks', 'film_names': ['Forrest Gump']}" try : parser.parse(misformatted) except OutputParserException as e: print (e) from langchain.output_parsers import OutputFixingParsernew_parser = OutputFixingParser.from_llm(parser=parser, llm=llm) new_parser.parse(misformatted)
自定义输出解析器 纳美星输出器 纳美星语网址 https://learnnavi.org/
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 import osfrom langchain_openai import ChatOpenAIapi_base = os.getenv("OPENAI_API_BASE" ) api_key = os.getenv("OPENAI_API_KEY" ) llm = ChatOpenAI( temperature=0.0 , base_url=api_base, api_key=api_key ) import refrom langchain_core.messages import AIMessagedef parse (ai_message: AIMessage ) -> str : """Convert message to Na'vi style language.""" content = ai_message.content navi_rules = { r'\b[Hh]ello\b' : 'Kaltxì' , r'\b[Hh]i\b' : 'Kaltxì' , r'\b[Tt]hank you\b' : 'Irayo' , r'\b[Gg]oodbye\b' : 'Eywa ngahu' , r'\b(friend|friends)\b' : 'eylan' , r'\b(brother|brothers)\b' : 'tsmukan' , r'\b(sister|sisters)\b' : 'tsmuke' , r'[!.]\s*$' : ' kxe!' , r'\?\s*$' : ' srak?' , r'\b(beautiful|pretty)\b' : 'na\'vi' , r'\b(sacred|holy)\b' : 'txe\'lan' , } result = content for pattern, replacement in navi_rules.items(): result = re.sub(pattern, replacement, result) result = f"Oel ngati kameie... {result} " return result chain = llm | parse chain.invoke("hello" )
布尔值解析器 通过继承BaseOutputParser的方式来扩展自定义输出器
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 import osfrom langchain_openai import ChatOpenAIapi_base = os.getenv("OPENAI_API_BASE" ) api_key = os.getenv("OPENAI_API_KEY" ) llm = ChatOpenAI( temperature=0.0 , base_url=api_base, api_key=api_key ) from langchain_core.exceptions import OutputParserExceptionfrom langchain_core.output_parsers import BaseOutputParserclass BooleanOutputParser (BaseOutputParser[bool ]): """Custom boolean parser.""" true_val: str = "YES" false_val: str = "NO" def parse (self, text: str ) -> bool : cleaned_text = text.strip().upper() if cleaned_text not in (self .true_val.upper(), self .false_val.upper()): raise OutputParserException( f"BooleanOutputParser expected output value to either be " f"{self.true_val} or {self.false_val} (case-insensitive). " f"Received {cleaned_text} ." ) return cleaned_text == self .true_val.upper() @property def _type (self ) -> str : return "boolean_output_parser" try : parser = BooleanOutputParser() parser.invoke("MEOW" ) except Exception as e: print (f"Triggered an exception of type: {type (e)} " ) parser = BooleanOutputParser(true_val="OKAY" ) parser.invoke("OKAY" ) parser = BooleanOutputParser() parser.invoke("YES" )