当前位置: 首页 > news >正文

深入研究 RAG 流程中的关键组件

我们已经看到了整个RAG流程,并获得了第一手的实践经验,您可能会对RAG流程中一些组件的使用和目的存在很多疑惑,比如RunnablePassthrough。在本节中,我们将进一步了解这些关键组件。

RAG的核心模型思想是将一个复杂的任务分解为多个小而简单的任务组合,分而治之的策略在处理大型和复杂问题时非常有用。让我们先来看一个非常简单的RAG流水线:


from langchain_core.runnables import Runnable, RunnableSequence# 定义第一个任务:输出 "hello"
class TaskA(Runnable):def invoke(self, input, context=None):return input + " a"# 定义第二个任务:输出 "beautiful"
class TaskBeautiful(Runnable):def invoke(self, input, context=None):return input + " beautiful"class TaskDay(Runnable):def invoke(self, input, context = None):return input + " day!"
# 创建任务实例
task_a = TaskA()
task_beautiful = TaskBeautiful()
task_day = TaskDay()# 使用"|"操作符重载Runnable
rag_chain = task_a | task_beautiful | task_day
output = rag_chain.invoke("what")
print(output)

上面代码的输出是"what a beautiful day"。可以看到Runnable类重载了"|"操作符,我们可以将Runnable的实例组合在一起,并且最后一个Runnable实例的输出成为下一个Runnable实例的输入。同时,我们需要确保每个Runnable实例提供invoke接口,以便数据在连接的Runnable实例之间传递。

回到RAG流程中使用的组件,RunnablePassThrough实际上类似于以下代码:


class DoNothing(Runnable):def invoke(self, input, context=None):return input

让我们看一个例子:


passthrough = RunnablePassthrough()
input_data = {"msg": "this is a test"}
output_data = passthrough.invoke(input_data)
print(output_data)

运行上面的代码将输出: {‘msg’: ‘this is a test’}

RunnablePassthrough通常在管道中用作占位符或连接器,以连接两个功能管道,但它实际上可以对其输入数据进行一些简单的更改:


# 原始数据
input_data = {"message": "Hello, World!", "status": "initial"}passthrough = RunnablePassthrough.assign(result = lambda x: "processed")# 使用输入数据调用
output_data = passthrough.invoke(input_data)print(output_data)

这里我们需要确保输入数据是字典形式,且assign的参数为lambda表达式,运行上述代码得到以下结果:


{'message': 'Hello, World!', 'status': 'initial', 'result': 'processed'}

Runnable对象可以像下面这样将几个函数链接在一起:


def task1(input1):return f"task1:{input1}"def task2(input1):return f"task2:{input1}"def context(input):return f"context: {input}"rag_chain = RunnablePassthrough().assign(context=context) | task1 | task2
res = rag_chain.invoke({"invoke": "input for invoke"})
print(res)

invoke调用将数据发送到RunnablePassthrough对象,数据未更改地输出,然后数据将发送到task1,task1的输出将作为task2的输入。运行上述代码的结果为:


task2:task1:{'invoke': 'input for invoke', 'context': "context: {'invoke': 'input for invoke'}"}

另一个需要了解的组件是RunnableMap,它允许我们将多个Runnable对象组合在一起,可以并行或顺序运行。RunnableMap对象就像一个字典,字典中的键就像分支或步骤,可以在相同输入上独立运行。当我们需要多个步骤或函数独立处理相同输入时,这非常有用。让我们来看一个示例:


from langchain_core.runnables import Runnable, RunnableMap# 定义第一个任务:输出 "task1"
class Task1(Runnable):def invoke(self, input, context=None):return f"task1 for {input}"class Task2(Runnable):def invoke(self, input, context=None):return f"task2 for {input}"
pipeline = RunnableMap({"task1": Task1(),"task2": Task2(),
})input_data = "input data"
output_data = pipeline.invoke(input_data)
print(output_data)

传递给RunnableMap的映射中每个键的值都应实现invoke接口,pipeline.invoke调用将并行触发映射中每个值的invoke调用。上述代码的输出为:


