報告摘要

Agent: architect (architect)
Confidence: 79%
Cost: $0.9663
Duration: 3m 39s
Task ID: 52038643-1011-40f9-80af-9df35d15ac1e


★ Insight ─────────────────────────────────────
這份分析揭示了幾個重要的架構模式教訓:

  1. 「全量讀取尾部資料」是 append-only JSONL 系統最常見的 antipattern。四個不同的模組(agent-tuner, audit-chain, search-index, explorer)都犯了同樣的錯——全量 readFile() + split('\n') + slice(-N)。一個通用的 tailJsonl() 工具可以一次解決四個問題。這就是為什麼架構分析要尋找「共同模式」而非逐個修補。

  2. EventBus 的 event payload 設計決定了下游效率的上限memory:updated 事件只攜帶 { chatId, type },缺少 index 資訊,逼迫 search-index 做全量重索引。這是典型的「事件設計太粗糙導致消費者過度補償」問題。在設計 EventBus 事件時,多帶一個 field 的成本趨近於零,但缺少它的代價是 O(N) vs O(1)

  3. 同步 I/O 在 Node.js 中的嚴重度常被低估readFileSync 在 1.2MB 時阻塞 50-100ms 看似不多,但在 Telegram bot 的 concurrent polling 架構中,這 100ms 意味著所有用戶的所有訊息完全凍結。Node.js 的單執行緒模型下,同步 I/O 的真實成本 = 阻塞時間 × 同時等待的請求數。
    ─────────────────────────────────────────────────


報告摘要

已完成全部 9 個瓶頸的深入分析。重新評估後的優先級排序:

確認修復(6 個)

方案 瓶頸 核心改動
B (P0) search-index 全量重索引 event payload 加 index,handler 精準 upsert
C (P0) explorer.ts 同步 I/O readFileSyncreadFile (async)
A (P1) agent-tuner / audit-chain / search-index JSONL 全量讀取 新增 tailJsonl() 工具,從尾部讀取
D (P1) search-index Maps 無上限 加入 enforceLimit(5000)

決定不修(3 個)

瓶頸 理由
chat-memory cache (#5) 單 chat 場景,洩漏量 ~0
narrative slice (#8) 有 archive 機制控制檔案大小
stdout += (#9) non-streaming 路徑 + 10MB cap + V8 rope string

關鍵架構決策

  • 不做 CappedMap 通用工具 — search-index 的三個 Map 互相耦合,通用化是過度設計
  • tailJsonl 是最高槓桿改動 — 一個工具同時解決 4 個模組的問題
  • Phase 1 兩個 P0 任務可完全並行,Phase 2 依賴 tailJsonl 工具先完成

報告已存入 soul/agent-reports/architect/2026-02-28-perf-bottleneck-analysis.md