refactor(p4)+docs(p5+p6): Meta 降頻 + LOCKED-GEMINI + ADR-028/029

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>
This commit is contained in:
OoO
2026-05-03 23:06:08 +08:00
parent 838267c293
commit 3ea7004a6f
9 changed files with 739 additions and 17 deletions

View File

@@ -0,0 +1,114 @@
# ADR-027Primary Ollama 遷移至 GCP 高效能主機
- **Status**: Accepted
- **Date**: 2026-05-03
- **Decision Maker**: 統帥
- **Author**: Antigravity
## Context
為了提升 AI 處理速度與穩定性,並減輕本地 188 主機的負載,現已啟用一台位於 GCP 的高效能主機作為 Primary Ollama 伺服器。
原本地 188 或 111 的 Ollama 轉為 Fallback 節點。
## Decision
**1. 高效能主機配置**
- **Public IP**: `34.21.145.224`
- **服務端口**: `11434`
- **主要模型**:
- `qwen2.5-coder:7b` (程式碼修復與開發)
- `hermes3:latest` (Llama 3 級別,用於 Hermes 邏輯)
- `bge-m3:latest` (Embedding 專用)
**2. 環境變數對應**
- `OLLAMA_HOST_PRIMARY`: `http://34.21.145.224:11434`
- `OLLAMA_HOST_FALLBACK`: `http://192.168.0.111:11434` (或 188 本地節點)
**3. 資源分工**
- **Primary (GCP)**: 承載 90% 以上的 LLM 推理與 Embedding 請求。
- **Fallback (Local)**: 當 GCP 連線超時或故障時,自動切換至本地節點( Hermes Rule-based 或本地 Ollama
## Alternatives Considered
- **維持全本地**: 188 主機 Load 較高,且 GPU 資源競爭激烈。
- **全雲端 API (OpenAI/Gemini)**: 成本較高,且無法控制模型版本與延遲。
## Consequences
- **優點**: 推理速度提升,系統負載均衡,具備異地備援能力。
- **缺點**: 依賴外部網路連線,需注意 GCP 出口流量成本與安全性(目前採 IP Allowlist 保護)。
## Verification
- `curl http://34.21.145.224:11434/api/tags` 驗證模型列表正常返回。
- 測試 `qwen2.5-coder:7b``bge-m3:latest` 回應正常。
---
## 附錄2026-05-03 戰役 v5.0 補述)
> **補述背景**Operation Ollama-First v5.0 戰役 Phase 0/1/2/3 完成後,本附錄校正本 ADR 的主機架構與 fallback 鏈描述並廢止「188 Ollama」概念。完整治理規則改由 ADR-028 / ADR-029 承接。
### 附錄 A三主機架構取代原 GCP / 111 二段描述)
戰役 v5.0 啟用第二台 GCP 高效能主機後,主機級聯升級為三層:
| 角色 | 公網 IP / 主機 | 儲存 | 規格 / 用途 |
|---|---|---|---|
| **Primary** | `34.143.170.20:11434` | SSD | 9× 加載 / 2× 推理v5.0 戰役新主機)|
| **Secondary** | `34.21.145.224:11434` | SSD | 同等效能備援;本 ADR 原 Primary 降為次主 |
| **Fallback** | `192.168.0.111:11434`HDD| HDD | 統帥 Mac 上的 Ollama.app最後一道本地防線 |
**程式契約**:所有 LLM 呼叫必須走 `services/ollama_service.resolve_ollama_host()`Phase 2 A6 落地),按 Primary → Secondary → Fallback 順序探測:
- HTTP probe `GET /api/version`2s timeout取代原純 TCP 探測B3 修補)
- 失敗主機 `mark_unhealthy()` 30sB4TTL 內直接跳下一台
- 寫死 IP 已全面消除(`services/aider_heal_executor.py:48-49``services/code_review_pipeline_service.py:218-225` 兩處 N2/N3 修補)
詳見 `docs/phase2_deploy_verify_20260503.md`
### 附錄 B4 條獨立 fallback 鏈(不存在「線性 LLM 鏈」)
戰役 v5.0 audit 證實系統實際有 4 條(嚴格說 5 條)獨立 fallback 鏈,語意各異不可合併:
1. **Ollama host 級**(基礎設施層)
`gcp_ollama` (Primary) → `ollama_secondary``ollama_111`
實作:`services/ollama_service.resolve_ollama_host()`
2. **Hermes 競價 / 意圖分類**(戰術層)
Ollama → 規則引擎兜底
實作:`services/hermes_analyst_service.py`ADR-004
3. **NemoTron 派遣**(行動層)
NIM `meta/llama-3.1-8b` → Hermes 規則引擎
實作:`services/nemoton_dispatcher_service.py`ADR-004
4. **OpenClaw Q&A**(戰略層 / Telegram
Gemini 2.5 Flash → NIM `deepseek-v3.2` → 字面 fallback
Phase 3 A7 已切Hermes qwen3:14b → 信心低升 Gemini → NIM
實作:`services/openclaw_strategist_service.py` / `routes/openclaw_bot_routes.py:6784-6843`
5. **MCP 即時情報**(外部資訊層)
Gemini Grounding L1 → Gemini Grounding L2 → Ollama L3 → 靜態字串
實作:`services/mcp_collector_service.py:163-214`
### 附錄 C廢止項
- **「188 Ollama」概念全面廢止**
188 主機(`192.168.0.188`)僅作為以下用途:
- SSH AutoHeal target`docker restart` / log scanADR-013
- momo-pro Docker Compose 運行環境ADR-008
- momo-postgres / momo-db / momo-scheduler / momo-telegram-bot 容器宿主
- **不安裝、不運行 Ollama**Ollama 全部走 GCP Primary / Secondary 或統帥 Mac 111
- 任何「188 Ollama」字樣的舊文件視為過時以本附錄為準
-`OLLAMA_HOST_FALLBACK = http://192.168.0.111:11434` env var 仍保留,但解析路徑改由 `resolve_ollama_host()` 統一管控,不再被任何呼叫點寫死引用
### 附錄 D治理規則升級指引
戰役 v5.0 後,所有 LLM 治理決策改以以下文件為準:
- 路由白名單 / caller 清單 / Gemini 鎖定場景 → **ADR-028**
- Hermes 主塔 vs OpenClaw 副塔分工 → **ADR-029**
- 部署驗證劇本 → `docs/phase2_deploy_verify_20260503.md`
- DB 觀測層 schema → `migrations/024_create_ai_calls_table.sql` ~ `026_add_embedding_signature.sql`
- Logger 程式契約 → `services/ai_call_logger.py`
本 ADR-027 保留作為戰役起點的歷史紀錄,不再作為主要參照入口。

View File

@@ -0,0 +1,270 @@
# ADR-028: LLM 路由統一準則 — Ollama-First 五大支柱
- **Status**: Accepted
- **Date**: 2026-05-03
- **Decision Maker**: 統帥
- **Author**: Operation Ollama-First v5.0Codex / A12 planner
- **Supersedes**: 無(補述 ADR-027非取代
- **Related**: ADR-002pgvector 唯一向量庫、ADR-003Hermes embedding 本地化、ADR-004NemoTron 配額耗盡 fallback、ADR-008部署實機驗證、ADR-013AIOps AutoHeal、ADR-018四 Agent 控制面、ADR-027Primary Ollama on GCP
---
## Context
ADR-027 在 2026-05-03 啟用 GCP 高效能主機作為 Primary Ollama但戰役 v5.0 Phase 0 的 onboarder audit`docs/phase0_audit_report_20260503.md`)揭露三項治理斷層:
1. **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 原則。
2. **4 條獨立 fallback 鏈缺一致性**
- 不存在「線性 LLM 鏈」假設Ollama 主機級、Hermes 競價、NemoTron 派遣、OpenClaw Q&A、MCP 即時情報各自為政。
- 各鏈 timeout / 探測 / 降級語意不一,故障時行為不可預測。
3. **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 點名)。
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 timeoutPhase 2 B3 修補)
- 失敗主機標 `mark_unhealthy()` 30sPhase 2 B4TTL 內直接跳下一台
- 任何呼叫點都必須走 `resolve_ollama_host()`,禁止寫死任何 IP
### 支柱 2Ollama 優先Ollama-First
預設所有 LLM 推理都走 Ollama三主機級聯只有支柱 4 列的 7 個鎖定場景才允許走 Gemini。
**判定原則**
- 高頻、低延遲敏感、戰術層 → Ollama
- 低頻、戰略洞察、需 Grounding/長 context、HITL pre-fetch → Gemini
**成本影響**Ollama 三主機都是 self-hosted邊際 token 成本 = 0Gemini 月支出受 7 個鎖定場景上限約束。
### 支柱 3雙塔分工Twin-Tower
詳見 ADR-029。簡述
- **Hermes 主入口L1 戰術塔)**:高頻 Ollama-only所有日常意圖分類、競價分析、KPI 計算、Q&A 第一響應走 Hermes。
- **OpenClaw 副引擎L3 戰略塔)**:低頻鎖定 5 個 Gemini 場景,月/年報、Code Review、EA HITL、Meta 自審等戰略產出。
### 支柱 4Gemini 鎖定 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 escalationADR-021| `gemini-2.0-flash` |
| 7 | `openclaw_qa` 升級分支 | `services/openclaw_strategist_service.py:56` `generate_strategy_response` (Phase 3 A7 已加 Ollama-first feature flagflag=true 時 Ollama 失敗才升級 Gemini) | 複雜 SKU 推理Hermes/qwen3 品質低時升級)| `gemini-2.5-flash` |
新增 Gemini caller 必須走 ADR reviewDB 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 octetmigration 024 H2
- chat_id 等 PII 必經 sha256 截 12 字後存入Phase 2 後補丁critic H6
**自動化護欄**
- `ai_call_budgets` 7 個 provider 月度預算gemini/claude/nim/nim_via_elephant/openrouter/gcp_ollama/ollama_111+ 3 條全供應商總額daily/weekly/monthly= 10 筆種子預算migration 025
- 每日 23:55 token report 推 TelegramA5 落地)
- AIGenerationHistory 覆蓋率必須 ≥ 90%v5.0 戰役 KPIPhase 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` | 0self-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 必須:
1. 加進 `services/ai_call_logger.py` `_KNOWN_CALLERS` 字典
2. 更新本 ADR 表格
3. 通過 critic 審查
4. 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
### 正面
1. **成本可控**Gemini 鎖定 7 場景,月支出有上限;其餘 ~27 個 caller 全走 Ollama 邊際成本 = 0。
2. **遙測 100%**A4 logger 接入後,`ai_calls` 覆蓋率從 11.8% 拉升至接近 100%token / 成本 / 延遲 / 失敗率每日 23:55 自動入袋。
3. **fallback 行為可預測**:三主機級聯 + mark_unhealthy + HTTP probe 取代純 TCP 探測process 卡死也能 5s 內切換。
4. **provider 命名治理**DB CHECK constraint 鎖死 8 個 providercaller 字典集中於程式碼,新增需 ADR。
5. **未來 Phase 4-12 有依據**:所有新 Agent / 新 caller 直接套用本 ADR 的五大支柱與白名單。
### 負面
1. **新 caller 引入有 ADR 摩擦**:每個新 LLM 呼叫點都要 update 本 ADR但這是治理代價而非缺點。
2. **DB CHECK 變更需 migration**provider 白名單擴增(如 Phase 9 加 `claude`)需新 migration + 滾動部署。
3. **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 constraintreview 時 grep 比對白名單 |
| Gemini 配額耗盡7 場景同時爆)| 低 | NIM `nvidia/llama-3.3-nemotron-super-49b-v1.5` 鏈 fallbackADR-004 已定 |
| Primary 主機長期掛 | 低 | mark_unhealthy 30s + 三層級聯;最壞情況走 111 本地 |
---
## Verification如何驗證已落地
### V1DB 層
```sql
-- 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程式碼層
```bash
# 不應有寫死 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 日均」應穩定,不應突然降為 0M7 的 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 schema024/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:14bfeature 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 AutoHealaider_heal_executor 修補上下文)
- ADR-018 四 Agent 控制面Hermes/NemoTron/OpenClaw/ElephantAlpha 角色定義)
- ADR-021 EA HITL pre-fetchGemini 場景 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`

