最优化大模型效果之 RAG(一):Naive RAG

news2024/11/15 22:22:47

Hi,我是 Hyde,今天的话题是 RAG(Retrieval-Augmented Generation),一种用于优化大模型效果的方法,翻译成中文就是检索增强生成

在之前的文章《最优化大模型效果的方向和思考》中,我们提到当前的大模型仍然存在诸多不足,例如受限于预训练数据,模型无法获知私有数据或训练节点以后的新知识,因此对于这类场景下的推理效果往往不佳,也存在着幻觉问题。面对此类问题,我们就可以选择使用 RAG 技术来弥补甚至解决。

RAG 的核心思想可以认为是将信息显式地提示给大模型以增强模型的生成能力和准确性,也就是说我们可以通过检索相关文档并将其作为上下文提供给模型,让模型从上下文中学习到模型不知道的知识,从而生成更准确的回答。

那么要构建一个 RAG 系统要做些什么呢?RAG 中有哪些组件?我们又可以从哪些方面来优化 RAG 的效果?这些就是我希望与大家探讨的内容,就让我们从最基本的 RAG 系统 —— Naive RAG 开始吧。

Naive RAG

Naive RAG 是最早也是最简单的 RAG 系统,只做了三件事情:

第一,Indexing:将知识存储起来。

第二,Retrieval:如何从大量的知识中找到我们需要的内容。

第三,Generation:如何结合用户的提问与检索到的知识,让模型生成有价值的答案。

下图是 Naive RAG 过程的一个示例:

Indexing 索引

建立 RAG 系统的第一步是建立索引,也就是将知识存储起来的过程。在这一步中,我们需要将文档划分为多个块(chunk),使用 embedding 模型计算每个段落的嵌入向量,并存储在向量数据库中。

这里有很多关键词,例如分块、embedding模型、向量数据库,这些都是索引过程中用到的一些关键的技术。

分块的原因在于一个文档中往往包含大量的信息,而生成回答时可能只需要用到其中的一部分内容。通过合理的分块,我们就可以将有用的片段返回,提高检索精度。同时,分块也能够确保输入提示词的长度符合上下文窗口限制。

向量数据库是一种特殊的数据存储方式。有别于关系型数据库和图数据库,向量数据库存储的往往是非结构化的数据(文本、图片等),并且使用向量间的相似程度来进行查询。

举一个直观的例子,我们往向量数据库中存入三个名词:“苹果”、“西瓜”和“汽车”,同时存储的还有这三个名词的嵌入向量。根据小学二年级就学过的线性代数的知识,向量可以用高维空间中的点坐标来表示。

例如,下图是一个三维的向量空间,因为“苹果”和“西瓜”同属于水果,因此相较于“汽车”,“苹果”和“西瓜”的坐标更加接近,嵌入向量也更相似。如果我们使用“水果”这个词进行查询,那么根据语义间的接近程度,我们查询到的就会是“苹果”或者“西瓜”,而不是“汽车”。

Embedding 模型就是一种专门为语句创建嵌入向量的模型,我们输入一个词语或段落,就会生成一个多维向量,例如 bge-m3 模型就会将词语转化为一个 1024 维的嵌入向量。

Retrieval 检索

明白什么是向量数据库以后,理解检索过程就非常了简单了。用户的提问经过 embedding 模型转换为嵌入向量后,再根据相似度从向量数据库中检索出最相关的 K 个文本块。这些文本块将作为参考信息合并到生成阶段的提示词中,来增强模型的生成。

Generation 生成

生成阶段的工作非常简单,通过将包含参考信息的上下文输入到模型,然后由模型基于提供的信息回答问题。如果有历史对话,也可以将其合并到提示词中,用于多轮对话。

生成阶段的提示词例如:

你是一个知识问答助手,你需要根据参考文档和历史对话,生成有用的回答。

## 历史对话
Question:xxxxx,
Answer:xxxxx,
Question:xxxxx,
Answer:xxxxx
...

## 参考内容
chunk1,
chunk2,
...

通过以上三件事情,大模型就具有了获取外部知识的能力,因此在包含私有数据和近期知识的场景下,模型的推理能力得到了飞跃性的提升。但 Naive RAG 毕竟还是非常 Naive 的,虽然简单明了,但也存在着许多问题。

  • 检索质量低: 使用长文本作为索引时,无法有效地突出主题,核心知识被大量无关信息淹没。而直接用用户的原始查询进行检索,无法准确抓住核心需求,导致用户查询和知识索引之间的匹配度不高,从而降低了检索的整体质量。
  • 生成质量差: 当未能检索到相关知识或检索到的知识质量不佳时,大模型在回答私域问题时容易产生幻觉,或给出空洞无用的回答。这使得知识库无法发挥其应有的价值。
  • 增强过程难: 将检索到的信息整合到不同任务中可能具有挑战性,有时会导致输出不连贯或不一致。此外,生成模型可能过度依赖增强信息,只是简单复述检索内容,而没有加入有洞察力或综合的信息。

