在上一节的 Chain 讲解中,只用了最简单的 StrOutputParser,它仅仅是把 AI 的回复从 AIMessage 对象变成了 str 字符串。这一节,我们将深入这个核心组件。

LangChain之解析器核心组件.
第一部分:OutputParser ------ 让模型"听话"地输出数据
OutputParser 主要做两件事:
- 立规矩(Format Instructions):自动生成一段提示词,告诉模型:"你必须给我输出 JSON,字段要是这样这样......"。
- 做翻译(Parse):把模型生成的文本(String),转换成程序可用的数据结构(Dict, List, Object)。
1. JsonOutputParser (最常用的解析器)
这是目前最实用的解析器。它能把模型的输出直接转成 Python 的 Dictionary(字典)。
场景:你需要从一段文本中提取具体的字段(如:人名、年龄、职业)。
代码实战:
我们需要借助 Pydantic 来定义数据结构(虽然 JsonOutputParser 可以不用 Pydantic,但配合使用是最规范的)。
python
from pydantic import BaseModel, Field
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
# 1. 定义数据"图纸" (使用原生 Pydantic)
class PersonInfo(BaseModel):
name: str = Field(description="人物的姓名")
age: int = Field(description="人物的年龄,必须是数字")
skills: list[str] = Field(description="人物掌握的技能列表")
# 2. 实例化解析器
parser = JsonOutputParser(pydantic_object=PersonInfo)
# 3. 构造 Prompt 模板 (必须挖一个坑留给格式指令)
prompt = ChatPromptTemplate.from_template(
"请从下面的文本中提取人物信息。\n\n文本:{text}\n\n{format_instructions}"
)
# 4. 初始化模型
model = ChatOpenAI(
model="arcee-ai/trinity-large-preview:free",
# model="Pro/zai-org/GLM-4.7",
)
# 5. 组装链 (Chain)
chain = prompt | model | parser
# 6. 运行链
# 注意:我们要把 parser.get_format_instructions() 动态传给 Prompt
text_input = "小李今年28岁了,他是个全栈工程师,平时精通Python、Java,周末还喜欢去冲浪。"
result = chain.invoke({
"text": text_input,
"format_instructions": parser.get_format_instructions() # 自动生成长篇的JSON要求指令
})
print(type(result))
print(result)
# <class 'dict'>
# {'name': '小李', 'age': 28, 'skills': ['Python', 'Java']}
原理解析:
如果你不加 format_instructions,模型可能会回一句:"好的,这是提取的信息:..."。
解析器收到这句话就会报错,因为它只要纯 JSON。
所以,解析器的核心不仅仅是"解析",更重要的是"提示(Prompting)"。
2. PydanticOutputParser (更严格的校验)
它和上面的 JsonOutputParser 很像,但更严格。如果模型输出的 JSON 缺字段或者类型不对(比如年龄输成了字符串 "eighteen"),它会抛出错误,甚至可以触发"自动修复机制"(Auto-fixing Parser,这是更高级的话题)。
适用场景 :金融、医疗等对数据格式要求极高的场景。
用法与上面基本一致,区别在于 invoke 后的返回值是 Person 类的对象,而不是 dict。
3. CommaSeparatedListOutputParser (简单的列表)
如果你只需要一个简单的列表,不需要复杂的 JSON。
代码实战:
python
from langchain_core.output_parsers import CommaSeparatedListOutputParser
parser = CommaSeparatedListOutputParser()
prompt = ChatPromptTemplate.from_template(
"列出5个{subject}的名称。\n{format_instructions}"
)
chain = prompt | ChatOpenAI() | parser
result = chain.invoke({
"subject": "水果",
"format_instructions": parser.get_format_instructions()
})
# 结果直接就是一个 Python List
# ['苹果', '香蕉', '橙子', '葡萄', '西瓜']
第二部分:RunnableLambda ------ 把"自定义函数"变成链的一环
在 LCEL 链中,我们不仅可以放 LangChain 的组件,还可以放任何 Python 函数 。
这让你可以在链的中间做数据清洗、逻辑判断、或者简单的计算。
LangChain 提供了一个包装器叫 RunnableLambda,它可以把普通函数变成"可链式调用"的组件。
1. 基础用法:数据清洗
假设模型输出的 JSON 里,名字全是小写,你想把它转换成大写。
代码实战:
python
from langchain_core.runnables import RunnableLambda
# 普通 Python 函数
def uppercase_name(data):
# 假设 data 是上一步解析出来的字典 {'name': 'john', ...}
data['name'] = data['name'].upper()
return data
# 在链中使用 (LCEL 会自动把函数识别为 RunnableLambda,也可以显式包裹)
chain = prompt | model | parser | RunnableLambda(uppercase_name)
2. 进阶用法:分支逻辑与调试
有时候你想看看链运行到一半时,数据长什么样。你可以写一个"打印函数"插进去。
python
def inspect_data(x):
print(f"【中间监控】当前数据: {x}")
return x # 必须返回 x,否则链就断了
chain = prompt | model | RunnableLambda(inspect_data) | parser
第三部分 打造"智能数据分析链"
现在我们将 Prompt + Model + JsonParser + 自定义函数 全部串联起来。
任务目标:
- 用户输入一段混乱的评论。
- 模型提取关键信息(情感分数、关键词)。
- 解析器转成字典。
- 自定义函数判断是否是"差评",并生成自动回复建议。
完整代码(请仔细阅读注释):
python
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_openai import ChatOpenAI
from langchain_core.runnables import RunnableLambda
# --- 1. 定义数据结构 ---
class ReviewAnalysis(BaseModel):
sentiment_score: int = Field(description="情感打分,1-10分,10分为最满意")
keywords: list[str] = Field(description="评论中的关键名词")
summary: str = Field(description="一句话总结评论内容")
# --- 2. 准备组件 ---
model = ChatOpenAI(model="gpt-3.5-turbo")
parser = JsonOutputParser(pydantic_object=ReviewAnalysis)
prompt = ChatPromptTemplate.from_template(
"""
你是一个电商评论分析师。请分析以下用户评论。
用户评论: {comment}
{format_instructions}
"""
)
# --- 3. 定义自定义业务逻辑函数 ---
def analyze_priority(analysis_dict):
"""
接收解析后的字典,增加一个'处理优先级'字段
"""
score = analysis_dict['sentiment_score']
if score <= 3:
analysis_dict['priority'] = "【红色警报】需人工立即介入"
analysis_dict['reply_strategy'] = "道歉并提供赔偿"
elif score <= 7:
analysis_dict['priority'] = "【黄色关注】需跟进"
analysis_dict['reply_strategy'] = "询问具体细节"
else:
analysis_dict['priority'] = "【绿色正常】"
analysis_dict['reply_strategy'] = "感谢评价"
print(f"处理优先级:{analysis_dict['priority']},回复策略:{analysis_dict['reply_strategy']}")
return analysis_dict
# --- 4. 组装终极链 (LCEL) ---
# 流程:输入 -> 提示词 -> 模型 -> 文本转JSON -> 业务逻辑处理
full_chain = (
prompt
| model
| parser
| RunnableLambda(analyze_priority)
)
# --- 5. 运行测试 ---
bad_review = "这个东西太烂了!快递慢得要死,打开还是坏的,气死我了!"
good_review = "东西不错,物流挺快的,下次还会买。"
print("=== 测试差评 ===")
result1 = full_chain.invoke({
"comment": bad_review,
"format_instructions": parser.get_format_instructions()
})
print(result1)
print("\n=== 测试好评 ===")
result2 = full_chain.invoke({
"comment": good_review,
"format_instructions": parser.get_format_instructions()
})
print(result2)
输出结果预期:
text
=== 测试差评 ===
处理优先级:【红色警报】需人工立即介入,回复策略:道歉并提供赔偿
{'sentiment_score': 1, 'keywords': ['东西', '快递', '坏的'], 'summary': '用户对商品和快递服务极度不满,表示收到的是损坏的产品。', 'priority': '【红色警报】需人工立即介入', 'reply_strategy': '道歉并提供赔偿'}
=== 测试好评 ===
处理优先级:【绿色正常】,回复策略:感谢评价
{'sentiment_score': 8, 'keywords': ['东西', '物流'], 'summary': '用户对商品和物流速度表示满意,表示下次会继续购买。', 'priority': '【绿色正常】', 'reply_strategy': '感谢评价'}
第四部分:总结
在 LangChain 的链中,解析器和自定义函数让你的应用从"聊天玩具"变成了"生产力工具"。
- OutputParser :解决了"非结构化文本 →\to→ 结构化数据 "的难题。
- 记得:
format_instructions是必不可少的,必须传给 Prompt。
- 记得:
- RunnableLambda :解决了"AI 逻辑 →\to→ 传统代码逻辑 "的衔接。
- 任何 Python 函数都可以是链的一部分。
现在的链结构变成了:
Prompt (输入处理) →\to→ Model (大脑) →\to→ Parser (格式化) →\to→ Function (业务处理)
掌握了这一步,你就已经具备了构建复杂数据处理 Pipeline 的能力!