可视化 RAG 数据 — EDA for Retrieval-Augmented Generation

news2024/11/18 21:30:56

目录

一、说明

二、准备好

三、准备文件

四、拆分和创建数据集的嵌入

五、构建 LangChain

六、问一个问题

七、可视化

八、下一步是什么?

九、引用


一、说明

        像 GPT-4 这样的大型语言模型 (LLM) 在文本理解和生成方面表现出令人印象深刻的能力。但是,他们在处理特定于域的信息时面临着挑战。当查询超出训练数据范围时,它们往往会产生错误答案的幻觉[1]。此外,LLM的推理过程缺乏透明度,使用户难以理解结论是如何得出的。

        为了应对这些挑战,已经开发了一种称为检索增强生成(RAG)的技术。RAG 向 LLM 的工作流添加了一个检索步骤,使其能够在响应查询时从其他来源(如您的私人文本文档)查询相关数据。这些文档可以预先划分为小片段,嵌入(紧凑向量表示)是使用 OpenAI 的 embedding-ada-002 等 ML 模型生成的。具有相似内容的代码段将具有类似的嵌入。当 RAG 应用程序收到问题时,它会将此查询投影到同一嵌入空间中,并检索与查询相关的相邻文档片段。然后,LLM 使用这些文档片段作为上下文来回答问题。此方法可以提供回答查询所需的信息,还可以通过向用户显示使用的代码片段来实现透明度。

        检索增强生成 [2]: 唐一轩, 杨毅: 多跳-RAG: 多跳查询的基准检索增强生成 (2021), arXiv — CC BY-SA 4.0

        在开发 RAG 应用程序时,正如许多其他领域所认识到的那样,对数据有一个很好的概述是很重要的。对于 RAG,可视化嵌入空间特别有用,因为 RAG 应用程序使用此空间来查找相关信息。由于查询与文档片段共享空间,因此需要考虑相关文档片段和查询之间的接近程度。我们建议将可视化与 UMAP [3] 等方法结合使用,将高维嵌入简化为更易于管理的 2D 可视化,同时保留重要的属性,例如代码段和查询之间的关系和邻近性。尽管高维嵌入被简化为只有两个组件,但仍然可以识别在嵌入空间中形成集群的问题及其相关文档片段。这有助于深入了解数据的性质。

        文档片段嵌入的 UMAP 降维,根据它们与“谁建造了纽博格林”问题的相关性着色——由作者创建

        在本文中,您将学习如何

  • 准备文档:从收集数据开始。本教程以 HTML 格式的维基百科一级方程式数据为例,为我们的 RAG 应用程序构建数据集。您也可以在这里使用自己的数据!
  • 拆分和创建嵌入:将收集的文档分解为更小的片段,并使用嵌入模型将它们转换为紧凑的矢量表示形式。这涉及使用拆分器、OpenAI 的 text-embedding-ada-002 和 ChromaDB 作为向量存储。
  • 构建 LangChain:通过组合用于创建上下文的提示生成器、用于获取相关片段的检索器和用于回答查询的 LLM (GPT-4) 来设置 LangChain。
  • 提问:了解如何向 RAG 应用程序提问。
  • 可视化:使用 Renumics-Spotlight 以 2D 形式可视化嵌入,并分析查询和文档片段之间的关系和邻近性。

        本简化教程将引导您完成开发 RAG 应用程序的每个阶段,并特别关注可视化结果的作用。

该代码可在 Github 上找到

二、准备好

首先,安装所有必需的软件包:

!pip install langchain langchain-openai chromadb renumics-spotlight 

        本教程使用 Langchain、Renumics-Spotlight python 包:

  • Langchain:一个集成语言模型和 RAG 组件的框架,使设置过程更加顺畅。
  • Renumics-Spotlight:一种可视化工具,用于以交互方式探索非结构化 ML 数据集。

        免责声明:本文作者也是 Spotlight 的开发者之一。

        所需的 ML 模型将从 OpenAI 中使用

  • GPT-4:一种最先进的语言模型,以其先进的文本理解和生成功能而闻名。
  • embedding-ada-002:设计用于创建文本嵌入表示形式的专用模型。

        设置你的OPENAI_API_KEY;例如,您可以在笔记本中使用 Notebook Line Magic 进行设置:

%env OPENAI_API_KEY=<your-api-key>

三、准备文件

        对于此演示,您可以使用我们准备的维基百科所有一级方程式文章的数据集。该数据集是使用 wikipedia-api 和 BeautifulSoup 创建的。您可以下载数据集。