这就需要我们针对 RAG 的各个环节进行优化,逐步克服 Naive RAG 的局限性,这就我们以后要讨论的主题——Advanced RAG。

构建 Naive RAG 系统

现在已经有很多成熟的框架可以快速搭建 Naive RAG 应用,例如 LangChain、LlamaIndex 等。甚至使用一些基于大模型的 bot 平台和工作流平台(例如Coze、Dify)也可以快速构建出基于 RAG 的应用。

我们这里以 LangChain 文档中的 Build a Retrieval Augmented Generation (RAG) App

为例,介绍如何使用 LangChain 构建一个简单的 Naive RAG 应用。

在开始前,我们需要一个 python 环境,并使用安装相应的 python 包,这里不再赘述。

案例简介

案例获取了 OpenAI 研究员 Lilian Weng 博客中的一篇文章,并建立了文章的向量数据库,用户可以通过询问大模型来获取文章内容的详细信息。

1. 文档加载

由于我们的目标文档是一篇网页博客,因此使用 WebBaseLoader 加载博客页面的 HTML,并使用

BeautifulSoup 解析博客的正文。

import bs4
from langchain_community.document_loaders import WebBaseLoader

# 使用 WebBaseLoader 加载网页的 HTML
# 使用 BeautifulSoup 将网页解析为文本
bs4_strainer = bs4.SoupStrainer(class_=("post-title", "post-header", "post-content"))
loader = WebBaseLoader(
    web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",),
    bs_kwargs={"parse_only": bs4_strainer},
)
# 加载网页的文本内容到 docs 变量中
docs = loader.load()

2. 文档分块

使用 RecursiveCharacterTextSplitter 进行文本分割,它将使用常见的分隔符(如换行符)递归地分割文档,直到每个块的大小合适。

在本例中,文章将被分割为最大 1000 个字符的文档块,块与块之间有 200 个字符的重叠。

from langchain_text_splitters import RecursiveCharacterTextSplitter

# 构建文本分割器,将文档分割为 1000 个字符的块,块与块之间有 200 个字符的重叠
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000, chunk_overlap=200, add_start_index=True
)
all_splits = text_splitter.split_documents(docs)

  1. 构建索引

索引这一步需要引入 embedding 模型和向量数据库,案例中使用了 OpenAI 的 embedding 模型及 Chroma 向量数据库.

from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings

vectorstore = Chroma.from_documents(documents=all_splits, embedding=OpenAIEmbeddings())

4. 构建检索器

案例中使用了 VectorStoreRetriever 检索器,即通过适量存储来检索文档。案例将检索模式设置为 similarity,k 值设为 6,这意味着检索器将返回向量存储中的相似度最高的前 6 个文本块。

# 构建检索器,并将检索模式设置为 similarity,每次返回前 6 个结果
retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 6})

5. 构建 RAG 链

为了实现生成这一步骤,我们需要构建 RAG 链。所谓的 RAG 链就是一个序贯执行的过程,将检索、构建提示词和生成答案等步骤通过串接起来,实现一个完成的 RAG 过程。

RAG 链条上有许多组件,有一些我们已经创建好了,例如检索器。而另一些则需要在接下来的过程中创建,比如大模型实例、提示词以及一些输出格式的解析器。

5.1 创建大模型实例

案例中使用了 OpenAI 的 “gpt-3.5-turbo-0125” 模型,因为 LangChain 做了许多集成方面的工作,我们可以非常方便的将其切换为国内的一些模型,例如阿里的 Qwen 系列模型、百度的文心系列模型等.

import getpass
import os

os.environ["OPENAI_API_KEY"] = getpass.getpass()

from langchain_openai import ChatOpenAI

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

5.2 构建提示词

LangChain 框架提供了大模型应用开发相关完整工具链条和活跃度社区生态,在此案例中调用了 LangChain 社区中的提示词 rlm/rag-prompt,并将检索器的检索结果拼接至提示词中。

from langchain import hub

prompt = hub.pull("rlm/rag-prompt")

example_messages = prompt.invoke(
    {"context": "filler context", "question": "filler question"}
).to_messages()

该提示词看起来是这个样子:

[HumanMessage(content=
"""
You are an assistant for question-answering tasks. 
Use the following pieces of retrieved context to answer the question. 
If you don't know the answer, just say that you don't know. 
Use three sentences maximum and keep the answer concise.
Question: {filler question}
Context: {filler context}
Answer:
"""
)]

5.3 将组件拼接成 RAG 链条

