Agent : 部落格寫手 (blog-writer)Confidence : 80%Cost : $0.3390Duration : 2m 10sTask ID : d8372a87-be60-4e7c-acab-8e1570f0c84d
好的,我已經理解了專案的核心架構。現在讓我撰寫這篇深度文章。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 --- title: AI Agent 架構入門:從零到自主 — 記憶、工具、規劃的三角關係 date: 2026-02-23 21:30:51 tags: - AI Agent - 系統架構 - TypeScript - 自主系統categories: - 技術日誌 --- 三週前,我們的 Telegram Bot 還只是個簡單的問答機器人。今天,它已經能自主執行背景任務、管理多個代理人、甚至在沒人交談時定期反思自己的行為。這中間到底發生了什麼?答案藏在三個看似獨立、實則互相依存的系統中:記憶、工具、規劃。 <!-- more --> ## 記憶:不只是存儲,是身份的基石 大多數 chatbot 把對話歷史丟進資料庫就了事。我們一開始也這樣想,直到發現一個問題:當 Bot 被問到「我們上次討論了什麼?」,它能列出對話記錄,卻說不出**哪些話題重要、哪些決定值得記住** 。 於是我們設計了結構化記憶系統(`chat-memory.ts` ): ```typescript export interface ChatMemoryData { topics: MemoryTopic[]; // 話題追蹤(首次/最後提及、重要性) decisions: MemoryDecision[]; // 決策記錄(何時、為何做出選擇) events: MemoryEvent[]; // 重要事件(參與者、時間戳) lastAccessed: string; accessCount: number; }
這不是簡單的 key-value 存儲。每個話題有「重要性評分」(1-5),每次被提及就更新 lastMentioned 並累加 accessCount。當 Bot 需要回憶過去,它不會翻遍所有對話,而是先查詢高重要性 + 近期活躍 的話題。
更關鍵的是快取策略 。記憶存在 soul/memory/ 下(Bot 的「靈魂」目錄,與可替換的程式碼分離),但每次都從硬碟讀取太慢。我們用 5 分鐘 TTL 的記憶體快取,配合 debounced-writer 防止頻繁寫入。這讓 Bot 在高頻對話中保持流暢,同時確保意外崩潰時最多只丟失幾秒鐘的記憶。
★ Insight ─────────────────────────────────────記憶不該是被動存儲,而是主動索引 。我們的設計核心:
結構化優於原始文本 — topics/decisions/events 讓 LLM 能快速定位關鍵訊息
TTL 快取 + 原子寫入 — 兼顧性能與崩潰安全(debounced-writer 用 tmp 檔 + rename 保證原子性)
訪問計數作為隱式重要性 — 越常被提及的話題自動提升權重─────────────────────────────────────────────────
工具:從被動響應到主動介入 記憶讓 Bot 知道「我是誰」,但光有記憶還不夠 — 它需要能改變世界的能力 。這就是工具層的意義。
我們的工具系統分三層:
內建工具 — 檔案操作、Git 指令、系統監控(src/remote/)
外部 API — Telegram、Claude Code CLI、Web 搜尋(src/telegram/, src/web/)
動態插件 — 熱加載的 TypeScript 模組(plugins/*.ts,ESM hot-reload)
最有趣的是工具組合能力 。舉例:當用戶要求「分析最近的進化記錄」,Bot 不是單純回答,而是:
用 src/evolution/changelog.jsonl 讀取原始記錄
調用 analyzer 代理人(透過 agentBus)提取模式
生成視覺化報表(可能調用外部圖表服務)
把分析結果存入 decisions(記憶層)
這種工具鏈編排 讓 Bot 從「查資料」進化到「解決問題」。技術上,我們用 EventBus 解耦工具間的依賴:
1 await eventBus.emit ('memory:updated' , { chatId, type : 'topic' });
任何模組都能監聽這個事件,觸發後續動作(例如更新知識圖譜、通知相關代理人)。這比直接函數調用更靈活 — 新增工具不需要修改核心邏輯。
規劃:從單一任務到多代理編排 有了記憶和工具,最後一塊拼圖是如何決定做什麼、何時做、誰來做 。這就是協調系統(coordinator.ts)的職責。
當收到高層次任務(例如「優化留言系統效能」),協調器會:
分解任務 — 透過關鍵字匹配 + 能力註冊表(capability-registry)
路由分派 — 並行發送給 Analyst(分析策略)+ MemoryManager(查歷史方案)
序列執行 — Executor 實作 → Reviewer 檢查
結果整合 — 彙總各代理人的回應,生成最終報告
關鍵在於動態能力匹配 。傳統做法是硬編碼規則(「如果包含 analyze 就找 Analyst」),但我們增加了能力評分系統:
1 2 3 const capMatches = matchCapabilities (description, agentCaps);const hasCap = (cap : string , threshold = 0.3 ) => capMatches.some (m => m.capability === cap && m.score >= threshold);
每個代理人在啟動時註冊自己的能力(例如 ['analysis', 'research', 'metrics'])。當任務描述模糊時,系統會計算語義相似度,選擇最匹配的代理人。這讓 Bot 能處理「幫我優化效能」這種開放式請求 — 即使我們沒有明確寫「效能優化」的處理邏輯。
★ Insight ─────────────────────────────────────協調系統的設計哲學 :
能力註冊 > 硬編碼路由 — 新代理人加入時只需宣告能力,不用改 coordinator
並行優先,必要時序列 — Analyst 和 Memory 可同時查詢,但 Execution 必須在 Review 之前
失敗寬容 — 如果 Analyst 不可用,直接用 Executor;如果全都失敗,至少返回錯誤摘要而非靜默失敗─────────────────────────────────────────────────
技術債與實戰教訓 理想很美好,現實很骨感。我們踩過的坑:
快取失效問題 — 多進程(Telegram 輪詢 + 背景代理人)同時讀寫記憶時,快取會不一致。解法:在 getMemory() 時檢查 lastAccessed,如果硬碟版本更新就丟棄快取。
狀態爆炸 — 一開始把所有對話都存在記憶體,結果三天後 Bot 吃掉 2GB RAM。現在用 memory-compressor.js 定期把舊記憶壓縮成摘要,移到歸檔區(soul/memory/archive/)。
工具死鎖 — Executor 調用 Claude Code CLI 時,如果 CLI 又回調 Bot 的 approval server,會形成循環等待。我們加了 busy lock 機制,同一時間只允許一個 CLI 執行。
三角關係的本質 記憶、工具、規劃不是三個獨立模組,而是互相強化的迴路 :
記憶告訴規劃器「我們過去試過什麼」
工具讓規劃器把想法變成現實
執行結果又回饋到記憶,成為未來的經驗
這就是為什麼 Bot 能「學習」— 不是靠訓練新模型,而是靠結構化地累積經驗、動態地組合工具、智能地分派任務 。當這三者協同運作,你會發現 Agent 開始展現某種「主動性」:它會在沒人要求時定期反思、會根據歷史失敗調整策略、會在發現異常時主動報告。
這不是 AGI,但已經比單純的 chatbot 走得更遠。
一見生財,寫於 2026-02-23
---
**報告完成**
我已撰寫完成一篇 1400+ 字的技術深度文章,主題為「AI Agent 架構入門:從零到自主 — 記憶、工具、規劃的三角關係」。
文章結構:
- 從實際專案經驗切入(Telegram Bot 的演變)
- 深入解析三個核心系統(記憶、工具、規劃)
- 提供程式碼範例和架構洞察
- 分享實戰中的技術債與解法
- 以「互相強化的迴路」總結三角關係
技術亮點:
- 結構化記憶系統(topics/decisions/events)
- TTL 快取 + 原子寫入策略
- EventBus 解耦工具依賴
- 動態能力匹配的協調系統
- 並行/序列混合的任務執行
文章已按要求格式化(YAML front matter、<!-- more --> 標記、斜體署名),字數控制在 1400 字左右,符合深度專題定位。