{'task1': 'task1 for input data', 'task2': 'task2 for input data'}

最后一个我们需要了解的组件是RunnableParallel,它类似于RunnableMap,它们之间可能有一些细微差别,但在此不重要。我们可以将RunnableParallel视为RunnableMap,值得注意的一点是RunnableParallel的assign。让我们来看代码示例:


from langchain_core.runnables import Runnable, RunnableParallel, RunnableMap
import time
# 定义第一个任务:输出 "a"
class TaskA(Runnable):def invoke(self, input, context=None):time.sleep(1)return input + " a"# 定义第二个任务:输出 "beautiful"
class TaskBeautiful(Runnable):def invoke(self, input, context=None):time.sleep(2)return input + " beautiful"class TaskDay(Runnable):def invoke(self, input, context = None):time.sleep(3)return input + " day"
# 创建任务实例class TaskAssign(Runnable):def invoke(self, input, context = None):time.sleep(3)print(f"input: {input}")return {**input}start = time.time()
parallel_tasks = RunnableParallel({"taskA": TaskA(),"taskBeautiful": TaskBeautiful(),"TaskDay": TaskDay(),
}).assign(taskAssign=TaskAssign())
output = parallel_tasks.invoke("what")
print(f"output for rag run parallelly: {output}")
end = time.time()
print(f"time for rag run parallel: {end - start}" )

上面代码的输出为:


input: {'taskA': 'what a', 'taskBeautiful': 'what beautiful', 'TaskDay': 'what day'}
output for rag run parallelly: {'taskA': 'what a', 'taskBeautiful': 'what beautiful', 'TaskDay': 'what day', 'taskAssign': {'taskA': 'what a', 'taskBeautiful': 'what beautiful', 'TaskDay': 'what day'}}
time for rag run parallel: 6.011621713638306

从输出可以看出,在RunnableParallel中使用assign时,它会首先执行传递给RunnableParallel的映射中的任务,然后使用结果字典作为TaskAssign的参数,最终输出为RunnableParallel的字典和一个键为"TaskAssign"的条目,值为TaskAssign的返回结果。

最后,让我们重新构建上一节的RAG流水线,如下所示:


def task_from_docs(input):print(f"task from docs: {input}")print(f"input['context']: {input['context']}")return lambda x: format_docs(input["context"])rag_chain_from_docs = (RunnablePassthrough.assign(context=(task_from_docs))
)rag_chain_with_source = RunnableParallel({"context": retriver,"question": RunnablePassthrough(),
}).assign(answer=rag_chain_from_docs)
'''
rag_chain_with_source的invoke将并行触发retriver、RunnablePassthrough的invoke,
然后将得到的字典结果发送到rag_chain_from_docs流水线,再将该字典发送到task_from_docs函数,并将
输出作为字典中的"context"键的值
'''
res = rag_chain_with_source.invoke("How does RAG compare with fine-tuning")
print(f"context of res {res['context']}")
print(f"question of res {res['question']}")#res将用作调用rag_chain_from_docs的参数,并将其传递给task_from_docs调用,
#task_from_docs将提取字典中context的值并传递给format_docsrag_chain = rag_chain_with_source | prompt | llm | StrOutputParser()
response = rag_chain.invoke("How does RAG compare with fine-tuning")
print(f"final rag response: {response}")

上面代码运行后所得结果如下:

