固化 Ollama 三主機路由紅線
Some checks failed
CD Pipeline / deploy (push) Has been cancelled

This commit is contained in:
OoO
2026-05-13 12:09:40 +08:00
parent 2130c4f54b
commit b65a319cb8
7 changed files with 105 additions and 49 deletions

View File

@@ -119,14 +119,15 @@ GDRIVE_FILE_PATTERN=即時業績_當日
# ==========================================
# Hermes 3 競價情報分析Module 2 / ADR-012
# ==========================================
# [預設 http://192.168.0.111:11434] Hermes Ollama 端點(內網免認證
HERMES_URL=http://192.168.0.111:11434
# [選填] Hermes Ollama 端點;留空時自動走 GCP-A → GCP-B → 111ADR-028
# 僅允許 http://34.143.170.20:11434、http://34.21.145.224:11434、http://192.168.0.111:11434
HERMES_URL=
# [預設 120] Hermes 推理 timeout批量 300 筆預估 ~90s
HERMES_TIMEOUT=120
# [預設 HERMES_URL] Embedding 服務主機ADR-003 對齊embedding 走 Hermes 主機)
EMBEDDING_HOST=http://192.168.0.111:11434
# [選填] Embedding 服務主機;留空時自動走同一條 Ollama 三主機級聯
EMBEDDING_HOST=
# [預設 45] Embedding API timeout優先使用 Ollama /api/embed舊節點 fallback /api/embeddings
EMBEDDING_TIMEOUT=45
@@ -155,14 +156,14 @@ ELEPHANT_ALPHA_PERFORMANCE_TRACKING=true
ELEPHANT_ALPHA_AUTO_ESCALATION_ENABLED=true
# Integration Settings
ELEPHANT_ALPHA_HERMES_URL=http://192.168.0.111:11434
ELEPHANT_ALPHA_HERMES_URL=
ELEPHANT_ALPHA_HERMES_MODEL=hermes3:latest
ELEPHANT_ALPHA_NEMOTRON_NIM_ENDPOINT=https://integrate.api.nvidia.com/v1
ELEPHANT_ALPHA_URL=https://integrate.api.nvidia.com/v1/chat/completions
ELEPHANT_ALPHA_OPENCLAW_GEMINI_ENDPOINT=https://generativelanguage.googleapis.com/v1beta
# ── Google Gemini API ───────────────────────────────────────────────────────
# OpenClaw 策略師 / MCP Collector / Code Review Pipeline 共用金鑰
# ── Google Gemini API(僅備援 / 鎖定場景)────────────────────────────────────
# Gemini 只能作為 Ollama 失敗備援或 ADR-028 鎖定場景,不可設為通用預設 provider
# 取得方式https://aistudio.google.com/app/apikey
# 注意Gemini 2.0 Flash 將於 2026-06-01 關閉,後續需遷移至 2.5 Flash
GEMINI_API_KEY=<change-me>
@@ -224,9 +225,9 @@ DEPLOY_SSH_KEY_PATH=/home/wooo/.ssh/id_ed25519
# [選填] 110 主機上的 repo 路徑
AIDER_REPO_PATH=/home/wooo/ewoooc
# [選填] Aider 使用的模型與 Ollama API endpoint
# [選填] Aider 使用的模型與 Ollama API endpoint;留空時自動走 GCP-A → GCP-B → 111
AIDER_MODEL=ollama/qwen2.5-coder:7b
OLLAMA_API_BASE=http://192.168.0.111:11434
OLLAMA_API_BASE=
# [選填] 自動修復安全閥
AIDER_MAX_DIFF_LINES=50
@@ -274,7 +275,7 @@ OPENCLAW_BOT_TOKEN=your_openclaw_bot_token_here
OPENCLAW_GROUP_ID=-1003940688311
OPENCLAW_ALLOWED_USERS=
# [選填] AI provider 選擇與外部資料源
# [選填] AI provider 選擇與外部資料源Gemini 不可設為預設,只能當 Ollama 備援
AI_PROVIDER=ollama
YOUTUBE_API_KEY=
GEMINI_TIMEOUT=60
@@ -283,7 +284,10 @@ GEMINI_TIMEOUT=60
# Ollama / MCP / 密碼政策
# ──────────────────────────────────────────────────────────────────────────
OLLAMA_HOST=https://ollama.wooo.work/ollama
OLLAMA_HOST=
OLLAMA_HOST_PRIMARY=http://34.143.170.20:11434
OLLAMA_HOST_SECONDARY=http://34.21.145.224:11434
OLLAMA_HOST_FALLBACK=http://192.168.0.111:11434
OLLAMA_MODEL=gemma3:4b
OLLAMA_TIMEOUT=120
OLLAMA_COPY_TIMEOUT=180

