diff --git a/.env.example b/.env.example index a6fefea..d44cc22 100644 --- a/.env.example +++ b/.env.example @@ -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 → 111(ADR-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= @@ -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 diff --git a/110-ollama-proxy.conf b/110-ollama-proxy.conf new file mode 100644 index 0000000..439e826 --- /dev/null +++ b/110-ollama-proxy.conf @@ -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"; + } +} diff --git a/AGENTS.md b/AGENTS.md index 5403a53..5ae0a7f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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. 常用入口 diff --git a/CONSTITUTION.md b/CONSTITUTION.md index 3866b74..0dda0f7 100644 --- a/CONSTITUTION.md +++ b/CONSTITUTION.md @@ -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-first,NVIDIA NIM Llama 3.1 8B 僅作備援,負責 tool calling 邏輯路由與 DB 寫入。NIM 限額 80 次/天 +- **OpenClaw(應用層)**: Ollama-first;Gemini 僅作備援或 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) diff --git a/docker-compose.yml b/docker-compose.yml index b530041..f82124f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -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: diff --git a/docs/AI_INTELLIGENCE_MODULE_SOT.md b/docs/AI_INTELLIGENCE_MODULE_SOT.md index b863e8a..1626f46 100644 --- a/docs/AI_INTELLIGENCE_MODULE_SOT.md +++ b/docs/AI_INTELLIGENCE_MODULE_SOT.md @@ -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-first;Gemini 僅備援 / 鎖定場景) 任務: 週策略報告、洞察報告、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:14b;NIM fallback | GCP-A → GCP-B → 111;NVIDIA NIM 備援 | Ollama 零;NIM 配額內免費 | NIM 80 | +| OpenClaw 策略師 | qwen3:14b / Gemini 鎖定場景 | Ollama-first;Gemini 備援 | 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.3s(3筆,實彈 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 healthy,port 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-A,AI/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` 正確設定 diff --git a/services/aider_heal_executor.py b/services/aider_heal_executor.py index dba5d42..40f34df 100644 --- a/services/aider_heal_executor.py +++ b/services/aider_heal_executor.py @@ -48,14 +48,14 @@ HEALTH_CHECK_URL: str = ( # ADR-027 Phase 2 N2:OLLAMA_API_BASE 改 lazy resolve(GCP 優先 / 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