iT邦幫忙

2026 iThome 鐵人賽

0

「一個真正具備靈魂的 AI Agent,必須能在長對話中維持精準的上下文記憶,並在每一次對話結束後,自動從互動中提煉精華(Active Learning),實現無需人工干預的自我進化閉環。」

先前,我們解剖了 FastAPI 主應用程式的 API 控制端點。在 /chat 的處理管線中,有兩個不可或缺的 Services Layer:
1. ConversationMemory:基於 aiosqlite 託管的對話歷程持久化資料庫,負責提供高效率的 20 輪 Sliding Window 檢索與歷史記憶壓縮。
2. LearningModule:負責在對話生成後,透過背景非阻斷任務從對話中萃取金融領域知識點,並以 0.85 相似度門檻進行去重後寫回 ChromaDB 向量庫。
今天我們將深入原始碼,解析這兩大服務模組的底層實作與防禦設計!

本篇重點摘要

  1. 剖析 ConversationMemory 的 SQLite DDL 設計、複合索引優化與 summarize_if_needed 壓縮邏輯。
  2. 拆解 LearningModule 的異步背景萃取、DEDUP_SIMILARITY_THRESHOLD = 0.85 去重演算法與累積 50 筆自動重構機制。
  3. 驗證「Fail-open / Fail-safe」防護型例外處理,確保背景學習失敗絕不干擾前台使用者對話。

一、ConversationMemory:異步 SQLite 持久化與記憶壓縮

ConversationMemory 使用 aiosqlite 實現全非阻斷式的資料庫操作,資料庫檔案預設存放在 data/conversations.db。
1. DDL 與效能索引設計
為了讓資料庫即使在累積超過 10,000 筆對話時依然能在 500 ms 內完成上下文查詢,系統建立了一個關鍵複合索引:

-- conversations 表格與索引建立
CREATE TABLE IF NOT EXISTS conversations (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id  TEXT    NOT NULL,
    role        TEXT    NOT NULL CHECK(role IN ('user', 'assistant', 'summary')),
    content     TEXT    NOT NULL CHECK(length(content) <= 10000),
    created_at  TEXT    NOT NULL DEFAULT (datetime('now', 'utc')),
    is_summary  INTEGER NOT NULL DEFAULT 0
);

-- 關鍵效能優化:針對 session_id 與 created_at 建立降冪複合索引
CREATE INDEX IF NOT EXISTS idx_session_created
    ON conversations(session_id, created_at DESC);
  2. 20 輪滑動視窗載入
     當 /chat 呼叫 load_context(session_id, limit=20) 時,模組會利用複合索引以 created_at DESC, id DESC 撈出最新的 20 筆紀錄,再透過 reversed(rows) 將其反轉為標準的時間軸順序(Oldest first),精準控管 Prompt Token 消耗。
  3. 記憶自動壓縮機制
     當同一個 Session 的對話累積達到 101 輪 時,系統會自動觸發壓縮邏輯:
        (1) 保留最新 20 輪:將前 81 輪舊對話提取出來,拼接為 summary_text。
        (2) 資料處理:開啟 SQLite Transaction,刪除舊的 81 筆記錄,並寫入一筆 role='summary'、is_summary=1 的壓縮 Turn。
        (3) 成果:將對話歷史重置為精簡的 21 輪(1 筆歷史摘要 + 20 筆近期對話),徹底解決超長對話 Token 溢位問題。

二、LearningModule:非阻斷式異步自主學習

LearningModule 是 Angelina 實現「越用越聰明」的核心。它接受 RAGEngine 與 GeminiGateway 的注入,完全在背景執行。
1. 異步背景任務與領域過濾
系統在回覆使用者後以 asyncio.create_task 觸發,不阻斷 Response 發送。
模組會呼叫 Gemini API(帶入 _EXTRACTION_SYSTEM_PROMPT),專注將對話內容分類並萃取至 5 大金融領域:
(1) 投資策略(股票、基金、資產配置)
(2) 稅務規則(稅務規劃、扣除額、資本利額)
(3) 預算原則(儲蓄率、緊急預備金)
(4) 風險管理(分散風險、停損機制)
(5) 市場數據事實(利率、指數點位、經濟指標)

  2. 餘弦相似度向量去重
     為避免重複的知識點充斥向量庫,模組在寫入前會呼叫 _rag_engine.search(query=text, top_k=1):
        (1) 去重門檻 (DEDUP_SIMILARITY_THRESHOLD = 0.85):若查詢到的最高相似度 $\ge 0.85$,認定為重複知識,直接剔除。
        (2) Fail-open 降級保護:若去重查詢過程中發生 Exception,會 Warning 並回傳 False(允許寫入),優先確保知識不會因瞬間網路異常而遺失。
        
  3. 門檻自動重構機制
     當新寫入的知識點累積達到 REBUILD_THRESHOLD = 50 筆時,模組會自動搜尋 data/notebooklm 下最新的導出檔案,並觸發 _rag_engine.rebuild_index() 重新進行全量索引優化,確保檢索品質保持在頂峰。
     

三、今日總結

透過 ConversationMemory 與 LearningModule 的代碼解剖,我們確認了:

  1. 記憶持久化與防爆:SQLite 複合索引保證了高檢索速度,101 輪自動壓縮機制則維持了 Context Window 的健康度。
  2. 零延遲自主學習:透過 asyncio.create_task、0.85 餘弦相似度去重與 50 筆自動 Rebuild 門檻,打造出了真正的 Production 級自我進化 Agent。

明日預告:敬請期待~!


上一篇
【Day 26】FastAPI Web 服務整合:/chat 與 /health API 端點實作
下一篇
【Day 28】RAG 向量引擎實作:ChromaDB 整合與語意檢索降級機制
系列文
打造零成本企業級 AI Agent:以 Gemini 2.5 Flash 構建金融分析助手與維運實戰30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言