首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

LangChain的LCEL和Runnable你搞懂了吗

编程知识
2024年08月01日 19:26

LangChain的LCEL估计行业内的朋友都听过,但是LCEL里的RunnablePassthrough、RunnableParallel、RunnableBranch、RunnableLambda又是什么意思?什么场景下用?

1、LCEL的定义和原理

LangChain的核心是Chain,即对多个组件的一系列调用。

LCEL是LangChain 定义的表达式语言,是一种更加高效简洁的调用一系列组件的方式。

LCEL使用方式就是:以一堆管道符("|")串联所有实现了Runnable接口的组件。

比如这样:

prompt_tpl = ChatPromptTemplate.from_messages(
    [
        ("system", "{parser_instructions}"),
        ("human", "列出{cityName}的{viewPointNum}个著名景点。"),
    ]
)

output_parser = CommaSeparatedListOutputParser()
parser_instructions = output_parser.get_format_instructions()

model = ChatOpenAI(model="gpt-3.5-turbo")

chain = prompt_tpl | model | output_parser

response = chain.invoke(
    {"cityName": "南京", "viewPointNum": 3, "parser_instructions": parser_instructions}
)

所以LangChain为了让组件能以LCEL的方式快速简洁的被调用,计划将所有组件都实现Runnable接口。比如我们常用的PromptTemplateLLMChainStructuredOutputParser 等等。

管道符("|")在Python里就类似or运算(或运算),比如A|B,就是A.or(B)

那对应到LangChain的Runnable接口里,这个or运算是怎么实现的呢?一起看到源码:

LangChain通过or将所有的Runnable串联起来,在通过invoke去一个个执行,上一个组件的输出,作为下一个组件的输入。

LangChain这风格怎么有点像神经网络呀,不得不说,这个世界到处都是相似的草台班子。嗨!

总结起来讲就是:LangChain的每个组件都实现了Runnable,通过LCEL方式,将多个组件串联到一起,最后一个个执行每个组件的invoke方法。上一个组件的输出是下一个组件的输入。

2、Runnable的含义和应用场景

2.1、RunnablePassthrough

定义

RunnablePassthrough 主要用在链中传递数据。RunnablePassthrough一般用在链的第一个位置,用于接收用户的输入。如果处在中间位置,则用于接收上一步的输出。

应用场景

比如,依旧使用上面的例子,接受用户输入的城市,如果输入城市是南京,则替换成北京,其余不变。代码如下。此处的{}RunnablePassthrough.assign()是同一个语义。

chain = (
    {
        "cityName": lambda x: '北京' if x["cityName"] == '南京' else x["cityName"],
        "viewPointNum": lambda x: x["viewPointNum"],
        "parser_instructions": lambda x: x["parser_instructions"],
    }
    | prompt_tpl
    | model
    | output_parser
)

2.2、RunnableParallel

定义

RunnableParallel看名字里的Parallel就猜到一二,用于并行执行多个组件。通过RunnableParallel,可以实现部分组件或所有组件并发执行的需求。

应用场景

比如,同时要执行两个任务,一个列出城市著名景点,一个列出城市著名书籍。

prompt_tpl_1 = ChatPromptTemplate.from_messages(
    [
        ("system", "{parser_instructions}"),
        ("human", "列出{cityName}的{viewPointNum}个著名景点。"),
    ]
)
prompt_tpl_2 = ChatPromptTemplate.from_messages(
    [
        ("system", "{parser_instructions}"),
        ("human", "列出关于{cityName}历史的{viewPointNum}个著名书籍。"),
    ]
)

output_parser = CommaSeparatedListOutputParser()
parser_instructions = output_parser.get_format_instructions()

model = ChatOpenAI(model="gpt-3.5-turbo")

chain_1 = prompt_tpl_1 | model | output_parser
chain_2 = prompt_tpl_2 | model | output_parser
chain_parallel = RunnableParallel(view_point=chain_1, book=chain_2)

response = chain_parallel.invoke(
    {"cityName": "南京", "viewPointNum": 3, "parser_instructions": parser_instructions}
)

2.3、RunnableBranch

定义

RunnableBranch主要用于多分支子链的场景,为链的调用提供了路由功能,这个有点类似于LangChain的路由链。我们可以创建多个子链,然后根据条件选择执行某一个子链。

应用场景

比如,有多个回答问题的链,先根据问题找到分类,然后在使用具体的链回答问题。

model = ChatOpenAI(model="gpt-3.5-turbo")
output_parser = StrOutputParser()

# 准备2条目的链:一条物理链,一条数学链
# 1. 物理链
physics_template = """
你是一位物理学家,擅长回答物理相关的问题,当你不知道问题的答案时,你就回答不知道。
具体问题如下:
{input}
"""
physics_chain = PromptTemplate.from_template(physics_template) | model | output_parser

# 2. 数学链
math_template = """
你是一个数学家,擅长回答数学相关的问题,当你不知道问题的答案时,你就回答不知道。
具体问题如下:
{input}
"""
math_chain = PromptTemplate.from_template(math_template) | model | output_parser

# 4. 其他链
other_template = """
你是一个AI助手,你会回答一下问题。
具体问题如下:
{input}
"""
other_chain = PromptTemplate.from_template(other_template) | model | output_parser


classify_prompt_template = """
请你对以下问题进行分类,将问题分类为"数学"、"物理"、"其它",不需要返回多个分类,返回一个即可。
具体问题如下:
{input}

分类结果:
"""
classify_chain = PromptTemplate.from_template(classify_prompt_template) | model | output_parser

answer_chain = RunnableBranch(
    (lambda x: "数学" in x["topic"], math_chain),
    (lambda x: "物理" in x["topic"], physics_chain),
    other_chain
)

