LangChain应用开发指南-熟用LCEL语法掌握Chain的精髓

引言

LangChain的核心概念是Chain,它是一种由多个流程构件组成的有向图,可以对输入的文本进行各种转换和处理,输出你想要的结果。LangChain提供了一种专门的表达式语言,叫做LCEL(LangChain Expression Language),它可以让你用简洁和灵活的语法来定义和操作Chain,无需编写复杂的代码。

今天我将带领大家使用LCEL语法来构建和组合Chain,实现强大的LLM应用。

本文为一个系列,之前内容没有看过的小伙伴可以点击链接查看: AI课程合集

LCEL语法基础

LCEL是一个用于构建复杂链式组件的语言,它支持流式处理、并行化、日志记录等功能。LCEL的基本语法规则是使用|符号将不同的组件连接起来,形成一个链式结构。|符号类似于Unix的管道操作符,它将一个组件的输出作为下一个组件的输入,从而实现数据的传递和处理。

LCEL的语法非常简洁和灵活,它可以用于各种场景和任务。例如,我们可以使用LCEL来实现以下功能:

  • 生成一个关于某个主题的笑话:我们可以将一个提示模板和一个语言模型组合起来,形成一个链式结构,如下所示:
python 复制代码
prompt = BasePromptTemplate("tell me a short joke about {topic}")
model = ChatModel()
output_parser = StrOutputParser()
joke = ({"topic": RunnablePassthrough()} | prompt | model | output_parser)

这个链式结构的作用是,首先根据用户输入的主题,生成一个提示,然后将提示传递给语言模型,让它生成一个笑话,最后将笑话转换为字符串,返回给用户。我们可以用以下代码来测试这个链式结构:

python 复制代码
joke.invoke("ice cream")
# > "Why did the ice cream go to therapy? \n\nBecause it had too many toppings and couldn't find its cone-fidence!"

通过以上案例,我们能够了解如何使用LCEL语言构建一个生成笑话的链式结构。我将为您解释其中的每一步:

  • 首先,我们传入用户想要的主题,例如 "ice cream",作为输入。
  • 通过{"topic": RunnablePassthrough()},将输入转化为字典类型{"topic": "ice cream"}
  • 然后,我们使用提示模板组件,根据用户输入的主题,生成一个提示,例如"tell me a short joke about ice cream",并将其封装为一个PromptValue类型的对象。这个对象可以适用于不同类型的语言模型,因为它可以生成字符串或消息序列。
  • 接着,我们使用大语言模型,会根据提示模板生成的提示,生成一段文本,例如"Why did the ice cream go to therapy?\nBecause it had too many toppings and couldn't cone-trol itself!",并将其封装为一个ChatMessage类型的对象。这个对象包含了生成者、内容和时间等信息。
  • 最后,我们使用输出解析器组件,根据用户的需求,将语言模型生成的文本转换为不同的格式或类型,例如字符串。这样,用户就可以方便地获取和使用生成的内容。

为什么要用LCEL?

LCEL语法的核心思想是:一切皆为对象,一切皆为链 。这意味着,LCEL语法中的每一个对象都实现了一个统一的接口:Runnable,它定义了一系列的调用方法(invoke, batch, stream, ainvoke, ...)。这样,你可以用同样的方式调用不同类型的对象,无论它们是模型、函数、数据、配置、条件、逻辑等等。而且,你可以将多个对象链接起来,形成一个链式结构,这个结构本身也是一个对象,也可以被调用。这样,你可以将复杂的功能分解成简单的组件,然后用LCEL语法将它们组合起来,形成一个完整的应用。

LCEL语法还提供了一些组合原语,让你可以更灵活地控制链式结构的行为,例如:

  • 并行化:你可以使用parallel原语将多个对象并行执行,提高效率和性能。
  • 回退:你可以使用fallback原语为某个对象指定一个备选对象,当主对象执行失败时,自动切换到备选对象,保证应用的可用性和稳定性。
  • 动态配置:你可以使用config原语为某个对象指定一个配置对象,根据运行时的输入或条件,动态地修改对象的参数或属性,增加应用的灵活性和适应性。

LCEL语法的优势

为了更好地理解LCEL语法的优势,我们可以将它与传统的编程语言进行对比,看看如果不使用LCEL语法,我们需要做哪些额外的工作。我们仍以上述笑话的生成链为例。

