【可能是全网最丝滑的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

相关文章

Python虚拟环境终极(含PyCharm的使用教程)

《Python虚拟环境终极(含PyCharm的使用教程)》:本文主要介绍Python虚拟环境终极(含PyCharm的使用教程),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录一、为什么需要虚拟环境?二、虚拟环境创建方式对比三、命令行创建虚拟环境(venv)3.1 基础命令3

使用Node.js制作图片上传服务的详细教程

《使用Node.js制作图片上传服务的详细教程》在现代Web应用开发中,图片上传是一项常见且重要的功能,借助Node.js强大的生态系统,我们可以轻松搭建高效的图片上传服务,本文将深入探讨如何使用No... 目录准备工作搭建 Express 服务器配置 multer 进行图片上传处理图片上传请求完整代码示例

Go 语言中的select语句详解及工作原理

《Go语言中的select语句详解及工作原理》在Go语言中,select语句是用于处理多个通道(channel)操作的一种控制结构,它类似于switch语句,本文给大家介绍Go语言中的select语... 目录Go 语言中的 select 是做什么的基本功能语法工作原理示例示例 1:监听多个通道示例 2:带

python连接本地SQL server详细图文教程

《python连接本地SQLserver详细图文教程》在数据分析领域,经常需要从数据库中获取数据进行分析和处理,下面:本文主要介绍python连接本地SQLserver的相关资料,文中通过代码... 目录一.设置本地账号1.新建用户2.开启双重验证3,开启TCP/IP本地服务二js.python连接实例1.

C语言函数递归实际应用举例详解

《C语言函数递归实际应用举例详解》程序调用自身的编程技巧称为递归,递归做为一种算法在程序设计语言中广泛应用,:本文主要介绍C语言函数递归实际应用举例的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录前言一、递归的概念与思想二、递归的限制条件 三、递归的实际应用举例(一)求 n 的阶乘(二)顺序打印

Python 安装和配置flask, flask_cors的图文教程

《Python安装和配置flask,flask_cors的图文教程》:本文主要介绍Python安装和配置flask,flask_cors的图文教程,本文通过图文并茂的形式给大家介绍的非常详细,... 目录一.python安装:二,配置环境变量,三:检查Python安装和环境变量,四:安装flask和flas

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

Ubuntu中远程连接Mysql数据库的详细图文教程

《Ubuntu中远程连接Mysql数据库的详细图文教程》Ubuntu是一个以桌面应用为主的Linux发行版操作系统,这篇文章主要为大家详细介绍了Ubuntu中远程连接Mysql数据库的详细图文教程,有... 目录1、版本2、检查有没有mysql2.1 查询是否安装了Mysql包2.2 查看Mysql版本2.

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1