简要说明
LangChain 已成为最常用的 Python 库 互动 法学硕士 在不到一年的时间里,LangChain 主要是为 POCs 因为它缺乏创造 复杂和可扩展的应用程序.
2023 年 8 月,他们发布了 朗查表语言(LCEL), 的新语法,弥补了 从 POC 到生产. .本文将引导您了解 LCEL 的来龙去脉,向您展示 LCEL 如何简化您的工作。 创建自定义链 以及如果您要建造房屋,为什么必须学习它 法律硕士申请!
提示、LLM 和链条,让我们温故而知新
在深入研究 LCEL 语法之前,我认为有必要温习一下 LangChain 的概念,如 LLM 和 Prompt,甚至是 Chain。.
法学硕士:在语言链中,llm 是对用于完成的模型的抽象,如 openai gpt3.5、laude 等...
提示:这是 LLM 对象的输入,它将提出 LLM 问题并给出其目标。.
链条:这是指调用 LLM 或任何 data 处理步骤的序列。.

既然定义都已经讲完了,我们不妨假设一下,我们想要创建一家公司!我们需要一个很酷、很响亮的名字和一个能赚钱的商业模式!
示例 - 公司名称和业务模式与旧链条
从 langchain.chains 导入 LLMChain
从 langchain.prompts 导入 PromptTemplate
从 langchain_community.llms 导入 OpenAI
USER_INPUT = "彩色袜子"
llm = OpenAI(temperature=0)
prompt_template_product = "一家制造 ?" 的公司的好名字是什么?"
company_name_chain = LLMChain(llm=llm, prompt=PromptTemplate.from_template(prompt_template_product))
company_name_output = company_name_chain(USER_INPUT)
prompt_template_business = "请为我的公司提供最佳商业模式创意,公司名称为:"
business_model_chain = LLMChain(llm=llm, prompt=PromptTemplate.from_template(prompt_template_business))
business_model_output = business_model_chain(company_name_output["text"])
print(company_name_output)
print(business_model_output)
>>>
>>>
这很容易理解,我们可以看到一些冗余,但还是可以处理的。.
让我们添加一些自定义功能,处理用户未按预期使用我们的链的情况。.
也许用户会输入一些与我们的链目标完全无关的内容?在这种情况下,我们要检测到它并做出适当的反应。.
示例 - 使用旧链进行定制和路由选择
从 langchain.chains 导入 LLMChain
从 langchain.prompts 导入 PromptTemplate
从 langchain_community.llms 导入 OpenAI
导入 ast
USER_INPUT = "Harrison Chase"
llm = OpenAI(temperature=0)
# -- 代码同前
prompt_template_product = "一家制造 ?" 的公司的好名字是什么?"
company_name_chain = LLMChain(llm=llm, prompt=PromptTemplate.from_template(prompt_template_product))
prompt_template_business = "请为我的公司提供最佳商业模式创意,公司名称为:"
business_model_chain = LLMChain(llm=llm, prompt=PromptTemplate.from_template(prompt_template_business))
# -- 新代码
prompt_template_is_product = (
"您的目标是找出用户输入的是否是一个可信的产品名称"
"问题、问候语、长句子、名人或其他非相关输入不视为产品n"
"输入:n"
"只回答'真'或'假',仅此而已'
)
prompt_template_cannot_respond = (
"您无法响应用户输入:n"
"要求用户输入产品名称,以便您从中创建一家公司"。"
)
cannot_respond_chain = LLMChain(llm=llm, prompt=PromptTemplate.from_template(prompt_template_cannot_respond))
company_name_chain = LLMChain(llm=llm, prompt=PromptTemplate.from_template(prompt_template_product))
business_model_chain = LLMChain(llm=llm, prompt=PromptTemplate.from_template(prompt_template_business))
is_a_product_chain = LLMChain(llm=llm, prompt=PromptTemplate.from_template(prompt_template_is_product))
# 如果我们在非空字符串上使用 bool,它将为 True,因此我们需要 `literal_eval`.
is_a_product = ast.literal_eval(is_a_product_chain(USER_INPUT)["text"])
如果 is_a_product:
company_name_output = company_name_chain(USER_INPUT)
business_model_output = business_model_chain(company_name_output["text"])
print(business_model_output)
否则
print(cannot_respond_chain(USER_INPUT))
这就有点难以理解了,让我们来总结一下:
开始出现多种问题:
什么是 LangChain Expression Language(LCEL)?
LCEL 是编写可组合生产就绪链的统一接口和语法,要理解它的含义有很多工作要做。.
首先,我们将重写之前的语法链,尝试理解新语法。.
示例:带有 LCEL 的公司名称和业务模式
from langchain_core.runnables import RunnablePassthrough
从 langchain.prompts 导入 PromptTemplate
从 langchain_community.llms 导入 OpenAI
USER_INPUT = "彩色袜子"
llm = OpenAI(temperature=0)
prompt_template_product = "一家制造 ?" 的公司的好名字是什么?"
prompt_template_business = "请为我的公司提供最佳商业模式创意,公司名称为:"
链 = (
PromptTemplate.from_template(prompt_template_product)
| llm
|
| PromptTemplate.from_template(prompt_template_business)
| llm
)
business_model_output = chain.invoke()
短短几行代码,却包含了大量不同寻常的内容:
但是,这样创建链的可组合性真的更好吗?
让我们通过添加 is_a_product_chain() 和用户输入不正确时的分支来测试一下。我们甚至可以使用 Python Typing 来键入链,让我们来做个良好的练习。.
示例 - 使用 LCEL 进行定制和路由选择
from typing import Dict
from langchain_core.runnables import RunnablePassthrough, RunnableBranch
从 langchain.prompts 导入 PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain.output_parsers import BooleanOutputParser
从 langchain_community.llms 导入 OpenAI
USER_INPUT = "哈里森-切斯"
llm = OpenAI(temperature=0)
prompt_template_product = "一家制造 ?" 的公司的好名字是什么?"
prompt_template_cannot_respond = (
"您无法响应用户输入:n"
"要求用户输入产品名称,以便您从中创建一家公司"。"
)
prompt_template_business = "请为我的公司提供最佳商业模式创意,公司名称为:"
prompt_template_is_product = (
"您的目标是找出用户输入的是否是一个可信的产品名称"
"问题、问候语、长句子、名人或其他非相关输入不视为产品n"
"输入:n"
"只回答'真'或'假',仅此而已'
)
答案用户链 = (
PromptTemplate.from_template(prompt_template_product)
| llm
|
| PromptTemplate.from_template(prompt_template_business)
| llm
).with_types(input_type=Dict[str, str], output_type=str)
is_product_chain = (
PromptTemplate.from_template(prompt_template_is_product)
| llm
| BooleanOutputParser(true_val='True', false_val='False')
).with_types(input_type=Dict[str, str], output_type=bool)
cannot_respond_chain = (
PromptTemplate.from_template(prompt_template_cannot_respond) | llm
).with_types(input_type=Dict[str, str], output_type=str)
full_chain = RunnableBranch(
(is_product_chain, answer_user_chain)、,
无法响应链
).with_types(input_type=Dict[str, str], output_type=str)
print(full_chain.invoke())
让我们列举一下它们的不同之处:
为什么 LCEL 更有利于工业化?
如果我在读这篇文章的时候,有人问我是否相信 LCEL,我可能会说不相信。语法太不一样了,我也许可以把我的代码组织成函数,得到几乎一模一样的代码。但我在这里写了这篇文章,所以肯定还有别的东西。.
开箱即用的调用、流和批处理功能
通过使用 LCEL,您的链条将自动拥有
my_chain = prompt | llm
# ---invoke--- #
result_with_invoke = my_chain.invoke(“hello world!”)
# ---batch--- #
result_with_batch = my_chain.batch([“hello”, “world”, “!”])
# --stream--- #
for chunk in my_chain.stream(“hello world!”):
print(chunk, flush=True, end=””)
迭代时,可以使用 invoke 方法来简化开发过程。但是,当在用户界面中显示链的输出时,您希望使用流式响应。现在,您可以使用流方法,而无需重写任何内容。.
开箱即用的异步方法
大多数情况下,应用程序的前台和后台是分开的,这意味着前台会向后台发出请求。如果有多个用户,您可能需要同时在后台处理多个请求。.
由于 LangChain 中的大部分代码只是在 API 调用之间等待,因此我们可以利用异步代码来提高 API 的可扩展性。 FastAPI 文档的并发汉堡故事.
无需担心实现问题,因为如果使用 LCEL,异步方法已经可用:
.ainvoke() / .abatch() / .astream:invoke、batch 和 stream 的异步版本。.
我还建议阅读 为什么使用 LangChain 文档中的 LCEL 页面 并附有每种同步/异步方法的示例。.
Langchain 通过创建一个名为 “Langchain ”的统一界面,实现了这些 "开箱即用 "的功能。 “可运行”. .现在,为了充分利用 LCEL,我们需要深入了解这个新的 Runnable 接口。.
Runnable 界面
到目前为止,我们在 LCEL 语法中使用的每个对象都是 Runnables。它是由 LangChain 创建的 python 对象,该对象自动继承了我们之前提到的所有功能,还有更多。通过使用 LCEL 语法,我们每一步都会组成一个新的 Runnable,这意味着最终创建的对象也将是一个 Runnable。. 有关界面的更多信息,请参阅官方文档.
下面代码中的所有对象要么是 Runnable,要么是自动转换为 Runnable 的字典:
from langchain_core.runnables import RunnablePassthrough, RunnableParallel
从 langchain.prompts 导入 PromptTemplate
从 langchain_community.llms 导入 OpenAI
链号一 = (
PromptTemplate.from_template(prompt_template_product)
| llm
| # <- 这将会改变
| PromptTemplate.from_template(prompt_template_business)
| llm
)
链号二 = (
PromptTemplate.from_template(prompt_template_product)
| llm
| RunnableParallel(company=RunnablePassthrough()) # <- 已更改
| PromptTemplate.from_template(prompt_template_business)
| llm
)
print(chain_number_one == chain_number_two)
>>> true
为什么要使用 RunnableParallel(),而不是简单的 Runnable()?
因为,RunnableParallel 中的每个 Runnable 都是并行执行的。这意味着,如果您的 Runnable 中有 3 个独立的步骤,它们将同时在机器的不同线程上运行,从而免费提高链的速度!
LCEL 的缺点
尽管 LCEL 有其优点,但也有一些潜在的缺点:
结论
总之,LangChain Expression Language(LCEL)是一款功能强大的工具,为构建 Python 应用程序带来了全新的视角。尽管它的语法非常规,但我仍强烈推荐使用 LCEL,原因如下:
更进一步...
可运行抽象
在某些情况下,我认为了解 LangChain 为使 LCEL 语法正常工作而实施的抽象方法非常重要。.
您可以通过以下方式轻松重新实现 Runnable 的基本功能:
类 Runnable:
def __init__(self, func):
self.func = func
def __or__(self, other):
def chained_func(*args, **kwargs):
# self.func 在左边,其他在右边
return other(self.func(*args, **kwargs))
return Runnable(chained_func)
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
def add_ten(x):
返回 x + 10
def div_by_two(x):
返回 x / 2
runnable_add_ten = Runnable(add_ten)
runnable_divide_by_two = Runnable(divide_by_two)
chain = runnable_add_ten | runnable_divide_by_two
结果 = chain(8) # (8+10) / 2 = 9.0 应该是答案
print(result)
>>> 9.0
Runnable 只是一个被 .__or__() 方法覆盖的 python 对象。.
在实践中,LangChain 增加了许多功能,例如将字典转换为 Runnable、类型功能、可配置性功能以及 invoke、批处理、流和异步方法!
那么,为什么不在下一个项目中试试 LCEL 呢?
如果您想了解更多信息,我强烈推荐您浏览 LCEL上的LangChain食谱.

博客