组件都准备妥当,就要可以开始拼装 RAG 链条的时候了,这里我们使用了 LangChain 中的 LECL 表达式来完成这项工作。

在大模型组件后,案例还添加了一个 StrOutputParser 解析器,用来将大模型的结果转化为 Json 格式。

from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

# 为文档块之间添加空行
def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)

# 通过 LECL 表达式组装 RAG 链条
rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser() # 输出解析器,负责将大模型的输出结果解析为 json 格式
)


6. 万事俱备,来试试效果吧

我们可以参照如下的方式调用 RAG 链,并获得回答的结果,一个简单的 Naive RAG 应用就搭建完成了。

# 调用 RAG 链条,生成回答结果
for chunk in rag_chain.stream("What is Task Decomposition?"):
    print(chunk, end="", flush=True)


7. 更进一步的工作

现在我们有一个非常简单和朴素的 Naive RAG APP,虽然可以运行,但是还存在许多问题。

第一,这个 APP 只能读取固定的一篇网页博客文章,如果我们想加载自定义的 PDF 文档就无法实现了。

第二,只支持单轮对话,大家可以尝试更改代码和提示词,来增加多轮对话的功能。

最后,这个 APP 没有前端界面,或许我们可以将它封装成 API ,然后做一些前端的工作来搭建页面。或者使用 Gridio、Streamlit、Chainlit 等工具来构建前端页面。

OK,非常感谢你的观看,我是 Hyde,我们下次见。

如何学习AI大模型?

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

在这里插入图片描述

👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。

在这里插入图片描述

1.AI大模型学习路线图
2.100套AI大模型商业化落地方案
3.100集大模型视频教程
4.200本大模型PDF书籍
5.LLM面试题合集
6.AI产品经理资源合集

👉获取方式:
😝有需要的小伙伴,可以保存图片到wx扫描二v码免费领取【保证100%免费】🆓

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1949823.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Google Test 学习笔记(简称GTest)

文章目录 一、介绍1.1 介绍1.2 教程 二、使用2.1 基本使用2.1.1 安装GTest (下载和编译)2.1.2 编写测试2.1.3 运行测试2.1.4 高级特性2.1.5 调试和分析 2.2 源码自带测试用例2.3 TEST 使用2.3.1 TestCase的介绍2.3.2 TEST宏demo1demo2 2.3.3 TEST_F宏2.3…

2-45 基于matlab的递归最小二乘法(RLS)对声音信号去噪

基于matlab的递归最小二乘法(RLS)对声音信号去噪,并对消噪前后的信号进行FFT分析,对比消噪前后的效果。可替换自己的声音信号进行分析。程序已调通,可直接运行。 2-45 递归最小二乘法(RLS) FFT分析 - 小红书…

聘请TPM管理咨询公司如何赢得员工认可?

聘请TPM管理咨询公司是一个重要的决策,它不仅能提升企业的运营效率和质量管理水平,而且需要得到员工的广泛认可才能确保改革的顺利实施。然而,赢得员工的认可并非易事,需要公司管理层和咨询公司共同努力,采取一系列措施…

崖山异构数据库迁移利器YMP初体验-Oracle迁移YashanDB

前言 首届YashanDB「迁移体验官」开放后,陆续收到「体验官」们的投稿,小崖在此把优秀的投稿文章分享给大家~今天分享的用户文章是《崖山异构数据库迁移利器YMP初体验-Oracle迁移YashanDB》(作者:小草),满满…

C++ | Leetcode C++题解之第275题H指数II

题目&#xff1a; 题解&#xff1a; class Solution { public:int hIndex(vector<int>& citations) {int n citations.size();int left 0, right n - 1;while (left < right) {int mid left (right - left) / 2;if (citations[mid] > n - mid) {right m…

C++ primer plus 第16章string 类和标准模板库, 函数符概念

C primer plus 第16章string 类和标准模板库, 函数符概念 C primer plus 第16章string 类和标准模板库, 函数符概念 文章目录 C primer plus 第16章string 类和标准模板库, 函数符概念16.5.1 函数符概念程序清单16.15 functor.cpp 16.5.1 函数符概念 正如 STL定义了容器和迭代…

【AOP实战】掌握Spring Boot AOP:重构代码,提升效率

文章目录 Spring Boot AOP - 面向切面编程AOP到底有什么不同AOP中的编程术语和常用注解定义切面环绕通知通知方法传参总结 Spring Boot AOP - 面向切面编程 AOP&#xff0c;即面向切面编程&#xff0c;其核心思想就是把业务分为核心业务和非核心业务两大部分。例如一个论坛系统…

ESP32和mDNS学习