27
110-ollama-proxy.conf Normal file
View File

@@ -0,0 +1,27 @@
# 110 Ollama GCP Proxy — ADR-028 三主機級聯轉發
server {
listen 11435;
location / {
proxy_pass http://34.143.170.20:11434;
proxy_connect_timeout 10s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_buffering off;
}
location /nginx-health {
return 200 "Ollama GCP-A Proxy OK\n";
}
}
server {
listen 11436;
location / {
proxy_pass http://34.21.145.224:11434;
proxy_connect_timeout 10s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_buffering off;
}
location /nginx-health {
return 200 "Ollama GCP-B Proxy OK\n";
}
}

View File

@@ -107,7 +107,7 @@
| 主機 | IP | 角色 |
|---|---|---|
| 110 | `192.168.0.110` | Gateway、Nginx、Gitea、n8n、Superset |
| 188 | `192.168.0.188` | App、DB、Ollama (Fallback)、生產容器 |
| 188 | `192.168.0.188` | App、DB、生產容器、AutoHeal target不可作為 Ollama 節點) |
| GCP-SSD-1 | `34.143.170.20` | Primary Ollama (High Performance SSD, All Models) |
| GCP-SSD-2 | `34.21.145.224` | Secondary Ollama (SSD Optimized, Redundancy) |
@@ -129,6 +129,7 @@
- `gunicorn.conf.py` 必須透過 `docker-compose.yml` bind mount 進 `momo-app`;除救急外,不以 `docker cp` 當常態部署方式。
- CD rebuild 應先完成 image build再短暫 recreate 三應用容器;禁止把 no-cache build 時間變成長時間 502。
- HTTP health / Blackbox / CD 探測必須打 `/health`,不可打 Dashboard 首頁 `/`,避免監控流量觸發重型查詢造成 worker starvation。
- 所有 AI Agent / LLM / embedding 呼叫必須 Ollama-first且只允許 GCP-A `34.143.170.20:11434` → GCP-B `34.21.145.224:11434` → 111 `192.168.0.111:11434` 三主機級聯Gemini 只能作為備援或 ADR-028 鎖定場景188 不可作為 Ollama 節點。
## 8. 常用入口

View File

