Model I/O 之 Output Parsers 
 语言模型返回的内容通常都是字符串的格式(文本格式),但在实际AI应用开发过程中,往往希望model可以返回更直观、更格式化的内容,以确保应用能够顺利进行后续的逻辑处理。此时, LangChain提供的 输出解析器 就派上用场了。
 输出解析器(Output Parser)负责获取 LLM 的输出并将其转换为更合适的格式。这在应用开发中及其重要。
1. 输出解释器种类 
LangChain有许多不同类型的输出解析器
- StrOutputParser :字符串解析器
 - JsonOutputParser :JSON解析器,确保输出符合特定JSON对象格式
 - XMLOutputParser :XML解析器,允许以流行的XML格式从LLM获取结果
 - CommaSeparatedListOutputParser :CSV解析器,模型的输出以逗号分隔,以列表形式返回输出DatetimeOutputParser :日期时间解析器,可用于将 LLM 输出解析为日期时间格式
 
除了上述常用的输出解析器之外,还有:
- EnumOutputParser :枚举解析器,将LLM的输出,解析为预定义的枚举值
 - StructuredOutputParser :将非结构化文本转换为预定义格式的结构化数据(如字典)
 - OutputFixingParser :输出修复解析器,用于自动修复格式错误的解析器,比如将返回的不符合预期格式的输出,尝试修正为正确的结构化数据(如 JSON)
 - RetryOutputParser :重试解析器,当主解析器(如 JSONOutputParser)因格式错误无法解析LLM 的输出时,通过调用另一个 LLM 自动修正错误,并重新尝试解析
 