该数据集基于维基百科上的文章,并根据知识共享署名-相同方式共享许可获得许可。原始文章和作者列表可以在相应的维基百科页面上找到。

        将提取的 html 放入 docs/ 子文件夹中。

        或者,您可以通过创建 docs/ 子文件夹并将您自己的文件复制到其中来使用您自己的数据集。

作者使用 Midjourney v6.0 创建的图像

四、拆分和创建数据集的嵌入

        您可以跳过此部分并下载嵌入一级方程式数据集的数据库。

        要自行创建嵌入,您首先需要设置嵌入模型和向量存储。 在这里,我们使用 OpenAIEmbeddings 中的 text-embedding-ada-002 和使用 ChromaDB 的矢量存储:

from langchain_openai import OpenAIEmbeddings
from langchain.vectorstores.chroma import Chroma

embeddings_model = OpenAIEmbeddings(model="text-embedding-ada-002")
docs_vectorstore = Chroma(
    collection_name="docs_store",
    embedding_function=embeddings_model,
    persist_directory="docs-db",
)

        向量存储将保留在 docs-db/ 文件夹中。

        为了填充向量存储,我们使用 BSHTMLLoader 加载 html 文档:

from langchain_community.document_loaders import BSHTMLLoader, DirectoryLoader
loader = DirectoryLoader(
    "docs",
    glob="*.html",
    loader_cls=BSHTMLLoader,
    loader_kwargs={"open_encoding": "utf-8"},
    recursive=True,
    show_progress=True,
)
docs = loader.load()

        并将它们分成更小的块

from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000, chunk_overlap=200, add_start_index=True
)
splits = text_splitter.split_documents(docs)

        此外,还可以创建可从元数据重构的 ID。如果您只有包含其内容和元数据的文档,则允许在数据库中找到嵌入。您可以将所有内容添加到数据库中并存储它:

import hashlib
import json
from langchain_core.documents import Document

def stable_hash(doc: Document) -> str:
    """
    Stable hash document based on its metadata.
    """
    return hashlib.sha1(json.dumps(doc.metadata, sort_keys=True).encode()).hexdigest()

split_ids = list(map(stable_hash, splits))
docs_vectorstore.add_documents(splits, ids=split_ids)
docs_vectorstore.persist()

您可以在本教程中找到有关拆分和整个过程的更多信息。

五、构建 LangChain

        首先,您需要选择一个 LLM 模型。在这里,我们使用 GPT-4。此外,您需要准备检索器以使用向量存储:

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4", temperature=0.0)
retriever = docs_vectorstore.as_retriever(search_kwargs={"k": 20})

        将参数设置为初始化模型时可确保确定性输出。temperature0.0ChatOpenAI

现在,让我们为 RAG 创建一个提示。LLM 将提供用户的问题和检索到的文档作为回答问题的上下文。它还被指示提供允许其回答的来源:

from langchain_core.prompts import ChatPromptTemplate

template = """
You are an assistant for question-answering tasks.
Given the following extracted parts of a long document and a question, create a final answer with references ("SOURCES").
If you don't know the answer, just say that you don't know. Don't try to make up an answer.
ALWAYS return a "SOURCES" part in your answer.

QUESTION: {question}
=========
{source_documents}
=========
FINAL ANSWER: """
prompt = ChatPromptTemplate.from_template(template)

        接下来,设置一个处理管道,该管道首先设置检索到的文档的格式,以包含页面内容和源文件路径。然后,将此格式化输入输入到语言模型 (LLM) 步骤中,该步骤根据组合的用户问题和文档上下文生成答案。

from typing import List

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


def format_docs(docs: List[Document]) -> str:
    return "\n\n".join(
        f"Content: {doc.page_content}\nSource: {doc.metadata['source']}" for doc in docs
    )


rag_chain_from_docs = (
    RunnablePassthrough.assign(
        source_documents=(lambda x: format_docs(x["source_documents"]))
    )
    | prompt
    | llm
    | StrOutputParser()
)
rag_chain = RunnableParallel(
    {
        "source_documents": retriever,
        "question": RunnablePassthrough(),
    }
).assign(answer=rag_chain_from_docs)

六、问一个问题

RAG 应用程序现在已准备好回答问题:

question = "Who built the nuerburgring"
response = rag_chain.invoke(question)
response["answer"]

这将打印一个正确答案:

'The Nürburgring was built in the 1920s, with the construction of the track beginning in September 1925. The track was designed by the Eichler Architekturbüro from Ravensburg, led by architect Gustav Eichler. The original Nürburgring was intended to be a showcase for German automotive engineering and racing talent (SOURCES: data/docs/Nürburgring.html).'

