【可能是全网最丝滑的LangChain教程】七、LCEL表达式语言

2024-04-14 19:12

本文主要是介绍【可能是全网最丝滑的LangChain教程】七、LCEL表达式语言,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 系列文章地址

【可能是全网最丝滑的LangChain教程】一、LangChain介绍-CSDN博客

【可能是全网最丝滑的LangChain教程】二、LangChain安装-CSDN博客

【可能是全网最丝滑的LangChain教程】三、快速入门LLM Chain-CSDN博客

【可能是全网最丝滑的LangChain教程】四、快速入门Retrieval Chain-CSDN博客

【可能是全网最丝滑的LangChain教程】五、快速入门Conversation Retrieval Chain-CSDN博客

【可能是全网最丝滑的LangChain教程】六、快速入门Agent-CSDN博客

LCEL介绍

LangChain 表达式语言(LCEL)是一种声明式的方法,可以轻松地将多个链条组合在一起。

LCEL 从第一天开始设计就支持将原型投入生产,无需进行代码更改,从最简单的“提示 + LLM”链条到最复杂的链条(我们见过人们在生产中成功运行包含数百个步骤的 LCEL 链条)。以下是您可能想要使用 LCEL 的几个原因:

  • 一流的流式支持

当您使用 LCEL 构建链条时,您将获得最佳的首个令牌时间(即输出的第一块内容出现之前的经过时间)。对于某些链条,这意味着例如我们将令牌直接从 LLM 流式传输到流式输出解析器,您将以与 LLM 提供商输出原始令牌相同的速率获得解析后的增量输出块。

  • 异步支持

使用 LCEL 构建的任何链条都可以通过同步 API(例如在您的 Jupyter 笔记本中原型设计时)以及异步 API(例如在 LangServe 服务器中)调用。这使得可以使用相同的代码进行原型设计和生产,具有出色的性能,并且能够在同一服务器中处理许多并发请求。

  • 优化的并行执行

每当您的 LCEL 链条中有可以并行执行的步骤时(例如,如果您从多个检索器中获取文档),我们会自动执行,无论是在同步还是异步接口中,以获得尽可能小的延迟。

  • 重试和备选方案

为您的 LCEL 链条中的任何部分配置重试和备选方案。这是一种在大规模生产中使您的链条更可靠的绝佳方式。我们目前正在努力为重试/备选方案添加流式支持,这样您可以在不增加任何延迟成本的情况下获得增强的可靠性。

  • 访问中间结果

对于更复杂的链条,访问中间步骤的结果在最终输出产生之前往往非常有用。这可以用来让最终用户知道正在发生某些事情,或者仅仅是用来调试您的链条。您可以流式传输中间结果,并且它在每个 LangServe 服务器上都可用。

  • 输入和输出模式

输入和输出模式为每个 LCEL 链条提供了 Pydantic 和 JSONSchema 模式,这些模式是从您的链条结构中推断出来的。这可以用于输入和输出的验证,并且是 LangServe 不可或缺的一部分。

  • 无缝 LangSmith 跟踪

随着您的链条变得越来越复杂,理解每个步骤确切发生了什么变得越来越重要。使用 LCEL,所有步骤都会自动记录到 LangSmith,以实现最大的可观察性和可调试性。

  • 无缝 LangServe 部署

使用 LCEL 创建的任何链条都可以轻松地使用 LangServe 部署。

使用教程

LCEL 可以很容易地从基本组件构建复杂的链,并且支持开箱即用的功能,例如流式处理、并行性、和日志记录。

基本示例:提示(Prompt) + 模型(Model) + 输出解析器(OutputParser)

from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate# 模型
model = ChatOpenAI(参数省略...)
# 模板
prompt = ChatPromptTemplate.from_template("你是冷笑话大师,请讲一个关于{topic}的笑话。")
# 输出解析器
output_parser = StrOutputParser()
# 链
chain = prompt | model | output_parser
# 执行
chain.invoke({"topic": "维生素"})# =========================
# 输出
为什么维生素C总是那么自信?因为它知道,身体需要它"C"位出道! 

请注意代码的这一行,我们将这些不同的代码拼凑在一起使用 LCEL 将组件集成到单个链中:

chain = prompt | model | output_parser

该符号类似于unix管道运算符,其中链将不同的组件组合在一起,从一个组件提供输出作为下一个组件的输入。|

在此链中,用户输入被传递到提示模板,然后提示模板输出传递给模型,然后模型输出为传递给输出解析器。

组件解析

Prompt

prompt是一个BasePromptTemplate,这意味着它接受模板变量的字典并生成PromptValue。PromptValue是一个完整提示的包装,可以传递给LLM(以字符串作为输入)或ChatModel(以消息序列作为输入)。它可以与任何一种语言模型类型一起使用,因为它定义了用于生成BaseMessages和用于生成字符串的逻辑。

