本文 AI 產出,尚未審核

LangChain 教學:RAG 工具整合 – RetrievalQA(RAG Chain)

簡介

在資訊爆炸的時代,檢索增強生成(Retrieval‑Augmented Generation, RAG) 成為讓大型語言模型(LLM)產出更可靠、具參考價值答案的關鍵技術。LangChain 作為 LLM 應用的開發框架,提供了 RetrievalQA(又稱 RAG Chain)這條即插即用的管線,讓開發者只要幾行程式碼就能把向量資料庫、搜尋器、以及 LLM 結合起來,完成「先找、再答」的完整流程。

本篇文章將從概念說明、實作範例、常見陷阱與最佳實踐,帶你一步步建立自己的 RetrievalQA,並探討它在真實專案中的應用場景。即使你是剛接觸 LangChain 的新手,只要跟著範例走,也能快速上手並在自己的產品或服務中發揮 RAG 的威力。


核心概念

1. RAG 的三大步驟

  1. 檢索(Retrieval):從外部知識庫(如 Pinecone、FAISS、Chroma)中找出與使用者問題最相關的文件片段。
  2. 組合(Combine):將檢索到的片段與原始問題一起送給 LLM,作為「上下文」供模型參考。
  3. 生成(Generation):LLM 依據上下文產生最終答案,並可選擇返回來源文件的引用資訊。

LangChain 把這三個步驟封裝成 RetrievalQAChain,只要提供 Retriever(檢索器)與 LLM,框架會自動完成組合與生成的流程。

2. 主要組件說明

組件 角色 常見實作
LLM 生成文字的模型(如 OpenAI 的 gpt‑3.5、Claude、Gemini) ChatOpenAI, ChatAnthropic
Retriever 從向量資料庫抓取相關片段 FAISSRetriever, PineconeRetriever, ChromaRetriever
PromptTemplate 定義 LLM 接收的提示字串格式 PromptTemplate.from_template
RetrievalQAChain 把上述三者串起來的完整管線 RetrievalQA.from_chain_type

3. 為什麼使用 RetrievalQA 而不是純粹的 LLM?

  • 降低幻覺(Hallucination):模型只能根據實際檔案內容回答,減少捏造事實。
  • 即時更新:只要把新文件加入向量庫,LLM 即可即時取得最新資訊,無需重新微調模型。
  • 成本控制:只把少量相關片段送給 LLM,減少 token 使用量,降低 API 費用。

程式碼範例

以下範例採用 Node.jsLangChainJS(版本 ≥ 0.0.200),示範從本機檔案建立向量庫、建立 Retriever、並組合成 RetrievalQA。

1. 初始化環境與安裝套件

npm i langchain openai @pinecone-database/pinecone

提示:本範例使用 OpenAI 的 gpt-3.5-turbo,請先在環境變數 OPENAI_API_KEY 中設定金鑰。

2. 建立向量資料庫(以 FAISS 為例)

import { OpenAIEmbeddings } from "langchain/embeddings/openai";
import { FAISS } from "langchain/vectorstores/faiss";
import { Document } from "langchain/document";

// 讀取本機文字檔,切分成段落
const rawText = await Deno.readTextFile("./data/knowledge.txt");
const docs = rawText.split("\n\n").map(p => new Document({ pageContent: p }));

// 使用 OpenAI Embeddings 產生向量,並建立 FAISS 索引
const embeddings = new OpenAIEmbeddings();
const vectorStore = await FAISS.fromDocuments(docs, embeddings);

說明Document 物件會保留原始文字與可選的 metadata(如檔案名稱、段落編號),方便日後回溯來源。

3. 建立 Retriever

// 只取最相似的 4 個片段
const retriever = vectorStore.asRetriever({
  k: 4,                 // 取回的文件數量
  searchType: "similarity"
});

註解asRetriever 會回傳符合 LangChain 介面的 Retriever,之後可以直接交給 RetrievalQA。

4. 建立 RetrievalQAChain

import { ChatOpenAI } from "langchain/chat_models/openai";
import { RetrievalQAChain } from "langchain/chains";

// LLM 設定
const llm = new ChatOpenAI({
  modelName: "gpt-3.5-turbo",
  temperature: 0.2   // 低溫度讓答案更穩定
});

// 組合成完整的 RAG Chain
const ragChain = RetrievalQAChain.fromLLM(
  llm,
  retriever,
  {
    // 可自訂提示模板,加入「請引用來源」的指示
    promptTemplate: `以下是與問題相關的文件片段,請根據這些資訊回答問題,並在答案結尾列出來源檔案名稱。  

問題: {question}  

文件片段: {context}`
  }
);

5. 呼叫 RetrievalQA,取得答案與來源

const userQuestion = "什麼是微服務架構的優點?";

const response = await ragChain.call({ query: userQuestion });

console.log("答案:", response.text);
console.log("引用來源:", response.sourceDocuments.map(d => d.metadata.source));

結果範例