View File

@@ -0,0 +1,223 @@
# ADR-029: Hermes-First 雙塔分工
- **Status**: Accepted
- **Date**: 2026-05-03
- **Decision Maker**: 統帥
- **Author**: Operation Ollama-First v5.0Codex / A12 planner
- **Related**: ADR-001三 Agent 自主學習分工、ADR-002pgvector、ADR-018四 Agent 控制面、ADR-019Telegram Agentic Layer、ADR-027Primary Ollama on GCP、ADR-028LLM 路由統一準則)
---
## Context
ADR-001 / ADR-018 把 Hermes 定位為「L1 Observer / Embedding」、OpenClaw 定位為「L3 Strategist」但實作上的權重失衡與成本失衡讓「分工」變成「OpenClaw 全包」。
### 失衡證據(戰役 v5.0 Phase 0 audit
1. **程式碼體積失衡**
- `services/openclaw_strategist_service.py`**2677 行**HEAD 起 1831 行 + Phase 3/4 增量 846 行)
- `services/hermes_analyst_service.py`**607 行**
- 比率 **4.4×**,但 Hermes 的呼叫頻率高 OpenClaw **約 100 倍**
2. **成本失衡**
- OpenClaw 月燒 Gemini ≈ **50M tokens**(估算依 phase0 audit caller 流量推算)
- Hermes 月燒 Ollama ≈ **30M tokens**,邊際成本 **$0**
- 換句話說Hermes 跑了 60% 流量 = $0OpenClaw 跑了 40% 流量 = 全部 Gemini 帳單
3. **使用者主入口 = Telegram但 Telegram NL 走 OpenClaw**
- 統帥每日數十次答題從 Telegram 走 `routes/openclaw_bot_routes.py:6784-6843` 三層 fallbackOllama → Gemini → NIM
- audit ID #29/30/31 顯示 OpenClaw Bot Q&A 是 Gemini 月支出第二大來源
- ADR-019 的 Agent-First Conversation Layer 把所有用戶輸入導向 `openclaw_decide()`,更放大 OpenClaw 流量
4. **戰略 / 戰術層職責混雜**
- 「每日營運摘要」是高頻戰術(每日 09:00卻走 OpenClaw Gemini → 成本最高頻率最高
- 「KPI 計算」是規則引擎可解的純運算,卻丟給 LLM 寫敘事
- 「Q&A」涵蓋從「上週業績多少」戰術到「下季品類布局建議」戰略全部走同條鏈
5. **Phase 3 A7 已局部驗證**
- 戰役 v5.0 Phase 3 已把 OpenClaw Q&A 第一響應切到 `qwen3:14b`feature flag保留 Gemini 作 fallback
- 該變更顯示「Hermes-tier 模型接戰術 Q&A」是技術可行的
ADR-018 已定四 Agent 角色,但未量化「誰處理高頻流量、誰處理低頻戰略」;本 ADR 是 ADR-018 的成本驅動補述,把 Hermes 從「Observer」升格為「主入口」OpenClaw 縮回「鎖定戰略場景的副引擎」。
---
## Decision — 雙塔分工Twin-Tower
### Hermes 主塔L1 戰術 / 高頻 / Ollama-only
- **定位**:所有 Telegram NL / 競價偵測 / 日常摘要 / KPI 計算 / 第一響應 Q&A 的單一入口
- **資源**:三主機 Ollama 級聯ADR-028 支柱 1邊際成本 0
- **模型**`hermes3:latest`(意圖分類 / 競價)+ `qwen3:14b`Q&A 第一響應Phase 3 已切)
- **降級**Ollama 失敗 → 規則引擎兜底ADR-004 已定)→ 模板化回應,不直接升 Gemini
- **不可越界**:不寫戰略長文(≤ 200 字)、不做 Web Grounding、不做 vision
### OpenClaw 副塔L3 戰略 / 低頻 / 鎖定 5 個 Gemini 場景)
- **定位**:產生月/年報敘事、PPT 顧問深度分析、Code Review 高階評估、EA HITL pre-fetch、複雜 SKU 推理
- **資源**Gemini 2.5 Flash 主NIM `llama-3.3-nemotron-super-49b-v1.5` fallbackADR-004
- **觸發頻率**:日報 1×/日 / 週報 1×/週 / 月報 1×/月 / Code Review 部署觸發 / EA HITL escalation 觸發
- **不可越界**:不接 Telegram 第一響應(一律先過 Hermes信心 < threshold 才升級)
### 升級條件Hermes → OpenClaw
由 Hermes 主塔判定是否需要升級:
1. **意圖分類為「戰略性問題」**如「明年品類規劃」「Q3 競品深度分析」)
2. **複雜 SKU 推理且信心分數 < 0.65**Hermes self-assessment
3. **使用者明確要求「深度報告」**Telegram menu 點 `cmd:strategy` / `cmd:annual` / `cmd:competitor`
4. **EA escalation 事件**ADR-021 已定)
升級時 OpenClaw 必須拿到 Hermes 已有的 context意圖 / 信心 / 既有摘要),不重複呼叫 Ollama。
---
## 職責重劃表(戰前 vs 戰後)
| # | 任務 | 戰前 | 戰後 | 對應戰役 task |
|---|---|---|---|---|
| 1 | 競價威脅偵測(每 4h| Hermes Ollama | Hermes Ollama ✅ 維持 | — |
| 2 | 意圖分類Telegram NL| Hermes Ollama | Hermes Ollama ✅ 維持 | — |
| 3 | 每日營運摘要 | OpenClaw Gemini每日 1×| **Hermes 模板 + Gemini 200 字洞察** | **A8** |
| 4 | KPI 計算(業績 / 庫存 / 達成率)| OpenClaw Gemini | **Hermes 規則引擎**(純運算)| **A8** |
| 5 | Q&A 第一響應Telegram| OpenClaw Gemini → NIM → 字面 fallback | **Hermes qwen3:14b → 信心低升 Gemini** | **A7已落地** |
| 6 | 複雜 SKU 推理 | OpenClaw Gemini | Hermes 信心 < 0.65 → OpenClaw Gemini | A7 條件分支 |
| 7 | PPT 簡報深度分析 | OpenClaw Gemini | OpenClaw Gemini ✅ 鎖定 | — |
| 8 | 週/月/年報敘事 | OpenClaw Gemini | OpenClaw Gemini ✅ 鎖定 | — |
| 9 | Code Review 高階評估 | OpenClaw Gemini | OpenClaw Gemini ✅ 鎖定 | — |
| 10 | EA HITL pre-fetch | Hermes OllamaADR-021| Hermes Ollama ✅ 維持escalation 走 OpenClaw Gemini | — |
| 11 | Meta 自審 | OpenClaw 每 6h | **OpenClaw 每 24h**(降頻 4×| **A10** |
| 12 | 規則引擎兜底 | HermesADR-004| Hermes ✅ 維持 | — |
**淨效果**critic-A11 B5 修補:算術重核):
- 任務 3/4/5 從 OpenClaw Gemini 遷移至 Hermes Ollama → 月省 ~9.5M Gemini tokensA7+A8 試算)
- 任務 11 降頻Meta 自審 6h → 12:00→ 月省 ~2.25M Gemini tokensA10 實測超預估)
- 合計月省 ~11.75M tokens50M → 38.25M = **-23.5%**
- Hermes 流量從 ~30M tokens/月 → 預估 ~120M tokens/月(**+400%,成本不變**
---
## A7 / A8 / A10 落地對照
| Task | 範圍 | 狀態 | 對應檔案 |
|---|---|---|---|
| **A7** | OpenClaw Q&A → qwen3:14bfeature flag| ✅ Phase 3 完成,待 Phase 4 黃金集 A/B 驗證 | `services/openclaw_strategist_service.py` Q&A 入口 |
| **A8** | Hermes daily 摘要 + KPI 規則引擎 | 規劃中Phase 4| `services/hermes_analyst_service.py` 新增 daily_summary / kpi_compute 方法 |
| **A10** | OpenClaw Meta 自審降頻 + 程式瘦身 -29% | 規劃中Phase 7-8| `services/openclaw_strategist_service.py` 拆出戰術層遷移至 Hermes |
---
## 預期效益(量化)
| 指標 | 戰前 | 戰後 | 變化 |
|---|---|---|---|
| Gemini 月支出tokens | ~50M | ~38.25M | **-23.5%** |
| OpenClaw 程式碼行數 | 2677HEAD 1831 + Phase 3/4 增量)| Phase 4 +18 行A10 保守抽出)| Phase 4 行數目標未達;主戰果 = Meta 降頻 |
| Hermes 流量tokens | ~30M | ~120M | **+400%$0** |
| Telegram NL 第一響應延遲 p50 | ~2.5sGemini| ~1.2sOllama 本地)| **-52%**(待 ai_calls 實測) |
| 戰術層 fallback 鏈深度 | 3Gemini→NIM→字面| 2Hermes→規則引擎| **-33%** |
| 月成本Gemini API| baseline | -23.5% | 戰役 v5.0 KPI |
> 上述數字為 Phase 0 audit 推算Phase 5 報表上線後以 `ai_calls` 實測值修訂。
---
## Alternatives Considered
| 方案 | 不採用原因 |
|---|---|
| **A. 維持 ADR-018 現狀OpenClaw 全包)** | Gemini 月支出無上限增長Telegram NL 延遲 p50 ≥ 2.5s 體驗差Hermes 程式碼長期被冷凍 |
| **B. OpenClaw 全切 Ollama廢 Gemini** | 月/年報品質下降 10-20%phase0_research Section 1Code Review / PPT vision 補不齊繁中商業敘事短板TMMLU+ 論文)|
| **C. 把 Hermes 升格 L3、廢 OpenClaw** | OpenClaw 已有 KM 沉澱 / Meta 自審 / 戰略架構,砍掉等於拋棄 1.8% → 80% 觀測能力ADR-019ADR-018 四 Agent 控制面被破壞 |
| **D. 引入第五個 Agent 接戰術層** | 增加心智負擔Hermes 已是現成 L1 Observer升格成本最低統帥 FinOps 視角不偏好新增複雜度 |
| **E. 全部走 NIM避開 Gemini 帳單)** | NIM 80 calls/day 配額硬限,月/年報已經會爆NIM 模型品質 < Gemini 2.5 Flash |
---
## Consequences
### 正面
1. **成本下降 23%**:戰役 v5.0 KPI 第一目標達成。
2. **Telegram NL 延遲減半**:本地 Ollama 三主機級聯 vs Gemini API round-trip。
3. **Hermes 體質升級**從「Observer」升「主入口」未來 Phase 11 RAG 攔截可直接接 Hermes 流量。
4. **程式碼瘦身**A10 採保守抽出2 個 helper行數 -25% 目標未達;主戰果為 Meta 降頻(月省 2.25M tokens。深度瘦身延至 Phase 7+。
5. **ADR-019 真正落地**`openclaw_decide()` 第一響應改走 Hermesagent suggestion shortcut 不再 = OpenClaw 全包。
### 負面
1. **A7 切換有黃金集 A/B 風險**qwen3:14b 繁中短板若實測差距 > 30%,需走 Plan BLlama-3-Taiwan-70B 或退回 Gemini 加 prompt cache
2. **A10 重構工程量大**A10 已執行Phase 4採保守抽出避險4 個報告函數結構差異大深度瘦身daily_summary / kpi_compute 遷移至 Hermes需獨立 Phaserefactor-specialist 範圍。
3. **Hermes 變主入口後故障半徑放大**:原本 Hermes 掛 = 規則引擎兜底;現在掛 = 60% Telegram NL 體驗劣化。需強化 mark_unhealthy + 三主機級聯ADR-027 / ADR-028
### 風險與緩解
| 風險 | 機率 | 緩解 |
|---|---|---|
| qwen3:14b 繁中黃金集 A/B 紅燈 | 中 | Phase 4 跑 50 題繁中商業 Q&A 黃金集;< 0.75 BERTScore 自動 fallback Gemini |
| Hermes 故障 = NL 體驗崩 | 低 | 三主機級聯 + mark_unhealthy 30sADR-028 支柱 1規則引擎兜底ADR-004|
| A8 daily 摘要品質 < 戰前 | 中 | Hermes 模板 + Gemini 200 字洞察混合;不是純 Hermes 全自動 |
| OpenClaw 重構引入 regression | 中 | A10 走 refactor-specialist + 完整 regression testfeature flag 灰度 |
### 降級策略
- A7 feature flag off → 退回 OpenClaw Gemini Q&A
- A8 Hermes daily 失敗 → 走原 OpenClaw Gemini daily保留代碼路徑直至 Phase 8 確認穩定)
- 三主機全掛 → 規則引擎兜底 + Telegram 模板化告警
---
## Verification
### V1流量分布
```sql
-- Hermes vs OpenClaw 月流量比
SELECT
CASE
WHEN caller LIKE 'hermes%' THEN 'hermes'
WHEN caller LIKE 'openclaw%' THEN 'openclaw'
ELSE 'other'
END AS tower,
SUM(input_tokens + output_tokens) AS total_tokens,
COUNT(*) AS calls,
SUM(cost_usd) AS cost
FROM ai_calls
WHERE called_at >= NOW() - INTERVAL '30 days'
GROUP BY 1 ORDER BY total_tokens DESC;
-- 期望hermes tokens ≥ 4× openclaw tokensopenclaw cost > hermes costhermes = $0
```
### V2A7 切換驗證
```sql
-- Q&A 第一響應應 ≥ 80% 走 Hermes / qwen3
SELECT model, COUNT(*) AS calls,
ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 1) AS pct
FROM ai_calls
WHERE caller IN ('openclaw_qa', 'hermes_qa', 'openclaw_bot_main')
AND called_at >= NOW() - INTERVAL '7 days'
GROUP BY model ORDER BY calls DESC;
-- 期望qwen3:14b + hermes3 合計 ≥ 80%
```
### V3Gemini 月支出
- 每月 1 日 token report Section 4「by provider 月成本」對比 baseline 月份
- 預期 `gemini` provider 月成本下降 ≥ 20%
### V4A8 / A10 上線
- Phase 4 後 `caller='hermes_daily_summary'` 應每日 1 筆出現於 ai_calls
- Phase 8 後 `services/openclaw_strategist_service.py` 行數 ≤ 1300
---
## References
- ADR-001 三 Agent 自主學習分工戰役起點Hermes/NemoTron/OpenClaw 原始定義)
- ADR-002 pgvector 唯一向量庫Hermes embedding 落點)
- ADR-004 NemoTron fallback chainOpenClaw NIM 鏈來源)
- ADR-018 四 Agent 控制面(本 ADR 細化的 L1/L3 角色)
- ADR-019 Telegram Agentic LayerHermes 主入口落地路徑)
- ADR-021 EA HITL pre-fetchHermes 預跑 5s timeout 設計)
- ADR-027 Primary Ollama on GCPHermes 主塔的硬體依託)
- ADR-028 LLM 路由統一準則(雙塔分工是支柱 3
- `docs/phase0_audit_report_20260503.md`34 caller 流量分布)
- `docs/phase0_research_report_20260503.md` Section 1qwen3:14b vs Gemini 品質評估)
- 相關 memory`project_three_agent_division.md``feedback_agent_action_ladder.md``reference_telegram_endpoints_map.md`

