RAG一文读懂|概念、应用场景、优势与项目代码示例
前言:在这个快速变化的数字时代,技术的每一次飞跃都为我们打开了新世界的大门。Geek Savvy,作为一个充满活力的年轻化社区,始终站在科技前沿,用极客的视角洞察行业趋势、技术创新和市场动态。我们不仅关注技术的发展,更致力于将这些前沿知识与实践相结合,为社区成员提供最前沿的科技资讯和深度解析。
今天,我们有幸与飞桨星河社区携手,共同探索人工智能的无限可能。飞桨星河社区,作为百度飞桨和文心大模型的生态家园,不仅为开发者和生态合作伙伴提供了强大的算力支持、丰富的模型数据、完善的工具链,还构建了一个充满活力的社区交流平台。在这里,每一位开发者都能找到志同道合的伙伴,共同推动技术的边界。
我们的文章将从Geek的独特视角出发,深入剖析RAG技术解析!
在2020年Facebook AI Research (FAIR) 团队发表一篇名为《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》的论文。这篇论文首次提出了RAG概念(它是目前大型语言模型领域的一个重要概念),并对该概念进行详细介绍和解释。
RAG模型结合了语言模型和信息检索技术。具体来说,当模型需要生成文本或者回答问题时,它首先从一个庞大的文档集合中检索出相关的信息。然后,它利用这些检索到的信息来指导文本的生成,从而提高预测的质量和准确性。
其中“检索”、“利用”、“生成”是RAG的关键部分。那我们怎么才能直观理解这三个部分呢?
这里我们举一个简单可以更好帮助你理解的例子:
比如你正在写一篇关于狗狗的文章,但你对狗狗的知识有限。这时候,你很可能会这么做。
检索(Retrieval):首先,你打开你的电脑,输入了关键词“狗狗”的搜索请求,从互联网上检索了大量的关于狗狗的文章、博客和信息。
利用(Utilization):接下来,你会分析这些搜索结果,并提取其中的重要信息,例如:狗狗的种类、行为习惯、饲养方式等等。你将这些信息整理成一个知识库,就像是一个巨大的百科全书,里面包含了关于狗狗的各种知识点。
生成(Generation):现在,你需要写你的文章。比如文章前你可能会提出一个问题:“狗狗的寿命是多久?”,你会使用你之前检索和整理的信息来回答你的问题或者生成文章的段落。你不仅仅是简单地复制粘贴,而是根据上下文和语法规则来生成自然流畅的文本。
其实上面“你”的这个工作流就是“RAG”的工作流,你可以把它想象成“你”就是那个RAG模型,即是“检索”、“利用”、“生成”。
现在我们了解了RAG的基本工作流之后,那RAG主要是用在哪里呢?它们无非就是在这些场景进行“检索”,”利用“和”生成“,那具体都是在做什么呢?
RAG技术可以在以下一些常见的自然语言处理任务中发挥作用:
问答系统(QA Systems):RAG可以用于构建强大的问答系统,能够回答各种用户提出的问题。它通过检索大规模文档集合来提供有深度的答案,无需针对每个问题进行特定训练。
文档生成和自动摘要(Document Generation and Automatic Summarization):RAG可用于自动生成文章段落、文档或自动摘要,基于检索的知识来填充文本,使得生成的内容更具信息价值。
智能助手和虚拟代理(Intelligent Assistants and Virtual Agents):RAG可以用于构建智能助手或虚拟代理,结合聊天记录上下文来回答用户的问题、提供信息和执行任务,无需特定任务微调。
信息检索(Information Retrieval):RAG可以改进信息检索系统,使其更准确和有深度。用户可以提出更具体的查询,而不仅仅是关键词匹配。
知识图谱填充(Knowledge Graph Population):RAG可以用于填充知识图谱中的实体关系,通过检索文档来识别和添加新的知识点。
以上是RAG一些常见的应用场景。现在我们知道RAG是做什么的了,那为什么在这些场景要用RAG而不是用微调或者其他方法来实现?
那么我们接下来聊一下RAG具体有哪些优势?
外部知识的利用:RAG模型可以有效地利用外部知识库,这提高了生成文本的可靠性。它可以引用大量的信息,以提供更深入、准确和有价值的答案。
数据更新及时性:RAG模型具备检索库的更新机制,可以实现即时的知识更新,无需重新训练模型。这意味着它可以提供与最新信息相关的回答,非常适合需要及时性的应用。
回复具有解释性:由于RAG模型的答案直接来自检索库,因此它的回复具有很强的可解释性,减少大模型的幻觉。用户可以核实答案的准确性,从信息来源中获取支持。
高度定制能力:RAG模型可以根据特定领域的知识库和prompt进行定制,使其快速具备该领域的能力。这意味着它适用于广泛的领域和应用,比如AI女友。
安全和隐私管理:RAG模型可以通过限制知识库的权限来实现安全控制,确保敏感信息不被泄露。这增强了数据安全性。
减少训练成本:RAG模型在数据上具有很强的可拓展性,可以将大量数据直接更新到知识库,以实现模型的知识更新。这一过程不需要重新训练模型,更经济实惠。
以下我们通过RAG与微调的比较,以帮助大家对自己具体的业务选择合适的策略:
任务特定 vs 通用性:微调通常是为特定任务进行优化,而RAG是通用的,可以用于多种任务。微调对于特定任务可能效果好,但在通用性问题上可能不够灵活。
知识引用 vs 学习:RAG模型通过引用知识库来生成答案,而微调是通过学习任务特定的数据。RAG的答案直接来自外部知识,更容易核实。
即时性 vs 训练:RAG模型可以实现即时的知识更新,无需重新训练,这在需要及时性的应用中具有优势。微调通常需要重新训练模型,时间成本较高。
可解释性 vs 难以解释性:RAG的答案可解释性强,因为它们来自知识库。微调模型的内部学习可能难以解释。
定制 vs 通用性:RAG可以定制为特定领域,而微调需要为每个任务特定的微调,需要更多任务特定的数据。
结合上面的比较,我们可以清楚的看到RAG的优势在于通用性、知识引用、即时性和可解释性,而微调在特定任务上可能更适用,但需要更多的任务特定数据和训练。选择使用哪种方法应根据具体的应用需求和任务来决定。
那具体RAG怎么做呢?我们用一个简单的代码示例来举例:基于ERNIE SDK和向量库的示例
## 文心ErnieBot SDK+LangChain 搭建个人知识库---以傅盛AI大课为例
一、首先安装erniebot
!pip install --upgrade erniebot## 测试embeddingimport ernieboterniebot.api_type = "aistudio"erniebot.access_token = "<你的token>"response = erniebot.Embedding.create(model="ernie-text-embedding",input=["我是百度公司开发的人工智能语言模型,我的中文名是文心一言,英文名是ERNIE-Bot,可以协助您完成范围广泛的任务并提供有关各种主题的信息,比如回答问题,提供定义和解释及建议。如果您有任何问题,请随时向我提问。" ])print(response.get_result())##[[0.12396156042814255, 0.06514577567577362, 0.05345790088176727, 0.05495057627558708, 0.01716597005724907, -0.08169233053922653, -0.02372867614030838, -0.050388969480991364, -0.04034141078591347, 0.05868257209658623, 0.016312476247549057, -0.058401163667440414, -0.042211249470710754, 0.045841023325920105, -0.14607082307338715, -0.04978140816092491, -0.03679147735238075, 0.012605858966708183, -0.014128394424915314, 0.0006767146405763924, 0.013087217696011066, -0.0018176172161474824, -0.04658341035246849, -0.06002342328429222, 0.023892290890216827, -0.03365868330001831, 0.08845338970422745, 0.07149643450975418, -0.01051111426204443, -0.01503442507237196, -0.01923832669854164, -0.09277807176113129, -0.008811017498373985, -0.025730334222316742, -0.011318848468363285, 0.026004960760474205, 0.013193491846323013, 0.05592338368296623, -0.07710710167884827, 0.01077062077820301, -0.05204102396965027, -0.011776845902204514, 0.04679800942540169, -0.006324325688183308, 0.07979235798120499, -0.05994
二、我们引入Chromadb 向量数据库
!pip install chromadb
三、自定义嵌入函数(网上没找到星河SDK结合langchain chromadb的相关文档,这里是自创的一个调用函数,大家可以优化一下)
import osimport erniebotfrom typing import Dict, List, Optionalimport chromadbfrom chromadb.api.types import Documents, EmbeddingFunction, Embeddingsdef embed_query(content):response = erniebot.Embedding.create(model="ernie-text-embedding",input=[content])result = response.get_result()print(result)return resultclass ErnieEmbeddingFunction(EmbeddingFunction):def __call__(self, input: Documents) -> Embeddings:embeddings = []for text in input:response = embed_query(text)try:embedding = response[0]embeddings.append(embedding)except (IndexError, TypeError, KeyError) as e:print(f"Error processing text: {text}, Error: {e}")return embeddingschroma_client = chromadb.Client()# chroma_client = chromadb.PersistentClient(path="chromac") #数据保存硬盘位置 可选collection = chroma_client.create_collection(name="demo", embedding_function=ErnieEmbeddingFunction())print(collection)
四、导入数据集
我们选用最近的傅盛AI大课作为知识库。
加入社群领取!!!(备注:傅盛AI大课)
五、文档切割
from langchain.text_splitter import CharacterTextSplitterfrom langchain.vectorstores import Chromafrom langchain.document_loaders import TextLoaderloader = TextLoader('./傅盛AI大课逐字稿.txt',encoding='utf-8')documents = loader.load()text_splitter = CharacterTextSplitter(chunk_size=600, chunk_overlap=20)docs = text_splitter.split_documents(documents)docs
六、embedding 嵌入
import uuiddocs_list=[]metadatas=[]ids=[]for item in docs:docs_list.append(item.page_content)metadatas.append({"source": "傅盛AI大课逐字稿"})ids.append(str(uuid.uuid4()))collection.add(documents=docs_list,metadatas=metadatas,ids=ids)
七、检索
query = "周鸿祎说见VC有两种错误的思维方式,分别是什么"results = collection.query(query_texts=[query],n_results=2)content=results['documents'][0][ ]prompt=f"""用户问题:{query}<context>{content}</context>根据<context>里的知识点回答用户问题"""response = erniebot.ChatCompletion.create(model="ernie-bot-4", messages=[{"role": "user", "content": prompt}])print(response.get_result())#周鸿祎说见VC有两种错误的思维方式,分别是:##1. 用过去的方式套今天的人工智能,比如比喻成OS。一旦比喻成操作系统,就得出结论全世界两套到三套,你觉得必然会被垄断、没有机会了,这种是典型的刻舟求剑。#2. 人容易对已经成功的事委曲求全,对于创新的新生代创业者容易求全责备。特别是有些做VC容易犯这个错误,比如OpenAI做成了,已经证明了,是个傻子都能看到OpenAI做的很成功,我们容易对它顶礼膜拜,恨不得跪下。对创业者很多还不成形的想法,因为八字没有一撇,光看到了你的很多缺点,这种价值观是不对的,容易Miss掉一些有潜力的项目。
八、封装函数
def main(query):results = collection.query(query_texts=[query],n_results=2)content=results['documents'][0]prompt=f"""用户问题:{query}<context>{content}</context>根据<context>里的知识点回答用户问题"""response = erniebot.ChatCompletion.create(model="ernie-bot-4", messages=[{"role": "user", "content": prompt}])return response.get_result()query=input("请输入您要查询的问题:")print(main(query))
请输入您要查询的问题:周鸿祎说见VC有两种错误的思维方式,分别是什么
周鸿祎说见VC有两种错误的思维方式,分别是:用过去的方式套今天的人工智能,比如比喻成OS。一旦比喻成操作系统,就得出结论全世界两套到三套,你觉得必然会被垄断、没有机会了,这种是典型的刻舟求剑。对于创新的新生代创业者容易求全责备。特别是有些做VC容易犯这个错误,比如OpenAI做成了,已经证明了,是个傻子都能看到OpenAI做的很成功,我们容易对它顶礼膜拜,恨不得跪下。对创业者很多还不成形的想法,因为八字没有一撇,光看到了你的很多缺点,我觉得这种价值观是不对的,容易Miss掉一些有潜力的项目。
代码地址:
https://aistudio.baidu.com/projectdetail/7431640
显然RAG也不仅仅满足于此,目前也诞生出了各种RAG的高阶用法,这里,我们可以使用互联网黑话中的术语“对齐颗粒度”来帮助理解。
在这个上下文中,“颗粒度”是指信息的精细程度,而“对齐”是指确保模型的理解和回应与信息的精细程度相匹配。
颗粒度就像信息的细节级别。好像我们上文提到的,假如我们在谈论狗狗的知识,颗粒度可以是关于不同狗狗品种的细节信息,也可以是有关狗的整体性质的一般信息。不同任务可能需要不同粒度的信息【这就是颗粒度】。这时候我们需要确保RAG模型的回答与问题或任务的精细程度相匹配。这意味着模型应该理解问题的颗粒度,并回应具有相同或类似颗粒度的答案【这就是对齐】。
通过不断优化RAG,使它具有更强大的颗粒度对齐能力。这意味着它可以更好地理解问题,找到与问题颗粒度匹配的信息,并生成相应颗粒度的答案。比如“讲一下金毛犬的特点”,高级RAG模型可以理解这是一个关于特定狗品种的问题,并会从知识库中提取金毛犬的细节信息,如体格、性格、历史等,以对齐问题的颗粒度,提供详细的回答。
在优化RAG的过程,又产生一系列相关的方法,如 :
索引优化:
提升数据粒度:对索引内容进行更精细的处理,如标准化或剔除无关字符。
优化索引结构:调整数据块大小、改变路径、加入图结构等。
添加元数据信息:为文档或文档块增加元数据,如修改时间、用途等。
对齐优化:使检索内容与用户提问尽可能对齐,提高相似度。
混合检索:结合多种表征方式的向量检索,以及字面、数字等检索。
向量表征模型优化:
微调:针对特定问题、领域或检索对进行微调。
动态嵌入:使用动态嵌入,使词汇的表征依赖于上下文。
检索后处理:
重排序:使用多样性排序器或在上下文窗口中交替放置最佳文档。
Prompt压缩:在生成回复之前压缩prompt,减少噪音信息。
递归检索和搜索引擎优化:
递归检索:分拆索引文段和返回文段,计算相似度时使用小片段,但返回大片段。
子查询:使用类似“检索语法树”的概念,如“should”、“must”、“filter”等检索策略。
RAG评估:
使用独立评估和端到端评估方法。
关注关键指标和能力,如答案准确性、相关性、上下文相关性、抗噪声能力、拒绝无效回答能力、信息综合能力和反事实鲁棒性能力。
除了以上5种方法外还有其他很多高级的RAG用法,大家可以对感兴趣的部分自行查阅相关论文进行学习了解。
了解更多请关注公众号👇🏻👇🏻👇🏻
未来已来,将至已至!