LangChain Expression Language

LangChain 表达式语言

5 分钟阅读

TL;DR(太长不看版)

  • 我们很高兴地宣布一种新的语法,用于创建具有组合的链。这 साथ एक नए इंटरफ़ेस के साथ आता है जो बैच,异步和流式传输 को बॉक्स से बाहर समर्थन करता है। 我们将这种语法称为 LangChain 表达式语言 (LCEL)
  • 我们创建了一个“LangChain 教师”,以帮助您学习 LCEL(假设您熟悉 LangChain)
  • 我们将在 8 月 2 日举办一场关于此内容以及如何使用它的网络研讨会
  • 其目的是使构建复杂链条更容易,并与 LangSmith(我们最近发布的旨在简化从原型到生产的平台)完美配合。

事实证明,在构建语言模型应用程序时,链式调用的想法很受欢迎。 链式调用可以有几种不同的形式,每种形式都有其自身的优势。 其中一些示例包括

进行多次 LLM 调用

链式调用可能意味着在序列中进行多次 LLM 调用。 语言模型通常是不确定的,并且可能会出错,因此进行多次调用以检查先前的输出或将较大的任务分解为小的步骤可以提高结果。

构建 LLM 的输入

链式调用可能意味着将数据转换与对 LLM 的调用相结合。 例如,使用用户输入格式化提示模板,或使用检索来查找要插入到提示模板中的其他信息。 这是必要的,因为您通常需要来自多个来源的数据才能执行任务,这些数据可能会在运行时根据输入获取。

使用 LLM 的输出

链式调用的另一种形式是指将 LLM 调用的输出传递给下游应用程序。 例如,使用 LLM 生成 Python 代码,然后运行该代码; 使用 LLM 生成 SQL,然后针对 SQL 数据库执行该代码。

还有一些关于使用语言模型的东西,使链式调用的想法很有吸引力。 当然,上述所有操作都可以用代码完成,但人们已经倾向于链式调用的想法 - 低代码/无代码平台构建语言模型应用程序的大量涌现就证明了这一点(有些像 FlowwiseLangFlow 构建在 LangChain 之上)。 为什么? 这已经成为一种迷因,但是如果 文本是通用接口,并且所有这些操作都涉及文本操作,那么这自然而然地为表达式语言支持这一点奠定了基础。

LangChain 诞生于使这些类型的操作变得容易的想法。 我们看到人们在做常见的模式,并将它们分解为预构建的链:LLMChain、ConversationalRetrievalChain、SQLQueryChain。

但是这些链条实际上并不可组合。 当然 - 我们有 SequentialChain,但这并不是非常易用。 并且在底层,其他链条涉及大量自定义代码,这使得很难为所有链条强制执行通用接口,并确保所有链条都具有同等水平的批量、流式传输和异步支持。

今天,我们很高兴地宣布一种构建链条的新方法。 我们将其称为 LangChain 表达式语言(与 SQLAlchemyExpressionLanguage 的精神相同)。 这是一种声明式方式,可以真正组合链条 - 并开箱即用地获得流式传输、批量和异步支持。 您可以使用所有相同的现有 LangChain 构造来创建它们。

我们提供了关于 如何使用该接口 以及 使用它的一些示例 的指南。 让我们看看下面更常见的方法之一

from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate

model = ChatOpenAI()
prompt = ChatPromptTemplate.from_template("tell me a joke about {foo}")
chain = prompt | model

chain.invoke({"foo": "bears"})
>>> AIMessage(content="Why don't bears ever wear shoes?\n\nBecause they have bear feet!", additional_kwargs={}, example=False)

这使用标准的 ChatOpenAI 模型和提示模板。 您使用 | 运算符将它们链接在一起,然后使用 chain.invoke 调用它。 我们还可以开箱即用地获得异步、批量和流式传输支持。

批量

batch 接受输入列表。 如果可以在内部进行优化(例如,从字面上批量调用 LLM 提供商),则会进行这些优化。

chain.batch([{"foo": "bears"}, {"foo": "cats"}])
>>> [AIMessage(content="Why don't bears ever wear shoes?\n\nBecause they have bear feet!", additional_kwargs={}, example=False),
 AIMessage(content="Why don't cats play poker in the wild?\n\nToo many cheetahs!", additional_kwargs={}, example=False)]

流式传输

stream 返回您可以使用的可迭代对象。

for s in chain.stream({"foo": "bears"}):
    print(s.content, end="")

异步

invokebatchstream 都公开了异步方法。 为了简单起见,我们在这里只展示了 ainvoke,但您可以查看我们的笔记本,其中深入探讨了该接口以了解更多信息。

await chain.ainvoke({"foo": "bears"})

在我们的食谱中,我们包含了使用以下方法执行此操作的示例

我们将不断加强对此的支持并添加更多功能示例,因此请告诉我们您希望看到什么。 我们还将更多地将其纳入 LangChain 中 - create_sql_query_chain 已经在使用它。

除了添加标准接口的好处之外,另一个好处是这将使用户更容易自定义链条的各个部分。 由于链条以如此声明式和可组合的性质表示,因此将更加清楚如何更换某些组件。 它现在还将提示放在最前面和中心位置 - 使修改这些提示的方式更加清晰。 LangChain 中的提示只是默认值,如果您认真尝试将应用程序投入生产,则很大程度上旨在针对您的特定用例进行修改。 以前,提示有点隐藏且难以更改。 使用 LCEL,它们更加突出且易于更换。

LangChain 表达式语言创建的链条与 LangSmith 无缝集成。 这是上面的跟踪记录

您可以在此处检查跟踪记录。 以前,在创建自定义链条时,实际上需要做很多工作来确保正确传递回调,以便可以正确跟踪它。 使用 LangChain 表达式语言,这会自动发生。

我们还通过创建一个“LangChain 教师”应用程序来尽可能简化人们的学习过程,该应用程序将引导您完成 LangChain 表达式语言入门的基础知识。 您可以在此处访问它。 我们将很快开源它。

我们还将在明天举办关于此的网络研讨会。 我们将介绍它公开的标准接口、如何使用它以及为什么要使用它。 在此处注册。

我们对这种简单而轻量级的方式能够真正将链条组合在一起感到非常兴奋。 如果您也感到兴奋,我们正在招聘可以直接从事这项工作的职位。 引起我们注意的最佳方式是打开一两个 PR 来添加更多功能。 还有很多东西要构建 :)