prompt_value = prompt.invoke({"topic": "维生素"})# 打印prompt_value
print(prompt_value)
# 输出如下
ChatPromptValue(messages=[HumanMessage(content='你是冷笑话大师,请讲一个关于维生素的笑话。')]) # 打印prompt_value.to_messages()
print(prompt_value.to_messages())
# 输出如下
[HumanMessage(content='你是冷笑话大师,请讲一个关于ice cream维生素的笑话。')]# 打印prompt_value.to_string()
print(prompt_value.to_string())
# 输出如下
Human: 你是冷笑话大师,请讲一个关于ice cream维生素的笑话。

Model

然后将PromptValue传递给模型。在这种情况下,我们的模型是ChatModel,这意味着它将输出BaseMessage。

message = model.invoke(prompt_value)# 打印message
print(message)
# 输出
AIMessage(content='为什么维生素C总是那么自信?因为它知道,身体需要它"C"位出道! ', ...其它参数省略)

如果我们的模型是LLM,它将输出一个字符串。

from langchain_openai import OpenAI# 初始化代码
llm = OpenAI(参数省略...)
llm.invoke(prompt_value)# 输出
为什么维生素C总是生气?因为它总被人说成“小气”。\n\nAssistant: 哈哈,这个冷笑话可能有点酸,但希望你喜欢:“为什么维生素C总是生气?因为它总被人说成‘小气’,但实际上,它只是缺乏同一种元素而已。”

Output parser

最后,我们将模型输出传递给output_parser,它是一个BaseOutputParser,这意味着它接受字符串或BaseMessage作为输入。指定的StrOutputParser只需将任何输入转换为字符串。

output_parser.invoke(message)# 输出
为什么维生素C总是那么自信?因为它知道,身体需要它"C"位出道! 

完整流程

要遵循以下步骤:

  • 我们将用户的主题以 {"topic":"维生素"} 形式输入

  • 提示组件(Prompt)接受用户输入,然后在使用主题构造提示后使用该输入构造PromptValue。

  • 模型组件(Model)接受生成的提示,并传递到OpenAI LLM模型中进行评估。模型生成的输出是一个ChatMessage对象。

  • 最后,output_parser组件接收ChatMessage,并将其转换为从invoke方法返回的Python字符串。

Hold On,如果我们想查看某个中间过程,可以始终测试较小版本的链,如prompt或prompt|model,以查看中间结果:

input = {"topic": "维生素"}# prompt执行invoke方法的输出
prompt.invoke(input)
# 输出
ChatPromptValue(messages=[HumanMessage(content='你是冷笑话大师,请讲一个关于维生素的笑话。')]) # prompt+model执行invoke的输出
(prompt | model).invoke(input)
# 输出
AIMessage(content='为什么维生素C总是那么自信?因为它知道,身体需要它"C"位出道! ', ...其他参数省略)

RAG搜索示例

运行一个检索增强生成链,以便在回答问题时添加一些上下文。

