使用UMAP降维可视化RAG嵌入

大型语言模型(LLMs)如 GPT-4 已经展示了出色的文本理解和生成能力。但它们在处理领域特定信息方面面临挑战,比如当查询超出训练数据范围时,它们会产生错误的答案。LLMs 的推理过程也缺乏透明度,使用户难以理解达成结论的方式。

检索增强生成(RAG)在 LLMS 的工作流程中添加了一个检索步骤,使其能够在响应查询时从其他来源(如私人文本文档)中查询相关数据。这些文档事先分成小段,然后使用embedding的 ML 模型生成嵌入。具有相似内容的段将具有相似的嵌入。当 RAG 应用程序收到一个问题时,它使用查询检索相关文档片段。然后 LLMS 使用这些文档片段作为上下文来回答问题。这种方法可以提供回答查询所需的信息,并通过展示使用的片段来增加回答的透明度。

对于RAG来说,可视化嵌入空间是一个非常重要的方法,因为RAG应用程序使用该空间来查找相关信息。查询的结果与文档片空间息息相关,所以可以使用像UMAP这样的可视化方法,将高维嵌入减少到更易于展示的2D进行可视化。虽然高维嵌入被简化为两个分量,但问题及其相关文档片段在嵌入空间中形成簇,仍然是可以被识别出来,尤其是这时肉眼可见的,所以这有助于深入了解数据的本质。

在本文中,我们将使用HTML格式的Wikipedia中的f1数据集,使用嵌入模型将它们转换为紧凑的矢量表示,并存储到ChromaDB中。使用LangChain构建RAG应用,并在2D中可视化嵌入,分析查询和文档片段之间的关系和接近度。

首先我们安装需要的库

 !pip install langchain langchain-openai chromadb renumics-spotlight

我们使用了Renumics-Spotlight python包,Renumics-Spotlight是一个交互式探索非结构化ML数据集的可视化工具。

而获得嵌入我们则直接使用了OpenAI的embedding-ada-002,所以这里要设置API的Key

 %env OPENAI_API_KEY=<your-api-key>

准备文件

对于数据集是使用wikipedia-api和BeautifulSoup创建的。

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

将提取的html放到docs/子文件夹中,或者可以通过创建docs/子文件夹的方式将你自己的文件复制到其中来使用自己的Dataset。

创建嵌入

要创建嵌入,首先需要设置嵌入模型和vectorstore。这里我们使用OpenAIEmbeddings中的text- embeddings -ada-002和使用ChromaDB的vectorstore:

 from langchain_openai import OpenAIEmbeddingsfrom langchain.vectorstores.chroma import Chromaembeddings_model = OpenAIEmbeddings(model="text-embedding-ada-002")docs_vectorstore = Chroma(collection_name="docs_store",embedding_function=embeddings_model,persist_directory="docs-db",)

vectorstore将持久化到docs-db 文件夹中。然后使用BSHTMLLoader加载html文档:

 from langchain_community.document_loaders import BSHTMLLoader, DirectoryLoaderloader = 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 RecursiveCharacterTextSplittertext_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200, add_start_index=True)splits = text_splitter.split_documents(docs)

从元数据重建的id,这样可以在数据库中查找嵌入。

 import hashlibimport jsonfrom langchain_core.documents import Documentdef 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 ChatOpenAIllm = ChatOpenAI(model="gpt-4", temperature=0.0)retriever = docs_vectorstore.as_retriever(search_kwargs={"k": 20})

在初始化ChatOpenAI模型时,将temperature参数设置为0.0可确保确定性输出。