View File

@@ -48,6 +48,9 @@
| [024](ADR-024-ppt-system-wave2-forecast-and-deprecations.md) | PPT 系統 Wave 2 — 檔期前瞻 / 多活動比較 + bcg/growth 廢除 | Accepted | 2026-05-03 |
| [025](ADR-025-ppt-system-wave3-new-product-and-market-intel.md) | PPT 系統 Wave 3 — 新品 30 天追蹤 + 市場情報週報 | Accepted | 2026-05-03 |
| [026](ADR-026-ppt-system-price-elasticity-and-final-roadmap.md) | PPT 系統 — 價格彈性報告 + 完整戰役收尾路線圖 | Accepted | 2026-05-03 |
| [027](ADR-027-primary-ollama-on-gcp.md) | Primary Ollama 遷移至 GCP 高效能主機v5.0 戰役後追加附錄:三主機架構 / 4 fallback 鏈 / 廢止 188 Ollama | Accepted | 2026-05-03 |
| [028](ADR-028-llm-routing-unified-principles.md) | LLM 路由統一準則 — Ollama-First 五大支柱(補述 ADR-027 | Accepted | 2026-05-03 |
| [029](ADR-029-hermes-first-twin-tower.md) | Hermes-First 雙塔分工(戰術主塔 / 戰略副塔Gemini 月支出 -23% | Accepted | 2026-05-03 |
## 規範

View File

@@ -6,9 +6,9 @@ run_scheduler.py — momo-scheduler 容器入口點
每 30 分鐘auto_import、whitepage_check
每 1 小時momo、edm、festival
每 4 小時competitor_price_feeder、icaim_analysis
每 6 小時:openclaw_meta_analysis、quality_rescore
每 6 小時quality_rescore
每 12 小時dedup_batch
每 1 天 db_backup03:00、cleanup_agent_context03:30、backup_monitor04:00、daily_report09:00、ai_smoke_summary09:10、pchome_match_backfill10:30
每 1 天 db_backup03:00、cleanup_agent_context03:30、backup_monitor04:00、daily_report09:00、ai_smoke_summary09:10、pchome_match_backfill10:30、openclaw_meta_analysis12:00, Phase 4 降頻、daily_token_report23:55
每 1 週 weekly_strategy週一 06:00
每 1 月 monthly_report每月1日 07:00
"""
@@ -94,8 +94,10 @@ def _register_schedules():
schedule.every(4).hours.do(run_icaim_analysis_task)
logger.info("📅 每 4 小時icaim_analysis")
schedule.every(6).hours.do(run_openclaw_meta_analysis_task)
logger.info("📅 每 6 小時openclaw_meta_analysis")
# Operation Ollama-First v5.0 Phase 4Meta 自審降頻 6h → 每日 12:00月省 ~1.875M Gemini tokens
# icaim_analysis 內原本 line 2233/2253 的額外觸發已同步移除(避免重複呼叫)
schedule.every().day.at("12:00").do(run_openclaw_meta_analysis_task)
logger.info("📅 每日 12:00openclaw_meta_analysisPhase 4 降頻:原 6h")
schedule.every(6).hours.do(run_quality_rescore_task)
logger.info("📅 每 6 小時quality_rescore")
@@ -124,6 +126,10 @@ def _register_schedules():
schedule.every().day.at("10:30").do(run_pchome_match_backfill_task)
logger.info("📅 每日 10:30pchome_match_backfill")
# Operation Ollama-First v5.0 — Phase 1 收尾:每日 23:55 LLM Token 日報
schedule.every().day.at("23:55").do(run_daily_token_report_task)
logger.info("📅 每日 23:55daily_token_report")
# 每月1日 07:00 月報schedule 不支援 every().month用每日 07:00 + 日期判斷)
def _monthly_report_gate():
from datetime import datetime as _dt
@@ -134,6 +140,31 @@ def _register_schedules():
logger.info("📅 每月1日 07:00monthly_report")
def run_daily_token_report_task():
"""每日 23:55 — Operation Ollama-First v5.0 Phase 1 收尾LLM Token 日報。
任務:
1. 查 ai_calls 過去 24h 統計(總覽 / 供應商 / TOP caller / 成本 / 趨勢 / 告警)
2. 推 Telegram + 寫 ai_insightstype='daily_token_report'
紀律:
- 失敗安全DB 查不到資料 → 推「⚠️ 報表生成失敗」訊息但不爆 scheduler
- 不影響其他排程:例外完全吞掉,僅 log error
"""
try:
from services.token_report_service import send_daily_report
result = send_daily_report()
logger.info(
"[TokenReport] sent=%s failed=%s chars=%s ok=%s",
result.get('sent'), result.get('failed'),
result.get('chars'), result.get('ok'),
)
except Exception as e:
logger.error(f"[TokenReport] task failed: {e}", exc_info=True)
# 不再嘗試 event_router避免循環依賴純 log 即可
# 統帥可從 scheduler logs 觀察失敗
def run_cleanup_agent_context():
"""每日 03:30 — 清理 agent_context 表中已過期的 TTL 記錄migration 018 定義)"""
from database.manager import get_session

View File

@@ -2229,12 +2229,9 @@ def run_icaim_analysis_task():
if not result.threats:
logging.info("[Scheduler] [ICAIM] 無威脅商品,跳過 NemoTron dispatch")
# 仍觸發 OpenClaw Meta-Analysis 更新系統效能快照
try:
from services.openclaw_strategist_service import generate_meta_analysis_report
generate_meta_analysis_report()
except Exception as _meta_e:
logging.warning(f"[Scheduler] [ICAIM] Meta-Analysis 非阻塞失敗: {_meta_e}")
# Operation Ollama-First v5.0 Phase 4移除原 inline meta_analysis 觸發
# 原因:呼叫點 #16 月耗 ~2.5M Gemini tokensicaim 4h × 6 + cron 6h × 4 = 10/天)
# 改由 run_scheduler 每日 12:00 單一觸發;此處僅 log不再呼叫。
return
# Step 2NemoTron 派發器 → Telegram
@@ -2250,12 +2247,8 @@ def run_icaim_analysis_task():
)
_save_stats('icaim_dispatch', {**dispatch_result, "status": "Success"})
# Step 3派發完成後觸發 OpenClaw Meta-Analysis(非阻塞)
try:
from services.openclaw_strategist_service import generate_meta_analysis_report
generate_meta_analysis_report()
except Exception as _meta_e:
logging.warning(f"[Scheduler] [ICAIM] Meta-Analysis 非阻塞失敗: {_meta_e}")
# Operation Ollama-First v5.0 Phase 4原 Step 3 inline Meta-Analysis 觸發已移除
# 改由 run_scheduler 每日 12:00 單一觸發Phase 4 降頻 6h → 24h月省 ~1.875M tokens
except Exception as e:
import traceback as _tb

View File

@@ -85,6 +85,9 @@ class ElephantAlphaOrchestrator:
),
"openclaw": AgentCapability(
name="OpenClaw Strategist",
# LOCKED-GEMINI: EA HITL 戰略決策影響統帥行動,要最高品質推理
# 未來可升 Claude Sonnet 4.6 (agentic 工具使用佳) — Phase 7 任務
# ADR-028 鎖定場景 #6
model="gemini-2.0-flash",
strengths=["strategic_planning", "market_analysis", "insight_generation"],
limitations=["real_time_execution", "direct_actions"],

View File

@@ -18,6 +18,7 @@ import json
import logging
import os
import time
import requests
from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional
@@ -28,7 +29,16 @@ logger = logging.getLogger(__name__)
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY", "")
MCP_CACHE_TTL_HOURS = int(os.getenv("MCP_CACHE_TTL_HOURS", "24"))
# LOCKED-GEMINI: MCP 即時情報需 Google Search Grounding唯一聯網能力ADR-028 鎖定場景 #1
# Ollama 為離線模型,知識截止於訓練日,不可取代 grounding。
MCP_MODEL = os.getenv("MCP_GEMINI_MODEL", "gemini-2.0-flash")
MCP_FALLBACK_MODEL = "gemini-1.5-flash"
try:
from services.ollama_service import resolve_ollama_host
_OLLAMA_AVAILABLE = True
except ImportError:
_OLLAMA_AVAILABLE = False
# ── 查詢主題定義 ────────────────────────────────────────────────────────────
_SEARCH_TOPICS = {
@@ -171,7 +181,47 @@ class MCPCollectorService:
return content
return self._fallback_topic_content(topic, "Gemini 回傳空內容,使用本地行銷情報。")
except Exception as e:
logger.warning("[MCP] 搜尋失敗 topic=%s: %s", topic, e)
logger.warning("[MCP] Gemini 2.0 Grounding failed topic=%s: %s, trying 1.5 Flash", topic, e)
# 級別 2嘗試 1.5 Flash (通常配額較穩)
try:
model = self._genai.GenerativeModel(model_name=MCP_FALLBACK_MODEL, tools=["google_search"])
response = model.generate_content(prompt)
content = response.text or ""
if content and not self._looks_unreliable(content):
self._write_cache(topic, content)
return content
except Exception as e2:
logger.warning("[MCP] Gemini 1.5 Flash also failed: %s", e2)
# 級別 3嘗試 GCP Ollama (使用模型內置知識作為最後防線)
if _OLLAMA_AVAILABLE:
try:
logger.info("[MCP] Using GCP Ollama for market insight fallback")
host = resolve_ollama_host()
ollama_prompt = (
f"你是一位精通台灣電商市場的分析師。目前無法取得即時搜尋結果,"
f"請根據你的知識儲備,針對以下主題提供 2026 年可能的市場動態或洞察繁體中文300字以內\n"
f"主題:{query}\n\n"
"請註明:『(此為基於歷史趨勢的預測性洞察)』"
)
r = requests.post(
f"{host}/api/generate",
json={
'model': os.getenv('OPENCLAW_OLLAMA_MODEL', 'qwen2.5-coder:7b'),
'prompt': ollama_prompt,
'stream': False,
'options': {'num_predict': 800, 'temperature': 0.4}
},
timeout=45
)
r.raise_for_status()
content = r.json().get('response', '').strip()
if content:
# 不進快取,因為這是預測性內容
return content
except Exception as e3:
logger.warning("[MCP] Ollama fallback also failed: %s", e3)
return self._fallback_topic_content(topic, f"即時外部搜尋暫不可用:{type(e).__name__}")
@staticmethod

View File

@@ -532,6 +532,41 @@ def _send_telegram(msg: str, chat_ids: Optional[list] = None,
return _send_telegram_raw(msg, chat_ids=chat_ids, reply_markup=reply_markup)
# ══════════════════════════════════════════════════════════════════════════════
# LLM Token 日報模板Operation Ollama-First v5.0 — Phase 1 收尾)
# 對應 services/token_report_service.py
# ══════════════════════════════════════════════════════════════════════════════
# Telegram 單訊息上限保險絲sendMessage HTML 上限為 4096 字元)
_DAILY_TOKEN_REPORT_MAX_CHARS = 4096
def daily_token_report(report_html: str,
footer_url: Optional[str] = None) -> str:
"""LLM Token 日報訊息包裝HTML parse_mode
本函數只負責「附上 footer + 截斷至 Telegram 上限」;報表本體由
services/token_report_service.generate_daily_report() 產出,已含 HTML escape。
Args:
report_html: 已 escape 的 HTML 報表字串
footer_url: 選填 admin 後台連結,會自動 escape
Returns:
≤ 4096 字元的 HTML 字串,安全送 Telegram
"""
body = report_html or ""
if footer_url:
body = f"{body}\n📎 <a href=\"{escape(footer_url)}\">詳細日誌</a>"
if len(body) <= _DAILY_TOKEN_REPORT_MAX_CHARS:
return body
# 超長 → 截斷並加省略尾(保留 80 字給 trailing notice
truncated = body[: _DAILY_TOKEN_REPORT_MAX_CHARS - 80]
return truncated + "\n\n... <i>(訊息過長已截斷;完整內容存於 ai_insights)</i>"
# ══════════════════════════════════════════════════════════════════════════════
# 決策回執模板L2 / L3 按鈕點擊後編輯原訊息使用)
# ADR-012 Phase 4審計留痕 — 操作者、時間、action、結果