答案:微服務架構的優點包括...  
引用來源:["microservice_intro.md", "architecture_comparison.md"]

6. 進階:使用多模組檢索(Hybrid Search)

// 結合向量相似度與 BM25 關鍵字搜尋
import { HybridRetriever } from "langchain/retrievers/hybrid";

const hybridRetriever = new HybridRetriever({
  vectorStore,
  keywordRetriever: vectorStore.asKeywordRetriever(), // 內建 BM25
  k: 5,
  weightVector: 0.7,   // 向量相似度佔 70%
  weightKeyword: 0.3   // 關鍵字搜尋佔 30%
});

const hybridChain = RetrievalQAChain.fromLLM(llm, hybridRetriever);

說明:在文件長度或語意模糊時,混合檢索能提升召回率,減少「找不到答案」的情況。

7. 端到端:從資料爬蟲到即時問答

import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
import { WebBaseLoader } from "langchain/document_loaders/web/base";

// 1. 抓取網頁內容
const loader = new WebBaseLoader("https://developer.mozilla.org/zh-TW/docs/Web/JavaScript");
const rawDocs = await loader.load();

// 2. 切分成適當長度的段落
const splitter = new RecursiveCharacterTextSplitter({ chunkSize: 1000, chunkOverlap: 200 });
const splitDocs = await splitter.splitDocuments(rawDocs);

// 3. 建立向量庫 & Retriever(同前例)
// 4. 建立 RetrievalQAChain
// 5. 問答

小技巧:使用 RecursiveCharacterTextSplitter 可以避免段落過長造成 token 超限,同時保留語意完整性。


常見陷阱與最佳實踐

陷阱 可能的後果 解決方案 / 最佳實踐
向量維度與模型不匹配 檢索結果品質下降,甚至報錯 使用與 LLM 相同的 Embedding 模型(如 text-embedding-ada-002)產生向量
檔案切分過粗 單段落過長導致 LLM 超出 token 限制,答案被截斷 ~500–1000 token 為上限切分,適度加入 chunkOverlap 防止斷句
Retriever k 設太大 增加成本、答案雜訊增多 先以 k=3~5 為起點,根據實驗調整;可結合 re‑ranking(如 cross‑encoder)進一步篩選
忽略來源 metadata 無法追蹤答案來源,失去可驗證性 Document 建立時加入 metadata.source,並在 Prompt 中要求模型列出來源
Prompt 太長 超過模型 token 上限,導致錯誤或被截斷 使用 模板化 Prompt,僅插入必要的 context,可使用 truncatesummarize 前置處理
未設定 temperature 產生不穩定或過於隨機的答案 在 RAG 場景建議 temperature ≤ 0.3,確保答案聚焦於檔案內容

其他實用技巧

  1. Cache 檢索結果:對於常見問題,可將檢索到的文件快取於 Redis,減少向量庫查詢次數。
  2. 分層檢索:先用關鍵字搜尋快速過濾,再用向量相似度精煉,提升效能。
  3. 安全過濾:在 LLM 回傳前,加入 Content Moderation(OpenAI Moderation API)避免不當內容。

實際應用場景

場景 需求 RAG 解法
客服機器人 即時回答商品規格、退換貨流程 把官方說明文件、FAQ 轉成向量庫,使用 RetrievalQA 產生精準答案
內部知識庫查詢 員工查詢作業 SOP、技術文件 將公司 Wiki、GitHub README、PDF 手冊匯入向量庫,提供跨文件搜尋
法律文件審查 從大量合約中找出特定條款 結合 BM25 + 向量檢索,快速定位相關條文,LLM 再產生摘要
教育平台 為學生提供教材相關的即時解說 把教科書、課程投影片切分向量化,RAG 能根據問題給出概念說明與引用頁碼
醫療輔助 查詢藥品適應症或副作用 將藥品說明書、臨床指南向量化,結合嚴格的安全過濾,提供醫師參考資訊

重點:在所有場景中,答案可追溯性(來源標示)是 RAG 最大的價值,讓使用者能自行驗證與深入閱讀原始資料。


總結

RetrievalQA(RAG Chain) 為 LangChain 提供了 「先找、後答」 的完整工作流,讓開發者能在 成本、準確度、可維護性 三方面取得平衡。從向量資料庫的建置、Retriever 的調校,到 Prompt 的設計與最佳實踐,只要掌握以下三個關鍵點,就能在各種應用領域快速部署高品質的問答系統:

  1. 向量化與切分:確保文件切分適當、向量模型與 LLM 相容。
  2. 檢索參數:合理設定 k、混合檢索與 re‑ranking,提升相關度。
  3. Prompt 與來源:在 Prompt 中明確要求列出來源,並使用低 temperature 讓答案更穩定。

只要依照本文提供的程式碼範例與最佳實踐,你就能在 數小時內 建立一套可在生產環境使用的 RAG 系統,為產品、服務或內部流程注入 AI 的智慧與效率。祝開發順利,期待看到你用 LangChain 打造的精彩應用!