我们将坚持一个问题。这个问题也将在下一节中用于进一步调查。

七、可视化

        为了在 Spotlight 中探索数据,我们使用 Pandas DataFrame 来组织我们的数据。让我们从向量存储中提取文本片段及其嵌入开始。另外,让我们标记正确答案:

import pandas as pd

response = docs_vectorstore.get(include=["metadatas", "documents", "embeddings"])
df = pd.DataFrame(
    {
        "id": response["ids"],
        "source": [metadata.get("source") for metadata in response["metadatas"]],
        "page": [metadata.get("page", -1) for metadata in response["metadatas"]],
        "document": response["documents"],
        "embedding": response["embeddings"],
    }
)
df["contains_answer"] = df["document"].apply(lambda x: "Eichler" in x)
df["contains_answer"].to_numpy().nonzero()

        问题和相关答案也会投影到嵌入空间中。它们的处理方式与文本片段相同:

question_row = pd.DataFrame(
    {
        "id": "question",
        "question": question,
        "embedding": embeddings_model.embed_query(question),
    }
)
answer_row = pd.DataFrame(
    {
        "id": "answer",
        "answer": answer,
        "embedding": embeddings_model.embed_query(answer),
    }
)
df = pd.concat([question_row, answer_row, df])

        此外,可以确定问题和文档片段之间的距离:

import numpy as np
question_embedding = embeddings_model.embed_query(question)
df["dist"] = df.apply(
    lambda row: np.linalg.norm(
        np.array(row["embedding"]) - question_embedding
    ),
    axis=1,
)

        这还可以用于可视化,并将存储在列中:distance