目录 mDNS的作用mDNS涉及到的标准文件组播地址IPv4 多播地址IPv6 多播地址预先定义好的组播地址 mDNS调试工具例程mDNS如何开发和使用注册服务查询服务 mDNS的作用 mDNS 是一种组播 UDP 服务&#xff0c;用来提供本地网络服务和主机发现。 你要和设备通信&#xff0c;需要记住…

PHP基础语法-Part1

脚本格式 PHP脚本以<?php开头&#xff0c;以?>结尾&#xff1b; PHP语句以分号结尾&#xff08;;&#xff09; PHP是解释型语言&#xff1b; 输入和输出 获取用户的输入&#xff1a; $input readline("input:"); echo $input; echo "input:";…

EEtrade:区块链是什么

区块链&#xff0c;这个近年来频繁出现在我们视野中的术语&#xff0c;已经从一个技术小众圈的词汇&#xff0c;逐渐演变为全球关注的焦点。从比特币的诞生&#xff0c;到如今在金融、供应链、物联网等领域的广泛应用&#xff0c;区块链技术正在深刻地改变着我们的生活。那么&a…

将YOLOv8模型从PyTorch的.pt格式转换为TensorRT的.engine格式

TensorRT是由NVIDIA开发的一款高级软件开发套件(SDK)&#xff0c;专为高速深度学习推理而设计。它非常适合目标检测等实时应用。该工具包可针对NVIDIA GPU优化深度学习模型&#xff0c;从而实现更快、更高效的运行。TensorRT模型经过TensorRT优化&#xff0c;包括层融合(layer …

ARCGIS PRO DSK GraphicsLayer创建文本要素

一、判断GraphicsLayer层【地块注记】是否存在&#xff0c;如果不存在则新建、如果存在则删除所有要素 Dim GraphicsLayer pmap.GetLayersAsFlattenedList().OfType(Of ArcGIS.Desktop.Mapping.GraphicsLayer).FirstOrDefault() 获取当前map对象中的GetLayer图层 Await Queue…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十六章 设备驱动IO控制

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

云计算安全扩展要求解读

云计算简介&#xff1a; 一种全新网络服务方式&#xff0c;将传统的以桌面为核 心的任务处理转变为以网络为核心的任务处理&#xff0c; 利用互联网实现自己想要完成的一切处理任务&#xff0c; 使网络成为传递服务、计算力和信息的综合媒 介&#xff0c;真正实现按需计算、多…

揭秘Django与Neo4j:构建智能知识图谱的终极指南

揭秘Django与Neo4j:构建智能知识图谱的终极指南 前言 图是一种用于对象之间的成对关系进行建模的数学结构。 它由两个主要元素组成:节点和关系。 节点:节点可以看作是传统数据库中的记录。每个节点代表一个对象或实体,例如一个人或一个地方。节点按标签分类,这有助于根…

自研点直播转码核心

1. 背景 视频转码是将视频文件经过解封装、解码、滤镜处理、编码、封装从而转换为另一个视频文件的过程&#xff0c;B站每天都有大量的视频原片上传后经过转码系统转换为多个不同分辨率。转换后的视频在画质接近原片的前提下会拥有更低的码率&#xff0c;因此会提高网络传输时的…

3.3-LSTM的改进

文章目录 1改进点1.1多层化1.2 dropout1.2.1具体概念1.2.2应该插入到LSTM模型的哪里 1.3权重共享 2改进之后的LSTMLM的代码实现2.1初始化2.2前向计算2.3反向传播 3相应的学习代码的实现4总结 1改进点 1.1多层化 加深神经网络的层数往往能够学习更复杂的模式&#xff1b;因此这…

定制化爬虫管理:为企业量身打造的数据抓取方案

在数据驱动的时代&#xff0c;企业如何高效、安全地获取互联网上的宝贵信息&#xff1f;定制化爬虫管理服务应运而生&#xff0c;成为解锁专属数据宝藏的金钥匙。本文将深入探讨定制化爬虫管理如何为企业量身打造数据抓取方案&#xff0c;揭秘其在海量信息中精准捕获价值数据的…

C++初阶学习——探索STL奥秘——标准库中的string类

1. 为什么学习string类&#xff1f; 在我们学习C语言的时候&#xff0c;有一个点是非常难处理的&#xff0c;那就是字符串&#xff0c;在我们对字符串访问&#xff0c;增删查改时都是非常不便的&#xff0c;所以我们封装了一个string类主要来处理字符串有关的问题 2. 标准库中…

Premiere简约手绘风格箭头标题文字动画素材MOGRT

18个简约手绘风格箭头标题文字动画 | Premiere Pro mogrt 具有可定制的颜色和可编辑的文本。包括手绘箭头和文本动画&#xff0c;非常适合在项目中添加动态指针、标记和方向指示器。非常适合信息图表、社交媒体内容、下三分之一、徽章和简约界面。 项目特点&#xff1a; 独特…