實(shí)戰(zhàn):從零搭建檢索增強(qiáng)生成問(wèn)答系統(tǒng))
1. 項(xiàng)目概述為什么RAG是當(dāng)下AI應(yīng)用開(kāi)發(fā)者的必修課最近和不少剛?cè)胄蠥I應(yīng)用開(kāi)發(fā)的朋友聊天發(fā)現(xiàn)一個(gè)挺普遍的現(xiàn)象大家一上來(lái)就想搞個(gè)大新聞琢磨著怎么用大模型直接生成一篇萬(wàn)字長(zhǎng)文或者讓AI寫(xiě)個(gè)復(fù)雜的程序。結(jié)果往往是模型要么“一本正經(jīng)地胡說(shuō)八道”要么給出的答案過(guò)于籠統(tǒng)離實(shí)際業(yè)務(wù)需求差了十萬(wàn)八千里。折騰半天信心受挫覺(jué)得大模型也就那么回事。如果你也有類似的困惑那今天聊的RAG技術(shù)可能就是解開(kāi)你心結(jié)的那把鑰匙。RAG全稱是檢索增強(qiáng)生成。這名字聽(tīng)起來(lái)有點(diǎn)學(xué)術(shù)但它的核心思想非常樸素讓大模型在回答問(wèn)題時(shí)先去看看“參考資料”。你可以把它想象成一個(gè)超級(jí)學(xué)霸的考試策略。一個(gè)只靠死記硬背模型參數(shù)的學(xué)霸面對(duì)開(kāi)放性問(wèn)題時(shí)可能會(huì)卡殼或跑偏。但RAG賦予了這個(gè)學(xué)霸一項(xiàng)特權(quán)——開(kāi)卷考試。當(dāng)問(wèn)題來(lái)臨時(shí)它先快速地從指定的資料庫(kù)比如公司內(nèi)部文檔、產(chǎn)品手冊(cè)、最新的行業(yè)報(bào)告里檢索出最相關(guān)的幾段內(nèi)容然后結(jié)合這些“參考資料”和自己的知識(shí)儲(chǔ)備組織出一個(gè)更精準(zhǔn)、更可靠的答案。對(duì)于AI大模型的小白和初級(jí)開(kāi)發(fā)者而言直接微調(diào)一個(gè)動(dòng)輒百億參數(shù)的大模型無(wú)論是數(shù)據(jù)準(zhǔn)備、計(jì)算資源還是技術(shù)門檻都像是一座難以逾越的高山。而RAG提供了一條更務(wù)實(shí)、更高效的路徑。它不要求你改動(dòng)大模型本身而是通過(guò)“外部知識(shí)庫(kù)檢索”的方式低成本、快速度地讓通用大模型具備“領(lǐng)域?qū)<摇钡哪芰Αo(wú)論是構(gòu)建一個(gè)能回答產(chǎn)品問(wèn)題的智能客服一個(gè)能基于內(nèi)部資料撰寫(xiě)報(bào)告的分析助手還是一個(gè)能理解個(gè)人知識(shí)庫(kù)的私人秘書(shū)RAG都是目前最主流、最成熟的解決方案。接下來(lái)我們就一起拆解這套“開(kāi)卷考試”系統(tǒng)是如何搭建的以及過(guò)程中有哪些你一定會(huì)踩的坑和必須掌握的技巧。2. RAG系統(tǒng)的核心架構(gòu)與工作流程拆解一個(gè)完整的RAG系統(tǒng)遠(yuǎn)不止是“檢索”加“生成”那么簡(jiǎn)單。它是一個(gè)精心設(shè)計(jì)的流水線每個(gè)環(huán)節(jié)的細(xì)節(jié)都直接影響最終答案的質(zhì)量。我們可以把它拆解為四個(gè)核心階段文檔處理、索引構(gòu)建、檢索召回和增強(qiáng)生成。理解這個(gè)流程是后續(xù)一切實(shí)操的基礎(chǔ)。2.1 文檔處理從原始資料到“可檢索”的片段這是所有工作的起點(diǎn)也是最容易埋下隱患的環(huán)節(jié)。你的原始數(shù)據(jù)可能是PDF、Word、網(wǎng)頁(yè)、甚至是數(shù)據(jù)庫(kù)里的記錄。RAG系統(tǒng)無(wú)法直接理解這些格式必須將它們轉(zhuǎn)化為結(jié)構(gòu)化的文本片段這個(gè)過(guò)程通常稱為“文本分塊”。分塊策略是這里的靈魂。很多人一開(kāi)始會(huì)簡(jiǎn)單粗暴地按固定字符數(shù)比如每500字切分這往往會(huì)導(dǎo)致災(zāi)難性的后果。想象一下一個(gè)重要的表格被從中間切斷或者一個(gè)問(wèn)題的答案恰好跨在兩個(gè)分塊之間檢索時(shí)就會(huì)丟失關(guān)鍵信息。我常用的策略是結(jié)合多種方式基于語(yǔ)義的分割利用句號(hào)、換行符等自然語(yǔ)言邊界進(jìn)行初步分割。這對(duì)于格式規(guī)整的文檔很有效。遞歸分割對(duì)于長(zhǎng)段落如果按語(yǔ)義分割后塊仍然太大再按字符數(shù)進(jìn)行二次分割。這保證了塊的大小在一定范圍內(nèi)既不會(huì)太大包含無(wú)關(guān)信息影響檢索精度也不會(huì)太小丟失上下文。重疊分割這是提升效果的關(guān)鍵技巧。在分割時(shí)讓相鄰的文本塊有一小部分內(nèi)容重疊例如前一個(gè)塊的后100字也是下一個(gè)塊的前100字。這能有效防止完整的語(yǔ)義單元被割裂確保檢索時(shí)即使邊界稍有偏差也能捕獲到核心內(nèi)容。實(shí)操心得分塊大小沒(méi)有黃金標(biāo)準(zhǔn)需要根據(jù)你的文檔類型和查詢特點(diǎn)進(jìn)行調(diào)試。技術(shù)文檔可能適合300-500字的小塊而分析報(bào)告可能需要800-1000字的大塊來(lái)保持論證的完整性。一個(gè)實(shí)用的方法是用一批典型問(wèn)題去測(cè)試不同分塊策略下的檢索效果選擇召回相關(guān)片段最準(zhǔn)的策略。2.2 索引構(gòu)建將文本轉(zhuǎn)化為機(jī)器理解的“指紋”分塊后的文本對(duì)人類是清晰的但對(duì)計(jì)算機(jī)依然是一堆符號(hào)。我們需要將其轉(zhuǎn)化為一種數(shù)學(xué)形式以便進(jìn)行快速相似度比較這就是嵌入的過(guò)程。嵌入模型就像一個(gè)“語(yǔ)義編碼器”它把一段文本無(wú)論長(zhǎng)短映射到一個(gè)高維空間比如768維或1024維中的一個(gè)點(diǎn)這個(gè)點(diǎn)就是該文本的向量表示。關(guān)鍵特性在于語(yǔ)義相似的文本它們的向量在空間中的距離通常用余弦相似度衡量會(huì)很接近。例如“如何訓(xùn)練一個(gè)神經(jīng)網(wǎng)絡(luò)”和“深度學(xué)習(xí)模型訓(xùn)練步驟”這兩個(gè)句子的向量就會(huì)靠得很近。選擇嵌入模型是另一個(gè)決策點(diǎn)。對(duì)于中文場(chǎng)景我強(qiáng)烈推薦BGEBAAI General Embedding系列模型如BGE-large-zh。它由智源研究院開(kāi)源在中文語(yǔ)義相似度任務(wù)上表現(xiàn)非常出色并且針對(duì)檢索任務(wù)進(jìn)行了優(yōu)化。對(duì)于剛開(kāi)始的項(xiàng)目完全可以從Hugging Face下載這些開(kāi)源模型在本地運(yùn)行成本可控。生成所有文本塊的向量后我們需要一個(gè)高效的系統(tǒng)來(lái)存儲(chǔ)它們并能快速找出與問(wèn)題向量最接近的那些塊。這就是向量數(shù)據(jù)庫(kù)的職責(zé)。它不像傳統(tǒng)數(shù)據(jù)庫(kù)那樣按行和列查找而是專門為高維向量的近似最近鄰搜索優(yōu)化。2.3 檢索召回大海撈針快準(zhǔn)穩(wěn)當(dāng)用戶提出一個(gè)問(wèn)題時(shí)系統(tǒng)會(huì)先用同樣的嵌入模型將問(wèn)題轉(zhuǎn)化為一個(gè)查詢向量。接著向量數(shù)據(jù)庫(kù)的任務(wù)就是在數(shù)百萬(wàn)甚至數(shù)十億的向量中快速找到與這個(gè)查詢向量最相似的Top K個(gè)文本塊例如最相似的5個(gè)。這個(gè)過(guò)程就是檢索召回。這里面的核心技術(shù)是近似最近鄰搜索算法。它犧牲一點(diǎn)點(diǎn)精度換來(lái)搜索速度的巨大提升。主流的向量數(shù)據(jù)庫(kù)如FAISS、Milvus、Chroma都內(nèi)置了高效的算法。FAISS是Meta開(kāi)源的庫(kù)輕量、高效非常適合作為入門選擇和中小規(guī)模數(shù)據(jù)量的場(chǎng)景。Milvus則是一個(gè)功能更全面的分布式向量數(shù)據(jù)庫(kù)支持持久化、動(dòng)態(tài)數(shù)據(jù)更新等生產(chǎn)級(jí)特性。檢索的質(zhì)量直接決定了生成答案的上限。如果檢索回來(lái)的都是不相關(guān)的文檔再?gòu)?qiáng)大的大模型也編不出正確答案。因此優(yōu)化檢索是RAG項(xiàng)目中最需要下功夫的地方之一。2.4 增強(qiáng)生成給大模型“劃重點(diǎn)”檢索到相關(guān)的文本片段后并不是簡(jiǎn)單地把它們?nèi)咏o大模型就完事了。我們需要精心構(gòu)造一個(gè)“提示詞”將用戶的問(wèn)題和這些參考資料組合起來(lái)交給大模型去生成最終答案。一個(gè)典型的提示詞模板如下請(qǐng)你基于以下提供的上下文信息來(lái)回答問(wèn)題。如果上下文信息中包含答案請(qǐng)嚴(yán)格依據(jù)上下文回答如果上下文信息不足以回答問(wèn)題請(qǐng)直接回答“根據(jù)提供的信息我無(wú)法回答該問(wèn)題”不要編造信息。 上下文信息 {這里拼接檢索到的文本塊每個(gè)塊用分隔符如“---”隔開(kāi)} 問(wèn)題{用戶的實(shí)際問(wèn)題} 請(qǐng)根據(jù)上下文信息回答問(wèn)題這個(gè)模板做了幾件關(guān)鍵事明確指令要求模型基于上下文回答抑制其內(nèi)部知識(shí)的隨意發(fā)揮。設(shè)置安全邊界當(dāng)信息不足時(shí)要求模型承認(rèn)未知避免幻覺(jué)。結(jié)構(gòu)化輸入清晰地將上下文與問(wèn)題分離幫助模型理解任務(wù)。最終大模型如GPT-4、Claude、或開(kāi)源的Qwen、ChatGLM會(huì)接收這個(gè)增強(qiáng)后的提示并生成一個(gè)融合了檢索知識(shí)的、有針對(duì)性的回答。至此一個(gè)完整的RAG流程就走通了。3. 核心組件深度解析Embedding模型與向量數(shù)據(jù)庫(kù)選型理解了流程我們?cè)賮?lái)深入看看兩個(gè)最核心的技術(shù)組件Embedding模型和向量數(shù)據(jù)庫(kù)。它們的選擇和配置是項(xiàng)目成敗的技術(shù)基石。3.1 Embedding模型語(yǔ)義理解的尺子Embedding模型的質(zhì)量直接決定了你的檢索系統(tǒng)“理解”文本的能力。一把不準(zhǔn)的尺子量什么都量不對(duì)。開(kāi)源 vs. 閉源/API對(duì)于初學(xué)者和大多數(shù)應(yīng)用場(chǎng)景我建議從開(kāi)源模型開(kāi)始。像前面提到的BGE系列還有text2vec、m3e等都是優(yōu)秀的中文開(kāi)源選擇。它們的好處是零成本下載后本地推理沒(méi)有API調(diào)用費(fèi)用。數(shù)據(jù)隱私敏感數(shù)據(jù)無(wú)需上傳到第三方。可定制理論上可以用自己的數(shù)據(jù)進(jìn)一步微調(diào)雖然對(duì)大多數(shù)RAG場(chǎng)景不是必須的。而OpenAI的text-embedding-ada-002等API服務(wù)優(yōu)勢(shì)在于開(kāi)箱即用的穩(wěn)定性和性能適合快速原型驗(yàn)證或?qū)Τ杀静幻舾小⒆非笫∈碌膱?chǎng)景。但你需要考慮數(shù)據(jù)出境、長(zhǎng)期成本以及API穩(wěn)定性等問(wèn)題。模型維度與性能權(quán)衡嵌入向量的維度如768、1024越高通常能承載更豐富的語(yǔ)義信息但也會(huì)帶來(lái)更大的存儲(chǔ)開(kāi)銷和稍慢的檢索速度。對(duì)于千萬(wàn)級(jí)以下的文檔塊768維的模型如BGE-base-zh通常已經(jīng)足夠。只有在語(yǔ)義非常復(fù)雜或?qū)纫髽O高的場(chǎng)景下才需要考慮1024維或更高維度的模型。一個(gè)常見(jiàn)的“坑”你在運(yùn)行RAG項(xiàng)目時(shí)可能會(huì)遇到類似“No embedding model is loaded. Set rag_embedding_model to a valid sentence_transformers model.”這樣的錯(cuò)誤。這幾乎總是因?yàn)榄h(huán)境配置問(wèn)題。以使用sentence-transformers庫(kù)加載BGE模型為例正確的姿勢(shì)是# 首先確保安裝了正確的庫(kù) pip install sentence-transformers # 在代碼中明確指定模型路徑或名稱 from sentence_transformers import SentenceTransformer model SentenceTransformer(BAAI/bge-large-zh-v1.5) # 使用明確的模型標(biāo)識(shí)如果網(wǎng)絡(luò)環(huán)境導(dǎo)致下載失敗你可以先手動(dòng)從Hugging Face倉(cāng)庫(kù)下載模型文件到本地然后從本地路徑加載model SentenceTransformer(‘/your/local/path/to/bge-model’)。3.2 向量數(shù)據(jù)庫(kù)海量向量的管家當(dāng)你的文本塊達(dá)到萬(wàn)級(jí)甚至百萬(wàn)級(jí)時(shí)線性遍歷比較所有向量是不現(xiàn)實(shí)的。向量數(shù)據(jù)庫(kù)通過(guò)引入索引結(jié)構(gòu)實(shí)現(xiàn)了亞秒級(jí)的海量檢索。FAISS輕量高效的瑞士軍刀FAISS不是一個(gè)完整的數(shù)據(jù)庫(kù)而是一個(gè)由Meta開(kāi)發(fā)的庫(kù)。它非常適合集成到你的應(yīng)用代碼中。優(yōu)點(diǎn)極其高效內(nèi)存/磁盤占用相對(duì)較小API簡(jiǎn)單學(xué)習(xí)成本低。缺點(diǎn)本身不提供持久化、多用戶并發(fā)、增刪改查等數(shù)據(jù)庫(kù)特性。你需要自己處理向量數(shù)據(jù)的保存和加載。典型使用場(chǎng)景文檔數(shù)量在百萬(wàn)以內(nèi)且文檔更新不頻繁的離線或半離線場(chǎng)景。例如一個(gè)每周更新一次知識(shí)庫(kù)的內(nèi)部問(wèn)答系統(tǒng)。Milvus / PGVector生產(chǎn)級(jí)的選擇當(dāng)你的項(xiàng)目需要邁向生產(chǎn)環(huán)境時(shí)就需要考慮更全面的解決方案。Milvus專為向量搜索設(shè)計(jì)的數(shù)據(jù)庫(kù)。它支持分布式部署、數(shù)據(jù)持久化、動(dòng)態(tài)插入/刪除、豐富的索引類型IVF_FLAT, HNSW等和監(jiān)控功能。它像是一個(gè)為向量數(shù)據(jù)量身定做的MySQL。PGVector是PostgreSQL的一個(gè)擴(kuò)展。如果你的技術(shù)棧本身就在用PostgreSQL并且向量數(shù)據(jù)規(guī)模不是特別巨大比如億級(jí)別以下PGVector是一個(gè)極其優(yōu)雅的選擇。它讓你能用熟悉的SQL語(yǔ)句同時(shí)處理結(jié)構(gòu)化數(shù)據(jù)和向量數(shù)據(jù)簡(jiǎn)化了技術(shù)架構(gòu)。選型建議快速驗(yàn)證想法用FAISS幾行代碼就能跑起來(lái)。中小型生產(chǎn)應(yīng)用文檔更新不頻繁FAISS 定期全量重建索引。中大型生產(chǎn)應(yīng)用需要實(shí)時(shí)更新、高并發(fā)首選Milvus。已有PostgreSQL且希望統(tǒng)一數(shù)據(jù)管理PGVector。注意事項(xiàng)無(wú)論選擇哪種索引類型的參數(shù)調(diào)優(yōu)如HNSW中的efConstruction和M參數(shù)都會(huì)顯著影響檢索速度和精度。通常需要在構(gòu)建時(shí)間和查詢精度之間做權(quán)衡。對(duì)于初期項(xiàng)目使用庫(kù)的默認(rèn)參數(shù)是一個(gè)安全的起點(diǎn)。4. 從零搭建一個(gè)RAG問(wèn)答系統(tǒng)實(shí)戰(zhàn)指南理論說(shuō)得再多不如動(dòng)手做一遍。讓我們以一個(gè)最常見(jiàn)的場(chǎng)景為例基于一組產(chǎn)品PDF手冊(cè)搭建一個(gè)智能問(wèn)答助手。我們將使用完全開(kāi)源的技術(shù)棧。4.1 環(huán)境準(zhǔn)備與依賴安裝我們選擇Python作為開(kāi)發(fā)語(yǔ)言因?yàn)樗凶钬S富的AI生態(tài)庫(kù)。# 創(chuàng)建項(xiàng)目目錄并進(jìn)入 mkdir rag-qa-demo cd rag-qa-demo # 創(chuàng)建虛擬環(huán)境推薦 python -m venv venv source venv/bin/activate # Linux/Mac # venv\Scripts\activate # Windows # 安裝核心依賴 pip install langchain langchain-community # 流行的RAG應(yīng)用框架能極大簡(jiǎn)化流程 pip install sentence-transformers # 用于加載BGE等嵌入模型 pip install faiss-cpu # FAISS庫(kù)如果不用GPU就裝cpu版本 pip install pypdf # 用于解析PDF文檔 pip install tiktoken # 用于文本分割時(shí)的長(zhǎng)度計(jì)算可選但推薦 # 大模型交互這里以調(diào)用開(kāi)源模型為例需要安裝相應(yīng)的庫(kù) # 例如使用Ollama本地運(yùn)行模型或者使用通義千問(wèn)、DeepSeek等API pip install ollama # 如果使用Ollama # 或者 pip install openai # 如果使用OpenAI/DeepSeek等兼容API的模型LangChain是一個(gè)框架它把文檔加載、分割、嵌入、檢索、提示詞組裝這些步驟都模塊化了讓我們能像搭積木一樣構(gòu)建RAG流程避免重復(fù)造輪子。4.2 文檔加載與智能分塊假設(shè)我們有一個(gè)名為product_manual.pdf的文件。我們首先需要加載并分割它。from langchain.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter # 1. 加載PDF文檔 loader PyPDFLoader(path/to/your/product_manual.pdf) documents loader.load() # 此時(shí)documents是一個(gè)包含每頁(yè)內(nèi)容的列表 # 2. 創(chuàng)建智能文本分割器 text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每個(gè)塊的最大字符數(shù) chunk_overlap100, # 塊之間的重疊字符數(shù) length_functionlen, # 計(jì)算長(zhǎng)度的方法 separators[\n\n, \n, 。, , , , ] # 分割優(yōu)先級(jí) ) # 3. 執(zhí)行分割 chunks text_splitter.split_documents(documents) print(f原始文檔被分割成了 {len(chunks)} 個(gè)文本塊。)這里的關(guān)鍵是RecursiveCharacterTextSplitter它會(huì)按照你提供的separators列表順序嘗試分割直到塊的大小符合chunk_size要求。chunk_overlap100確保了上下文連貫性。4.3 向量化與索引構(gòu)建接下來(lái)我們使用BGE模型為每個(gè)文本塊生成向量并用FAISS存儲(chǔ)起來(lái)。from langchain.embeddings import HuggingFaceEmbeddings from langchain.vectorstores import FAISS # 1. 初始化嵌入模型 # 這里使用BGE的小模型更快。對(duì)于生產(chǎn)環(huán)境可以考慮BAAI/bge-large-zh-v1.5 model_name BAAI/bge-small-zh-v1.5 embeddings HuggingFaceEmbeddings( model_namemodel_name, model_kwargs{device: cpu}, # 如果有GPU可改為 cuda encode_kwargs{normalize_embeddings: True} # 將向量標(biāo)準(zhǔn)化通常有利于余弦相似度計(jì)算 ) # 2. 將文本塊向量化并創(chuàng)建FAISS索引 vectorstore FAISS.from_documents(chunks, embeddings) # 3. 將索引保存到本地下次可直接加載無(wú)需重新計(jì)算 vectorstore.save_local(faiss_index_product_manual) print(向量索引已構(gòu)建并保存。)執(zhí)行完這段代碼后當(dāng)前目錄下會(huì)生成faiss_index_product_manual文件夾里面包含了所有向量和索引數(shù)據(jù)。這個(gè)過(guò)程可能會(huì)花費(fèi)一些時(shí)間取決于文檔大小和模型速度。4.4 檢索鏈路的組裝與問(wèn)答索引準(zhǔn)備好后我們就可以接受用戶查詢了。# 首先加載之前保存的索引 vectorstore FAISS.load_local(faiss_index_product_manual, embeddings, allow_dangerous_deserializationTrue) # 將向量庫(kù)轉(zhuǎn)換為一個(gè)檢索器可以設(shè)置返回最相似的K個(gè)結(jié)果 retriever vectorstore.as_retriever(search_kwargs{k: 4}) # 返回4個(gè)最相關(guān)的塊 # 現(xiàn)在我們模擬一個(gè)大模型。這里以使用Ollama本地運(yùn)行的Qwen2.5模型為例。 # 你需要先確保Ollama服務(wù)已啟動(dòng)并且拉取了qwen2.5:7b模型 (ollama pull qwen2.5:7b) from langchain.llms import Ollama llm Ollama(modelqwen2.5:7b, temperature0.1) # temperature調(diào)低讓答案更確定 # 使用LangChain的檢索問(wèn)答鏈它會(huì)自動(dòng)處理檢索、提示詞組裝和生成 from langchain.chains import RetrievalQA qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # 最常用的類型將所有檢索到的上下文“塞”進(jìn)提示詞 retrieverretriever, return_source_documentsTrue, # 返回源文檔便于調(diào)試 chain_type_kwargs{ prompt: ... # 這里可以傳入自定義的提示詞模板覆蓋默認(rèn)模板 } ) # 進(jìn)行問(wèn)答 query 這款產(chǎn)品的主要安全注意事項(xiàng)有哪些 result qa_chain.invoke({query: query}) print(問(wèn)題, query) print(答案, result[result]) print(\n--- 參考來(lái)源 ---) for i, doc in enumerate(result[source_documents]): print(f[片段{i1}]: {doc.page_content[:200]}...) # 打印每個(gè)來(lái)源片段的前200字符這段代碼構(gòu)建了一個(gè)完整的RAG問(wèn)答流水線。當(dāng)你提出問(wèn)題時(shí)系統(tǒng)會(huì)通過(guò)retriever從FAISS索引中找出4個(gè)最相關(guān)的文本塊。RetrievalQA鏈會(huì)將這些文本塊和你的問(wèn)題按照內(nèi)置的模板組裝成完整的提示詞。將組裝好的提示詞發(fā)送給qwen2.5:7b模型。將模型生成的答案返回給你同時(shí)附上檢索到的源文檔片段方便你驗(yàn)證答案的可靠性。5. 效果優(yōu)化與進(jìn)階技巧超越基礎(chǔ)RAG一個(gè)能跑起來(lái)的RAG系統(tǒng)只是開(kāi)始要讓其真正好用必須進(jìn)行優(yōu)化。以下是幾個(gè)提升效果的關(guān)鍵方向。5.1 檢索優(yōu)化讓召回更精準(zhǔn)基礎(chǔ)檢索可能返回一些相關(guān)但不完全對(duì)口的文檔。我們可以引入重排序技術(shù)。原理先用簡(jiǎn)單的檢索器如基于向量的相似度召回較多的候選文檔比如20個(gè)然后使用一個(gè)更精細(xì)但計(jì)算成本更高的重排序模型對(duì)這20個(gè)文檔根據(jù)與問(wèn)題的相關(guān)度進(jìn)行重新打分和排序最后只取Top 4個(gè)最好的交給大模型。好處能顯著提升最終輸入給大模型的上下文質(zhì)量從而直接提升答案質(zhì)量。對(duì)于存在大量相似文檔的場(chǎng)景尤其有效。工具可以使用BGE-reranker等專門的重排序模型LangChain也提供了CohereRerank等集成雖然Cohere是API服務(wù)。5.2 提示詞工程給模型更清晰的指令默認(rèn)的提示詞模板可能不夠好。我們可以設(shè)計(jì)更強(qiáng)大的提示詞。角色設(shè)定讓模型扮演特定角色如“你是一位嚴(yán)謹(jǐn)?shù)漠a(chǎn)品技術(shù)支持專家”。格式要求要求答案以要點(diǎn)列表形式呈現(xiàn)或先總結(jié)后詳述。引用來(lái)源要求模型在答案中注明依據(jù)的是哪個(gè)源文檔的哪部分內(nèi)容雖然模型不一定能精確定位但可以鼓勵(lì)它更忠實(shí)于上下文。分步思考對(duì)于復(fù)雜問(wèn)題可以要求模型“先一步步推理再給出最終答案”。一個(gè)進(jìn)階的提示詞模板可能長(zhǎng)這樣你是一位資深的{領(lǐng)域}專家請(qǐng)嚴(yán)格根據(jù)以下提供的上下文信息來(lái)回答用戶的問(wèn)題。 上下文 {context} /上下文 用戶的問(wèn)題是{question} 請(qǐng)你遵循以下步驟 1. 仔細(xì)分析上下文找出所有與問(wèn)題相關(guān)的內(nèi)容。 2. 綜合這些相關(guān)內(nèi)容組織你的答案。 3. 答案必須準(zhǔn)確、簡(jiǎn)潔如果上下文信息不足請(qǐng)明確告知。 4. 請(qǐng)用中文回答。 最終答案5.3 評(píng)估與迭代數(shù)據(jù)驅(qū)動(dòng)的優(yōu)化如何知道你的RAG系統(tǒng)變好了還是變差了你需要一套評(píng)估方法。構(gòu)造測(cè)試集收集或人工編寫(xiě)一批典型問(wèn)題并準(zhǔn)備好標(biāo)準(zhǔn)答案或至少是相關(guān)文檔出處。量化指標(biāo)檢索精度檢索到的Top K個(gè)文檔中有多少是真正相關(guān)的答案相關(guān)性生成的答案在多大程度上回答了問(wèn)題可以通過(guò)更強(qiáng)大的模型如GPT-4來(lái)打分事實(shí)一致性答案中的事實(shí)是否與提供的源文檔一致用于對(duì)抗幻覺(jué)持續(xù)迭代當(dāng)你調(diào)整分塊策略、更換嵌入模型或修改提示詞后跑一遍測(cè)試集用這些指標(biāo)來(lái)衡量變化。這才是工程化的做法。6. 常見(jiàn)問(wèn)題排查與實(shí)戰(zhàn)避坑指南在實(shí)際開(kāi)發(fā)中你一定會(huì)遇到各種各樣的問(wèn)題。這里我總結(jié)了一些高頻坑點(diǎn)和解決方案。6.1 檢索結(jié)果不相關(guān)這是最常見(jiàn)的問(wèn)題表現(xiàn)為答案胡言亂語(yǔ)或答非所問(wèn)。檢查嵌入模型確認(rèn)你使用的嵌入模型是否適合你的文本語(yǔ)言中文用中文模型。嘗試換一個(gè)模型如從text2vec換成BGE看看效果。調(diào)整分塊大小分塊太大包含無(wú)關(guān)信息太小則丟失上下文。嘗試將chunk_size從500調(diào)整為300或800。優(yōu)化檢索數(shù)量search_kwargs{“k”: 4}中的k值。對(duì)于簡(jiǎn)單問(wèn)題k2或3可能更精準(zhǔn)對(duì)于復(fù)雜問(wèn)題可能需要k5或6。檢查向量索引確認(rèn)構(gòu)建索引時(shí)使用的嵌入模型和查詢時(shí)使用的是同一個(gè)模型。不同模型生成的向量空間不同無(wú)法直接比較。6.2 答案出現(xiàn)“幻覺(jué)”模型無(wú)視檢索到的上下文自己編造信息。強(qiáng)化提示詞約束在提示詞中明確強(qiáng)調(diào)“嚴(yán)格根據(jù)上下文”、“如果上下文沒(méi)有就說(shuō)不知道”。使用更嚴(yán)厲的語(yǔ)氣。啟用重排序確保輸入給模型的上下文是高度相關(guān)的降低模型被無(wú)關(guān)信息干擾或覺(jué)得上下文沒(méi)用而自己發(fā)揮的概率。調(diào)整LLM參數(shù)將大模型的temperature參數(shù)調(diào)低如0.1降低其回答的隨機(jī)性使其更傾向于遵從上下文。提供更充足的上下文適當(dāng)增加檢索數(shù)量k給模型更全面的信息。6.3 處理長(zhǎng)文檔或復(fù)雜問(wèn)題的能力弱當(dāng)文檔很長(zhǎng)或問(wèn)題涉及多個(gè)方面時(shí)基礎(chǔ)RAG可能力不從心。嘗試“Map-Reduce”鏈這是LangChain提供的一種高級(jí)鏈。它將復(fù)雜問(wèn)題分解為子問(wèn)題對(duì)每個(gè)子問(wèn)題并行檢索并生成答案Map最后將所有子答案綜合成最終答案Reduce。適合摘要、多角度分析等任務(wù)。引入圖數(shù)據(jù)庫(kù)或傳統(tǒng)檢索對(duì)于高度結(jié)構(gòu)化、關(guān)系復(fù)雜的數(shù)據(jù)如知識(shí)圖譜可以將向量檢索與圖查詢結(jié)合。先用向量檢索找到相關(guān)實(shí)體再用圖數(shù)據(jù)庫(kù)查詢這些實(shí)體間的關(guān)系。6.4 系統(tǒng)性能瓶頸隨著文檔量增長(zhǎng)檢索變慢內(nèi)存占用高。索引類型選擇在FAISS或Milvus中使用更高效的索引類型如HNSW它在速度和精度上有很好的平衡。量化使用向量量化技術(shù)在可接受的精度損失下大幅減少內(nèi)存占用和加速檢索。分級(jí)檢索先使用簡(jiǎn)單的關(guān)鍵詞匹配如BM25從海量文檔中快速篩選出一個(gè)子集再在這個(gè)子集上使用精確但耗時(shí)的向量檢索。這就是經(jīng)典的“稀疏檢索稠密檢索”混合模式。搭建RAG系統(tǒng)的過(guò)程就是一個(gè)不斷遇到問(wèn)題、分析問(wèn)題、解決問(wèn)題的循環(huán)。從最簡(jiǎn)單的流程跑通到每一個(gè)環(huán)節(jié)的精細(xì)調(diào)優(yōu)每一步的提升都會(huì)直接反映在最終答案的質(zhì)量上。它不需要你具備訓(xùn)練大模型的深厚功力但非常考驗(yàn)?zāi)愕墓こ虒?shí)踐能力和對(duì)業(yè)務(wù)需求的理解深度。記住沒(méi)有一勞永逸的配置最好的系統(tǒng)永遠(yuǎn)是那個(gè)針對(duì)你的數(shù)據(jù)和問(wèn)題場(chǎng)景持續(xù)迭代出來(lái)的系統(tǒng)。