我们使用下面的提示:

 from langchain_core.prompts import ChatPromptTemplatetemplate = """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 Listfrom langchain_core.runnables import RunnableParallel, RunnablePassthroughfrom langchain_core.output_parsers import StrOutputParserdef 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的为问题回答

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).'

这个问题也将在下一步中用于进一步得到确认。

可视化

为了进行可视化,我们使用Pandas DataFrame来组织数据。从从矢量存储中提取文本片段及其嵌入。我们还要标出正确的答案:

 import pandas as pdresponse = 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 npquestion_embedding = embeddings_model.embed_query(question)df["dist"] = df.apply(lambda row: np.linalg.norm(np.array(row["embedding"]) - question_embedding),axis=1,)

这个距离还可以用于可视化:

 from renumics import spotlightspotlight.show(df)

上面的语句会打开一个新的浏览器窗口。左上角的表格部分显示数据集的所有字段。右上方的相似性图中突出显示它们。

可以看到,包含正确答案的单个文档片段和最相关的文件离问题和答案很近。

总结

使用降维技术可以使用户和开发人员访问嵌入空间。在可视化空间中,可以通过浏览相邻的数据点来进行检索增强的检查。降维可视化虽然有助于理解数据,但也可能存在信息损失,因为它将高维数据映射到一个较低维度的空间中。因此,在进行检查时,需要权衡信息丢失和效果提升之间的关系。

完整代码:
https://avoid.overfit.cn/post/31e45d66ef1547e397bbbef2ebcf38c8

作者:Markus Stoll

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

黄金交易策略(Nerve Nnife.mql4):三档移动止盈机制设计

和中国电费一样&#xff0c;一档档的上。 完整EA&#xff1a;Nerve Knife.ex4黄金交易策略_黄金趋势ea-CSDN博客 mql4代码节选如下&#xff1a; //第一张单上涨2500&#xff0c;开始SL跟踪300点if (count 1 && !follow_p_3){double ctp calcTotalProfit(0, "b…

课堂秩序要求有哪些内容

你是否曾经疑惑&#xff0c;为什么有些课堂总是秩序井然&#xff0c;而有些则混乱不堪&#xff1f;作为一位经验丰富的老师&#xff0c;我想告诉你&#xff0c;课堂秩序不仅仅是学生安静听讲那么简单&#xff0c;它背后涉及到许多关键因素&#xff0c;直接影响着教学质量和学习…

2024.2.10 DMS(数据库管理系统)初体验

数据库管理系统(Database Management System)是一种操纵和管理数据库的大型软件&#xff0c;用于建立、使用和维护数据库&#xff0c;简称DBMS。它对数据库进行统一的管理和控制&#xff0c;以保证数据库的安全性和完整性。用户通过DBMS访问数据库中的数据&#xff0c;数据库管…

【书生·浦语大模型实战营】学习笔记1

大模型成为发展通用人工智能的重要途经 专用模型&#xff1a;针对特定任务&#xff0c;一个模型解决一个问题 通用大模型&#xff1a;一个模型应对多种任务、多种模态 书生浦语大模型系列 上海人工智能实验室 轻量级、中量级、重量级 7B 和 123B的轻量级和中量级大模型都是开源…

嵌入式电子产品开发感悟!

​ 2023特别深有感触的有以下几个事件&#xff1a; 1. 早在2月底就提交报告&#xff1a;抓紧开一款便携式的空气波压力按摩仪外壳&#xff0c;包括模具费和100台试产物料费用总计不超过22W&#xff0c;保证最迟在4月中旬全部生产好&#xff0c;以供业务参加5月份开始的大健康展…

linux学习之虚拟地址

在以往的学习中我们经常接触地址&#xff0c;电脑像一个小房间&#xff0c;它的空间是有限不可重叠的&#xff0c;但是可以覆盖。想象一下如果我们要放很多东西进去&#xff0c;如果没有合理的安排&#xff0c;所有东西乱放&#xff0c;那么我们需要寻找某一个东西的时候需要把…

vivado不使用的引脚约束方法

不需要分配的引脚约束方法:收藏备用 方法一&#xff1a; 方法一&#xff1a; set_property SEVERITY {Warning} [get_drc_checks NSTD-1] set_property SEVERITY {Warning} [get_drc_checks RTSTAT-1] set_property SEVERITY {Warning} [get_drc_checks UCIO-1]#方法二 set_p…

宠物空气净化器哪个牌子好?养猫家庭如何挑选宠物空气净化器?

养猫的朋友都知道&#xff0c;猫咪掉毛是一个令人头痛的问题。猫毛和皮屑会漂浮在空气中&#xff0c;不仅遍布全屋的各个角落&#xff0c;而且清理起来也非常麻烦&#xff0c;特别是那些难以清除的猫毛。更糟糕的是&#xff0c;这些猫毛还可能引发人们的过敏反应&#xff0c;如…

Redis -- 渐进式遍历

家&#xff0c;是心的方向。不论走多远&#xff0c;总有一盏灯为你留着。桌上的碗筷多了几双&#xff0c;笑声也多了几分温暖。家人团聚&#xff0c;是最美的风景线。时间&#xff1a;2024年 2月 8日 12:51:20 目录 前言 语法 示例 前言 试想一个场景,那就是在key非常多的…

345. Reverse Vowels of a String(反转字符串中的元音字母)

题目描述 给你一个字符串 s &#xff0c;仅反转字符串中的所有元音字母&#xff0c;并返回结果字符串。 元音字母包括 ‘a’、‘e’、‘i’、‘o’、‘u’&#xff0c;且可能以大小写两种形式出现不止一次。 问题分析 不要被题目迷惑了&#xff0c;题意是将元音字符提取出来…

Javaweb之SpringBootWeb案例之事务管理的详细解析

1. 事务管理 1.1 事务回顾 在数据库阶段我们已学习过事务了&#xff0c;我们讲到&#xff1a; 事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位。事务会把所有的操作作为一个整体&#xff0c;一起向数据库提交或者是撤销操作请求。所以这组操作要么同时成功&am…

推荐系统|召回05_矩阵补充、最近邻查找

文章目录 矩阵补充Matrix Completion模型结构模型训练模型存储 矩阵补充Matrix Completion 模型结构 通过用户ID和物品ID分别找到对应的向量&#xff0c;然后去做内积&#xff0c;内积的数值可以去衡量匹配的程度。 不共享参数的意思是指用户ID和物品ID使用不同的Embedding L…