Task2 的任务是组队 + 寻找灵感,这里不作阐述;Task3 的任务是实现 RAG 应用,阅读文档并观看卢哥的直播后,结合个人经验做个分享。
运行大语言模型,对 LLM 使用的加深,我们发现,在使用过程中,大模型会有很多幻觉出现。为了解决幻觉,科研人员提出了各种各样的方案,努力提高长上下文下的召回精度,但就成本与效果而言,在目前都不如简单粗暴的检索增强生成(RAG)。
幻觉
什么是幻觉?简而言之就是“胡说八道”,指模型生成的内容与现实世界事实或用户输入不一致的现象。研究人员将大模型的幻觉分为事实性幻觉(Factuality Hallucination)和忠实性幻觉(Faithfulness Hallucination)。
事实性幻觉,是指模型生成的内容与可验证的现实世界事实不一致。
比如问模型“第一个在月球上行走的人是谁?”,模型回复“Charles Lindbergh在1951年月球先驱任务中第一个登上月球”。实际上,第一个登上月球的人是Neil Armstrong。事实性幻觉又可以分为事实不一致(与现实世界信息相矛盾)和事实捏造(压根没有,无法根据现实信息验证)。
忠实性幻觉,则是指模型生成的内容与用户的指令或上下文不一致。
比如让模型总结今年10月的新闻,结果模型却在说2006年10月的事。忠实性幻觉也可以细分,分为指令不一致(输出偏离用户指令)、上下文不一致(输出与上下文信息不符)、逻辑不一致三类(推理步骤以及与最终答案之间的不一致)。
那么致使大模型产生幻觉的原因都有哪些?
首先“病从口入”,大模型的粮食 数据,是致使它产生幻觉的一大原因。这其中就包括数据缺陷、数据中捕获的事实知识的利用率较低。具体来说,数据缺陷分为错误信息和偏见(重复偏见、社会偏见),此外大模型也有知识边界,所以存在领域知识缺陷和过时的事实知识。
即便大模型吃掉了大量数据,也会在利用时出现问题。大模型可能会过度依赖训练数据中的一些模式,如位置接近性、共现统计数据和相关文档计数,从而导致幻觉。比如说,如果训练数据中频繁共现“加拿大”和“多伦多”,那么大模型可能会错误地将多伦多识别为加拿大的首都。
此外,大模型还可能会出现长尾知识回忆不足、难以应对复杂推理的情况。
大模型产生幻觉的另外两个关键因素是 预训练偏差 与 推理,详细请看 量子位-大模型幻觉
Embedding
在学习 RAG 之前,我们还需要理解什么是 Embedding。
在机器学习和自然语言处理(NLP)中,Embedding 是一种将非结构化数据,如单词、句子或者整个文档,转化为实数向量的技术。这些实数向量可以被计算机更好地理解和处理.我们可以把一个词 (token) 表示成有限维度空间中的表示。
比如,我们可以把苹果映射成 (5,5),把梨子映射成 (4,5),把芯片映射到 (1,2)。放到坐标系中,坐标的相近表示梨子和苹果的语义有很大的重复成分,而芯片与苹果的距离,自然比梨子与苹果的距离要远。此时这些数字坐标映射就可以理解为简单的 Embedding。
我们可以通过 Embedding 模型,将一个词很方便 映射 到对应的实数多维表示空间,这个映射关系是提前训练得到的,越准确的 Embedding 模型可以让我们越好的区别不同语义特征的差异性,这也就对 RAG 的准确检索带来了更大的好处。
在搭建 RAG 系统时,我们往往可以通过使用 Embedding 模型来构建词向量 —— 我们可以选择使用各个公司的在线 Embedding API,也可以使用本地嵌入模型将数据构建为词向量;由于我们通常是对文档操作,这里的向量化是对文档块 (chunk) 进行;我们可以将一个文档分成多个段落,每个段落分别进行 Embedding 操作,得到结果后存储到对应的数据库中保存,以便后续的检索。
对于数据库,在 RAG 中,通常使用的也就是 Embedding 相关的数据库 —— 向量数据库。向量数据库是一种基于向量空间模型的数据库系统,它能够利用向量运算进行数据检索的高效处理,常见的向量数据库包括 Faiss、Annoy、Milvus 等等,在 baseline2 中我们使用的就是 Chroma。这些向量数据库通常与 LLM 结合使用,以提高数据检索和处理的效率。
RAG
那什么是 Retrieval-Augmented Generation(RAG)检索增强生成应用? 检索增强生成,顾名思义,就是利用检索来增强大模型的生成结果。
具体而言, RAG 主要是在这样的场景下被需要的:想象一下,当你有一个冷门的知识需要理解,但大模型没有基于这个知识训练过,或者说你想把这个知识全部输入大模型进行问答,但是大模型的上下文没有那么长;那么,我们需要一个好的方法让大模型可以基于我们新的知识进行对话,这就是 RAG的意义所在。
检索增强生成 (RAG) 通过向量数据库检索的方式,获取我们问题预期想要回答涉及的知识,然后结合这个知识让大模型基于知识生成最后的问答结果,满足了我们对提问的真实性需求。
既然 RAG 这么高效实用,如何构建一个 RAG 系统?具体而言,RAG 有很多的实现方式,在这里我们使用最简单的实现方法,遵循最传统的规则,包括索引 创建(Indexing)、检索(Retrieval)和 生成(Generation),总的来说包括以下三个关键步骤:
-
将语料库划分成一个个分散的块(chunk),然后使用 embedding 模型构建向量索引,并存储到向量数据库
-
RAG 根据 query (当前提问) 与索引块(Indexed Chunk)的向量相似度识别并对块进行检索
-
模型根据检索块(Retrieved Chunk)中获取的上下文信息生成答案
这个流程可以用下图展示:
由图可知,我们通过基于提问检索出的知识块,和提问一起拼接输入到大模型问答后,让大模型的回答更加接近我们的提问预期,可靠性大幅度增加。但这也并非 RAG 技术的终点,我们可以通过更多额外方式增强 RAG 的效果。
检索前 可以将同类话题合并,减少歧义;增强片段独立性等
检索后 重新排布,提高检索块与提问的关联度;语义搜索,相似性搜索等
LlamaIndex
为了搭建初级的 RAG 系统,可以使用 LlamaIndex、LangChain、Haystack 等框架。这里我们使用 LlamaIndex。
LlamaIndex 的官网:LlamaIndex - LlamaIndex。将数据喂给 LlamaIndex 后,它会建立很多的抽象数据结构,这里介绍几个关键的。
Indexing 是一种数据结构,它允许我们快速检索我们所查询的相关上下文,你可以把它简单理解为一种对 "node" 的抽象组织方式,在 llamaindex 中存在多种不同的组织 node 的方式。 Indexing 将数据存储在Node对象(代表原始文档的 chunk )中 ,并公开支持额外配置和自动化的Retriever接口。当我们看到 Node 对象的时候,可以把他简单理解为段落 chunk。对于LlamaIndex,它是检索增强生成(RAG)用例的核心基础。
在高层次上,Indexing 是从 Documents 构建的 node 组成的。它们用于构建 Query Engine(帮助提问的)等,可以通过您的数据进行问答和聊天。
Vector Stores 负责收纳 chunks 的嵌入向量。默认情况下,LlamaIndex 使用一个简单的内存向量存储,非常适合快速实验。它们可以通过调用 vector_store.persist()
进行持久化。官网:Vector Stores - LlamaIndex
在 baseline2 中我们使用的就是 Chroma,也可以更换不同的向量数据库进行实验。插件式方式扩展安装
这里的 embedding 模型为 bge(https://github.com/huggingface/text-embeddings-inference),可以更换 embedding 模型为 Jina(https://jina.ai/embeddings/) ,bce(https://github.com/netease-youdao/BCEmbedding) 等。
当然也可以更换插件,这里使用的是 IPEX-LLM on Intel CPU - LlamaIndex。
构建 RAG 体系的关键代码:
# 导入需要的模块和类
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.ollama import Ollama
# 1. 使用 SimpleDirectoryReader 加载数据
# SimpleDirectoryReader 是一个简单的目录读取器,能从指定目录中读取所有文件的数据
documents = SimpleDirectoryReader("data").load_data()
# 2. 设置嵌入模型为 bge-base
# HuggingFaceEmbedding 是一个嵌入模型类,用于将文本转换为向量表示
# 这里我们使用的是 "BAAI/bge-base-en-v1.5" 模型
Settings.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-base-en-v1.5")
# 3. 使用 Ollama 快速接入大语言模型
# Ollama 是一个模型的快速调用框架
# 这里我们指定使用 "llama3" 模型,并设置请求超时时间为 360 秒
Settings.llm = Ollama(model="llama3", request_timeout=360.0)
# 4. 创建一个向量存储索引
# VectorStoreIndex 是一个用于存储和查询向量的索引类
# from_documents 方法是从文档数据创建索引
index = VectorStoreIndex.from_documents(documents)
# 5. 将索引转换为查询引擎
# as_query_engine 方法将现有的向量存储索引转换为一个查询引擎
# 查询引擎是一个通用接口,允许您对数据提出问题。
query_engine = index.as_query_engine()
# 6. 使用查询引擎进行查询
# query 方法接受一个查询字符串,并返回一个响应对象
# 这里我们查询 "作者小时候做了什么?"
response = query_engine.query("What did the author do growing up?")
# 7. 打印查询结果
# 打印从查询引擎返回的响应
print(response)
思考
上面的介绍的都是文本,能不能检索更多不同的模态?比如,我们能够实现一个简单的图文对话工具,不需要视觉大模型,而利用一个 图文字典 向量数据库,通过匹配输入图找到对应的向量数据库最接近的图像 embedding,然后返回该图对应的真实文本解释给大语言模型;此时我们实现的就是图像多模态的 RAG 系统。图像、音频、视频、蛋白质......任何可编码对象都是我们能够检索的,甚至跨不同模态进行检索。
下图就是一种图片与文字的不同的转化,CLIP (Contrastive Language-Image Pretraining)
直观的分离,Visualizing MNIST: An Exploration of Dimensionality Reduction - colah's blog:
如何提高检索精度?
-
从知识库的组织让检索更精确
-
从大模型的能力提高让检索更精确
-
通过多模型检查结果实现自动化测试精度
-
通过更多传统语义匹配、混淆度检测方式让回答结果更加固定
-
通过调节参数(温度值等)让回复更可控
分享
提高 RAG 效果,尽量让语义独立。
微调可以增强理解,但是次数需要限制,过多会增加幻觉。下图就是训练次数与部署效果的对照:
指代消解(Coreference Resolution)是自然语言处理中的一项任务,旨在确定文本中不同表达是否指代同一实体。换句话说,它涉及找到并连接文本中指代相同事物的代词和名词短语。
举个例子,有一个句子 "小明去了商店。他买了一些苹果。"。"他" 和 "小明" 指代同一个人。指代消解的任务就是识别出 "他" 这个代词指代的是 "小明"。步骤包含:文本预处理、候选指代生成、特征提取、匹配、后处理。
分享网站:
重排rerank: LLM之RAG实战(十七)| 高级RAG:通过使用LlamaIndex重新排序来提高检索效率
网上的简单开发:纯手工搭建 RAG 框架——Tiny RAG(tiny-universe/content/TinyRAG)
大模型幻觉笔记: Extrinsic Hallucinations in LLMs by lilian | 散步的小屋
领域大佬:Lil'Log (lilianweng.github.io)
大佬“散步的小屋”网站分享:https://www.aispacewalk.cn/docs/other/awesomeweb
RAG 的指代消解:你真的会写 Prompt ? 剖析 RAG 应用中的指代消解 - Zilliz 向量数据库
截图工具:Flameshot | Open Source Screenshot Software
英特尔与八仙童的故事:https://zh.wikipedia.org/wiki/%E8%8B%B1%E7%89%B9%E5%B0%94
英特尔芯片的故事:芯片相关-- Cpu历史--intel系列 - 知乎 (zhihu.com)
openvino部署 RAG 应用:https://github.com/openvinotoolkit/openvino
上一期链接:Datawhale AI 夏令营——CPU部署大模型(LLM天池挑战赛)——Task1学习笔记_从零入门cpu部署大模型 llm天池-CSDN博客
标签:检索,RAG,Task2,AI,模型,Datawhale,LlamaIndex,幻觉,向量 From: https://blog.csdn.net/m0_63566347/article/details/140525867