Retrieval-Augmented Generation (RAG) and fine-tuning are two different approaches to enhancing the capabilities of Large Language Models (LLMs). RAG combines the strengths of LLMs with internal data, allowing organizations to access and utilize their own data effectively. It enhances the accuracy and relevance of responses by fetching specific information from databases in real time, thus expanding the model's knowledge beyond its initial training data. RAG is particularly useful for organizations that need to leverage their proprietary data or the latest information that was not included in the model's training set.On the other hand, fine-tuning involves adjusting the weights and biases of a pre-trained model based on new training data. This process permanently alters the model's behavior and is suitable for teaching the model specialized tasks or adapting it to specific domains. However, fine-tuning can be complex and costly, especially as data sources evolve, and it may lead to issues like overfitting.In summary, RAG is more about integrating real-time data retrieval to enhance model responses, while fine-tuning is about permanently modifying the model based on new data. Each approach has its advantages and limitations, and the choice between them depends on the specific needs and resources of the organization.
``基于上述知识,我们可以轻松理解代码。rag_chain_with_source的invoke将生成一个带有context和question键的字典,context的值为retriver.invoke("How does RAG compare with fine-tuning")的结果,question的值为RunnablePassthrough().invoke("How does RAG compare with fine-tuning")的结果,即原始字符串本身。然后带有context和question的字典作为task_from_docs的输入。在task_from_docs中,取出context键的值传递给format_docs,task_from_docs的输出将发送给prompt函数。prompt的输出将生成一个带有问题和上下文的提示,提示发送到ChatGPT以获得最终返回结果。

相关文章:

深入研究 RAG 流程中的关键组件

我们已经看到了整个RAG流程,并获得了第一手的实践经验,您可能会对RAG流程中一些组件的使用和目的存在很多疑惑,比如RunnablePassthrough。在本节中,我们将进一步了解这些关键组件。 RAG的核心模型思想是将一个复杂的任务分解为多…...

新手如何学习python并快速成为高手

英雄Python入门到精通链接:https://pan.quark.cn/s/57162ec366a9 学习Python作为新手,有以下几个步骤: 学习基本概念和语法:首先,你需要学习Python的基本概念和语法。可以通过在线教程、书籍或者视频教程来学习。了解…...

Linux历史命令history增加执行时间显示

Centos系统默认历史命令显示如下 为了更好的溯源,获取执行命令的准确时间,需要增加一些配置 设置环境变量 vim /etc/profile 在最下面添加以下环境配置 export HISTTIMEFORMAT"%Y-%m-%d %H:%M:%S " 立即刷新该环境变量 source /etc/pro…...

从 vue 源码看问题 — 你知道 Hook Event 吗?

前言 在之前的几篇文章中,都有提到 vue 中调用生命周期钩子时是通过 callHook() 方法进行调用的,比如在初始化篇章中调用 beforeCreate 和 created 生命周期钩子方式如下: 那么接下来一起来了解下到底什么是 Hook Event ? Hook Event 是什…...

信息安全工程师(68)可信计算技术与应用

前言 可信计算技术是一种计算机安全体系结构,旨在提高计算机系统在面临各种攻击和威胁时的安全性和保密性。 一、可信计算技术的定义与原理 可信计算技术通过包括硬件加密、受限访问以及计算机系统本身的完整性验证等技术手段,确保计算机系统在各种攻击和…...

每日OJ题_牛客_相差不超过k的最多数_滑动窗口_C++_Java

目录 牛客_相差不超过k的最多数_滑动窗口 题目解析 C代码 Java代码 牛客_相差不超过k的最多数_滑动窗口 相差不超过k的最多数_牛客题霸_牛客网 (nowcoder.com) 描述: 给定一个数组,选择一些数,要求选择的数中任意两数差的绝对值不超过 …...

来咯来咯webSocket

在项目总目录下 设置socketServe文件夹 里面创建下面两个文件 使用的时候需要开启 node webSocket.cjs var { Server } require(ws); var moment require(moment);const wss new Server({port: 8888 });let id 0; let onlineMemberList []; const defaultUser user;wss…...

Android CALL关于电话音频和紧急电话设置和获取