这段代码非常简洁和清晰,只需要几行就可以实现我们想要的功能。而且,这段代码还具有很高的可扩展性和灵活性,例如:

  • 如果我们想要以流式的方式获取笑话,我们只需要改变调用方法,使用stream代替invoke
python 复制代码
# 调用笑话对象,传入一个主题字符串,得到一个笑话字符串的流
joke.stream("dog")
  • 如果我们想要同时处理多个主题,我们只需要改变调用方法,使用batch代替invoke
python 复制代码
# 调用笑话对象,传入一个主题字符串的列表,得到一个笑话字符串的列表
joke.batch(["dog", "cat", "banana"])
  • 如果我们想让请求异步执行只需要
python 复制代码
joke.ainvoke("dog")
  • 模型的变更也十分简单,只需要变更modal变量的定义即可
ini 复制代码
prompt = BasePromptTemplate("tell me a short joke about {topic}")
# 改用gpt-3.5-turbo的llm
model = OpenAI(model="gpt-3.5-turbo")
output_parser = StrOutputParser()
joke = ({"topic": RunnablePassthrough()} | prompt | model | output_parser)
  • 同时LCEL标准模型中的对象都可以直接增加同类型对象作为fallbacks,操作上只需要执行with_fallbacks方法即可。由于整条链亦是LCEL标准模型,因而链亦可配置fallbacks
ini 复制代码
# 增加OpenAI的llm作为ChatModel的fallbacks
prompt = BasePromptTemplate("tell me a short joke about {topic}")
model = ChatModel()
fallback_llm = OpenAI(model="gpt-3.5-turbo")
modal_with_fallback = model.with_fallbacks([fallback_llm])
output_parser = StrOutputParser()
joke = ({"topic": RunnablePassthrough()} | prompt | modal_with_fallback | output_parser)

以上只是一些简单的例子,你可以根据自己的需求,使用LCEL语法提供的更多的组合原语,实现更复杂的功能和效果。

那么,如果我们不使用LCEL语法,而是使用传统的编程语言,我们需要做哪些额外的工作呢?我们以Python为例,看看我们需要写多少代码,才能实现与LCEL语法相同的功能。

从上面的代码可以看出,如果我们不使用LCEL语法,而是使用传统的编程语言,我们需要写很多的代码,才能实现与LCEL语法相同的功能。而且,这些代码还存在很多的问题,例如:

  • 代码的可读性和可维护性很差,需要花费很多的时间和精力去理解和修改。
  • 代码的可扩展性和灵活性很低,需要对代码进行大量的修改,才能实现不同的功能和效果。
  • 代码的可复用性和可移植性很差,需要对代码进行大量的修改,才能适应不同的场景和平台。

因此,我们可以看出,LCEL语法相比传统的编程语言,具有很多的优势,它可以让我们更高效、更简单、更灵活地构建复杂的AI应用。

总结

在本文中,我们介绍了如何使用LangChain的LECL语法。我们介绍了LECL的基本语法以及基于LECL的流、异步等多种用法,并对比了不适用LECL语法开发的情况。

我们希望本文能够帮助你了解LangChain中特色的LECL语法,鼓励你尝试使用LangChain开发自己的应用。如果你有任何问题或建议,欢迎联系我们,我们期待与你的交流和合作。

参考资料:

1\] Why use LCEL.[python.langchain.com/docs](https://link.juejin.cn?target=https%3A%2F%2Fpython.langchain.com%2Fdocs "https://python.langchain.com/docs")

相关推荐
Victor35616 分钟前
Redis(137)Redis的模块机制是什么?
后端
Victor35619 分钟前
Redis(136)Redis的客户端缓存是如何实现的?
后端
不知更鸟5 小时前
Django 项目设置流程
后端·python·django
黄昏恋慕黎明7 小时前
spring MVC了解
java·后端·spring·mvc
G探险者9 小时前
为什么 VARCHAR(1000) 存不了 1000 个汉字? —— 详解主流数据库“字段长度”的底层差异
数据库·后端·mysql
百锦再9 小时前
第18章 高级特征
android·java·开发语言·后端·python·rust·django
Tony Bai9 小时前
Go 在 Web3 的统治力:2025 年架构与生态综述
开发语言·后端·架构·golang·web3
程序猿20239 小时前
项目结构深度解析:理解Spring Boot项目的标准布局和约定
java·spring boot·后端
RainbowSea10 小时前
内网穿透配置和使用
java·后端
掘金码甲哥10 小时前
网关上的限流器
后端