掘金 人工智能 05月22日 10:28
【AI LangChain开发-3】LCEL打造高效、灵活的AI应用流程
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文介绍了LangChain Expression Language (LCEL),一种用于构建AI应用的声明式语言。LCEL通过简洁、直观的方式组织LangChain组件,提高了代码的可读性、可维护性和复用性,特别适用于复杂的LLM应用开发。文章对比了LangChain的命令式和LCEL的声明式编程,阐述了LCEL的设计哲学,并展示了其核心能力,包括可组合性、并发任务、流式输出、异步调用以及错误处理机制。最后,文章通过多轮对话代理的示例,展示了LCEL在实际应用中的价值,并提供了进一步学习的建议。

⚙️ LCEL 是一种声明式语言,它通过使用简洁的 `|` 运算符连接组件,使得代码结构更加清晰易懂,解决了 LangChain 命令式编程中代码冗长、难以维护的问题。

🧩 LCEL 基于 `Runnable` 接口,实现了统一的抽象,所有组件都具备相同的基本能力,这简化了组件间的集成,并提升了代码的可复用性,方便开发者构建复杂的AI应用。

🚀 LCEL 提供了多种核心能力,包括可组合性与可重用性、并发任务、流式输出、异步调用和错误处理机制。这些特性使得开发者能够构建更高效、更灵活的AI应用,例如多轮对话代理。

💡 LCEL 简化了复杂性,提高了可维护性,增强了复用性,并与监控、调试和部署工具无缝集成,这些优势使得LCEL成为构建复杂AI应用的理想选择。

1. LCEL 能为你做什么?为什么它现在才变得重要?

1. LCEL 能为你做什么?为什么现在特别重要?

在构建 AI 应用的过程中,你可能已经发现:随着逻辑复杂度上升,LangChain 的代码会变得越来越冗长、难维护。组件嵌套、数据流转不清晰,调试也愈发困难。这正是 LCEL(LangChain Expression Language) 诞生的背景。

它是一种声明式语言,让你用更简洁、直观的方式组织 LangChain 组件,构建高可读性、高复用性的处理链,尤其适合应对日益复杂的 LLM 应用开发需求。

简单来说:LangChain 越复杂,越需要 LCEL。

LangChain 命令式 vs LCEL

LangChain命令式:

from langchain_core.prompts.chat import (    ChatPromptTemplate,    SystemMessagePromptTemplate,    HumanMessagePromptTemplate)from langchain_community.chat_models import ChatOllama# 系统提示词模版template = "你是一个翻译专家,你擅长将 {input_language} 翻译成 {output_language}"system_message_prompt = SystemMessagePromptTemplate.from_template(template)# 用户提示词模版human_template = "{text}"human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)# 构建对话的完整提示词模版chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])# 格式化输入,生成完整对话的消息message = chat_prompt.format_messages(input_language="English", output_language="中文", text="I like swimming")# 使用llama3模型,执行对话并生成内容llm = ChatOllama(model="llama3.2")response = llm.invoke(message)print(response.content)  

使用LCEL:

from langchain_core.prompts.chat import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplatefrom langchain_community.chat_models import ChatOllamafrom langchain_core.output_parsers import StrOutputParser# 创建提示模板system_template = "你是一个翻译专家,你擅长将 {input_language} 翻译成 {output_language}"system_message_prompt = SystemMessagePromptTemplate.from_template(system_template)human_message_prompt = HumanMessagePromptTemplate.from_template("{text}")chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])# 创建模型和输出解析器llm = ChatOllama(model="llama3.2")output_parser = StrOutputParser()# 创建LCEL链chain = chat_prompt | llm | output_parser# 使用链result = chain.invoke({    "input_language": "English",    "output_language": "中文",    "text": "I like swimming"})print(result)

LCEL使用简单的|操作符连接各个组件,将不同的组件链接在一起,将一个组件的输出作为下一个组件的输入。在这个链条中,用户输入被传递给提示模板,然后提示模板的输出被传递给模型,然后模型的输出被传递给输出解析器。

为什么现在需要LCEL?

    代码简洁性:使用|运算符连接组件,消除了大量中间变量和嵌套调用可维护性:数据流向清晰明了,使代码更易理解和修改组件复用:可以轻松提取、重组和重用链的各个部分一致性接口:统一的调用方式(invokestream等),无需担心不同组件的接口差异

2. LCEL 的设计哲学与编程范式

在深入LCEL细节之前,我们需要理解其背后的核心设计理念,这将帮助你以正确的思维模式来设计和开发LCEL应用。

一切皆 Runnable:统一抽象的力量

LCEL的基础是Runnable接口,所有组件(从提示模板到语言模型再到输出解析器)都实现了这个接口,具备相同的基本能力:

invoke()      # 同步调用ainvoke()     # 异步调用batch()       # 批量处理abatch()      # 异步批量处理stream()      # 流式处理astream()     # 异步流式处理

这种统一抽象极大简化了组件间的集成,因为每个组件都以相同的方式"说话"。

声明式 vs 命令式:控制流转为数据流

3. LCEL 的核心能力与特性

现在让我们深入了解LCEL提供的实际能力,并通过具体示例看看如何利用这些特性构建高效的AI应用。

可组合性与可重用性

LCEL的核心优势在于其极强的组合能力,让你可以像搭积木一样构建复杂流程:

# 基本组件prompt = ChatPromptTemplate.from_template("写一篇关于{topic}的总结,50字以内")llm = ChatOllama(model="llama3.2")output_parser = StrOutputParser()# 组合成链content_chain = prompt | llm | output_parser# 构建复杂链advanced_chain = (    RunnablePassthrough.assign( content=lambda x: content_chain.invoke({"topic": x["topic"]}))    | ChatPromptTemplate.from_template("将这段内容的关键字提取出来:{content}")    | llm    | output_parser)# 显式调用链result = advanced_chain.invoke({"topic": "人工智能"})print(result)

