你是否曾經問 AI 一個問題,卻得到完全不相關或錯誤的答案?傳統 LLM 只能依賴自身訓練時的知識,遇到新資料,它也只能「憑直覺回答」,結果往往出現幻覺(Hallucination)。
今天,我要帶你踏入RAG(Retrieval-Augmented Generation) 魔法迷宮,探索如何讓模型在生成答案前,先去搜尋最有價值的知識寶石,最後在 Ollama 的水晶球中生成精準且可靠的答案。✨
我站在迷宮入口,四周漂浮著卷軸和閃爍水晶,每一個都可能藏著答案。今天,我們將用 RAG 的魔法,把散落的知識碎片整合,打造可即時使用的智慧水晶球。
傳統 LLM 在生成答案時面臨幾個問題:
RAG 的解決方案很簡單:Retrieve → Augment → Generate
就像魔法師先去圖書館挑選寶石,再用水晶球鑄造答案,既快速又可靠。
核心概念
def rag(query):
hits = search(query)
prompt = build_prompt(query, hits)
answer = llm(prompt)
return answer
1️⃣ Embedding 查詢向量化 → 尋找語義寶石
將使用者問題轉換成向量(embedding),讓模型可以計算語義相似度,而不只是字面比對。
這邊使用的模型是 all-mpnet-base-v2,它會將每個句話映射成 768 維向量,並保持語義上的相似關係。例如:「什麼是向量搜尋?」與「如何進行 semantic search?」向量距離接近,代表語義相似。
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("all-mpnet-base-v2")
def get_embedding(text: str, use_sentence_transformers: bool = True) -> List[float]:
if (
use_sentence_transformers
):
vector = model.encode(text)
return vector.tolist()
2️⃣ 向量搜尋(Vector Search) → 在知識迷宮中導航
有了向量後,我們使用向量資料庫(Qdrant / Pinecone / Weaviate)進行搜尋。
Qdrant 採用 HNSW(Hierarchical Navigable Small World)演算法,像一張多層地圖:頂層快速找到大方向,底層精準定位相似向量。
chunks, sources, msg, arxiv_ids, total_hits = qdrant_client.search(
query=query,
query_vector=query_embedding,
size=5,
min_score=0.0,
)
⚡ 小提示:size 控制返回數量,min_score 過濾不夠相似的碎片。
3️⃣ 建立結構化 Prompt → 打造魔法咒語
透過結構化,我們可以指定每個知識段落的標題、來源的論文與上下文,甚至加上 系統提示(system prompt) 來設定回答風格或語氣。例如:
這樣生成的答案不僅精準,也更具可讀性與一致性。
prompt_data = langchain_client.prompt_builder.create_structured_prompt(
query, reranked, system_settings.user_language
)
4️⃣ 呼叫 LLM 生成答案 → 水晶球顯現智慧
最後一步是將整理好的 prompt 交給 LLM 生成答案。在我們的架構中,LangChain 封裝了 LLM 呼叫的細節,包括:
resp = langchain_client.llm_context(
final_prompt,
query,
user_language=system_settings.user_language,
system_prompt=system_settings.system_prompt,
)
可能會印象深刻沒錯。
qdrant_client.search
是我們曾經在 Day 5 介紹過的 "Read / 搜尋 Points"langchain_client.llm_context
是 Day 6 介紹的 "LangChain 封裝"
query_embedding = get_embedding(query)
chunks, sources, msg, arxiv_ids, total_hits = qdrant_client.search(
query=query,
query_vector=query_embedding,
size=system_settings.top_k,
min_score=0.3,
)
if chunks:
reranked = re_ranking(
chunks,
query,
vector_weight=vector_weight,
bm25_weight=bm25_weight,
) # 💡是可選步驟
prompt_data = langchain_client.prompt_builder.create_structured_prompt(
query, reranked, system_settings.user_language
)
resp = langchain_client.llm_context(
final_prompt,
query,
user_language=system_settings.user_language,
system_prompt=system_settings.system_prompt,
)
re_ranking 為可選步驟。
user_language 可支援翻譯功能,讓知識問答多語化。
structured_prompt 確保答案格式整齊。
在實務工程場景中,這套流程非常有用:
user_language
讓答案自動翻譯,適用全球化產品。今天,我不只是探索魔法迷宮,更學會了如何讓散落的知識碎片經過檢索、結構化,最終在 Ollama 的水晶球中發光。我的魔法地圖越畫越清晰,迷宮的寶石逐漸被鑑定、雕刻、整合,形成可即時使用的智慧水晶球。