跳到主要内容LangChain 输出解析器与 LCEL 链构建实战指南 | 极客日志PythonAI
LangChain 输出解析器与 LCEL 链构建实战指南
LangChain 中 OutputParser 的使用方法和基于 LCEL 构建链的技术。内容涵盖为何需要输出解析器、CommaSeparatedList 和 Pydantic 解析器的代码实践、JSON 及正则解析器的应用场景。重点阐述了 LCEL 表达式语言如何通过管道符组合组件,对比了传统 invoke 调用与 LCEL 链的差异,并补充了流式输出、异步支持及错误处理等高级特性。文章旨在帮助开发者提升大模型应用的结构化数据处理能力和代码可维护性。
樱花落尽2 浏览 LangChain 输出解析器与 LCEL 链构建实战指南
本文详细介绍 LangChain 中 OutputParser 的使用,以及如何基于 LangChain Expression Language (LCEL) 构建高效的 链。通过结构化输出和链式调用,可以显著提升大模型应用的稳定性和可维护性。
1. 输出解析器 OutputParser
1.1 为什么需要 OutputParser
在常规使用 LangChain 构建 LLM 应用的流程中,通常遵循 Prompt 输入 -> 调用 LLM -> LLM 输出 的步骤。然而,很多时候我们需要 LLM 返回的数据是格式化的(例如 JSON、列表或特定对象),以便后续程序进行逻辑处理或数据库存储。
虽然可以在 Prompt 中要求 LLM 输出特定格式,但直接依赖 LLM 的文本生成往往不够稳定。这时就需要引入输出解析器。LLM 的输出内容会先传给输出解析器,解析器负责校验并转换数据为预期的 Python 对象格式。
1.2 代码实践:系统自带解析器
示例 1:逗号分隔列表
将调用 LLM 的结果解析为逗号分隔的列表。例如询问某个城市有 N 个著名景点。
from langchain_openai import ChatOpenAI
from langchain.output_parsers import CommaSeparatedListOutputParser
from langchain.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "{parser_instructions}"),
("human", "列出{cityName}的{viewPointNum}个著名景点。")
])
output_parser = CommaSeparatedListOutputParser()
parser_instructions = output_parser.get_format_instructions()
print("解析器指令:\n", parser_instructions)
final_prompt = prompt.invoke({
"cityName": "南京",
"viewPointNum": 3,
"parser_instructions": parser_instructions
})
model = ChatOpenAI(
model="gpt-3.5-turbo",
openai_api_key="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
openai_api_base="https://api.aigc369.com/v1"
)
response = model.invoke(final_prompt)
print("原始响应:", response.content)
ret = output_parser.invoke(response)
print("解析结果:", ret)
示例 2:自定义 Pydantic 格式
除了使用内置格式,还可以利用 Pydantic 定义严格的数据结构。这能确保返回数据的类型安全。
- 定义数据结构类,继承
pydantic.BaseModel。
- 使用
PydanticOutputParser。
- 生成 Prompt、调用 LLM、解析结果。
from typing import List
from langchain.output_parsers import PydanticOutputParser
from langchain.prompts import ChatPromptTemplate
from langchain.schema import HumanMessage
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_openai import ChatOpenAI
class BookInfo(BaseModel):
book_name: str = Field(description="书籍的名字")
author_name: str = Field(description="书籍的作者")
genres: List[str] = Field(description="书籍的体裁")
output_parser = PydanticOutputParser(pydantic_object=BookInfo)
print("格式指令:\n", output_parser.get_format_instructions())
prompt = ChatPromptTemplate.from_messages([
("system", "{parser_instructions} 你输出的结果请使用中文。"),
("human", "请你帮我从书籍的概述中,提取书名、作者,以及书籍的体裁。书籍概述会被三个#符号包围。\n###{book_introduction}###")
])
book_introduction = """
《朝花夕拾》原名《旧事重提》,是现代文学家鲁迅的散文集,收录鲁迅于 1926 年创作的 10 篇回忆性散文。文集作为'回忆的记事',多侧面地反映了作者鲁迅青少年时期的生活。
"""
model = ChatOpenAI(
model="gpt-3.5-turbo",
openai_api_key="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
openai_api_base="https://api.aigc369.com/v1"
)
final_prompt = prompt.invoke({
"book_introduction": book_introduction,
"parser_instructions": output_parser.get_format_instructions()
})
response = model.invoke(final_prompt)
result = output_parser.invoke(response)
print("解析后的对象:", result)
print("书名:", result.book_name)
1.3 其他常用解析器
除了上述两种,LangChain 还提供了多种解析器以适应不同场景:
- JsonOutputParser: 强制 LLM 输出 JSON 格式,适合需要复杂嵌套结构的场景。
- RegexParser: 使用正则表达式提取信息,适用于非结构化文本中的关键信息抽取。
- StructuredOutputParser: 结合 Pydantic 和 Prompt 模板,提供更灵活的约束。
在使用时,建议始终包裹在 try-except 块中,以处理解析失败的情况。
try:
parsed_result = output_parser.invoke(response)
except Exception as e:
print(f"解析失败:{e}")
2. 利用 LCEL 构建链
2.1 LCEL 简介
LCEL (LangChain Expression Language) 是 LangChain 表达式语言的简称。它提供了一种声明式的、流式的方式来组合不同的组件(如 Prompt、Model、Parser)。
在 LangChain 中,只要实现了 Runnable 接口并且拥有 invoke 方法,都可以成为链的一部分。这意味着它们可以接收上一个组件的输出作为自己的输入。
LCEL 的核心优势在于使用管道符 | 连接各个组件。这种方式不仅书写简洁,还支持异步 (astream, ainvoke) 和流式输出 (stream, astream_events)。
2.2 不使用 LCEL vs 使用 LCEL
传统方式
不使用 LCEL 时,代码需要显式地调用每个组件的 invoke 方法,变量传递繁琐,难以复用。
final_prompt = prompt.invoke({"book_introduction": book_introduction, ...})
response = model.invoke(final_prompt)
result = output_parser.invoke(response)
LCEL 方式
使用 LCEL 后,代码变得非常直观,且天然支持错误处理和流式传输。
chain = prompt | model | output_parser
ret = chain.invoke({"book_introduction": book_introduction, ...})
2.3 LCEL 的高级特性
1. 流式输出
LCEL 原生支持流式传输,这对于用户体验至关重要,可以让用户看到 LLM 逐字生成的过程。
for chunk in chain.stream({"book_introduction": book_introduction, ...}):
print(chunk, end="", flush=True)
2. 异步支持
对于高并发场景,可以使用 ainvoke 或 astream。
import asyncio
async def main():
result = await chain.ainvoke({"book_introduction": book_introduction, ...})
return result
3. 状态管理
LCEL 可以与 RunnableWithMessageHistory 配合使用,轻松实现对话记忆功能。
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
memory = ConversationBufferMemory()
conversation = ConversationChain(llm=model, memory=memory)
3. 常见陷阱与最佳实践
3.1 解析错误处理
LLM 可能会偶尔违反格式约束。务必在解析前验证输出,或使用更严格的 Prompt 指令。
3.2 上下文窗口限制
在构建长链时,注意中间变量的大小。如果 Prompt 过长,可能导致 Token 溢出。建议使用 max_tokens 参数控制输出长度。
3.3 调试技巧
使用 langchain.debug 模式或打印中间步骤的输出来排查问题。
import logging
logging.basicConfig(level=logging.DEBUG)
4. 总结
本文详细讲解了 LangChain 的输出解析器机制,包括内置解析器和自定义 Pydantic 解析器的用法。同时深入探讨了 LCEL 链的构建方式,对比了传统调用与 LCEL 管道调用的区别,并补充了流式输出、异步处理等高级特性。
掌握这些技术点,能够帮助开发者构建出更加健壮、高效且易于维护的大语言模型应用。在实际项目中,建议根据具体业务需求选择合适的解析器,并充分利用 LCEL 的声明式特性来简化代码逻辑。
相关免费在线工具
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
- curl 转代码
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown转HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online