iT邦幫忙

2025 iThome 鐵人賽

DAY 27
0
AI & Data

AI 營養師 + Web3 數位健康護照系列 第 27

Day27. 個人專屬 AI 營養顧問 EP. 1:這個 FAQ 有加 RAG~

  • 分享至 

  • xImage
  •  

當個人飲食紀錄累積到一定數量時,就可以當成使用者個人的飲食參考資料,進一步讓 AI 做出更符合使用者的個人情況分析

一、加入「個人專屬顧問」功能:

https://ithelp.ithome.com.tw/upload/images/20251009/20129220FZUhunCpsg.jpg

按下「個人專屬顧問」後,會開啟 FAQ 頁面

https://ithelp.ithome.com.tw/upload/images/20251009/20129220UzB6AGam8c.jpg

二、加入 RAG 功能的 FAQ:

1. RAG 是什麼?

RAG (Retrieval-Augmented Generation) 是一種結合了「檢索」與「生成」的人工智慧技術架構。傳統的大型語言模型(LLM)像是一個知識淵博但記憶停留在過去某個時間點的「通才」,無法得知內部、私有或最新的資訊。

RAG 徹底改變了這一點。它的核心思想是:當使用者提出問題時,系統首先去一個特定的資料庫(例如:個人筆記、公司的內部文件、專案的歷史紀錄)中「檢索」最相關的資訊片段,然後將這些資訊片段連同原始問題一起「餵」給 LLM,讓它基於這些具體的、即時的資料來「生成」一個精確、有根據的回答。

簡單的說:

  • 沒有 RAG 的 LLM: 問一位小吃店的時薪工讀生關於店內全職員工的員工餐,他只能根據店內菜單上的食材自行臆測。
  • 有 RAG 的 LLM: 先把員工餐照片交給這位工讀生,然後再問他,正常情況下,是可以給出一個標準的回答。

2. 為什麼 FAQ 要導入 RAG?

  • 理解自然語言: 使用者可以用日常對話的方式提問,例如「我昨天吃的牛肉麵熱量高不高?」而不是只能搜尋「牛肉麵」。
  • 答案更精準、減少幻覺: LLM 的回答被嚴格限制在從某個資料庫中檢索到的內容。在本專案中,就是從使用者過往的飲食分析紀錄。這能有效避免 LLM「一本正經地胡說八道」。
  • 知識庫易於更新: 不需要重新訓練模型。只要有新的飲食紀錄被儲存,它就會自動成為 RAG 系統知識庫的一部分,可供即時查詢。
  • 提供答案來源: RAG 系統可以輕易地告訴使用者,答案是根據哪幾筆歷史紀錄來生成的,大大的提升答案的可信度。

三、先寫測試

1. TDD 的基本流程是「紅燈 -> 綠燈 -> 重構」:

  1. 寫一個失敗的測試(紅燈):
    先針對一個期望的功能,寫一個測試案例。在功能還沒開發前,這個測試肯定是失敗的。
  2. 寫最少的程式碼讓測試通過(綠燈):
    接著開始實作 RAG 的核心邏輯(索引、檢索、生成),目標是讓剛剛那個測試案例成功通過。
  3. 重構(Refactor):
    測試通過後,就可以安心地整理和優化程式碼。

2. 如何在專案中實踐TDD?

以專案中的 tests/test_rag_service.py 檔案為例:

步驟一:定義期望行為,寫下失敗的測試 (紅燈)

期望 RAG 系統能做到兩件事:

  1. 正確地為文件建立索引。
  2. 根據關鍵字查詢到正確的文件。

所以,可以先寫下一個像 test_index_and_query 這樣的測試函式,由於此時專案的 rag_service.pyrebuild_indexquery_records 函式都還沒寫,因此這個測試絕對是無法通過的(紅燈)。

def test_index_and_query(app):
    """測試 index_record 與 query_records 的基本行為。"""
    with app.app_context():
        # 1. 準備 (Arrange): 建立兩筆測試資料
        db.create_all()
        r1 = create_dummy_record(app, {
            'summary': '牛肉麵,高蛋白,熱量高',
            # ... 其他欄位
        })
        r2 = create_dummy_record(app, {
            'summary': '沙拉,低卡路里,富含纖維',
            # ... 其他欄位
        })

        # 2. 執行 (Act): 呼叫將要開發的函式
        rebuild_index()

        # 3. 斷言 (Assert): 驗證結果是否符合預期
        # 斷言 1: 索引應該被建立了
        assert len(INVERTED_INDEX) > 0

        # 斷言 2: 查詢「牛肉」時,應該要能找到 r1 這筆紀錄
        res = query_records('牛肉', top_k=2)
        assert any(r['id'] == r1.id for r in res)

步驟二:寫最少的程式碼讓測試通過 (綠燈)

接著,請在 rag_service.py 中,加入 rebuild_indexquery_records 兩個函式,目的就是讓上面這個測試從失敗變為成功。

  • rebuild_index 的程式碼需要遍歷資料庫中的 AnalysisRecord,並將 summary 等欄位後,填入 INVERTED_INDEX 這個全域變數中。
  • query_records 的程式碼需要接收一個查詢詞(如 '牛肉'),去 INVERTED_INDEX 中找到對應的文件 ID,然後回傳文件的資訊。

只要這兩個函式能滿足測試中的 assert 條件,測試就會通過(綠燈)。

步驟三:重構 (Refactor)

測試通過後,就可以安心地進行優化 rebuild_indexquery_records 的程式碼。例如:

  • 提高 tokenize 的準確度。
  • query_records 加入更複雜的評分機制或 fallback 策略。
  • 改善程式碼的可讀性或效能。

每做一次修改,就要重新執行一次測試。只要測試依然是綠燈,就代表重構是OK的(沒有破壞原有的功能)。


上一篇
Day26. 手動測試已經測到厭世了嗎?這次就請 AI 幫忙測:Chrome DevTools MCP 自動測試
系列文
AI 營養師 + Web3 數位健康護照27
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言