@@ -169,6 +169,14 @@
- ✅ **正確**: Gunicorn runtime 必須保留可併發回應輕量 health check 的 worker 設定,例如 `gthread` + `GUNICORN_THREADS`。
- ❌ **禁止**: 用會觸發大量 DB 查詢或模板渲染的頁面作為探測目標,避免監控流量本身造成 worker starvation。
### 第 18.2 條AI / LLM 路由主機紅線(絕對禁止違反)
- ✅ **正確**: 所有 AI Agent、LLM 推理與 embedding 預設必須走 Ollama 三主機級聯GCP-A `34.143.170.20:11434` → GCP-B `34.21.145.224:11434` → 111 `192.168.0.111:11434`。
- ✅ **正確**: 所有通用文字生成、Q&A 第一響應、Hermes、NemoTron qwen3 路徑、AiderHeal 與 embedding 必須透過 `services/ollama_service.resolve_ollama_host()` 或同等核准 wrapper 取得主機。
- ✅ **正確**: Gemini 只能作為 Ollama 主路徑失敗後的備援,或 ADR-028 明確鎖定的低頻特殊場景。
- ❌ **禁止**: 將 `AI_PROVIDER`、`OLLAMA_HOST`、`HERMES_URL`、`EMBEDDING_HOST`、`OLLAMA_API_BASE` 指向非 GCP-A / GCP-B / 111 的 Ollama 端點。
- ❌ **禁止**: 新增 Gemini-first 的 AI Agent、LLM caller 或把 Gemini 設為通用預設 provider新增 Gemini caller 必須走 ADR review。
- ❌ **禁止**: 使用 188 主機作為 Ollama 節點188 只作為 App/DB/容器宿主與 AutoHeal target。
---
## 第六章:版本管理規範
@@ -332,9 +340,9 @@
## 第十三章AI 四 Agent 自主學習與自動化架構規範2026-04-29 修訂)
### 第 40 條:四 Agent 分工架構(絕對禁止違反)
- **Hermes採集層**: `192.168.0.111` Ollama,負責 embedding、去重、品質分數計算。成本 = $0
- **NemoTron處理層**: NVIDIA NIM Llama 3.1 8B負責 tool calling 邏輯路由與 DB 寫入。限額 80 次/天
- **OpenClaw / Gemini(應用層)**: 負責最終 PPT 生成、洞察報告對外輸出。成本最高,最後動用
- **Hermes採集層**: Ollama 三主機級聯GCP-A → GCP-B → 111,負責 embedding、去重、品質分數計算。成本 = $0
- **NemoTron處理層**: qwen3:14b Ollama-firstNVIDIA NIM Llama 3.1 8B 僅作備援,負責 tool calling 邏輯路由與 DB 寫入。NIM 限額 80 次/天
- **OpenClaw應用層**: Ollama-firstGemini 僅作備援或 ADR-028 鎖定場景,負責最終 PPT 生成、洞察報告對外輸出。
- **ElephantAlpha編排層**: 負責跨 Agent orchestration、HITL、AutoHeal bridge 與受控執行計畫,不可繞過安全入口
- ❌ **禁止**:讓 OpenClaw 做 Hermes 層的苦力工作(高算力浪費)
- ❌ **禁止**:讓 Hermes 直接生成對外報告(品質不足)
@@ -353,7 +361,7 @@
- **理由**:混合查詢(`WHERE` 結構化 + `ORDER BY embedding <->` 語意)只有 pgvector 能一條 SQL 搞定ADR-002
### 第 43 條Embedding 本地化(強制要求)
- ✅ **正確**:使用 `bge-m3`(或 `nomic-embed-text`)掛載在 Hermes 主機 `192.168.0.111` Ollama
- ✅ **正確**:使用 `bge-m3`(或 `nomic-embed-text`)掛載在 Ollama 三主機級聯GCP-A → GCP-B → 111
- ❌ **禁止**:呼叫外部 Embedding API成本與隱私雙重問題
- **維度**1024 dim`vector(1024)` 欄位ADR-003

View File