这种设计让你可以构建可重用的链组件

并发任务

# 并行执行多个检索器from langchain_core.prompts import ChatPromptTemplatefrom langchain_core.runnables import RunnableParallelfrom langchain_community.chat_models import ChatOllama# 基础组件prompt = ChatPromptTemplate.from_template("给我讲一个关于 {topic} 的笑话")llm = ChatOllama(model="llama3.2")# 绑定变量后再组装chain_1 = prompt.partial(topic="程序员") | llmchain_2 = prompt.partial(topic="人工智能") | llm# 并发执行parallel_jokes = RunnableParallel(    joke1 = chain_1,    joke2 = chain_2,)# 调用results = parallel_jokes.invoke({})# 输出结果print("程序员笑话:", results["joke1"].content)print("AI 笑话:", results["joke2"].content)

流式输出

from langchain_core.prompts import ChatPromptTemplateprompt = ChatPromptTemplate.from_template("给我讲一个关于 {topic} 的笑话")llm = ChatOllama(model="llama3.2")chain = prompt | llm# 流式输出for chunk in chain.stream({"topic": "冰淇淋"}):    print(chunk.content, end="", flush=True)

异步调用

import asynciofrom langchain_core.prompts import ChatPromptTemplate# 定义 prompt 和模型prompt = ChatPromptTemplate.from_template("给我讲一个关于 {topic} 的笑话")llm = ChatOllama(model="llama3.2")chain = prompt | llmawait chain.ainvoke({"topic": "雪花"})

错误处理与回退机制

在LLM应用程序中,可能会出现许多故障点,无论是LLM API的问题、模型输出不佳、其他集成的问题等等。回退可以帮助您优雅地处理和隔离这些问题。

from langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import PromptTemplatefrom langchain_core.runnables import RunnableLambdafrom langchain_ollama import ChatOllama# 定义提示模板和解析器prompt = PromptTemplate.from_template("请将以下文本翻译为英文:{text}")llm = ChatOllama(model="llama3.2")parser = StrOutputParser()chain = prompt | llm | parser# 定义备用链,返回默认响应fallback_chain = RunnableLambda(lambda x: "无法翻译输入文本。")# 创建带有回退机制的链chain_with_fallback = chain.with_fallbacks([fallback_chain])# 执行链result = chain_with_fallback.invoke({"text": "你好"})print(result)

这段代码正常情况输出:Hello,如果我故意让模型调用出错,比如修改为

chain_with_fallback.invoke({"text66": "你好"})

输出结果就会是:无法翻译输入文本。

4. LCEL 应用场景示例

4.1 多轮对话代理:融合记忆机制与工具调用能力

在实际应用中,我们常常希望构建一个不仅能自然对话、还能调用外部功能(如天气查询、数据库检索等)且具备上下文记忆的智能体。通过 LCEL(LangChain Expression Language)构建这样的 多链组合 Agent,可以轻松实现:

下面的示例中,我们构建了一个具备 “记忆 + 工具调用 + 对话” 三种能力的对话代理。用户可以先提问天气,再在后续轮次中基于上下文继续提问,比如“那我该穿什么?”——代理会通过记忆理解,结合第一个问题的回答来答复第2个问题。

from langchain.agents import initialize_agent, Tool, AgentTypefrom langchain.memory import ConversationBufferMemoryfrom langchain_ollama import ChatOllamadef fake_weather(city: str) -> str:    """获取指定城市的天气情况"""    return f"{city} 今天多云转晴,最高气温 22℃,最低气温 10℃,北风微风,空气良。"# 定义工具, Agent 根据描述调用weather_tool = Tool(    name="天气查询",    func=fake_weather,    description="获取指定城市的天气情况,输入应该是城市名称,例如:北京")tools = [weather_tool]# 初始化模型llm = ChatOllama(model="llama3.2", temperature=0)# 创建记忆,便于多轮对话理解上下文。memory = ConversationBufferMemory(    memory_key="chat_history",    return_messages=True)# 创建代理,具备工具调用能力的智能体(Agent)agent = initialize_agent(    tools=tools,    llm=llm,    agent=AgentType.CONVERSATIONAL_REACT_DESCRIPTION, #对话型 Agent 类型,结合工具调用和语言模型推理,适合对话交互。    memory=memory,    verbose=True # 可选,会打印 Agent 推理过程。)# 测试对话user_inputs = [    "帮我查一下北京的天气",    "那明天我去那边穿什么合适?"]for i, user_input in enumerate(user_inputs, 1):    print(f"\n[轮次 {i}]")    print(f"用户: {user_input}")    try:        response = agent.run(user_input)        print(f"助手: {response}")    except Exception as e:        print(f"出现错误: {e}")

输出

5. 总结与下一步建议

LCEL 的价值总结

    简化复杂性:通过声明式语法处理复杂的AI组件交互提高可维护性:清晰展示数据流,使代码更易理解增强复用性:轻松组合和重用链的各个部分生态系统支持:与监控、调试和部署工具无缝集成

延伸学习路径

下一步我们继续带大家快速掌握:

    LangGraph:基于LCEL构建更复杂的状态管理和循环控制流LangServe:将LCEL链部署为可扩展的API服务LangSmith:深入跟踪和调试链的执行情况AutoGraph:自动化工作流构建和优化

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

LCEL LangChain LLM AI应用开发
相关文章