+----+------------------------------------------+----------------------------+------------------------------------------------------------------------+----------------------------------------------------+----------------------------------------+--------+------------------------------+-------------------+------------+
|    | id                                       | question                   | embedding                                                              | answer                                             | source                                 |   page | document                     |   contains_answer |       dist |
|----+------------------------------------------+----------------------------+------------------------------------------------------------------------+----------------------------------------------------+----------------------------------------+--------+------------------------------+-------------------+------------|
|  0 | question                                 | Who built the nuerburgring | [0.005164676835553928, -0.011625865528385777,  ...                     | nan                                                | nan                                    |    nan | nan                          |               nan | nan        |
|  1 | answer                                   | nan                        | [-0.007912757349432444, -0.021647867427574807, ...                     | The Nürburgring was built in the 1920s in the town | nan                                    |    nan | nan                          |               nan |   0.496486 |
|  2 | 000062fd07a090c7c84ed42468a0a4b7f5f26bf8 | nan                        | [-0.028886599466204643, 0.006249633152037859,  ...                     | nan                                                | data/docs/Hamilton–Vettel rivalry.html |     -1 | Media reception...           |                 0 |   0.792964 |
|  3 | 0003de08507d7522c43bac201392929fb2e26b86 | nan                        | [-0.031988393515348434, -0.002095212461426854, ...                     | nan                                                | data/docs/Cosworth GBA.html            |     -1 | Team Haas[edit]...           |                 0 |   0.726574 |
|  4 | 000543bb633380334e742ec9e0c15a188dcb0bf2 | nan                        | [-0.007886063307523727, 0.007812486961483955,  ...                     | nan                                                | data/docs/Interlagos Circuit.html      |     -1 | Grand Prix motorcycle racing.|                 0 |   0.728354 |
|    |                                          |                            |                                                                        |                                                    |                                        |        | Brazilian motorcycle...      |                   |            |
+----+------------------------------------------+----------------------------+------------------------------------------------------------------------+----------------------------------------------------+----------------------------------------+--------+------------------------------+-------------------+------------

Renumics Spotlight 可以从以下方式开始:


from renumics import spotlight
spotlight.show(df)

        它将打开一个新的浏览器窗口。左上角的表格部分显示数据集的所有字段。您可以使用“可见列”按钮选择“问题”、“答案”、“源”、“文档”和“dist”列。按“dist”对表格进行排序,在顶部显示问题、答案和最相关的文档片段。选择前 14 行以在右上角的相似性图中突出显示它们。

        文档片段嵌入的 UMAP 降维,根据它们与“谁建造了纽博格林?”问题的相关性着色——由作者与 Renumics Spotlight 一起创建

        您可以观察到,最相关的文档与问题和答案非常接近。这包括包含正确答案的单个文档片段。

八、下一步是什么?

        单个问题、答案和相关文档的良好可视化显示了 RAG 的巨大潜力。使用降维技术可以使用户和开发人员可以访问嵌入空间。本文中具体介绍的实用性仍然非常有限。探索这些方法在提出许多问题的可能性,从而说明RAG系统在运行中的使用或通过评估问题检查嵌入空间的覆盖范围,仍然令人兴奋。请继续关注后续的更多文章。

        通过使用增强数据科学工作流程的 Spotlight 等工具,可以更轻松地实现 RAG 的可视化。尝试使用您自己的数据编写代码,并在评论中告诉我们您的结果!

        我是一名专业人士,擅长为非结构化数据的交互式探索创建高级软件解决方案。我撰写有关非结构化数据的文章,并使用强大的可视化工具进行分析并做出明智的决策。

九、引用

[1] 高云帆, 熊云, 高新宇, 贾康祥, 潘金柳, 毕玉溪, 戴毅, 孙佳伟, 郭倩宇, 王萌, 王浩芬: 大型语言模型的检索增强生成:调查 (2024), arxiv

[2] Yixuan Tang, Yi Yang: MultiHop-RAG: Benchmarking Retrieval-Augmented Generation for Multi-Hop Queries (2021), arXiv

[3] Leland McInnes、John Healy、James Melville:UMAP:用于降维的均匀流形近似和投影 (2018),arXiv

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

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

相关文章

fpga_直方图均衡

直方图均衡是一种用于图像增强和对比度调整的图像处理技术。它通过重新分配图像中像素的灰度级分布&#xff0c;使得图像的直方图变得更加均衡&#xff0c;从而增强图像的视觉效果。 一 直方图 直方图源于柱状图 二 数字图像与灰度直方图 如图所示&#xff0c;灰度直方图是读…

【Vue渗透】Vue Devtools 浏览器插件

下载地址 Vue Devtools 浏览器插件 Vue站点渗透思路 【Vue渗透】Vue站点渗透思路 简介 Vue Devtools 是 Vue 官方发布的调试浏览器插件&#xff0c;可以安装在 Chrome 和 Firefox 等浏览器上&#xff0c;直接内嵌在开发者工具中&#xff0c;使用体验流畅。Vue Devtools 由…

【扩散模型】【网络结构探索】神经网络扩散:Neural Network Diffusion(论文解读)

项目地址&#xff1a;https://github.com/NUS-HPC-AI-Lab/Neural-Network-Diffusion 文章目录 摘要一、前言二、Nerual Network Diffusion &#xff08;神经网络扩散&#xff09;2.1扩散模型&#xff08;预备知识&#xff09;2.2 总览2.3 参数自动编码器2.4 参数生成 三、实验3…

harbor(docker仓库)仓库部署 - 高可用

harbor&#xff08;docker仓库&#xff09;仓库部署 - 高可用 1. harbor高可用1.1 方案说明1. 双主复制2. 多harbor实例共享后端存储 1.2 部署高可用&#xff08;多harbor实例共享后端存储&#xff09;1. 服务器划分2. 安装harbor&#xff08;先部署一套Harbor&#xff0c;用于…

【LeetCode每日一题】 单调栈的案例84 柱状图中最大的矩形

84 柱状图中最大的矩形 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例 1: 输入&#xff1a;heights [2,1,5,6,2,3] 输出&#xff1a;10 解释…

unity ui界面优化

优化一个比较复杂的界面&#xff0c;里面有多个rt和组件。 在初次打开这个界面的时候会发生1s多的卡顿&#xff0c;还是非常严重的。 分析 通过profiler分析 1.打开界面时卡顿。 分析&#xff1a;除了update和dotween相关逻辑&#xff0c;主要在于打开时的lua function调用…

【Python笔记-设计模式】装饰器模式

一、说明 装饰器模式是一种结构型设计模式&#xff0c;旨在动态的给一个对象添加额外的职责。 (一) 解决问题 不改变原有对象结构的情况下&#xff0c;动态地给对象添加新的功能或职责&#xff0c;实现透明地对对象进行功能的扩展。 (二) 使用场景 如果用继承来扩展对象行…

多维时序 | Matlab实现CPO-BiTCN-BiGRU冠豪猪优化时间卷积神经网络双向门控循环单元多变量时间序列预测模型

多维时序 | Matlab实现CPO-BiTCN-BiGRU冠豪猪优化时间卷积神经网络双向门控循环单元多变量时间序列预测模型 目录 多维时序 | Matlab实现CPO-BiTCN-BiGRU冠豪猪优化时间卷积神经网络双向门控循环单元多变量时间序列预测模型预测效果基本介绍程序设计参考资料 预测效果 基本介绍…

JAVA--File类与IO流

目录 1. java.io.File类的使用 1.1 概述 1.2 构造器 1.3 常用方法 1、获取文件和目录基本信息 2、列出目录的下一级 3、File类的重命名功能 4、判断功能的方法 5、创建、删除功能 2. IO流原理及流的分类 2.1 Java IO原理 2.2 流的分类 2.3 流的API 3. 节点流之一…

Unity之PUN2插件实现多人联机射击游戏

目录 &#x1f4d6;一、准备工作 &#x1f4fa;二、UI界面处理 &#x1f4f1;2.1 登录UI并连接PUN2服务器 &#x1f4f1;2.2 游戏大厅界面UI &#x1f4f1;2.3 创建房间UI &#x1f4f1;2.4 进入房间UI &#x1f4f1;2.5 玩家准备状态 &#x1f4f1;2.6 加载战斗场景…

SpringCloud-Gateway解决跨域问题

Spring Cloud Gateway是一个基于Spring Framework的微服务网关&#xff0c;用于构建可扩展的分布式系统。在处理跨域问题时&#xff0c;可以通过配置网关来实现跨域资源共享&#xff08;CORS&#xff09;。要解决跨域问题&#xff0c;首先需要在网关的配置文件中添加相关的跨域…

【EI会议征稿通知】2024年软件自动化与程序分析国际学术会议(SAPA 2024)

2024年软件自动化与程序分析国际学术会议&#xff08;SAPA 2024) 2024 International Conference on Software Automation and Program Analysis 在当今科技社会中&#xff0c;软件产业呈快速发展趋势&#xff0c;软件自动化与程序分析技术在提高软件质量、降低开发成本、提升…

【Java】继承与抽象(实验三)

目录 一、实验目的 二、实验内容 三、实验小结 一、实验目的 了解继承的概念&#xff0c;掌握派生类的定义。掌握派生类构造方法的执行过程。掌握方法的重载与覆盖。掌握抽象类的概念及上转型对象的使用 二、实验内容 1、定义一个抽象类Shape&#xff0c;类中封装属性name…

详解AP3216C(三合一sensor: 光照、距离、照射强度)驱动开发

目录 概述 1 认识AP3216C 1.1 AP3216C特性 1.2 AP3216C内部结构 1.3 AP3216C 硬件电路 1.4 AP3216C工作时序 1.4.1 I2C 写数据协议 1.4.2 I2C 读数据协议 1.5 重要的寄存器 1.5.1 系统配置寄存器 1.5.2 和中断相关寄存器 1.5.3 IR数据寄存器 1.5.4 ALS 数据寄存器 …

C++之stack与queue的模拟实现

一、 stack的介绍和使用 1. stack的介绍 stack 的文档介绍 翻译&#xff1a; 1. stack 是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入与提取操作。 2. stack 是作为容器适配器被实现的&#xff…

C++的queue容器->基本概念、常用接口

#include<iostream> using namespace std; #include <queue> #include <string> //队列 queue class Person { public: Person(string name, int age) { this->m_Name name; this->m_Age age; } string m_Name; int…

.netcore 6.0/7.0项目迁移至.netcore 8.0 注意事项

1、SqlSugarCore 相关 1.1 主项目添加数据&#xff0c;否则会报数据库连接错误&#xff1a; <InvariantGlobalization>false</InvariantGlobalization> <PropertyGroup><TargetFramework>net8.0</TargetFramework><Nullable>enable</…

PostMan使用自带js库base64编码、sha256摘要、环境变量的使用

目录 1、环境变量的使用2、base64编码、sha256摘要、以及脚本的使用3、脚本代码 在请求调试接口的过程中&#xff0c;因为要使用大量相同的参数&#xff0c;使用变量的方式能很大程度上减轻接口调用的工作量 版本说明&#xff1a;Postman for Windows&#xff0c;Version&#…

【办公类-16-10-02】“2023下学期 6个中班 自主游戏观察记录(python 排班表系列)

背景需求&#xff1a; 已经制作了本学期的中4班自主游戏观察记录表 【办公类-16-10-01】“2023下学期 中4班 自主游戏观察记录&#xff08;python 排班表系列&#xff09;-CSDN博客文章浏览阅读398次&#xff0c;点赞10次&#xff0c;收藏3次。【办公类-16-10-01】“2023下学…

无人机竞赛常用目标检测方法--色块检测

本次开源计划主要针对大学生无人机相关竞赛的视觉算法开发。 开源代码仓库链接&#xff1a;https://github.com/zzhmx/Using-color-gamut-limitations-such-as-HSV-and-RGB-for-object-detection.git 主要使用传统算法&#xff0c;如果想要使用进阶版机器学习算法&#xff0c;请…