@@ -63,6 +63,8 @@ services:
- ./auth.py:/app/auth.py:ro
- ./gunicorn.conf.py:/app/gunicorn.conf.py:ro
- ./scheduler.py:/app/scheduler.py:ro
- ./scripts:/app/scripts:ro
- ./migrations:/app/migrations:ro
- ./services:/app/services:ro
- ./routes:/app/routes:ro
- ./database:/app/database:ro
@@ -87,10 +89,11 @@ services:
- POSTGRES_USER=${POSTGRES_USER:-momo}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB:-momo_analytics}
# Ollama 主機GCP 優先 / 111 自動備援ADR-003
- OLLAMA_HOST_PRIMARY=${OLLAMA_HOST_PRIMARY:-http://34.21.145.224:11434}
# Ollama 主機GCP-A → GCP-B → 111 自動備援ADR-028
- OLLAMA_HOST_PRIMARY=${OLLAMA_HOST_PRIMARY:-http://34.143.170.20:11434}
- OLLAMA_HOST_SECONDARY=${OLLAMA_HOST_SECONDARY:-http://34.21.145.224:11434}
- OLLAMA_HOST_FALLBACK=${OLLAMA_HOST_FALLBACK:-http://192.168.0.111:11434}
# EMBEDDING_HOST 若未設定,由 resolve_ollama_host() 自動決定(GCP 優先
# EMBEDDING_HOST 若未設定,由 resolve_ollama_host() 自動決定(三主機級聯
- EMBEDDING_HOST=${EMBEDDING_HOST:-}
# ADR-020: Code Review 全自動修復主開關
# 預設 true任何 finding 一律觸發 AiderHeal可在 .env 顯式設 false 即時切斷
@@ -214,8 +217,9 @@ services:
# H7 (2026-04-24): POSTGRES_* 改由 env_file: .env 唯一來源,移除 compose 層插值避免空值覆蓋
- USE_POSTGRESQL=true
- POSTGRES_PORT=5432
# Ollama 主機GCP 優先 / 111 自動備援ADR-003
- OLLAMA_HOST_PRIMARY=${OLLAMA_HOST_PRIMARY:-http://34.21.145.224:11434}
# Ollama 主機GCP-A → GCP-B → 111 自動備援ADR-028
- OLLAMA_HOST_PRIMARY=${OLLAMA_HOST_PRIMARY:-http://34.143.170.20:11434}
- OLLAMA_HOST_SECONDARY=${OLLAMA_HOST_SECONDARY:-http://34.21.145.224:11434}
- OLLAMA_HOST_FALLBACK=${OLLAMA_HOST_FALLBACK:-http://192.168.0.111:11434}
- EMBEDDING_HOST=${EMBEDDING_HOST:-}
env_file:
@@ -271,8 +275,9 @@ services:
# H7 (2026-04-24): POSTGRES_* 改由 env_file: .env 唯一來源,移除 compose 層插值避免空值覆蓋
- USE_POSTGRESQL=true
- POSTGRES_PORT=5432
# Ollama 主機GCP 優先 / 111 自動備援ADR-003
- OLLAMA_HOST_PRIMARY=${OLLAMA_HOST_PRIMARY:-http://34.21.145.224:11434}
# Ollama 主機GCP-A → GCP-B → 111 自動備援ADR-028
- OLLAMA_HOST_PRIMARY=${OLLAMA_HOST_PRIMARY:-http://34.143.170.20:11434}
- OLLAMA_HOST_SECONDARY=${OLLAMA_HOST_SECONDARY:-http://34.21.145.224:11434}
- OLLAMA_HOST_FALLBACK=${OLLAMA_HOST_FALLBACK:-http://192.168.0.111:11434}
- EMBEDDING_HOST=${EMBEDDING_HOST:-}
env_file:

View File

@@ -1,25 +1,34 @@
# MOMO PRO — AI 競價情報模組 Single Source of Truth
> **最後更新**: 2026-05-01 (台北時間)
> **狀態**: 🟢 四 AI Agent 自動化閉環已落地 — EventRouter / AutoHeal / OpenClaw Memory / ElephantAlpha bridge / Prometheus metrics / Smoke Dashboard / Smoke Trend Management / Telegram Summary / Grafana provisioning / Prometheus scrape / CD Gunicorn 掛載具測試覆蓋
> **適用版本**: V10.22 Legacy 5888 入口清理版
> **最後更新**: 2026-05-12 (台北時間)
> **狀態**: 🟢 四 AI Agent 自動化閉環已落地LLM 路由紅線升級為 Ollama-first 三主機級聯Gemini 僅備援 / 鎖定場景
> **適用版本**: V10.91
---
## 零、LLM 路由紅線2026-05-12
- 所有 AI Agent、LLM 推理與 embedding 預設必須走 Ollama 三主機級聯GCP-A `34.143.170.20:11434` → GCP-B `34.21.145.224:11434` → 111 `192.168.0.111:11434`
- `services/ollama_service.resolve_ollama_host()` 是主機解析契約;`OLLAMA_HOST``HERMES_URL``EMBEDDING_HOST``OLLAMA_API_BASE` 只接受 GCP-A / GCP-B / 111 或 110 的核准轉發端口。
- Gemini 只能作為 Ollama 主路徑失敗後的備援,或 ADR-028 明確鎖定的 MCP Grounding、PPT/vision、週/月報、Code Review、EA HITL、複雜 SKU 升級等低頻場景。
- 188 `192.168.0.188` 僅是 App / DB / scheduler / Telegram bot 容器宿主與 AutoHeal target不可作為 Ollama 節點。
- 通用 AI 文案、關鍵字、商品洞察與 Telegram Q&A 第一響應不得 Gemini-first。
## 一、四 AI Agent 路由架構
```
SQL漏斗(~300筆)
[Hermes 3 8B] — 分析師 (本地 Ollama, 零成本)
模型: hermes3:latest @ 192.168.0.111:11434
[Hermes 3 8B] — 分析師 (Ollama 三主機級聯, 零成本)
模型: hermes3:latest @ GCP-A → GCP-B → 111
任務: 競價威脅分類 → TOP 20 HIGH/MED/LOW
[NemoTron NIM] — 派發器 (雲端, 免費配額)
模型: meta/llama-3.1-8b-instruct @ NVIDIA NIM
[NemoTron / qwen3] — 派發器
主路徑: qwen3:14b @ Ollama 三主機級聯
備援: NVIDIA NIM meta/llama-3.1-8b-instruct
任務: Tool Calling → Telegram 告警 / DB 寫入
[OpenClaw / Gemini] — 策略師 (費用審批制)
[OpenClaw] — 策略師 (Ollama-firstGemini 僅備援 / 鎖定場景)
任務: 週策略報告、洞察報告、L3 HITL 建議
[ElephantAlpha] — 編排者 (L3 Orchestrator)
@@ -41,9 +50,9 @@ SQL漏斗(~300筆)
| 角色 | 模型 | 主機 | 成本 | 每日限額 |
|------|------|------|------|---------|
| Hermes 分析師 | hermes3:latest / embedding model | 192.168.0.111:11434 或 188 Ollama | 零 | 無限 |
| NemoTron 派發器 | meta/llama-3.1-8b-instruct | NVIDIA NIM | 免費 80/天 | 80 |
| OpenClaw 策略師 | Gemini | 雲端 | 需審批 | — |
| Hermes 分析師 | hermes3:latest / bge-m3 | GCP-A → GCP-B → 111 Ollama | 零 | 無限 |
| NemoTron 派發器 | qwen3:14bNIM fallback | GCP-A → GCP-B → 111NVIDIA NIM 備援 | Ollama 零NIM 配額內免費 | NIM 80 |
| OpenClaw 策略師 | qwen3:14b / Gemini 鎖定場景 | Ollama-firstGemini 備援 | Ollama 零Gemini 需控管 | — |
| ElephantAlpha 編排者 | ElephantAlpha | 依部署環境 | 受控 | HITL / 任務制 |
---
@@ -363,7 +372,7 @@ python3 services/competitor_price_feeder.py
─────────────────────
⚙️ 運算足跡:
• 🔍 分析: Hermes 3 8B (本地 111) | 耗時: 34.2s | Tokens: 512 | $0 成本
• 🔍 分析: Hermes 3 8B (GCP-A/GCP-B/111 Ollama) | 耗時: 34.2s | Tokens: 512 | $0 成本
• ⚡ 決策: NemoTron NIM | 185 Tokens | $0 (配額內 2/80)
```
@@ -386,7 +395,7 @@ python3 services/competitor_price_feeder.py
─────────────────────
⚙️ 運算足跡:
• 🔍 分析: Hermes 3 8B (本地 111) | 耗時: 34.2s | Tokens: 512 | $0 成本
• 🔍 分析: Hermes 3 8B (GCP-A/GCP-B/111 Ollama) | 耗時: 34.2s | Tokens: 512 | $0 成本
• ⚡ 決策: NemoTron NIM | 185 Tokens | $0 (配額內 2/80)
```
@@ -407,18 +416,18 @@ python3 services/competitor_price_feeder.py
─────────────────────
⚙️ 運算足跡:
• 🔍 分析: Hermes 3 8B (本地 111) | 耗時: 34.2s | Tokens: 512 | $0 成本
• 🔍 分析: Hermes 3 8B (GCP-A/GCP-B/111 Ollama) | 耗時: 34.2s | Tokens: 512 | $0 成本
• ⚡ 決策: NemoTron NIM | 185 Tokens | $0 (配額內 2/80)
```
#### 類別四(未來)Gemini 雲端推理週報
#### 類別四Gemini 備援 / 鎖定場景推理週報
```
... (前文省略) ...
─────────────────────
⚙️ 運算足跡:
• 🔍 彙整: Hermes 3 8B (本地 111) | 耗時: 12s | $0 成本
• 🧠 推理: Gemini 1.5 Flash | 8,420 Tokens | 費用: 約 $0.003 USD
• 🔍 彙整: Hermes 3 8B (GCP-A/GCP-B/111 Ollama) | 耗時: 12s | $0 成本
• 🧠 備援/鎖定場景: Gemini 2.5 Flash | 8,420 Tokens | 費用: 約 $0.003 USD
```
### 5.4 運算足跡資料來源
@@ -459,7 +468,7 @@ python3 services/competitor_price_feeder.py
|------|--------------|
| Hermes 分析師 | `[Hermes 分析師]` |
| NemoTron 派發器 | `[NemoTron 派發器]` |
| Gemini 策略師 | `[Gemini 策略師]` (未來) |
| Gemini 備援 | `[Gemini 備援]`(僅 Ollama 失敗或 ADR-028 鎖定場景) |
### 三種告警類型
| Tool | 觸發條件 | Telegram 格式 |
@@ -476,7 +485,7 @@ python3 services/competitor_price_feeder.py
| 參數 | 值 |
|------|---|
| 模型 | `hermes3:latest` |
| Ollama URL | `http://192.168.0.111:11434` |
| Ollama URL | GCP-A `http://34.143.170.20:11434` → GCP-B `http://34.21.145.224:11434` → 111 `http://192.168.0.111:11434` |
| Timeout | 120s |
| Temperature | 0.1 |
| 實測推理時間 | **19.3s3筆實彈 2026-04-17** |
@@ -506,7 +515,7 @@ python3 services/competitor_price_feeder.py
| P1 | 告警去重 TTL | 同一 SKU 短期內重複告警未防範 |
| P1 | `daily_sales_snapshot` 欄位防禦 | 若 Excel 欄位名變更JOIN 條件會靜默失效 |
| P2 | Scheduler 整合 | 每6小時自動觸發 Hermes→NIM→Telegram 管線 |
| P2 | Gemini 策略師 | 週報生成(需費用審批後實作) |
| P2 | Gemini 備援治理 | 僅保留 ADR-028 鎖定場景與 Ollama 失敗備援,新增 caller 必須走 ADR |
---
@@ -519,7 +528,9 @@ python3 services/competitor_price_feeder.py
| PostgreSQL | 192.168.0.188 | `momo-db` | pgvector/pgvector:pg14含所有 AI 相關表 |
| momo-app | 192.168.0.188 | `momo-pro-system` | **Up healthyport 5002:80**5001 被 docker-registry 佔用,已改 5002 |
| momo-scheduler | 192.168.0.188 | `momo-scheduler` | 常駐排程容器 |
| Hermes 3 8B | 192.168.0.111 | Ollama 原生 | `hermes3:latest`E2E 可達 |
| Ollama Primary | 34.143.170.20 | Ollama 原生 | GCP-AAI/LLM/embedding 主路徑 |
| Ollama Secondary | 34.21.145.224 | Ollama 原生 | GCP-B同等備援 |
| Ollama Fallback | 192.168.0.111 | Ollama 原生 | 最後一道本地防線 |
| E2E 驗證容器 | 192.168.0.188 | `momo-e2e-test` | 臨時容器,含新服務模組 |
### 188 `/home/ollama/momo-pro/.env` 正確設定

View File

@@ -48,14 +48,14 @@ HEALTH_CHECK_URL: str = (
# ADR-027 Phase 2 N2OLLAMA_API_BASE 改 lazy resolveGCP 優先 / 111 備援)。
# 注意:本變數透過 SSH 傳入 110 上的 Aider CLI 執行環境line 312 OLLAMA_API_BASE=...
# 所以每次 execute_code_fix 啟動時才需要值;此處僅作為「無 env 時的預設」。
# 顯式 env 設定者(運維/.env優先使用,符合向下相容
# 顯式 env 設定者(運維/.env只接受 GCP-A/GCP-B/111避免自動修復流量繞過 ADR-028
def _default_ollama_api_base() -> str:
"""Lazy 取得 Aider CLI 用的 Ollama API base避免 import-time 寫死 111。"""
env_val = os.getenv("OLLAMA_API_BASE")
if env_val:
return env_val
try:
from services.ollama_service import resolve_ollama_host
from services.ollama_service import approved_ollama_env, resolve_ollama_host
env_val = approved_ollama_env("OLLAMA_API_BASE")
if env_val:
return env_val
return resolve_ollama_host()
except Exception:
# 兜底:保留原行為 — 內網 111