热门搜索:和平精英 原神 街篮2 

您的位置:首页 > > 教程攻略 > ai资讯 >可视化FAISS矢量空间并调整RAG参数提高结果精度

可视化FAISS矢量空间并调整RAG参数提高结果精度

来源:互联网 更新时间:2026-07-28 15:18

开源大语言模型的进步有目共睹,写代码、做推荐、文本摘要、问答,样样都越来越拿手。但问题在于,一旦碰到模型训练数据里没见过的内部文档——比如公司内部的合规文件、商业秘密或者隐私信息——LLM就容易“出戏”,产生幻觉,给出不相关、甚至完全捏造的回答。

应对这个挑战,检索增强生成(RAG)是个很实用的方案。它的思路很直接:在生成回答之前,先从外部知识库里检索相关的文档片段,然后把它们当上下文给LLM。这样一来,语料库的质量、以及在向量空间里的表示方式(也就是嵌入),就直接决定了RAG的精度。

这篇文章,我们会用可视化库renumics-spotlight,把FAISS向量空间里高维的嵌入映射到2维平面上,然后通过调整几个关键的矢量化参数,看看能不能提升RAG的回答精度。LLM方面,我们选的是TinyLlama 1.1B Chat——这个模型和Llama 2同架构,但体量小、反赌,准确度损失也没那么大,做快速实验再合适不过。

系统设计

整个QA系统分成两个模块,如图所示。

LoadFVectorize模块

负责加载PDF或网页文档,做初步处理和向量化;

第二个模块

加载LLM,实例化FAISS检索器,再构建包含LLM、检索器和自定义提示模板的检索链。最后,我们对向量空间进行可视化。

代码实现

1. 安装必要的库

renumics-spotlight这个库用了类似UMAP的降维方法,能把高维嵌入压缩成好理解的2D可视化,同时保留关键特征。之前我们也聊过UMAP,但这次是把它整合到完整的系统里。先装依赖:

pip install langchain faiss-cpu sentence-transformers flask-sqlalchemy psutil unstructured pdf2image unstructured_inference pillow_heif opencv-python pikepdf pypdf
pip install renumics-spotlight
CMAKE_ARGS="-DLLAMA_METAL=on" FORCE_CMAKE=1 pip install --upgrade --force-reinstall llama-cpp-python --no-cache-dir

最后一行是安装带Metal支持的llama-cpp-python,这样在M1处理器上加载TinyLlama时可以硬件加速。

2. LoadFVectorize模块

这个模块包含三个函数:

  • load_doc

    :加载在线PDF,每个块512字符,重叠100字符,返回文档列表。
  • vectorize

    :调用load_doc获取文档块,创建嵌入并保存到本地目录opdf_index,同时返回FAISS实例。
  • load_db

    :检查磁盘上是否有FAISS库文件,有则加载,没有则调用vectorize创建。

完整代码如下:

# LoadFVectorize.py
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.document_loaders import OnlinePDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS

def load_doc() -> 'List[Document]':
    loader = OnlinePDFLoader("https://support.riverbed.com/bin/support/download?did=7q6behe7hotvnpqd9a03h1dji&version=9.15.0")
    documents = loader.load()
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=100)
    docs = text_splitter.split_documents(documents)
    return docs

def vectorize(embeddings_model) -> 'FAISS':
    docs = load_doc()
    db = FAISS.from_documents(docs, embeddings_model)
    db.sa ve_local("./opdf_index")
    return db

def load_db() -> 'FAISS':
    embeddings_model = HuggingFaceEmbeddings()
    try:
        db = FAISS.load_local("./opdf_index", embeddings_model)
    except Exception as e:
        print(f'Exception: {e}\nNo index on disk, creating new...')
        db = vectorize(embeddings_model)
    return db

3. 主模块

主模块先定义TinyLlama的提示模板,格式如下:

<|system|>{context}
<|user|>{question}
<|assistant|>

我们选用了TheBloke的量化版本TinyLlama,以GGUF格式加载,内存占用极小。

然后利用LoadFVectorize返回的FAISS对象创建检索器,实例化RetrievalQA,最后进行查询。代码:

# main.py
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
from langchain_community.llms import LlamaCpp
from langchain_community.embeddings import HuggingFaceEmbeddings
import LoadFVectorize
from renumics import spotlight
import pandas as pd
import numpy as np

qa_template = """<|system|>
You are a friendly chatbot who always responds in a precise manner. If answer is 
unknown to you, you will politely say so.
Use the following context to answer the question below:
{context}
<|user|>
{question}
<|assistant|>
"""
QA_PROMPT = PromptTemplate.from_template(qa_template)

llm = LlamaCpp(
    model_path="./models/tinyllama_gguf/tinyllama-1.1b-chat-v1.0.Q5_K_M.gguf",
    temperature=0.01,
    max_tokens=2000,
    top_p=1,
    verbose=False,
    n_ctx=2048
)

db = LoadFVectorize.load_db()
faiss_retriever = db.as_retriever(search_type="mmr", search_kwargs={'fetch_k': 3}, max_tokens_limit=1000)

qa_chain = RetrievalQA.from_chain_type(
    llm,
    retriever=faiss_retriever,
    chain_type_kwargs={"prompt": QA_PROMPT}
)

