新聞中心
隨著開(kāi)源大型語(yǔ)言模型的性能不斷提高,編寫和分析代碼、推薦、文本摘要和問(wèn)答(QA)對(duì)的性能都有了很大的提高。但是當(dāng)涉及到QA時(shí),LLM通常會(huì)在未訓(xùn)練數(shù)據(jù)的相關(guān)的問(wèn)題上有所欠缺,很多內(nèi)部文件都保存在公司內(nèi)部,以確保合規(guī)性、商業(yè)秘密或隱私。當(dāng)查詢這些文件時(shí),會(huì)使得LLM產(chǎn)生幻覺(jué),產(chǎn)生不相關(guān)、捏造或不一致的內(nèi)容。

創(chuàng)新互聯(lián)基于成都重慶香港及美國(guó)等地區(qū)分布式IDC機(jī)房數(shù)據(jù)中心構(gòu)建的電信大帶寬,聯(lián)通大帶寬,移動(dòng)大帶寬,多線BGP大帶寬租用,是為眾多客戶提供專業(yè)服務(wù)器托管報(bào)價(jià),主機(jī)托管價(jià)格性價(jià)比高,為金融證券行業(yè)托管服務(wù)器,ai人工智能服務(wù)器托管提供bgp線路100M獨(dú)享,G口帶寬及機(jī)柜租用的專業(yè)成都idc公司。
為了處理這一挑戰(zhàn)的一種可用技術(shù)是檢索增強(qiáng)生成(retrieve - augmented Generation, RAG)。它涉及通過(guò)在響應(yīng)生成之前引用其訓(xùn)練數(shù)據(jù)源之外的權(quán)威知識(shí)庫(kù)來(lái)增強(qiáng)響應(yīng)的過(guò)程。RAG應(yīng)用程序包括一個(gè)檢索系統(tǒng),用于從語(yǔ)料庫(kù)中獲取相關(guān)文檔片段,以及一個(gè)LLM,用于使用檢索到的片段作為上下文生成響應(yīng),所以語(yǔ)料庫(kù)的質(zhì)量及其在向量空間中的表示(稱為嵌入)在RAG的準(zhǔn)確性中發(fā)揮重要作用。
在本文中,我們將使用可視化庫(kù)renumics-spotlight在2-D中可視化FAISS向量空間的多維嵌入,并通過(guò)改變某些關(guān)鍵的矢量化參數(shù)來(lái)尋找提高RAG響應(yīng)精度的可能性。對(duì)于我們選擇的LLM,將采用TinyLlama 1.1B Chat,這是一個(gè)緊湊的模型,與Llama 2相同的架構(gòu)。它的優(yōu)點(diǎn)是具有更小的資源占用和更快的運(yùn)行時(shí)間,但其準(zhǔn)確性沒(méi)有成比例的下降,這使它成為快速實(shí)驗(yàn)的理想選擇。
系統(tǒng)設(shè)計(jì)
QA系統(tǒng)有兩個(gè)模塊,如圖所示。
LoadFVectorize模塊加載pdf或web文檔。對(duì)于最初的測(cè)試和可視化。第二個(gè)模塊加載LLM并實(shí)例化FAISS檢索,然后創(chuàng)建包含LLM、檢索器和自定義查詢提示的檢索鏈。最后我們對(duì)它的向量空間進(jìn)行可視化。
代碼實(shí)現(xiàn)
1、安裝必要的庫(kù)
renumics-spotlight庫(kù)使用類似umap的可視化,將高維嵌入減少到更易于管理的2D可視化,同時(shí)保留關(guān)鍵屬性。我們?cè)谝郧暗奈恼轮幸步榻B過(guò)umap的使用,但是只是功能性的簡(jiǎn)單介紹,這次我們作為完整的系統(tǒng)設(shè)計(jì),將他整合到一個(gè)真正可用的實(shí)際項(xiàng)目中。首先是安裝必要的庫(kù):
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- pcp -python庫(kù),該庫(kù)將用于在M1處理器上加載帶有硬件加速的TinyLlama。
2、LoadFVectorize模塊
模塊包括3個(gè)功能:
load_doc處理在線pdf文檔的加載,每個(gè)塊分割512個(gè)字符,重疊100個(gè)字符,返回文檔列表。
vectorize調(diào)用上面的函數(shù)load_doc來(lái)獲取文檔的塊列表,創(chuàng)建嵌入并保存到本地目錄opdf_index,同時(shí)返回FAISS實(shí)例。
load_db檢查FAISS庫(kù)是否在目錄opdf_index中的磁盤上并嘗試加載,最終返回一個(gè)FAISS對(duì)象。
該模塊代碼的完整代碼如下:
# 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
# access an online pdf
def load_doc() -> 'List[Document]':
loader = OnlinePDFLoader("https://support.riverbed.com/bin/support/download?did=7q6behe7hotvnpqd9a03h1dji&versinotallow=9.15.0")
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=100)
docs = text_splitter.split_documents(documents)
return docs
# vectorize and commit to disk
def vectorize(embeddings_model) -> 'FAISS':
docs = load_doc()
db = FAISS.from_documents(docs, embeddings_model)
db.save_local("./opdf_index")
return db
# attempts to load vectorstore from disk
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 db3、主模塊
主模塊最初定義了以下模板的TinyLlama提示符模板:
<|system|>{context}<|user|>{question}<|assistant|>另外采用來(lái)自TheBloke的量化版本的TinyLlama可以極大的減少內(nèi)存,我們選擇以GGUF格式加載量化LLM。
然后使用LoadFVectorize模塊返回的FAISS對(duì)象,創(chuàng)建一個(gè)FAISS檢索器,實(shí)例化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
# Prompt template
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|>
"""
# Create a prompt instance
QA_PROMPT = PromptTemplate.from_template(qa_template)
# load LLM
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
)
# vectorize and create a retriever
db = LoadFVectorize.load_db()
faiss_retriever = db.as_retriever(search_type="mmr", search_kwargs={'fetch_k': 3}, max_tokens_limit=1000)
# Define a QA chain
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處理的:
visualize_distance訪問(wèn)FAISS對(duì)象的屬性__dict__,index_to_docstore_id本身是值docstore-ids的關(guān)鍵索引字典,用于向量化的總文檔計(jì)數(shù)由索引對(duì)象的屬性ntotal表示。
vs = db.__dict__.get("docstore")
index_list = db.__dict__.get("index_to_docstore_id").values()
doc_cnt = db.index.ntotal調(diào)用對(duì)象索引的方法reconstruct_n,可以實(shí)現(xiàn)向量空間的近似重建
embeddings_vec = db.index.reconstruct_n()有了docstore-id列表作為index_list,就可以找到相關(guān)的文檔對(duì)象,并使用它來(lái)創(chuàng)建一個(gè)包括docstore-id、文檔元數(shù)據(jù)、文檔內(nèi)容以及它在所有id的向量空間中的嵌入的列表:
doc_list = 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]])然后使用列表創(chuàng)建一個(gè)包含列標(biāo)題的DF,我們最后使用這個(gè)DF進(jìn)行可視化
df = pd.DataFrame(doc_list,columns=['id','metadata','document','embedding'])在繼續(xù)進(jìn)行可視化之前,還需要將問(wèn)題和答案結(jié)合起來(lái),我們創(chuàng)建一個(gè)單獨(dú)的問(wèn)題以及答案的DF,然后與上面的df進(jìn)行合并,這樣能夠顯示問(wèn)題和答案出現(xiàn)的地方,在可視化時(shí)我們可以高亮顯示:
# add rows for question and answer
embeddings_model = HuggingFaceEmbeddings()
question_df = pd.DataFrame(
{
"id": "question",
"question": question,
"embedding": [embeddings_model.embed_query(question)],
})
answer_df = pd.DataFrame(
{
"id": "answer",
"answer": answer,
"embedding": [embeddings_model.embed_query(answer)],
})
df = pd.concat([question_df, answer_df, df])這里使用使用np.linalg.norm在文件和問(wèn)題嵌入上的進(jìn)行距離大小的計(jì)算:
question_embedding = embeddings_model.embed_query(question)
# add column for vector distance
df["dist"] = df.apply(
lambda row: np.linalg.norm(
np.array(row["embedding"]) - question_embedding
),axis=1,)因?yàn)閟potlight可以對(duì)df進(jìn)行可視化,所有我們直接調(diào)用即可
spotlight.show(df)這一步將在瀏覽器窗口中啟動(dòng)spotlight。
運(yùn)行測(cè)試
1、基本測(cè)試
下面是我們選擇的樣本問(wèn)題:
What versions of TLS supported by Client Accelerator 6.3.0?
正確答案是:
Client Accelerator 6.3.0 supports TLS 1.1 or 1.2.
以下額外信息可能包含在響應(yīng)中。
You must enable this capability using the following CLI command on the Client Accelerator:(config) # policy id?
?ssl backend client-tls-1.2Even though TLS 1.1 is not mentioned in the syntax of this command, using ?this command automatically enables support for both TLS 1.1 and 1.2.
然后我們看看TinyLlama對(duì)上述問(wèn)題的回答:
Client Accelerator 6.3.0 supports TLS 1.1 or 1.2 as the default ?supported TLS versions with Client Accelerator. You must enable this ?capability using the following CLI command on the Client Accelerator:```(config) # policy id?
?ssl backend client-tlss1.2```Note that this command only applies to TLS 1.1 or TLS?1.2. If you need to ?support older TLS versions, you can use the?ssl backend?command with ?the?client-tlss1.0?or?client-tlss1.1?option?instead.
看起來(lái)與實(shí)際答案非常相似,但它并不完全正確,因?yàn)檫@些TLS版本不是其默認(rèn)值。
那么我們來(lái)看看他是從哪些段落中找到的答案呢?
在可以spotlight中使用visible 按鈕來(lái)控制顯示的列。按“dist”對(duì)表格進(jìn)行排序,在頂部顯示問(wèn)題、答案和最相關(guān)的文檔片段。查看我們文檔的嵌入,它將幾乎所有文檔塊描述為單個(gè)簇。這是合理的,因?yàn)槲覀冊(cè)紁df是針對(duì)特定產(chǎn)品的部署指南,所以被認(rèn)為是一個(gè)簇是沒(méi)有問(wèn)題的。
單擊Similarity Map選項(xiàng)卡中的過(guò)濾器圖標(biāo),它只突出顯示所選的文檔列表,該列表是緊密聚集的,其余的顯示為灰色,如圖下所示。
2、測(cè)試塊大小和重疊參數(shù)
由于檢索器是影響RAG性能的關(guān)鍵因素,讓我們來(lái)看看影響嵌入空間的幾個(gè)參數(shù)。TextSplitter的塊大小chunk size(1000,2000)和/或重疊overlap (100,200)參數(shù)在文檔分割期間是不同的。
對(duì)所有組合的對(duì)于輸出似乎相似,但是如果我們仔細(xì)比較正確答案和每個(gè)回答,準(zhǔn)確答案是(1000,200)。其他回答中不正確的細(xì)節(jié)已經(jīng)用紅色突出顯示。我們來(lái)嘗試使用可視化嵌入來(lái)解釋這一行為:
從左到右觀察,隨著塊大小的增加,我們可以觀察到向量空間變得稀疏且塊更小。從底部到頂部,重疊逐漸增多,向量空間特征沒(méi)有明顯變化。在所有這些映射中整個(gè)集合仍然或多或少地呈現(xiàn)為一個(gè)單一的簇,并只有幾個(gè)異常值存在。這種情況在生成的響應(yīng)中是可以看到的因?yàn)樯傻捻憫?yīng)都非常相似。
如果查詢位于簇中心等位置時(shí)由于最近鄰可能不同,在這些參數(shù)發(fā)生變化時(shí)響應(yīng)很可能會(huì)發(fā)生顯著變化。如果RAG應(yīng)用程序無(wú)法提供預(yù)期答案給某些問(wèn)題,則可以通過(guò)生成類似上述可視化圖表并結(jié)合這些問(wèn)題進(jìn)行分析,可能找到最佳劃分語(yǔ)料庫(kù)以提高整體性能方面優(yōu)化方法。
為了進(jìn)一步說(shuō)明,我們將兩個(gè)來(lái)自不相關(guān)領(lǐng)域(Grammy Awards和JWST telescope)的維基百科文檔的向量空間進(jìn)行可視化展示。
def load_doc():
loader = WebBaseLoader(['https://en.wikipedia.org/wiki/66th_Annual_Grammy_Awards','https://en.wikipedia.org/wiki/James_Webb_Space_Telescope'])
documents = loader.load()
...只修改了上面代碼其余的代碼保持不變。運(yùn)行修改后的代碼,我們得到下圖所示的向量空間可視化。
這里有兩個(gè)不同的不重疊的簇。如果我們要在任何一個(gè)簇之外提出一個(gè)問(wèn)題,那么從檢索器獲得上下文不僅不會(huì)對(duì)LLM有幫助,而且還很可能是有害的。提出之前提出的同樣的問(wèn)題,看看我們LLM產(chǎn)生什么樣的“幻覺(jué)”
Client Accelerator 6.3.0 supports the following versions of Transport Layer Security (TLS):
- TLS 1.2\2. TLS 1.3\3. TLS 1.2 with Extended Validation (EV) certificates\4. TLS 1.3 with EV certificates\5. TLS 1.3 with SHA-256 and SHA-384 hash algorithms
這里我們使用FAISS用于向量存儲(chǔ)。如果你正在使用ChromaDB并想知道如何執(zhí)行類似的可視化,renumics-spotlight也是支持的。
總結(jié)
檢索增強(qiáng)生成(RAG)允許我們利用大型語(yǔ)言模型的能力,即使LLM沒(méi)有對(duì)內(nèi)部文檔進(jìn)行訓(xùn)練也能得到很好的結(jié)果。RAG涉及從矢量庫(kù)中檢索許多相關(guān)文檔塊,然后LLM將其用作生成的上下文。因此嵌入的質(zhì)量將在RAG性能中發(fā)揮重要作用。
在本文中,我們演示并可視化了幾個(gè)關(guān)鍵矢量化參數(shù)對(duì)LLM整體性能的影響。并使用renumics-spotlight,展示了如何表示整個(gè)FAISS向量空間,然后將嵌入可視化。Spotlight直觀的用戶界面可以幫助我們根據(jù)問(wèn)題探索向量空間,從而更好地理解LLM的反應(yīng)。通過(guò)調(diào)整某些矢量化參數(shù),我們能夠影響其生成行為以提高精度。
分享名稱:可視化FAISS矢量空間并調(diào)整RAG參數(shù)提高結(jié)果精度
當(dāng)前鏈接:http://m.fisionsoft.com.cn/article/dhihidp.html


咨詢
建站咨詢
