問題所在:一位聰明卻看不到你檔案的實習生
到這一步你已經明白,大型語言模型本質是一個在「凍結」的文本快照上訓練出來的下一詞預測器。那份快照就是模型的全部世界。問它你公司的退款政策、上週的事故報告,或一份它從沒見過的合約,它只有兩個選擇:承認不知道,或者——更常見地——給出一個流暢、像模像樣、卻完全編造的答案。這種自信的編造叫幻覺,它不是靠改提示詞就能消除的 bug。
把模型想成一位才華橫溢的新實習生:他讀過大半個公開網際網路,卻完全打不開你的檔案櫃。他不是故意撒謊,只是用「聽起來對」的內容去填空白。解法既顯而易見又很人性化:提問之前,先把相關頁面遞給他。檢索增強生成正是如此——取出正確的文件,貼進提示裡,再發問。模型於是基於你提供的文本來推理,而不是憑記憶瞎猜。
嵌入:把語義變成座標
要把對的頁面遞給模型,你得先找到它們。關鍵字搜尋在這裡會失靈:使用者問「我怎麼把錢拿回來?」而你的政策寫的是「退款資格」。沒有一個詞重合,意思卻完全一樣。讓 RAG 能跑起來的關鍵,是嵌入——一個把任意一段文本轉成一串數字(向量)的模型,使得語義相近的文本落在空間裡彼此靠近,不管用詞是否一致。
在階梯前段你已經見過這個思想,那就是 word2vec:「國王 − 男人 + 女人 ≈ 王后」。現代的嵌入模型對整句乃至整段做同樣的事,所用的正是與 LLM 同源的 Transformer 機制。每段文本都成為一個幾百乃至上千維空間裡的點。所謂「靠近」就只是幾何——通常是兩個向量間的餘弦相似度,它衡量的是兩者的夾角,而非長度。
query: "how do I get my money back?" -> [0.21, -0.05, 0.88, ...] chunk: "Refund eligibility and process" -> [0.19, -0.07, 0.85, ...] chunk: "Office holiday schedule 2026" -> [-0.4, 0.6, 0.02, ...] cosine(query, refund_chunk) = 0.94 <- near, retrieve this cosine(query, holiday_chunk) = 0.11 <- far, ignore
向量資料庫與檢索流水線
如果只有十份文件,你大可把查詢和每一份逐一比對。但真實語料庫往往有數百萬個片段,每次請求都和每個片段比一遍會慢到無法忍受。向量資料庫正是為此而生:它存下你所有的嵌入,給定一個查詢向量,便用「近似最近鄰」索引在毫秒級返回最相近的若干個。它就是讓大規模資料檢索變得可行的那台搜尋引擎。
整套流程分兩個階段。第一階段是離線的、只做一次的慢活:載入文件、切成片段、為每個片段生成嵌入、把向量存起來。第二階段是線上的快迴圈:每個使用者問題都觸發它——給問題生成嵌入、找出最近的片段、貼進提示,再要求模型只依據這些提供的文本作答。
它為何能減少幻覺——又為何無法根除
RAG 能減少幻覺,是因為它改變了任務本身。沒有它時,模型必須從被壓縮、有損的記憶裡回想出一個事實——這種回憶任務它常常做不好。有了它,模型做的是閱讀理解:答案就明明白白地擺在提示裡,於是「抄出相關句子並改寫」遠比「記住讀過的一切」來得容易、可靠得多。額外的好處是,你可以把來源段落展示給使用者,讓答案變得可核查——這是裸 LLM 永遠做不到的。
但要誠實面對它的邊界。RAG 的上限完全取決於檢索品質。如果對的片段壓根沒被取出來——切片太差、嵌入模型太弱、查詢太含糊——模型就會基於錯誤的上下文作答,或者退回到老一套的瞎猜。即便上下文完美無缺,模型仍可能與之矛盾、讀錯它,或把它和陳舊記憶混為一談。RAG 能大幅降低幻覺率,卻無法將其歸零。請把「有依據」理解成「來源更可靠」,而非「保證為真」。
把它做好——以及哪些雜訊可以忽略
搭一個初版 RAG 系統其實很簡單,這正是它迷人之處——一個週末就能跑出可用的原型。讓它可靠才是真功夫,而這功夫幾乎全在檢索,而非模型。把精力花在:怎麼切片(尊重標題和段落邊界)、怎麼嵌入(選一個強勁、新近的嵌入模型),以及加一道「重排序」——用更精細的模型把候選片段重新打分,再送進提示。關鍵字搜尋與向量搜尋的混合,通常勝過任何單獨一種。
要像對待工程產物那樣去評測它,而不是憑感覺。準備一小批答案已知的真實問題,分開衡量兩件事:檢索有沒有把對的片段撈出來(這是檢索品質問題),以及模型有沒有忠實地依據它作答(這是生成品質問題)?把這兩個分數拆開,你才知道該修哪一頭——後面講評測的幾篇會大量依賴這個習慣。同時留一個簡單的關鍵字基線在手邊也很值得,用來證明你的向量流水線確實對得起它帶來的複雜度。
最後,抵制兩種炒作。RAG 不是通往通用人工智慧的墊腳石,也不是什麼全新的記憶形式——它就是一套取文本的「管道」。另外,隨著上下文視窗越來越大,有人問能否乾脆跳過檢索、把所有東西一股腦貼進去。對單份小文件,有時確實可以。但對任何真實語料庫,灌進幾百萬個 token 更慢、更貴,反而更不準——因為模型對埋在巨大草堆裡的事實關注得更差。檢索之所以始終有用,恰恰是因為「挑選該讀什麼」本身就是關鍵所在。