query = 'What versions of TLS supported by Client Accelerator 6.3.0?'
result = qa_chain({"query": query})
print(f'--------------\nQ: {query}\nA: {result["result"]}')

visualize_distance(db, query, result["result"])

最后一行visualize_distance负责向量空间可视化。这个函数通过FAISS对象的内部属性获取文档ID和嵌入,然后重建整个向量空间:

vs = db.__dict__.get("docstore")
index_list = db.__dict__.get("index_to_docstore_id").values()
doc_cnt = db.index.ntotal
embeddings_vec = db.index.reconstruct_n()

接着构建DataFrame,并加入问题和答案的嵌入,同时计算每个文档块与问题嵌入的距离:

doc_list = []
for i, doc_id in enumerate(index_list):
    a_doc = vs.search(doc_id)
    doc_list.append([doc_id, a_doc.metadata.get("source"), a_doc.page_content, embeddings_vec[i]])
df = pd.DataFrame(doc_list, columns=['id','metadata','document','embedding'])

embeddings_model = HuggingFaceEmbeddings()
question_embedding = embeddings_model.embed_query(question)
question_df = pd.DataFrame({"id":"question", "question":question, "embedding":[question_embedding]})
answer_df = pd.DataFrame({"id":"answer", "answer":answer, "embedding":[embeddings_model.embed_query(answer)]})
df = pd.concat([question_df, answer_df, df])

df["dist"] = df.apply(lambda row: np.linalg.norm(np.array(row["embedding"]) - question_embedding), axis=1)

spotlight.show(df)

这一步会在浏览器中启动Spotlight交互界面。

运行测试

1. 基本测试

我们用一个样本问题来测试:

What versions of TLS supported by Client Accelerator 6.3.0?

正确答案是:

Client Accelerator 6.3.0 supports TLS 1.1 or 1.2.

附加信息里还提到具体的CLI命令细节。来看看TinyLlama的回答:

Client Accelerator 6.3.0 supports TLS 1.1 or 1.2 as the default supported TLS versions ... (后略)

表面看和正确答案很像,但仔细看它说了“default”——这是一个不准确的细节。那么,模型是从哪些文档片段里找到答案的呢?

在Spotlight中,用“visible”按钮控制显示的列,按“dist”排序后,问题、答案和最相关的文档片段会出现在顶部。观察整个嵌入空间,几乎所有的文档块都聚成了一个簇——这很合理,因为原始PDF是针对特定产品的部署指南,内容高度同质。

在Similarity Map选项卡里点击过滤器图标,选中的文档列表会高亮显示,其他呈灰色,如图所示。

2. 测试块大小和重叠参数

检索器是影响RAG性能的关键因素。我们调整了TextSplitter的块大小(1000、2000)和重叠(100、200)参数,观察对嵌入空间的影响。

所有组合的输出看起来差别不大,但仔细对比正确答案和每个回答,发现参数为(1000, 200)时答案最准确,其他组合的回答里出现了不正确的细节(已用红色标出)。为什么?让我们从可视化嵌入来理解。

从左到右观察,随着块大小增加,向量空间变得稀疏,块更小;从下到上,重叠增加,但向量空间特征没有明显变化。所有映射仍然大致呈现为一个簇,只有少量离群点。这也解释了为什么回答非常相似——因为整个语料库本身就高度同质。

如果查询恰好位于簇中心附近,那么最近邻可能随参数变化而改变,回答就可能出现明显差异。当RAG应用对某些问题的回答不理想时,生成类似的可视化图表并结合问题分析,往往能找到优化语料库划分的方向。

为了进一步说明,我们加入了两个不相关领域的维基百科文档(格莱美奖和詹姆斯·韦布空间望远镜)。只修改了load_doc函数中的URL,其余代码不变。运行后得到下图:

可以看到两个清晰的、互不重叠的簇。如果提问的内容落在任何一个簇之外,那么检索到的上下文对LLM不仅无益,反而很可能有害。我们拿同样的问题去问,看看LLM会怎么“幻觉”:

Client Accelerator 6.3.0 supports the following versions of Transport Layer Security (TLS): 1.22. TLS 1.33. TLS 1.2 with EV certificates...(明显错误)

这里用的是FAISS做向量存储。如果你用的是ChromaDB,renumics-spotlight同样支持可视化。

总结

检索增强生成让我们能借助LLM的能力,即使模型没见过内部文档,也能得到靠谱的回答。其核心是从向量库中检索相关文档块,再交给LLM当作上下文。因此,嵌入的质量直接决定了RAG的效果。

在本文中,我们演示并可视化了几个关键矢量化参数对LLM性能的影响。借助renumics-spotlight,可以直观地看到整个FAISS向量空间,并基于问题探索空间分布。通过调整块大小、重叠等参数,我们能够影响生成行为,从而提升精度。

关于宇宙的好的网名有哪些
关于宇宙的好的网名有哪些

类型:角色扮演

大小:1

语言:简体中文

平台:互联网

游戏下载

热门手游

手机号码测吉凶
本站所有软件,都由网友上传,如有侵犯你的版权,请发邮件haolingcc@hotmail.com 联系删除。 版权所有 Copyright@2012-2013 haoling.cc