final_chain =  {"topic": classify_chain, "input": itemgetter("input")} | RunnableLambda(print_info) | answer_chain
# final_chain.invoke({"input":"地球的半径是多少?"})
final_chain.invoke({"input":"对y=x求导的结果是多少?"})

2.4、RunnableLambda

定义

要说牛批还得是RunnableLambda,它可以将Python 函数转换为 Runnable对象。这种转换使得任何函数都可以被看作 LCEL 链的一部分,我们把自己需要的功能通过自定义函数 + RunnableLambda的方式包装一下,集成到 LCEL 链中,这样算是可以跟任何外部系统打通了。

应用场景

比如,在执行过程中,想在中间插入一段自定义功能(如 打印日志 等),可以通过自定义函数 + RunnableLambda的方式实现。

def print_info(info: str):
    print(f"info: {info}")
    return info

prompt_tpl_1 = ChatPromptTemplate.from_messages(
    [
        ("system", "{parser_instructions}"),
        ("human", "列出{cityName}的{viewPointNum}个著名景点。"),
    ]
)

output_parser = CommaSeparatedListOutputParser()
parser_instructions = output_parser.get_format_instructions()

model = ChatOpenAI(model="gpt-3.5-turbo")

chain_1 = prompt_tpl_1 | model | RunnableLambda(print_info) | output_parser


response = chain_1.invoke(
    {"cityName": "南京", "viewPointNum": 3, "parser_instructions": parser_instructions}
)

3、总结

本篇主要聊了LangChain的LCEL表达式,以及LangChain链的原理,以及常用的几个Runnable的定义和应用场景,希望对你有帮助。

近期我准备推出一个关于《助力开发者加持AI技术》的专栏,感兴趣的小伙伴可以加微信交流。

本篇完结!欢迎 关注、加微信(yclxiao)交流、二维码如下!!!

原文链接:https://mp.weixin.qq.com/s/l-EPH0hsmzQousPz8-MXcQ

From:https://www.cnblogs.com/mangod/p/18337425
本文地址: http://shuzixingkong.net/article/677
0评论
提交 加载更多评论
其他文章 Jenkins 配置即代码(Configuration as Code)详解
1、概述 在《Centos7下安装配置最新版本Jenkins(2.452.3)》这篇博文中讲解了如何安装Jenkins,虽然在安装Jenkins时安装了一些必备的推荐插件,但在企业环境中使用Jenkins之前,我们仍需完成一系列手动配置工作,如配置 System Configuration、Secu
Jenkins 配置即代码(Configuration as Code)详解 Jenkins 配置即代码(Configuration as Code)详解 Jenkins 配置即代码(Configuration as Code)详解
Vue Hook 封装通用型表格
一、创建通用型表格的需求 实现一个通用型表格组件,具备以下功能: 动态列配置。 分页功能。 排序功能。 可扩展的行操作功能。 二、设计通用型表格组件 首先,需要设计一个基础的表格组件,它接受列配置、数据和分页信息等参数。 1. 创建 useTable Hook 在 src/hooks 目录下创建 u
在Python中使用sqlalchemy来操作数据库的几个小总结
在探索使用 FastAPI, SQLAlchemy, Pydantic,Redis, JWT 构建的项目的时候,其中数据库访问采用SQLAlchemy,并采用异步方式。数据库操作和控制器操作,采用基类继承的方式减少重复代码,提高代码复用性。在这个过程中设计接口和测试的时候,对一些问题进行跟踪解决,并
ThinkPHP6支持金仓数据库(Kingbase)解决无法使用模型查询问题
参考了很多前人的文章,最后只支持Db::query原生查询,不支持thinkphp数据模型方法,这在实际项目中是很难接受的,特分享出解决方案。 先按照流程配置如下: 1.准备工作 首先确认PHP支持金仓数据库的扩展,可以去金仓官网下载,安装配置(详细配置略过……)。 使用 php -m 命令检查,显
ThinkPHP6支持金仓数据库(Kingbase)解决无法使用模型查询问题 ThinkPHP6支持金仓数据库(Kingbase)解决无法使用模型查询问题 ThinkPHP6支持金仓数据库(Kingbase)解决无法使用模型查询问题
运行期加载时共享库路径搜索优先级实验
目录前言实验环境目录说明单独测试不配置路径默认路径ld.so.cacheRUNPATHLD_LIBRARY_PATHRPATH优先级测试附录库文件源码主程序源码makefile脚本run_nonerun_defaultrun_ld_so_cacherun_runpathrun_ld_library_
架构演化学习思考(3)
架构演化学习思考(3) 接上一篇我们继续对命令模式进行学习。 在这节内容中,我们聊一下经典的命令模式,还记得上一篇文章开头我们实现的简单的命令模式吗?来看代码,非常简单易解。 public interface ICommand { void Execute(); } public class Pla
架构演化学习思考(3)
P5665 [CSP-S2019] 划分
讲解 P5665 [CSP-S2019] 划分。 由朴素 dp 入手,先用二分优化,然后用走指针优化,之后注意到单调性,将状态数压缩,然后使用单调队列优化转移。
如何通过PowerShell批量修改O365用户的office phone属性值
我的博客园:https://www.cnblogs.com/CQman/ 如何通过PowerShell批量修改O365用户的office phone属性值? 需求信息: 组织中的O365用户在创建时,已手动录入了办公电话(Office phone),现在需要在办公电话前面加上统一的数字,如“0571
如何通过PowerShell批量修改O365用户的office phone属性值 如何通过PowerShell批量修改O365用户的office phone属性值 如何通过PowerShell批量修改O365用户的office phone属性值