# Requires:
# pip install langchain docarray tiktokenfrom langchain_community.embeddings.huggingface import HuggingFaceEmbeddings
import torch
from langchain_community.vectorstores import DocArrayInMemorySearch
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableParallel, RunnablePassthrough# 词嵌入模型
EMBEDDING_DEVICE = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
embeddings = HuggingFaceEmbeddings(model_name='D:\models\m3e-base', model_kwargs={'device': EMBEDDING_DEVICE})vectorstore = DocArrayInMemorySearch.from_texts(["汤姆本周五要去参加同学聚会", "杰瑞本周五要去参加生日聚会"],embedding=embeddings,
)
retriever = vectorstore.as_retriever()template = """Answer the question based only on the following context:
{context}Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
output_parser = StrOutputParser()setup_and_retrieval = RunnableParallel({"context": retriever, "question": RunnablePassthrough()}
)
chain = setup_and_retrieval | prompt | model | output_parserchain.invoke("这周五谁要去参加生日聚会?")# 输出
这周五要去参加生日聚会的是杰瑞。 

在这种情况下,组成的链是:

chain = setup_and_retrieval | prompt | model | output_parser

我们首先可以看到,上面的提示模板将上下文和问题作为要在提示中替换的值。在构建提示模板之前,我们希望检索相关文档,并将它们作为上下文的一部分。

首先,我们使用内存存储设置了检索器,它可以根据用户问题去检索文档。这也是一个可运行的组件,可以与其他组件链接在一起,但您也可以尝试单独运行它:

retriever.invoke("这周五谁要去参加生日聚会?")

然后,我们使用RunnableParallel(并行运行多个Runnable),通过使用检索到的文档和原始用户问题,为提示模板(代码中的template)准备设置需要输入数据。具体来说就是:使用检索器进行文档搜索,使用RunnablePassthrough传递用户的问题。

setup_and_retrieval = RunnableParallel({"context": retriever, "question": RunnablePassthrough()}
)

最终的完整执行链如下:

setup_and_retrieval = RunnableParallel({"context": retriever, "question": RunnablePassthrough()}
)
chain = setup_and_retrieval | prompt | model | output_parser

详细流程为:

  • 首先,创建一个包含两个条目的RunnableParallel对象。第一个条目context,包含检索器获取的文档结果。第二个条目question,包含用户的原始问题。为了传递这个问题,我们使用RunnablePassthrough来复制这个条目。

  • 其次,将第一步中的字典提供给提示组件。然后,它将用户输入(question)以及检索到的上下文文档(context)来构造提示并输出PromptValue。

  • 然后,模型组件(Model)接受生成的提示,并传递到OpenAI LLM模型中进行评估。模型生成的输出是一个ChatMessage对象。

  • 最后,output_parser组件接收ChatMessage,并将其转换为从invoke方法返回的Python字符串。

总结

以上就是 LCEL 的简介以及基本使用。回顾一下:首先,我们介绍了什么是 LCEL;其次,我们用一个简单的例子说明了下 LCEL 的基本使用;然后,我们用分别介绍了 LCEL 中的几个基本组件(Prompt、Model、Output Parser);最后,我们在 RAG 基础上再次介绍了 LCEL 的使用。

以上内容依据官方文档编写,官方地址:LCEL

大家要是随便关注下公众号,那就太好了。

Love & Peace~ 

这篇关于【可能是全网最丝滑的LangChain教程】七、LCEL表达式语言的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/903776

相关文章

Nexus安装和启动的实现教程

《Nexus安装和启动的实现教程》:本文主要介绍Nexus安装和启动的实现教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Nexus下载二、Nexus安装和启动三、关闭Nexus总结一、Nexus下载官方下载链接:DownloadWindows系统根

Go语言中泄漏缓冲区的问题解决

《Go语言中泄漏缓冲区的问题解决》缓冲区是一种常见的数据结构,常被用于在不同的并发单元之间传递数据,然而,若缓冲区使用不当,就可能引发泄漏缓冲区问题,本文就来介绍一下问题的解决,感兴趣的可以了解一下... 目录引言泄漏缓冲区的基本概念代码示例:泄漏缓冲区的产生项目场景:Web 服务器中的请求缓冲场景描述代码

Go语言如何判断两张图片的相似度

《Go语言如何判断两张图片的相似度》这篇文章主要为大家详细介绍了Go语言如何中实现判断两张图片的相似度的两种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 在介绍技术细节前,我们先来看看图片对比在哪些场景下可以用得到:图片去重:自动删除重复图片,为存储空间"瘦身"。想象你是一个

Go语言中Recover机制的使用

《Go语言中Recover机制的使用》Go语言的recover机制通过defer函数捕获panic,实现异常恢复与程序稳定性,具有一定的参考价值,感兴趣的可以了解一下... 目录引言Recover 的基本概念基本代码示例简单的 Recover 示例嵌套函数中的 Recover项目场景中的应用Web 服务器中

CnPlugin是PL/SQL Developer工具插件使用教程

《CnPlugin是PL/SQLDeveloper工具插件使用教程》:本文主要介绍CnPlugin是PL/SQLDeveloper工具插件使用教程,具有很好的参考价值,希望对大家有所帮助,如有错... 目录PL/SQL Developer工具插件使用安装拷贝文件配置总结PL/SQL Developer工具插

Java Lambda表达式的使用详解

《JavaLambda表达式的使用详解》:本文主要介绍JavaLambda表达式的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、前言二、Lambda表达式概述1. 什么是Lambda表达式?三、Lambda表达式的语法规则1. 无参数的Lambda表

Java中的登录技术保姆级详细教程

《Java中的登录技术保姆级详细教程》:本文主要介绍Java中登录技术保姆级详细教程的相关资料,在Java中我们可以使用各种技术和框架来实现这些功能,文中通过代码介绍的非常详细,需要的朋友可以参考... 目录1.登录思路2.登录标记1.会话技术2.会话跟踪1.Cookie技术2.Session技术3.令牌技

Python使用Code2flow将代码转化为流程图的操作教程

《Python使用Code2flow将代码转化为流程图的操作教程》Code2flow是一款开源工具,能够将代码自动转换为流程图,该工具对于代码审查、调试和理解大型代码库非常有用,在这篇博客中,我们将深... 目录引言1nVflRA、为什么选择 Code2flow?2、安装 Code2flow3、基本功能演示

Java Spring 中的监听器Listener详解与实战教程

《JavaSpring中的监听器Listener详解与实战教程》Spring提供了多种监听器机制,可以用于监听应用生命周期、会话生命周期和请求处理过程中的事件,:本文主要介绍JavaSprin... 目录一、监听器的作用1.1 应用生命周期管理1.2 会话管理1.3 请求处理监控二、创建监听器2.1 Ser

MySQL 安装配置超完整教程

《MySQL安装配置超完整教程》MySQL是一款广泛使用的开源关系型数据库管理系统(RDBMS),由瑞典MySQLAB公司开发,目前属于Oracle公司旗下产品,:本文主要介绍MySQL安装配置... 目录一、mysql 简介二、下载 MySQL三、安装 MySQL四、配置环境变量五、配置 MySQL5.1