目錄
- 一、從一個簡單的問題開始
- 二、語言模型“閉卷考試”的困境
- 三、RAG 是什么—LLM 的現實世界“外掛”
- 四、RAG 的七步流程
- 第一步:加載數據(Load)
- 第二步:切分文本(Chunking)
- 第三步:向量化(Embedding)
- 向量化:把句子變成“可以計算距離”的坐標點
- 向量化模型做了啥?
- 相似度怎么計算?
- 總結一下
- 第四步:存入向量數據庫(Vector Store)
- 第五步:接收用戶問題(Query)
- 第六步:檢索相關文段(Retrieve)
- 第七步:組織 Prompt,交給大模型生成回答(Generate)
- 總結
如果關注 AI 領域,那么 RAG 這個名詞你肯定不陌生,這篇文章,我們就來揭開它的神秘面紗。為什么需要 RAG,它到底是什么,能解決什么問題。
一、從一個簡單的問題開始
假設你在和一個 AI 聊天助手對話,你問它:
“北京到上海高鐵多久?”
這看起來像個非常簡單的問題,但它考驗的卻是 AI 模型的知識廣度和知識時效性。
你希望它能回答類似這樣:
“大約 4.5 到 6 小時,具體取決于車次。”
但是,假設這個 AI 模型訓練得比較早,它可能回答是——
“我不知道。”
或者:
“我認為北京和上海之間目前沒有高鐵。”(因為它只看到了 2010 年以前的數據)
這就暴露出一個大語言模型的通病:
訓練完就定格了,它不會自己更新知識。
二、語言模型“閉卷考試”的困境
所有的大語言模型(如 GPT、Claude、Gemini)在訓練時都要讀取大量文本,比如:
- 維基百科
- 新聞網站
- Reddit 論壇
- Github 代碼
- 開放書籍、論文
訓練結束后,它就像一個“背書高手”,記住了大量的知識。但這也意味著一但遇到新知識
、實時內容
、你私有的數據
,它就歇菜了。
所以問題就來了:怎么讓模型既有“語言能力”,又能隨時“看資料再回答”呢?
這時候就該 RAG 登場了!
三、RAG 是什么—LLM 的現實世界“外掛”
RAG,全稱是 Retrieval-Augmented Generation,翻譯為“檢索增強生成”。
通過字面意思也能看出來它的核心作用,通過檢索來增強生成(廢話)
用通俗話來講:
它讓 AI 在回答之前,先“查資料”,再用大模型來“組織語言”。
就像你考試的時候如果不確定答案,那就翻課本,然后用自己的話組織一段回答。
想象一個真實的場景,比如你在一家 SaaS 公司,客戶經常問你:
- “你們的產品怎么綁定企業微信?”
- “有沒有 API 文檔?”
- “怎么開具發票?”
這些內容,可能都寫在:
- 幫助中心文檔
- FAQ 文檔
- 客服聊天記錄
- 內部知識庫
而傳統的 ChatGPT 模型對這些你們內部的這些專屬知識一無所知。
這時候你就可以用 RAG,它的基本流程是:
- 用戶提問
- 在你的知識庫里“檢索”相關文檔段落(比如找到 API 文檔那一段)
檢索
- 把這些內容和用戶問題一起送進語言模型
增強
- 生成一個有針對性的、個性化的回答。
生成
這樣的系統既懂你公司,又能寫好回答。
所以 RAG 的核心優勢顯而易見:
優點 | 解釋 |
---|---|
實時更新 | 你改了文檔,模型就能學會新內容,不需要重新訓練 |
私有知識 | 可以在不暴露給外部模型的前提下使用公司內部數據 |
可控性強 | 檢索什么,傳給模型什么,你可以干預整個過程 |
更少幻覺 | 模型參考真實資料后,不容易瞎編 |
所以,總的來說,大語言模型就像是通用的大腦,RAG 則讓它接入你自己的知識,RAG 不是讓模型更“聰明”,而是讓它更“有見識”。
通過上面的描述,RAG 聽起來很簡單嘛。
但真正的 RAG 系統背后可是有很多技術細節:
- 文檔如何分段(chunking)
- 怎樣計算用戶問題和文檔的“語義相似度”(向量檢索)
- 檢索出幾條內容?怎么拼接 Prompt?
- 模型是否支持多輪記憶和上下文壓縮?
- 如何緩存和優化響應速度?
等等,這些都會影響最終效果。
四、RAG 的七步流程
我們已經大致了解了 RAG 的原理,現在我們就從宏觀視角來看看 RAG 的全流程是怎么樣的。
第一步:加載數據(Load)
RAG 的第一步,就是從你現有的資料中**“把內容讀進來”**。比如我們加載一份 FAQ 文檔:
import { TextLoader } from "langchain/document_loaders/fs/text";const loader = new TextLoader("docs/faq.txt");
const rawDocs = await loader.load();
輸出結果是一個標準格式:
[{pageContent: "退訂說明:用戶如需退訂,請登錄控制臺,點擊賬戶管理。",metadata: { source: "faq.txt" }},...
]
這就像是把原始文檔清洗成結構化文本,供后續使用。
第二步:切分文本(Chunking)
為什么要切分?因為文檔太大了,大模型一次吃不下。
我們需要把文檔拆成段落級別的小塊(chunk),通常每塊控制在幾百字以內。
切分工具(在 langchain.js 中):
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";const splitter = new RecursiveCharacterTextSplitter({chunkSize: 500,chunkOverlap: 50
});
const docs = await splitter.splitDocuments(rawDocs);
第三步:向量化(Embedding)
現在我們已經把文檔切分了,但是有一個問題:
計算機如何知道,兩個句子意思相近?
比如下面這兩個問法:
- “怎么取消訂閱?”
- “我不想繼續用了,怎么退?”
我們人類一看就知道是同一個意思。可對計算機來說,它只看到一串字符,完全不懂“語義”。
那怎么辦?
我們需要給它一種能“看出意思相似”的方式,這就是向量化。
向量化:把句子變成“可以計算距離”的坐標點
你可以把“向量化”想象成這樣的過程:
我們給每個句子分配一個“坐標點”,讓相近意思的句子靠得近,差很多的句子離得遠。
比如:
句子 | 向量(簡化表示) |
---|---|
“怎么退訂服務?” | [0.9, 0.1, 0.4] |
“不想用了怎么辦?” | [0.88, 0.12, 0.45] |
“產品價格是多少?” | [0.1, 0.8, 0.9] |
你可以把每個向量想象成一個坐標點在三維空間中:
- 第一個句子和第二個句子很靠近(表示意思差不多)
- 第三個句子在遠處(表示是完全不同的問題)
于是我們就可以計算兩個句子之間的“距離”,這個距離越近,它們的意思就越像。
這就是所謂的**“語義相似度計算”**。
向量化模型做了啥?
現在的語言模型已經很強大,它們會從大量語料中學會如何把意思相近的詞語、句子放到更接近的坐標位置上。
你只要給它一句話,它就會返回一個長長的向量,比如:
[0.12, -0.03, 0.77, ..., 0.01] // 長度可能是 1536 維
雖然我們看不懂這個向量長啥樣,但這沒關系——我們只需要知道:它可以拿來計算“相似度”
相似度怎么計算?
最常用的方式就是:
計算兩個向量的夾角是否接近(余弦相似度)
可以理解為:
- 兩個方向完全一樣的箭頭,表示“非常相似”
- 兩個方向差很多,說明“幾乎沒關系”
總結一下
概念 | 通俗理解 |
---|---|
向量 | 把一個句子的意思表示成一組數字坐標 |
向量化 | 把句子轉成向量(embedding 模型來做) |
相似度 | 比較兩個向量距離近不近,距離越近意思越相近 |
所以,向量化的本質就是:把語言變成“可以比較距離的東西”,讓計算機能看出語義像不像。
第四步:存入向量數據庫(Vector Store)
我們把每段文本 + 它的向量
都存到一個數據庫里,方便后續檢索。
可用的數據庫有:
- FAISS(本地)
- Pinecone / Weaviate / Chroma(云服務)
- Milvus(工業級)
示例(用 FAISS):
import { FaissStore } from "langchain/vectorstores/faiss";const store = await FaissStore.fromDocuments(docs, embeddings);
現在,你就有了一個可以按語義相似度查內容的數據庫了。
第五步:接收用戶問題(Query)
終于輪到用戶提問了,比如:
“怎么退訂你們的服務?”
這個問題會經過同樣的向量化過程,再去數據庫中查最接近的問題片段。
第六步:檢索相關文段(Retrieve)
將用戶問題的向量丟進數據庫,找出前幾段最相似的內容(通常是 top-3 或 top-5):
const results = await store.similaritySearch("怎么退訂服務?", 3);
返回類似:
["退訂說明:請登錄控制臺,點擊賬戶管理頁面...","退訂功能位于控制臺左側菜單欄...",...
]
這就是查資料的部分。
第七步:組織 Prompt,交給大模型生成回答(Generate)
最后,我們把:
- 用戶問題
- 檢索到的文檔片段
組織成一個 Prompt,交給 LLM:
const prompt = `
你是一個客服助手,請參考以下內容回答用戶問題:資料:
---
1. ${results[0]}
2. ${results[1]}
3. ${results[2]}
---用戶提問:
怎么退訂服務?請根據資料,用簡潔的語言回答:
`;
然后喂給 OpenAI 或其他模型:
const res = await llm.call(prompt);
得到最終回答:
“您好,您可以登錄控制臺,進入‘賬戶管理’,點擊‘退訂管理’即可操作退訂。”
至此,一個完整的 RAG 流程就完成了。
當然這只是最簡單籠統的流程介紹,具體的每個環節都是很復雜的,比如算法的選取以及參數的調整等等等等…
總結
RAG = 查文檔 + 用大模型答題,RAG 本質上讓 LLM 具備了實時訪問企業知識庫的能力,既規避了幻覺,又能針對性回答個性化問題。