所有入門單元免費開放 · 課程內容持續更新中

文件問答機器人(RAG)

讓 AI 根據你提供的文件回答問題,而且每個答案都附上出處。從切塊、向量搜尋到評估,親手做一個 RAG 系統,並知道它答錯時該從哪裡查起。

高階約 20 小時6 個里程碑

開始前,建議先完成

依建議順序排列。還沒全部完成也可以開始,遇到不會的再回去補。

  1. 10LLM API:用程式呼叫大型語言模型
  2. 11Agent 原理:工具使用與 Agent 迴圈
  3. 12RAG 知識庫:讓 AI 讀懂你的資料
  4. 03工程基本功:寫出可維護的 Python

里程碑

  1. 1

    準備文件與評估題

    選定一組文件,先寫好 20 題問題和標準答案,作為之後衡量好壞的依據。

  2. 2

    切塊與建立索引

    把文件切成段落、轉成向量並存起來,可以重新執行而不會重複建立。

  3. 3

    搜尋相關段落

    輸入一個問題,能找出最相關的幾個段落,而且人工檢查大多是對的。

  4. 4

    組合提示並附來源回答

    模型只根據找到的段落回答,標示出處;找不到答案時誠實說不知道。

  5. 5

    評估與調整

    用評估題庫跑一次分數,調整切塊或搜尋設定後再跑,記錄每次的差異。

  6. 6

    整理成可維護的專案

    拆成清楚的模組,加上測試與說明文件,別人照著說明就能執行。

為什麼做這個專案

公司裡最常聽到的問題之一是:「那份規定寫在哪裡?」員工手冊、產品說明、內部 FAQ,資料都在,只是找不到。

一般的聊天助理不知道你公司的文件內容。RAG(檢索增強生成)的做法是:先從你的文件裡找出相關段落,再交給模型根據這些段落回答。這是目前企業導入 AI 最常見的架構之一,親手做一次,你會真正理解它的強項和弱點。

RAG 的兩個階段:先把文件切塊、轉成向量、建立索引;提問時搜尋最相關的段落,和問題一起組合成提示,交給 LLM 回答並附上來源

大部分答錯的問題,原因都在「搜尋」這一步,而不是模型本身。

開始前的準備

  • 完成「LLM API」與「Agent 原理」,能用程式呼叫模型並處理回傳
  • 讀過「RAG 知識庫」單元,了解 Embedding、切塊和向量搜尋的概念
  • 熟悉「工程基本功」的虛擬環境、模組與 pytest
  • 準備一組文件。建議用公開資料練習,例如政府機關的公開問答、開源專案的說明文件,或你自己寫的筆記

實作指南

里程碑 1:準備文件與評估題

先寫考題,再寫程式。這是這個專案最重要、也最常被跳過的一步。

準備一個 eval.jsonl,每一行是一題:

{"question": "新進員工第一年有幾天特休?", "answer": "依到職滿半年後給 3 天", "source": "員工手冊.md"}

題目要涵蓋不同類型:直接查得到的、需要合併兩段的、文件裡根本沒有答案的。最後一種很重要,用來測試它會不會亂掰。

請 AI 幫你出題

以下是一份文件的內容。請幫我出 10 題問答評估題,包含 6 題能直接在文中找到答案、2 題需要合併兩個段落、2 題文中沒有答案。每題附上標準答案和出處段落。

AI 出的題目你要逐題檢查,標準答案錯了,後面的分數就都沒有意義。

里程碑 2:切塊與建立索引

最簡單的切法是依標題或段落切,再限制每塊的長度:

def chunk_by_heading(text, source, max_chars=800):
    chunks, current = [], ""
    for line in text.splitlines():
        if line.startswith("#") and current:
            chunks.append(current.strip())
            current = ""
        current += line + "\n"
        if len(current) > max_chars:
            chunks.append(current.strip())
            current = ""
    if current.strip():
        chunks.append(current.strip())
    return [{"text": c, "source": source} for c in chunks]

接著選一個 Embedding 模型把每塊轉成向量。可以用雲端服務,也可以用在本機執行的開源模型。向量和原文一起存起來,小專案用一個檔案或 SQLite 就夠了。

里程碑 3:搜尋相關段落

把問題也轉成向量,計算它和每一塊的相似度,取最高的幾塊:

import numpy as np

def top_k(query_vec, chunk_vecs, k=4):
    sims = chunk_vecs @ query_vec / (
        np.linalg.norm(chunk_vecs, axis=1) * np.linalg.norm(query_vec)
    )
    return np.argsort(sims)[::-1][:k]

先別急著接模型。拿評估題來測,人工看找到的段落裡有沒有答案。這一步的準確度,決定了整個系統的上限。

里程碑 4:組合提示並附來源回答

系統提示裡把規則講清楚:

你是公司內部文件的問答助理。
只能根據下方 <documents> 裡的內容回答。
每個重點後面標示來源,例如 [員工手冊.md]。
如果文件中沒有答案,請回答「文件中找不到這個問題的答案」,不要推測。

把找到的段落用標籤包起來放進使用者訊息,模型比較容易分清楚哪些是資料、哪些是問題。

里程碑 5:評估與調整

寫一支腳本跑完所有評估題,記錄三件事:搜尋有沒有找到正確出處、答案是否正確、沒答案的題目有沒有誠實說不知道。

答案正不正確,可以先自己判斷,題目多了再請另一個模型幫忙評分,但要抽查它評得對不對。

一次只改一個變數,例如切塊長度從 800 改成 400,再跑一次,把結果記在表格裡:

版本 切塊長度 找到正確出處 答案正確 誠實說不知道
v1 800 待填 待填 待填
v2 400 待填 待填 待填

里程碑 6:整理成可維護的專案

把程式拆成 chunking.py、index.py、retrieve.py、answer.py,為切塊和搜尋寫幾個 pytest 測試,再寫一份 README 說明怎麼安裝、建立索引和提問。

請 Coding Agent 幫你整理

請讀這個專案的所有檔案,提出一個模組拆分方案,說明每個檔案的職責。先給我方案,我同意後再動手。拆完後評估腳本的分數應該和拆之前一樣。

延伸挑戰

  • 混合搜尋:結合關鍵字搜尋和向量搜尋,比較評估分數
  • 文件更新時,只重建有變動的部分
  • 加一個簡單的網頁介面
  • 把搜尋包成一個工具,讓 Agent 自己決定什麼時候查文件
完成標準
  • 有至少 20 題評估題,其中包含文件中沒有答案的題目
  • 每個答案都標示出處,點回原文可以找到依據
  • 沒有答案的題目,機器人會說找不到,而不是亂掰
  • 有一張表格記錄至少兩個版本的評估結果
  • 專案有模組、測試和 README,換一台電腦照著做也能執行

做完了?分享你的作品!

到交流區貼上作品連結和心得,你的經驗會幫到下一個人。

前往交流區

專案討論

卡關了、有心得,或發現內容需要更新?都歡迎留言。留言使用 GitHub 帳號登入。

留言區即將開放。現在可以先到 GitHub 討論區 發問,或看看 交流頁 的其他管道。