2. 解析器的使用 
2.1 字符串解析器 
StrOutputParserStrOutputParser 简单地将 任何输入 转换为 字符串 。它是一个简单的解析器,从结果中提取content字段举例:将一个对话模型的输出结果,解析为字符串输出
messages = [
    SystemMessage(content="You are a helpful assistant that translates English to Chinese."),
    HumanMessage(content="What is the meaning of life?")
]
result = chat_model.invoke(messages)
print(f"LLM 响应:{result}")
parser = StrOutputParser()
response = parser.invoke(result)
print(f"解析器解析后输出:{response}")输出结果:
LLM 响应:content='生命的意义是什么?' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 6, 'prompt_tokens': 29, 'total_tokens': 35, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_efad92c60b', 'id': 'chatcmpl-CXegjivtcvKgUWM3V0RCvHs1yXFvl', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--23762c04-2813-418f-9f95-694086105be2-0' usage_metadata={'input_tokens': 29, 'output_tokens': 6, 'total_tokens': 35, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}
解析器解析后输出:生命的意义是什么?2.2 JSON解析器 
JsonOutputParser,即JSON输出解析器,是一种用于将大模型的 自由文本输出 转换为 结构化JSON数据 的工具。适合场景:特别适用于需要严格结构化输出的场景,比如 API 调用、数据存储或下游任务处理。
实现方式
方式1:用户自己通过提示词指明返回Json格式
方式2:借助JsonOutputParser的 get_format_instructions() ,生成格式说明,指导模型输出JSON 结构
方式 1 示例:
parser = JsonOutputParser()
messages = [
    SystemMessage(content="You are a helpful assistant that translates Chinese to English."),
    HumanMessage(content="生命的意义是什么? 问题用q表示,答案用a表示,返回一个JSON格式")
]
result = chat_model.invoke(messages)
response = parser.invoke(result)
print(f"LLM 响应:{result}")
print(f"解析器解析后输出:{response}")输出:
LLM 响应:content='```json\n{\n  "q": "生命的意义是什么?",\n  "a": "生命的意义因人而异,可能包括追求幸福、实现个人价值、与他人建立关系、探索世界等。在不同的文化和哲学观点中,对生命意义的理解也各不相同。"\n}\n```' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 70, 'prompt_tokens': 43, 'total_tokens': 113, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_efad92c60b', 'id': 'chatcmpl-CXfKtbpqcpXzx58ikmFCePKuDdmew', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--59e73b70-42b2-4fb4-9a36-352557714996-0' usage_metadata={'input_tokens': 43, 'output_tokens': 70, 'total_tokens': 113, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}
解析器解析后输出:{'q': '生命的意义是什么?', 'a': '生命的意义因人而异,可能包括追求幸福、实现个人价值、与他人建立关系、探索世界等。在不同的文化和哲学观点中,对生命意义的理解也各不相同。'}举例2:使用指定的JSON格式
output_parser = JsonOutputParser()
# 返回一些指令或模板,这些指令告诉系统如何解析或格式化输出数据
format_instructions = output_parser.get_format_instructions()
print(format_instructions)输出
Return a JSON object.示例:
parser = JsonOutputParser()
format_instructions = parser.get_format_instructions()
messages = [
    SystemMessage(content="""You are a helpful assistant that translates Chinese to English.
Please output your response in JSON format with the following structure:
- "chinese": the original Chinese text
- "english": the English translation
{format_instructions}""".format(format_instructions=format_instructions)),
    HumanMessage(content="生命的意义是什么?")
]
result = chat_model.invoke(messages)
response = parser.invoke(result)
print(f"LLM 响应:{result}")
print(f"解析器解析后输出:{response}")输出
LLM 响应:content='{\n  "chinese": "生命的意义是什么?",\n  "english": "What is the meaning of life?"\n}' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 26, 'prompt_tokens': 62, 'total_tokens': 88, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_efad92c60b', 'id': 'chatcmpl-CXfWetMRKFexFCIlyhTAAkXnuhrnQ', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--01717e75-2e93-45dc-9507-5a9004baf3eb-0' usage_metadata={'input_tokens': 62, 'output_tokens': 26, 'total_tokens': 88, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}
解析器解析后输出:{'chinese': '生命的意义是什么?', 'english': 'What is the meaning of life?'}2.3 XML解析器 
XMLOutputParserXMLOutputParser 将模型的自由文本输出转换为可编程处理的 XML 数据。
如何实现:在 PromptTemplate 中指定 XML 格式要求,让模型返回 形式的数据。
注意:XMLOutputParser 不会直接将模型的输出保持为原始XML字符串,而是会解析XML并转换成Python字典 (或类似结构化的数据)。目的是为了方便程序后续处理数据,而不是单纯保留XML格式
parser = XMLOutputParser()
format_instructions = parser.get_format_instructions()
messages = [
    HumanMessage(content="""说出陈凯歌的3个电影,请将影片附在<movie></movie>标签中
{format_instructions}""".format(format_instructions=format_instructions)),
]
result = chat_model.invoke(messages)
response = parser.invoke(result)
print(f"LLM 响应:{result}")
print(f"解析器解析后输出:{response}")输出
LLM 响应:content='```xml\n<movies>\n   <movie>霸王别姬</movie>\n   <movie>英雄</movie>\n   <movie>无极</movie>\n</movies>\n```' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 39, 'prompt_tokens': 180, 'total_tokens': 219, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_efad92c60b', 'id': 'chatcmpl-CXfen7Ggi0dxuVRnr0ImgCsC4UehP', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--9bb3f1ad-23f4-4f64-9784-29b672fee3d0-0' usage_metadata={'input_tokens': 180, 'output_tokens': 39, 'total_tokens': 219, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}
解析器解析后输出:{'movies': [{'movie': '霸王别姬'}, {'movie': '英雄'}, {'movie': '无极'}]}2.4 列表解析器 
CommaSeparatedListOutputParser 列表解析器:利用此解析器可以将模型的文本响应转换为一个用 逗号分隔的列表(List[str])
parser = CommaSeparatedListOutputParser()
format_instructions = parser.get_format_instructions()
messages = [
    HumanMessage(content="""说出陈凯歌的3个电影,
    格式要求:{format_instructions}""".format(format_instructions=format_instructions))
]
result = chat_model.invoke(messages)
response = parser.invoke(result)
print(f"LLM 响应:{result}")
print(f"解析器解析后输出:{response}")输出
LLM 响应:content='霸王别姬,霍元甲,梅兰芳' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 13, 'prompt_tokens': 50, 'total_tokens': 63, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_efad92c60b', 'id': 'chatcmpl-CXiG5ZCiDYnGAM9dWFzOGsVIqycI1', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--c08e44be-7df4-4b8f-b36f-d4be215ae89f-0' usage_metadata={'input_tokens': 50, 'output_tokens': 13, 'total_tokens': 63, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}
解析器解析后输出:['霸王别姬', '霍元甲', '梅兰芳']2.5 日期解释器 
日期解析器 DatetimeOutputParser 利用此解析器可以直接将LLM输出解析为日期时间格式。get_format_instructions(): 获取日期解析的格式化指令,指令为:"Write a datetime stringthat matches the following pattern: '%Y-%m-%dT%H:%M:%S.%fZ',输出示例:1206-08-16T17:39:06.176399Z
示例
parser = DatetimeOutputParser()
format_instructions = parser.get_format_instructions()
messages = [
    HumanMessage(content="""说出陈凯歌 霸王别姬 电影的播出时间,
    格式要求:{format_instructions}""".format(format_instructions=format_instructions))
]
result = chat_model.invoke(messages)
response = parser.invoke(result)
print(f"LLM 响应:{result}")
print(f"解析器解析后输出:{response}")输出
LLM 响应:content='1993-01-01T00:00:00.000000Z' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 17, 'prompt_tokens': 121, 'total_tokens': 138, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_efad92c60b', 'id': 'chatcmpl-CXiSfihOja6c4uqhMjc2MnYVdQTHE', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--f9cdb9e0-81de-452f-9b44-dfa15581ef81-0' usage_metadata={'input_tokens': 121, 'output_tokens': 17, 'total_tokens': 138, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}
解析器解析后输出:1993-01-01 00:00:00