# Phase 2 部署驗證劇本(ADR-027 真正落地) > **Date**: 2026-05-03 > **Phase**: Operation Ollama-First v5.0 — Phase 2(A6 debugger) > **修補項**: B1 / B2 / B3 / B4 / N2 / N3 > **修改檔**: `config.py` / `services/ollama_service.py` / `services/aider_heal_executor.py` / `services/code_review_pipeline_service.py` > **新檔**: `tests/test_ollama_resolve.py`(13 tests,本機已通過) --- ## 一、部署前 dry-run(本機) ### 1.1 語法檢查 ```bash cd "/Users/ooo/Library/Mobile Documents/com~apple~CloudDocs/momo-pro-system" python3 -m py_compile config.py services/ollama_service.py \ services/aider_heal_executor.py services/code_review_pipeline_service.py \ tests/test_ollama_resolve.py && echo "PYCOMPILE_OK" ``` 期望:`PYCOMPILE_OK`(已驗證) ### 1.2 Unit test ```bash MOMO_ALLOW_INSECURE_CONFIG_FOR_TESTS=true /opt/anaconda3/bin/python3 -m pytest \ tests/test_ollama_resolve.py \ tests/test_phase3f_cleanup_contracts.py \ tests/test_app_startup_contracts.py \ tests/test_ai_call_logger.py \ tests/test_code_review_pipeline_security.py \ tests/test_auto_heal_safety.py -v ``` 期望:56 passed(13 新 + 43 既有)。已驗證。 ### 1.3 import 一致性 ```bash MOMO_ALLOW_INSECURE_CONFIG_FOR_TESTS=true /opt/anaconda3/bin/python3 -c " from config import get_ollama_host, get_hermes_url, get_embedding_host from services.ollama_service import resolve_ollama_host, mark_unhealthy print('get_ollama_host =', get_ollama_host()) print('get_hermes_url =', get_hermes_url()) print('get_embedding_host =', get_embedding_host()) print('resolve_ollama_host=', resolve_ollama_host()) " ``` 期望(網路通時):四行都印 `http://34.21.145.224:11434`(GCP 可達)或 `http://192.168.0.111:11434`(GCP 不可達)。 不可出現 `https://ollama.wooo.work/ollama`(舊寫死 URL)。 --- ## 二、部署後驗證(SSH 188) ### 2.1 容器健康 ```bash ssh wooo@192.168.0.110 "ssh ollama@192.168.0.188 \"\ docker ps --format '{{.Names}} | {{.Status}}' | grep momo-; \ docker exec momo-pro python3 -c 'from config import get_ollama_host; print(get_ollama_host())' 2>&1\"" ``` 期望: - `momo-pro | Up`(重啟後新容器) - 列印的 host 不是 `https://ollama.wooo.work/ollama` ### 2.2 OllamaHost 解析 log(B3 HTTP probe 驗證) ```bash ssh wooo@192.168.0.110 "ssh ollama@192.168.0.188 \"\ docker logs momo-pro --since 10m 2>&1 | grep -E 'OllamaHost' | tail -20\"" ``` 期望(GCP 可達): ``` [OllamaHost] GCP 主機可用,使用 Primary: http://34.21.145.224:11434 ``` 期望(GCP 掛時): ``` [OllamaHost] GCP 主機無法連線,自動切換 Fallback: http://192.168.0.111:11434 ``` 罕見(process 卡死,TCP 通但 HTTP 掛): ``` [OllamaHost] GCP HTTP 探測失敗但 TCP 仍通,疑似 process 卡死:http://34.21.145.224:11434 [OllamaHost] GCP 主機無法連線,自動切換 Fallback: http://192.168.0.111:11434 ``` > 第三種日誌是 **Phase 2 修補後才會看見的新觀測能力**,舊版純 TCP 探測不會印。 ### 2.3 mark_unhealthy 觸發(B4 驗證) 當 LLM generate 真的失敗時,會看見: ``` [OllamaHost] 主機標記為 unhealthy(30s 跳過):http://34.21.145.224:11434 ``` 立刻在下一次任何 ollama 呼叫的 log 看: ``` [OllamaHost] Primary http://34.21.145.224:11434 仍在 unhealthy TTL 內,跳過直接 fallback: http://192.168.0.111:11434 ``` ### 2.4 AiderHeal OLLAMA_API_BASE 動態化(N2 驗證) 下次 AiderHeal 觸發時 grep: ```bash ssh wooo@192.168.0.110 "ssh ollama@192.168.0.188 \"\ docker logs momo-pro --since 30m 2>&1 | grep 'aider_ollama_api_base' | tail -5\"" ``` 期望: ``` event=aider_ollama_api_base host=http://34.21.145.224:11434 ``` (GCP 可達時)或 `host=http://192.168.0.111:11434`(fallback)。 **絕不可** 仍顯示 `http://192.168.0.111:11434` 當 GCP 是可達的。 ### 2.5 Code Review provider tag(N3 驗證) 下次 Code Review pipeline 觸發後: ```bash ssh wooo@192.168.0.110 "ssh ollama@192.168.0.188 \"\ docker exec momo-postgres psql -U momo -d momo_analytics -c \ \\\"SELECT caller, provider, meta->>'host' AS host \ FROM ai_calls \ WHERE caller = 'code_review_hermes' \ ORDER BY created_at DESC LIMIT 5;\\\"\"" ``` 期望(GCP 通時): ``` caller | provider | host code_review_hermes | gcp_ollama | http://34.21.145.224:11434 ``` 絕不可仍標 `ollama_111` 當 host 是 GCP。 --- ## 三、模擬故障驗證(選做) ### 3.1 模擬 GCP 不可達 → 5s 內 fallback 在 188 上臨時封鎖 GCP IP: ```bash ssh wooo@192.168.0.110 "ssh ollama@192.168.0.188 \"\ sudo iptables -A OUTPUT -d 34.21.145.224 -j DROP\"" ``` 立即觸發 sales copy(or 任何 LLM 入口),看 log: - 第一次呼叫應 timeout(2s 內 _is_reachable 失敗)→ 切 fallback - 之後 30s 內所有呼叫直接走 fallback - 30s 後 cache TTL 過期,會重新探測(仍封鎖則繼續 fallback;解封後恢復 GCP) 恢復: ```bash ssh wooo@192.168.0.110 "ssh ollama@192.168.0.188 \"\ sudo iptables -D OUTPUT -d 34.21.145.224 -j DROP\"" ``` > 此項屬統帥權限,debugger 不執行。 --- ## 四、回滾 SOP 若部署後出問題,最快回滾: ```bash git revert git push origin main # 等 Gitea CD 自動部署 ``` 也可以單獨回退 ollama_service.py: ```bash git checkout HEAD~1 -- services/ollama_service.py config.py ``` (其他三檔變更可獨立保留) --- ## 五、commit 草稿 ``` [V-New] ADR-027 Phase 2:Ollama 主機解析全鏈 lazy + HTTP probe + unhealthy 標記 修補 6 項讓 ADR-027「GCP 優先」真正 100% 落地: B1 — config.OLLAMA_HOST 改 lazy resolve(移除寫死 ollama.wooo.work URL) B2 — config.EMBEDDING_HOST / HERMES_URL 改 lazy(避免 import-time freeze) B3 — _is_reachable 改 HTTP probe (/api/version, 2s timeout),TCP 改作觀測點 B4 — 新增 mark_unhealthy(),generate / embedding 失敗時標 30s,cache 失效 N2 — aider_heal_executor.OLLAMA_API_BASE 改 lazy resolve(每次 execute 重評估) N3 — code_review_pipeline_service Hermes scan 改 get_hermes_url() 取代 freeze 新增:tests/test_ollama_resolve.py(13 tests) 變更:config.py / services/ollama_service.py / services/aider_heal_executor.py / services/code_review_pipeline_service.py 驗證:56 tests 全綠(13 新 + 43 既有 regression),py_compile 全綠。 驗證劇本:docs/phase2_deploy_verify_20260503.md(給統帥 SSH 188 跑)。 ```