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

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

引言

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

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

LCEL语法基础

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

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

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

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

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
# 调用笑话对象,传入一个主题字符串,得到一个笑话字符串的流
joke.stream("dog")
  • 如果我们想要同时处理多个主题,我们只需要改变调用方法,使用batch代替invoke
# 调用笑话对象,传入一个主题字符串的列表,得到一个笑话字符串的列表
joke.batch(["dog", "cat", "banana"])
  • 如果我们想让请求异步执行只需要
joke.ainvoke("dog")
  • 模型的变更也十分简单,只需要变更modal变量的定义即可
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
# 增加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.https://python.langchain.com/docs
责任编辑:武晓燕 来源: AI小智
相关推荐

2011-11-30 16:29:41

2023-10-16 16:05:44

PythonPyCharm编程语言

2011-04-18 11:00:34

使用音频BlackBerry

2011-12-05 15:44:45

Knockout

2012-01-04 16:21:11

2011-12-05 14:50:13

Knockout

2011-11-29 16:38:58

Knockout

2011-04-15 16:05:00

监听UI对象的改变BlackBerry

2011-11-29 16:56:30

Knockout

2011-04-15 15:16:28

使用图像对象画图BlackBerry

2022-08-02 08:01:09

开发插件Chrome前端技术

2011-07-25 16:21:22

Sencha touc

2011-04-15 14:22:20

图片操作UIBlackBerry

2010-06-13 09:27:56

Widget开发

2009-06-24 16:30:21

JSF组件模型

2012-03-26 09:27:40

谷歌安卓开发谷歌安卓

2011-06-09 18:24:36

QT Wince

2023-05-15 18:44:07

前端开发

2012-01-04 16:11:49

Knockout

2011-06-07 09:10:41

BlackBerry 开发
点赞
收藏

51CTO技术栈公众号