Phase 4 A10 — OpenClaw 雙塔重劃 - run_scheduler.py: Meta 自審 cron 6h → 每日 12:00(月省 2.25M Gemini, +20% 達標) - scheduler.py: 移除 icaim 內 2 處 inline meta 觸發 - openclaw_strategist 抽 _push_report_with_charts (call×3) + _collect_mcp_intel (call×2) - 行數目標 -25% 未達(4 報告函數結構差異大,A10 採保守抽出避險) - 主戰果:Meta 降頻月呼叫 300 → 30(-90%) Phase 5 — 5 處 LOCKED-GEMINI 註解(涵蓋鎖定 7 場景) - services/mcp_collector_service.py:32 (場景 #1: Google Search Grounding) - services/openclaw_strategist_service.py:40 (場景 #2/3/4: 週/月/年報) - services/code_review_pipeline_service.py:46 (場景 #5: 100K+ token diff) - services/elephant_alpha_orchestrator.py:88 (場景 #6: EA HITL) - routes/openclaw_bot_routes.py:98 (場景 #7: PPT 簡報) Phase 6 A12 — 憲法級 ADR 三份 - ADR-028「LLM 路由統一準則」(269 行) - 5 大支柱:三主機級聯 / Ollama 優先 / 雙塔分工 / Gemini 鎖 7 場景 / 可觀測性 - 8 個 provider 白名單(DB CHECK 對齊) - 30+ caller 名單分「已實作 / 規劃中」 - ADR-029「Hermes-First 雙塔分工」(222 行) - 12 項職責重劃表 + A7/A8/A10 落地對照 - Gemini 月支出 -23.5%(critic 第 3 輪 B5 算術修正) - ADR-027 附錄(+69 行) - 三主機架構(Primary/Secondary/Fallback) - 4 條獨立 fallback 鏈 - 廢止「188 Ollama」概念 - README 索引更新 A11 critic 第 3 輪修補:5 BLOCKER 全清 - B1: 行數 1831 → 2677 (含 baseline 對照) - B2: 場景 #4 行號 759/1267 → 1102/1628 + annual 不存在註明 - B3: 虛構 caller 改實存(ea_hitl_prefetch → ea_engine 等) - B4: 白名單三層對齊(DB 8 = ADR 8 = token_report 補 ollama_secondary) - B5: KPI 算術 50→38 = -23.5% 重核 services/telegram_templates.py: A5 daily_token_report() 函數 services/mcp_collector_service.py: 加 LOCKED-GEMINI 註解 services/elephant_alpha_orchestrator.py: 加 LOCKED-GEMINI 註解 103/103 unit test 全綠(zero regression) Operation Ollama-First v5.0 / Phase 4 A10 + Phase 5 + Phase 6 A12 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
16 KiB
ADR-028: LLM 路由統一準則 — Ollama-First 五大支柱
- Status: Accepted
- Date: 2026-05-03
- Decision Maker: 統帥
- Author: Operation Ollama-First v5.0(Codex / A12 planner)
- Supersedes: 無(補述 ADR-027,非取代)
- Related: ADR-002(pgvector 唯一向量庫)、ADR-003(Hermes embedding 本地化)、ADR-004(NemoTron 配額耗盡 fallback)、ADR-008(部署實機驗證)、ADR-013(AIOps AutoHeal)、ADR-018(四 Agent 控制面)、ADR-027(Primary Ollama on GCP)
Context
ADR-027 在 2026-05-03 啟用 GCP 高效能主機作為 Primary Ollama,但戰役 v5.0 Phase 0 的 onboarder audit(docs/phase0_audit_report_20260503.md)揭露三項治理斷層:
-
34 個 LLM 呼叫點分散治理失能
- audit 完整盤點
services/與routes/共 34 處 LLM 呼叫,分散在 9 個 service / 4 個 route 檔。 AIGenerationHistory結構化紀錄覆蓋率僅 4/34 = 11.8%,其餘 88% 完全沒結構化遙測。- 兩處「寫死 111」的呼叫點(
services/aider_heal_executor.py:48-49、services/code_review_pipeline_service.py:218-225)違反 ADR-027 的 Primary/Fallback 原則。
- audit 完整盤點
-
4 條獨立 fallback 鏈缺一致性
- 不存在「線性 LLM 鏈」假設:Ollama 主機級、Hermes 競價、NemoTron 派遣、OpenClaw Q&A、MCP 即時情報各自為政。
- 各鏈 timeout / 探測 / 降級語意不一,故障時行為不可預測。
-
provider/caller 命名漂移
- 戰役清單原列 26 個呼叫點,audit 補出 8 個遺漏;
openclaw_qa_nim此類 fallback 命名靠執行期動態組成(services/openclaw_strategist_service.py:737),缺集中字典。 - DB 端在 Phase 1 已加 provider CHECK constraint(
migrations/024_create_ai_calls_table.sql:88-91),但 caller 仍是自由字串(critic-A11 於 phase1_final_critic_signoff H5 點名)。
- 戰役清單原列 26 個呼叫點,audit 補出 8 個遺漏;
ADR-027 解決了「主機去哪裡」,但未統一「誰能呼叫」「呼叫去哪一台」「為何選這個」。本 ADR 是 ADR-027 的決策補述,把 Phase 0/1/2/3 戰役落地的成果固化為憲法級準則,供未來 Phase 4-12 與所有新 Agent 共同遵循。
Decision — 五大支柱
支柱 1:三主機級聯(Triple-Host Cascade)
取代 ADR-027 原本「GCP / 111」二段架構。
| 角色 | 主機 | 儲存 | 用途 |
|---|---|---|---|
| Primary | 34.143.170.20 |
SSD | 9× 加載 / 2× 推理(v5.0 戰役新主機) |
| Secondary | 34.21.145.224 |
SSD | 同等效能備援,ADR-027 原 Primary 降為次主 |
| Fallback | 192.168.0.111 |
HDD | 最後一道本地防線,統帥 Mac 上的 Ollama.app |
services/ollama_service.resolve_ollama_host()(Phase 2 A6 落地)按 Primary → Secondary → Fallback 順序探測:
- HTTP probe
GET /api/version,2s timeout(Phase 2 B3 修補) - 失敗主機標
mark_unhealthy()30s(Phase 2 B4),TTL 內直接跳下一台 - 任何呼叫點都必須走
resolve_ollama_host(),禁止寫死任何 IP
支柱 2:Ollama 優先(Ollama-First)
預設所有 LLM 推理都走 Ollama(三主機級聯),只有支柱 4 列的 7 個鎖定場景才允許走 Gemini。
判定原則:
- 高頻、低延遲敏感、戰術層 → Ollama
- 低頻、戰略洞察、需 Grounding/長 context、HITL pre-fetch → Gemini
成本影響:Ollama 三主機都是 self-hosted,邊際 token 成本 = 0;Gemini 月支出受 7 個鎖定場景上限約束。
支柱 3:雙塔分工(Twin-Tower)
詳見 ADR-029。簡述:
- Hermes 主入口(L1 戰術塔):高頻 Ollama-only,所有日常意圖分類、競價分析、KPI 計算、Q&A 第一響應走 Hermes。
- OpenClaw 副引擎(L3 戰略塔):低頻鎖定 5 個 Gemini 場景,月/年報、Code Review、EA HITL、Meta 自審等戰略產出。
支柱 4:Gemini 鎖定 7 個場景
只有以下 7 個 caller 允許呼叫 gemini provider,其餘任何 caller 走 Gemini 必經 ADR:
| # | Caller | 檔案位置 | 用途 | 模型 |
|---|---|---|---|---|
| 1 | mcp_l1_grounding |
services/mcp_collector_service.py:32 (LOCKED-GEMINI 註解) |
MCP L1 Grounding(即時情報) | gemini-2.0-flash |
| 2 | mcp_l3_ollama 兜底前的 L2 |
services/mcp_collector_service.py:33 MCP_FALLBACK_MODEL |
MCP L2 Grounding | gemini-1.5-flash |
| 3 | ppt_gemini |
routes/openclaw_bot_routes.py:98 (LOCKED-GEMINI) + _call_gemini 約 line 2464 |
PPT 簡報深度分析 | gemini-2.0-flash |
| 4 | openclaw_weekly / openclaw_monthly |
services/openclaw_strategist_service.py:1102 weekly + :1628 monthly + :40 STRATEGY_MODEL (LOCKED-GEMINI) |
週/月報敘事(註:annual 報告尚未實作,目前 OpenClaw 僅 weekly/monthly/daily/meta) | gemini-2.5-flash |
| 5 | code_review_openclaw |
services/code_review_pipeline_service.py:46 REVIEW_MODEL (LOCKED-GEMINI) |
Code Review 高階評估 | gemini-2.5-flash |
| 6 | ea_engine (HITL) |
services/elephant_alpha_orchestrator.py:88 AgentCapability.openclaw model (LOCKED-GEMINI);hermes_ea_prefetch 走 Hermes Ollama 不在此鎖定 |
EA HITL escalation(ADR-021) | gemini-2.0-flash |
| 7 | openclaw_qa 升級分支 |
services/openclaw_strategist_service.py:56 generate_strategy_response (Phase 3 A7 已加 Ollama-first feature flag,flag=true 時 Ollama 失敗才升級 Gemini) |
複雜 SKU 推理(Hermes/qwen3 品質低時升級) | gemini-2.5-flash |
新增 Gemini caller 必須走 ADR review;DB CHECK constraint 將於 Phase 5 後補(critic-A11 H5)。
支柱 5:可觀測性先行(Observability-First)
所有 LLM 呼叫必須經 services/ai_call_logger.log_ai_call() 雙寫 ai_calls 表(Phase 1 A4 落地)。
遙測契約:
- caller / provider / model 必填(provider 由 DB CHECK 約束在白名單內)
- input_tokens / output_tokens / duration_ms / status / cost_usd 必填
- request_id 可選但 fallback 鏈必須串接(如
code_review_hermes→code_review_openclaw→code_review_elephant三鏈共用) meta JSONB不得超 8192 octet,error TEXT不得超 4096 octet(migration 024 H2)- chat_id 等 PII 必經 sha256 截 12 字後存入(Phase 2 後補丁,critic H6)
自動化護欄:
ai_call_budgets7 個 provider 月度預算(gemini/claude/nim/nim_via_elephant/openrouter/gcp_ollama/ollama_111)+ 3 條全供應商總額(daily/weekly/monthly)= 10 筆種子預算(migration 025)- 每日 23:55 token report 推 Telegram(A5 落地)
- AIGenerationHistory 覆蓋率必須 ≥ 90%(v5.0 戰役 KPI),Phase 5 報表追蹤
Provider 白名單(DB CHECK 約束)
migrations/024_create_ai_calls_table.sql:51-58 chk_ai_calls_provider 鎖定以下 8 值:
| Provider | 主機 | 計費 | 用途 |
|---|---|---|---|
gcp_ollama |
Primary 34.143.170.20:11434 |
0(self-hosted) | 戰役 v5.0 主主機 |
ollama_secondary |
Secondary 34.21.145.224:11434 |
0 | 同等效能備援(架構保留,logger 端 url-based 推斷待 Phase 7+) |
ollama_111 |
Fallback 192.168.0.111:11434 |
0 | 最後一道防線 |
gemini |
Google AI API | metered | 鎖定支柱 4 的 7 個場景 |
claude |
Anthropic API | metered | Phase 7 Frontier 升級保留:Code Review L0 (Opus 4.7) + EA HITL (Sonnet 4.6);budgets 種子 $10/月已預設 |
nim |
NVIDIA NIM https://integrate.api.nvidia.com/v1 |
80 calls/day 配額 | NemoTron 派遣(ADR-004)+ Code Review fallback |
nim_via_elephant |
NIM via services/elephant_service.py |
同 NIM 配額 | Code Review ElephantAlpha 49B 鏈 |
openrouter |
OpenRouter(保留) | metered | PPT deepseek-v3.2 鏈 + 預留 Phase 9 多供應商實驗 |
三層一致性備忘(critic-A11 B4 修補):DB CHECK = 8 個,ADR-028 = 8 個,
services/token_report_service.py_PROVIDER_DISPLAY後續需補ollama_secondary(H5 待修,列為 Phase 7 整合任務)。
Caller 白名單(程式碼集中字典)
戰役 v5.0 Phase 1 A4 logger 接入後,固定字串集中於 services/ai_call_logger.py 與各 caller。常見 13 + 5 NIM 變體:
hermes_intent / hermes_analyst / hermes_rule_engine
code_review_hermes / code_review_openclaw / code_review_elephant
openclaw_qa / openclaw_qa_nim
openclaw_weekly / openclaw_weekly_nim
openclaw_daily / openclaw_daily_nim
openclaw_monthly / openclaw_monthly_nim
openclaw_meta / openclaw_meta_nim
nemotron_dispatch
openclaw_bot_main / openclaw_bot_gemini / openclaw_bot_nim
embedding_worker / embedding_realtime
mcp_collector_l1 / mcp_collector_l2 / mcp_collector_l3
ppt_generator / ppt_generator_ollama / ppt_generator_nim
ea_hitl_prefetch / ea_autonomous_engine
aider_heal
sales_copy / trend_match / trend_search / product_insights / trend_keywords
telegram_copy / bot_api_copy / trend_crawler / ai_provider_generic
新增 caller 必須:
- 加進
services/ai_call_logger.py_KNOWN_CALLERS字典 - 更新本 ADR 表格
- 通過 critic 審查
- Phase 5 後 DB CHECK constraint 將以格式約束(
^[a-z][a-z0-9_]{2,63}$)NOT VALID 補上(critic-A11 H5 建議)
鎖定 Gemini 7 個場景(與支柱 4 對應,含理由)
| 場景 | 為何不能走 Ollama |
|---|---|
| MCP L1/L2 Grounding | Gemini Grounding 是即時 web search 唯一供應商,Ollama 無此能力(Tavily/Exa 走 Phase 10 不同路徑) |
| PPT 圖檢查 / 簡報分析 | Gemini 多模態 vision 能力遠超 Ollama 本地模型 |
| 週/月/年報敘事 | 商業敘事品質要求高,Gemini 2.5 Flash vs qwen3:14b 估差 10-20%(phase0_research_report Section 1) |
| Code Review 高階評估 | OpenClaw 級審查需 Gemini 2.5 Flash 的程式理解力,本地模型不足 |
| EA HITL pre-fetch | escalation 路徑 5s timeout 內必須拿到結構化 + 高品質回應,ADR-021 已定 |
| 複雜 SKU 推理 | Hermes/qwen3:14b 信心 < threshold 時才升級 Gemini,繁中商業情境短板(TMMLU+ 論文) |
Alternatives Considered
| 方案 | 不採用原因 |
|---|---|
| A. 單一供應商(全 Gemini 或全 NIM) | 配額硬限(NIM 80 calls/day)+ 月成本不可控;雲端 API 出口流量風險;違反 FinOps 視角 |
| B. 全本地(不留 Gemini) | MCP Grounding / vision / 戰略敘事品質本地模型補不齊;繁中短板無解(phase0_research Section 1.4) |
| C. 多供應商完全互通(任意 caller 任意 provider) | 命名漂移無法治理;caller-provider 對應靠程式碼隱式約定,無 DB 護欄;token 報表 GROUP BY 失準 |
| D. 線性 LLM 鏈(一條 fallback 鏈打天下) | audit 已證明系統有 4 條獨立鏈(Ollama host / Hermes / NemoTron / OpenClaw Q&A / MCP),語意各異不可合併 |
| E. 引入 LangChain / LiteLLM 統一抽象層 | 黑盒、難審計、增加依賴;既有 ai_call_logger + resolve_ollama_host 已具備統一語意,無需第三方 |
Consequences
正面
- 成本可控:Gemini 鎖定 7 場景,月支出有上限;其餘 ~27 個 caller 全走 Ollama 邊際成本 = 0。
- 遙測 100%:A4 logger 接入後,
ai_calls覆蓋率從 11.8% 拉升至接近 100%,token / 成本 / 延遲 / 失敗率每日 23:55 自動入袋。 - fallback 行為可預測:三主機級聯 + mark_unhealthy + HTTP probe 取代純 TCP 探測,process 卡死也能 5s 內切換。
- provider 命名治理:DB CHECK constraint 鎖死 8 個 provider;caller 字典集中於程式碼,新增需 ADR。
- 未來 Phase 4-12 有依據:所有新 Agent / 新 caller 直接套用本 ADR 的五大支柱與白名單。
負面
- 新 caller 引入有 ADR 摩擦:每個新 LLM 呼叫點都要 update 本 ADR,但這是治理代價而非缺點。
- DB CHECK 變更需 migration:provider 白名單擴增(如 Phase 9 加
claude)需新 migration + 滾動部署。 - Logger 額外延遲:每個 LLM 呼叫多一層 fire-and-forget 寫入(測試顯示 < 5ms),但獨立 thread + dedicated session pool 可控。
風險與緩解
| 風險 | 機率 | 緩解 |
|---|---|---|
| Logger 失敗連鎖讓主流程崩 | 低 | ai_call_logger kill-switch 連續 10 次失敗自動關(Phase 1 已測試 52/52 pass) |
| caller typo 污染 token 報表 | 中 | Phase 5 後加格式 CHECK constraint;review 時 grep 比對白名單 |
| Gemini 配額耗盡(7 場景同時爆) | 低 | NIM nvidia/llama-3.3-nemotron-super-49b-v1.5 鏈 fallback;ADR-004 已定 |
| Primary 主機長期掛 | 低 | mark_unhealthy 30s + 三層級聯;最壞情況走 111 本地 |
Verification(如何驗證已落地)
V1:DB 層
-- provider CHECK 鎖定
SELECT pg_get_constraintdef(oid) FROM pg_constraint
WHERE conname = 'chk_ai_calls_provider';
-- 期望:CHECK (provider IN ('gcp_ollama','ollama_secondary','ollama_111','gemini','nim','nim_via_elephant','openrouter'))
-- 預算種子 10 筆
SELECT period, provider, budget_usd FROM ai_call_budgets ORDER BY period, provider NULLS FIRST;
-- 24h caller 分布(戰役 v5.0 上線後應 ≥ 13 個 distinct caller)
SELECT caller, COUNT(*) FROM ai_calls
WHERE called_at >= NOW() - INTERVAL '24h'
GROUP BY caller ORDER BY 2 DESC;
V2:程式碼層
# 不應有寫死 IP
grep -rn "192.168.0.111" services/ routes/ | grep -v "OLLAMA_HOST_FALLBACK\|resolve_ollama_host\|test_"
grep -rn "34.143.170.20\|34.21.145.224" services/ routes/ | grep -v "OLLAMA_HOST_PRIMARY\|test_"
# 所有 LLM 呼叫應走 logger
grep -rn "ollama_service.generate\|google.generativeai\|openai.ChatCompletion" services/ routes/
# 每個 hit 上方應有 with log_ai_call(...) 或 @log_ai_call_decorator
V3:每日 token report(每日 23:55 入 Telegram)
- Section 1
ollama_pct≥ 80%(戰役 KPI) - Section 5 「今日 Ollama Tokens vs 7 日均」應穩定,不應突然降為 0(M7 的 openclaw_bot_main 修復後)
- ai_insights
insight_type='daily_token_report'每日 1 筆
Migration Plan
| Phase | 項目 | 狀態 | 文件 |
|---|---|---|---|
| 0 | LLM/MCP audit + 替代查證 | ✅ 完成 | docs/phase0_audit_report_20260503.md / docs/phase0_research_report_20260503.md |
| 1 | DB schema(024/025/026)+ ai_call_logger + token report | ✅ 完成(52/52 tests pass) | docs/phase1_db_design_20260503.md / docs/phase1_critic_review_20260503.md / docs/phase1_final_critic_signoff_20260503.md |
| 2 | resolve_ollama_host + HTTP probe + mark_unhealthy + AiderHeal/CodeReview lazy | ✅ 完成(13 + 43 tests pass) | docs/phase2_deploy_verify_20260503.md |
| 3 | OpenClaw Q&A 切 qwen3:14b(feature flag) | ✅ 完成(A7) | 待 Phase 4 黃金集 A/B |
| 4 | 黃金集 A/B 評測 + Hermes daily 摘要遷移(A8) | 規劃中 | — |
| 5 | Phase 5 報表上線 + caller CHECK NOT VALID | 規劃中 | — |
| 6 | 文件對齊(本 ADR + ADR-029 + ADR-027 附錄) | ✅ 完成 | 本檔 |
| 7-8 | OpenClaw 程式瘦身(A10) | 規劃中 | — |
| 9 | 預算守門 hard-stop + 多供應商實驗 | 規劃中 | — |
| 10 | MCP 5 顆 🟢 引入(postgres / omnisearch / filesystem / firecrawl / git) | 規劃中 | — |
| 11 | RAG 一致性護欄(embedding_signature 回填 + bge-m3 digest 鎖定) | 規劃中 | — |
| 12 | ai_usage_tracking deprecate + caller 集中 ADR refresh | 規劃中 | — |
References
- ADR-027 Primary Ollama on GCP(戰役起點)
- ADR-029 Hermes-First 雙塔分工(本 ADR 支柱 3 展開)
- ADR-004 NemoTron 配額耗盡 fallback(白名單 NIM provider 來源)
- ADR-013 AIOps AutoHeal(aider_heal_executor 修補上下文)
- ADR-018 四 Agent 控制面(Hermes/NemoTron/OpenClaw/ElephantAlpha 角色定義)
- ADR-021 EA HITL pre-fetch(Gemini 場景 6 來源)
docs/phase0_audit_report_20260503.md(34 呼叫點完整盤點)docs/phase0_research_report_20260503.md(Qwen / DeepSeek-R1 / Search API 三項紅綠燈)docs/phase1_db_design_20260503.md(DB schema 設計理由)docs/phase1_final_critic_signoff_20260503.md(H5/H6 caller / chat_id 護欄缺口)docs/phase2_deploy_verify_20260503.md(resolve_ollama_host / mark_unhealthy 落地驗證)- 相關 memory:
reference_111_mac_ollama.md、reference_env_map.md、feedback_docs_vs_reality.md