Memory System
Agenvoy 的 memory 層針對 conversation memory 有三個層級,另加一個跨 session 的 error memory 層。
| 層級 | 後端 | 範圍 |
|---|---|---|
| 1. Context window(24 則訊息 + summary) | history.json + summary.json |
session |
| 2. 語意搜尋(近期) | ToriiDB DBSessionHist(vector) |
session |
| 3. 全文封存(全部歷史) | 透過 go-sqlkit 的 SQLite FTS5 | session |
| Error memory | ToriiDB error_memory(90 天 TTL) |
跨 session |
| 操作者筆記 | SQLite note + note_fts5(trigram) |
全域 |
三層 conversation memory
1. Context window(limits.max_history_messages,預設 24)
每個 session 完整保留最近 N 則訊息並餵入 LLM context window。更舊的內容仍留在 history.json,但不送給 LLM。
滾動式 summary(summary.json)將較舊的對話濃縮,並於每個 turn 開頭注入 system prompt,讓較舊 context 得以在 N 則訊息窗口之外存續。
增量游標: .summary_cursor(per-session;舊的 summary.meta.json 於啟動時遷移)持有 last_message_time(格式 YYYY-MM-DD HH:MM:SS,由訊息內容中的 timestamp 擷取)。每次 summary.Generate 呼叫時:
filterAfterTime(histories, cursor)只保留t > cursor的訊息- 每個 chunk 執行一次
generatePassLLM call(system prompt 已含{{.Summary}}=舊 summary,因此合併在生成期間完成 —— 無獨立mergePass,避免 2 倍成本) - 成功時,游標推進至該 chunk 的最大 timestamp +
SaveSummary觸發 mtime gate generatePass失敗 →return(不對後續 chunk 計費;下一次 cron tick 重試)
2. 語意搜尋 —— ToriiDB(近期對話)
chat_history 工具以 mode=search 搭配 match=semantic 透過 ToriiDB db.VSearch 執行 vector 相似度搜尋。每次命中觸發 context window 擴展:命中前 2 則 + 命中後 1 則。
ToriiDB 條目於 history.json compaction 期間清理 —— 早於 compact cutoff 的條目被移除,讓 ToriiDB 專注於近期對話。較舊資料存於 SQLite(層級 3)。
3. 全文封存 —— SQLite FTS5(全部歷史)
每則寫入 history.json 的訊息都會透過 go-sqlkit 雙寫至 SQLite(~/.config/agenvoy/.store/history.db)。即使 history.json 已 compact,SQLite 始終持有完整對話歷史。
chat_history 工具以 mode=search 搭配 match=keyword 對 SQLite 封存執行 FTS5 全文搜尋 + 對近期條目執行 ToriiDB 子字串比對,並合併結果。
Compaction: 當 history.json 超過 max_history_bytes(預設 5 MiB)時,最舊訊息在完整的 user+assistant pair 邊界上裁剪至 80%。cutoff timestamp 記錄於 SQLite message_meta.start_at,使 keyword 搜尋排除 history.json 已存在的條目(避免重複)。早於 cutoff 的 ToriiDB 條目亦被移除。
Backfill: 首次遇到(SQLite 對某 session 無資料但 history.json 有內容)時,整份既有歷史 backfill 進 SQLite。
Timestamps: 以 UTC unix 奈秒儲存。訊息內容中的 timestamp 透過 time.ParseInLocation(本地時區)解析並轉為 UTC 儲存。搜尋查詢使用 time.Now().UnixNano()(已為 UTC)。
執行期壓縮
除了上述儲存分層,internal/agents/exec/compact 負責把單次長時間執行維持在模型視窗內。各階段獨立,依序套用且只做到夠用為止:
| 階段 | 觸發 | 效果 |
|---|---|---|
CheckThreshold(model) |
每次迭代 | 當前模型的 token 預算——其 context window 的 80 %(Gemini 與較新 GPT 為 1 M、grok-4.5 為 500 K、其他 GPT/Grok 為 256 K、Claude 為 200 K、其餘預設 128 K) |
ToolHistory |
超出預算 | 將最舊的 tool-call 往返摘要成文字 |
ExtractOldHistories |
仍超出預算 | 把較舊的對話輪次併入滾動摘要 |
TrimFallback |
Provider 回報 context 長度錯誤 | 丟掉最舊的一組對話後重送 |
RawToolFallback |
執行途中切換模型 | 將 tool 歷史轉為純文字,讓新模型可讀 |
手動壓縮可從 TUI(/compact;/memory 指令已移除,重設改為 /reset)或 POST /v1/session/:id/memory 觸發。該端點以 action 區分:compact 丟棄較舊訊息並回傳 removed、summary 重建滾動摘要並回傳 count、reset 清空對話——mode: "summary" 保留滾動摘要,mode: "all" 一併清除。
搜尋路由
match 參數 |
來源 | 使用情境 |
|---|---|---|
semantic(預設) |
ToriiDB VSearch | 「我們討論過關於 X 的什麼?」—— 基於語意 |
keyword |
SQLite FTS5(封存)+ ToriiDB 子字串(近期) | 「找出含 'sandbox' 的訊息」—— 精確文字 |
跨 session error memory
Tool 失敗與解決它的修正方式以 90 天 TTL 存於 error_memory,跨 session 存續。只有以 outcome=resolved 寫入的紀錄會被儲存;failed / abandoned 的寫入會被丟棄,因此不再保留放棄的策略。命中時(透過關鍵字 Contains 或 db.VSearch),該條目的 TTL 透過 db.Expire 續期。
當同一 tool 名稱在未來 session 失敗時,toolCall.go 自動查詢 error_memory,把最多 3 筆相關紀錄以 related_errors 附在失敗的工具結果後;agent 套用已記錄的修正方式。
紀錄中的作法可在 web 儀表板的 Lessons 頁面編輯(PATCH /v1/torii/error,改寫 action 並保留 TTL);GET /v1/torii/error 列出紀錄。
儲存佈局
| 儲存 | 內容 | 生命週期 |
|---|---|---|
history.json |
近期訊息(hot,LLM 每 turn 讀取) | 5 MiB 時自動 compact |
ToriiDB DBSessionHist |
帶 embeddings 的近期訊息 | compact 時清理(移除早於 cutoff 的條目) |
SQLite messages |
曾寫入的所有訊息(雙寫) | reset / remove-session 時清除 |
SQLite message_meta |
start_at —— compact cutoff timestamp |
reset / remove-session 時清除 |
summary.json |
滾動式 summary blob | reset 後存續 |
ToriiDB error_memory |
已解決的 tool 錯誤記錄與其修正方式 | 90 天 TTL(命中時續期) |
Reset / remove 行為
| 操作 | history.json |
ToriiDB DBSessionHist |
SQLite(messages + meta) | summary.json |
|---|---|---|---|---|
| Compact(自動) | 裁剪至 80% | 移除早於 cutoff 的條目 | 不動(已含全部資料) | 不動 |
Reset(/reset,mode=summary) |
刪除 | 清除 | 清除 | 保留 |
Reset(mode=all) |
刪除 | 清除 | 清除 | 刪除 |
| Remove session | 刪除目錄 | 清除 | 清除 | 刪除目錄 |
Migration 注意
Session 與 error memory 過去存於 per-session JSON 檔,現已改置於 ~/.config/agenvoy/.store/ 底下的嵌入式 store——ToriiDB(db_0 工具快取、db_1 對話向量、db_2 錯誤記憶、db_3 online marker),history.db 承載 session 設定、操作者筆記、訊息封存、action 歷史、檔案歷史與用量。筆記於 v0.35.3 自 ToriiDB 移入 SQLite note 表,state 表亦於同版移除。bot.json / bot.md / config.json / status.json / usage.log / summary.meta.json 於 daemon 啟動時遷移進來,之後不再寫入。勿重新引入 JSON 路徑。
[!NOTE] 本文件由 Claude 讀取完整原始碼後自動生成。