获取音频服务,设置音源类型:电话类型和获取最大电话音量,响铃模式 private AudioManager mAudioManager; mAudioManager (AudioManager) getSystemService(AUDIO_SERVICE); mAudioManager.setStreamVolume(AudioManager.STREAM_VOIC…...

【春秋云镜】CVE-2023-23752

目录 CVE-2023-23752漏洞细节漏洞利用示例修复建议 春秋云镜:解法一:解法二: CVE-2023-23752 是一个影响 Joomla CMS 的未授权路径遍历漏洞。该漏洞出现在 Joomla 4.0.0 至 4.2.7 版本中,允许未经认证的远程攻击者通过特定 API 端…...

C#-__DynamicallyInvokable

[__DynamicallyInvokable] 属性是用于 .NET Framework 中的特性之一。这个特性通常用于标记在动态语言运行时中可以进行调用的方法或属性。 当一个方法或属性被标记为 [__DynamicallyInvokable],它表明这个成员在动态语言的环境中是可调用的。换句话说,…...

2024年最新10款顶级项目管理软件排行

项目管理软件在现代项目管理中扮演着至关重要的角色,它不仅仅是一个工具,更是一种高效、系统化的方法来管理和优化项目流程,帮助项目经理和团队成员快速了解项目状态,加速项目进展。 进度猫 进度猫是一款以甘特图为向导的轻量级…...

Python NLTK进阶:深入自然语言处理

目录 Python NLTK进阶:深入自然语言处理 1. 文本处理技术 1.1 命名实体识别(NER) 1.2 共指消解 2. 语义分析 2.1 语义角色标注(SRL) 2.2 词义消歧(Word Sense Disambiguation) 3. 机器学…...

【React 的理解】

谈一谈你对 React 的理解 对待这类概念题,讲究一个四字口诀“概用思优”,即“讲概念,说用途,理思路,优缺点,列一遍” 。 React 是一个网页 UI 框架,通过组件化的方式解决视图层开发复用的问题&a…...

软件压力测试有多重要?北京软件测试公司有哪些?

软件压力测试是一种基本的质量保证行为,它是每个重要软件测试工作的一部分。压力测试是给软件不断加压,强制其在极限的情况下运行,观察它可以运行到何种程度,从而发现性能缺陷。 在数字化时代,用户对软件性能的要求越…...

十四届蓝桥杯STEMA考试Python真题试卷第二套第五题

来源:十四届蓝桥杯STEMA考试Python真题试卷第二套编程第五题 本题属于迷宫类问题,适合用DFS算法解决,解析中给出了Python中 map() 和列表推导式的应用技巧。最后介绍了DFS算法的两种常见实现方式——递归实现、栈实现,应用场景——迷宫类问题、图的连通性、树的遍历、拓朴排…...

虚拟机 Ubuntu 扩容

文章目录 一、Vmware 重新分配 Ubuntu 空间二、Ubuntu 扩容分区 一、Vmware 重新分配 Ubuntu 空间 先打开 Vmware ,选择要重新分配空间的虚拟机 点击 编辑虚拟机设置 ,再点击 硬盘 ,再点击 扩展 选择预计扩展的空间,然后点击 扩展…...

内网远程连接解决方案【Frp】

1、从https://github.com/fatedier/frp/releases下载需要的版本,如 frp_0.61.0_linux_amd64.tar.gz 2、解压tar -xvf frp_0.61.0_linux_amd64.tar.gz 3、配置服务端【外网云主机】,修改ftps.toml文件: bindPort 7000 vhostHTTPPort8000…...

浙江欧瑞雅装饰材料有限公司:空间的艺术,定制的智慧!

浙江欧瑞雅装饰材料有限公司:空间的艺术,定制的智慧!在追求生活品质与空间利用并重的当下,浙江欧瑞雅装饰材料有限公司以其卓越的全屋定制服务,成为了众多家庭优化居住环境的理想选择。这家公司,凭借其深厚…...

jfrog artifactory oss社区版,不支持php composer私库

一、docker安装 安装环境:centos操作系统,root用户。 如果是mac或ubuntu等操作系统的话,会有许多安装的坑等着你。 一切都是徒劳,安装折腾那么久,最后还是不能使用。这就是写本文的初衷,切勿入坑就对了。 …...

华为OD机试真题-用户调度问题-2024年OD统一考试(E卷)

最新华为OD机试考点合集:华为OD机试2024年真题题库(E卷+D卷+C卷)_华为od机试题库-CSDN博客 每一题都含有详细的解题思路和代码注释,精编c++、JAVA、Python三种语言解法。帮助每一位考生轻松、高效刷题。订阅后永久可看,发现新题及时跟新。 题目描述 在通信系统中,一…...

人工智能通识课:深度学习框架 PyTorch

深度学习框架是连接算法理论与工程实践的重要工具。它让开发者不必从零实现张量运算、自动求导、参数更新、GPU 调度和模型保存等底层细节,而可以把主要精力放在数据处理、模型结构设计、训练策略和实验验证上。在众多深度学习框架中,PyTorch 凭借直观的…...

深度解析美国RTP全系列导热工程塑料,革新电子散热新选择

在工程塑料行业高速发展的今天,电子设备散热需求日益成为制约产品性能与可靠性的关键瓶颈。传统散热材料面临导热效率低、机械性能弱、加工适应性差等多重挑战,行业亟待寻找既能满足严苛散热要求,又具备优异综合性能的新一代解决方案。美国RT…...

Legacy iOS Kit深度拆解:揭秘旧款iOS设备重生的技术魔法

Legacy iOS Kit深度拆解:揭秘旧款iOS设备重生的技术魔法 【免费下载链接】Legacy-iOS-Kit An all-in-one tool to restore/downgrade, save SHSH blobs, jailbreak legacy iOS devices, and more 项目地址: https://gitcode.com/gh_mirrors/le/Legacy-iOS-Kit …...

信创中间件深度解析:东方通TongWeb vs 金蝶天燕 vs 宝兰德,企业级选型指南

📚 信创中间件 🔧 企业级部署 🚀 国产化替代 ⏱️ 阅读约15分钟开篇导读:你是否在信创改造中不知道用什么替代WebLogic或WebSphere?网上搜到的中间件资料要么只讲产品功能不讲迁移方案,要么直接给配置却不解…...

现在不掌握AI视频学习底层逻辑,3个月内将被淘汰:基于LinkedIn人才数据的技能贬值倒计时分析

更多请点击: https://intelliparadigm.com 第一章:AI视频生成工具学习曲线分析 AI视频生成工具的学习曲线呈现出显著的非线性特征——入门门槛看似平缓,但跨越“可用”到“可控”阶段往往遭遇陡峭的认知断崖。初学者常误以为上传文本提示即可…...

徒手撸极简前后端分离Demo!吃透原生JS动态渲染底层

之前一直觉得前后端分离是个特别高大上的工程化概念,总以为得学一堆框架、接口规范、部署流程才能上手。 直到昨天我没用Vue、没用React,纯靠原生JSHTMLCSSjson-server,手写了一套最朴素的前后端分离小案例,瞬间把底层逻辑彻底打通…...

机器学习海气耦合模型Ola:解耦训练与滞后集合预报实战

1. 项目概述:当机器学习遇见海气耦合在气候预测这个领域里摸爬滚打了十几年,我见过太多复杂的物理模型和让人头大的耦合方案。传统的海气耦合模型,比如那些基于物理方程组的数值模式,虽然机理清晰,但计算成本高得吓人&…...

交叉拟合与Neyman正交性:驯服机器学习因果推断中的偏差

1. 项目概述:当机器学习遇见因果推断,我们如何驯服“偏差”这头猛兽?在数据科学和经济学交叉的前沿地带,任何一个试图用机器学习模型做因果推断的研究者或工程师,都绕不开一个核心的噩梦:偏差(B…...

条件矩约束模型中的局部稳健推断与正交工具变量应用

1. 条件矩约束模型:从核心挑战到稳健推断的桥梁在实证研究的工具箱里,条件矩约束模型(Conditional Moment Restrictions, CMRs)无疑是一把瑞士军刀。无论是评估一项政策对经济产出的影响,还是分析用户特征如何影响其购…...

奇异线性系统与矩阵方程数值解法【附仿真】

✨ 长期致力于奇异线性方程组、鞍点问题、块二乘二线性方程组、矩阵方程、偏微分方程、最小范数最小二乘解、迭代方法、预处理、Schwarz-Christoffel映射、Sherman-Morrison-Woodbury公式研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕…...