diff --git a/.env.example b/.env.example index 3ee9f96..4ba9d69 100644 --- a/.env.example +++ b/.env.example @@ -220,18 +220,18 @@ BOT_API_TOKEN=your_bot_api_token_here # ADR-020 規定預設 true(任何 finding 一律自動觸發 AiderHeal,安全網=Git+CI/CD 回滾) # 僅在需要短期關閉自動修復鏈時設為 false CODE_REVIEW_OLLAMA_MODEL=qwen2.5-coder:7b -CODE_REVIEW_OLLAMA_TIMEOUT=45 +CODE_REVIEW_OLLAMA_TIMEOUT=15 CODE_REVIEW_OLLAMA_SECONDARY_MODEL=gemma3:4b -CODE_REVIEW_OLLAMA_SECONDARY_TIMEOUT=25 +CODE_REVIEW_OLLAMA_SECONDARY_TIMEOUT=60 CODE_REVIEW_OLLAMA_FALLBACK_MODEL=hermes3:latest CODE_REVIEW_OLLAMA_FALLBACK_TIMEOUT=20 CODE_REVIEW_OLLAMA_NUM_PREDICT=384 CODE_REVIEW_OLLAMA_KEEP_ALIVE=5m CODE_REVIEW_HERMES_TIMEOUT=35 CODE_REVIEW_HERMES_PRIMARY_MODEL=qwen2.5-coder:7b -CODE_REVIEW_HERMES_PRIMARY_TIMEOUT=35 +CODE_REVIEW_HERMES_PRIMARY_TIMEOUT=15 CODE_REVIEW_HERMES_SECONDARY_MODEL=gemma3:4b -CODE_REVIEW_HERMES_SECONDARY_TIMEOUT=25 +CODE_REVIEW_HERMES_SECONDARY_TIMEOUT=45 CODE_REVIEW_HERMES_FALLBACK_MODEL=hermes3:latest CODE_REVIEW_HERMES_FALLBACK_TIMEOUT=20 CODE_REVIEW_HERMES_NUM_PREDICT=384 diff --git a/config.py b/config.py index 6da6b19..5a263fe 100644 --- a/config.py +++ b/config.py @@ -325,7 +325,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '') # ========================================== # 系統版本與路徑 # ========================================== -SYSTEM_VERSION = "V10.409" +SYSTEM_VERSION = "V10.410" LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log') public_url = PUBLIC_URL # 用於模板顯示 diff --git a/docs/AI_INTELLIGENCE_MODULE_SOT.md b/docs/AI_INTELLIGENCE_MODULE_SOT.md index 06fe3dd..80ae187 100644 --- a/docs/AI_INTELLIGENCE_MODULE_SOT.md +++ b/docs/AI_INTELLIGENCE_MODULE_SOT.md @@ -19,7 +19,7 @@ - Code Review pipeline 也必須 Ollama-first:Hermes scan 與 OpenClaw assessment 都走 `OllamaService` 三主機 retry;Gemini telemetry 只能以 `code_review_openclaw_gemini` 出現,表示 Ollama/可選 Claude 備援都失敗後才啟用。 - Code Review Hermes scan 預設不呼叫 LLM,改用 deterministic fast static scan,避免部署後先卡三段 Ollama timeout;需要 LLM 掃描時才以 `CODE_REVIEW_HERMES_LLM_SCAN_ENABLED=true` 啟用本地矩陣。 - Code Review Hermes LLM scan 啟用時才使用本地模型矩陣:GCP-A `qwen2.5-coder:7b`、GCP-B `gemma3:4b`;落到 111 時由 `OllamaService` 降級到 `llama3.2:latest`。不啟用 Gemini 備援,三段本地掃描失敗時只回空 findings 並交由 OpenClaw 本地矩陣續跑。 -- Code Review OpenClaw assessment 保持主機順序 GCP-A → GCP-B → 111,但可使用主機適配本地模型:GCP-A `qwen2.5-coder:7b`、GCP-B `gemma3:4b`;落到 111 時由 `OllamaService` 降級到 `llama3.2:latest`。Code Review 的 Ollama `keep_alive` 預設為 `5m`,不得再用 `24h` 長駐 runner 壓住 GCP-B/111。三段本地 Ollama 全失敗後才允許雲端備援。 +- Code Review OpenClaw assessment 保持主機順序 GCP-A → GCP-B → 111,但可使用主機適配本地模型:GCP-A `qwen2.5-coder:7b`、GCP-B `gemma3:4b`;primary timeout 預設 `15s`、secondary timeout 預設 `60s`,讓 A 掛時快速讓位給 B,且 B 有足夠時間完成審查 prompt。落到 111 時由 `OllamaService` 降級到 `llama3.2:latest`。Code Review 的 Ollama `keep_alive` 預設為 `5m`,不得再用 `24h` 長駐 runner 壓住 GCP-B/111。三段本地 Ollama 全失敗後才允許雲端備援。 - OpenClaw Telegram Q&A 主路徑也不得綁單一 host:`_call_qwen3_qa()` 必須透過 `OllamaService` 跑 GCP-A → GCP-B → 111,並把實際落點寫入 `ai_calls.provider`。 - OpenClaw Telegram 圖片商品辨識也必須 Ollama-first:`_identify_product_name_with_ollama_vision()` 透過 `OllamaService` 嘗試 GCP-A → GCP-B → 111;Gemini 只允許以 `openclaw_bot_image_gemini` caller 作為失敗後備援。 - OpenClaw 週報、月報、Meta analysis、日報洞察、Telegram PPT 分析與 MCP fallback 也必須 Ollama-first;Gemini caller 只能帶 `_gemini_fallback` 或明確 fallback caller 語意,且不得先於 Ollama/NIM 被呼叫。OpenClaw strategy 的 Ollama `keep_alive` 預設為 `5m`,避免報告型任務把 GCP-B/111 runner 長駐 24h。 diff --git a/docs/memory/history_logs.md b/docs/memory/history_logs.md index db8f2b4..14e4730 100644 --- a/docs/memory/history_logs.md +++ b/docs/memory/history_logs.md @@ -13,6 +13,7 @@ ## 📅 詳細更新日誌 (考古存檔) ### 2026-05-24:PChome 近門檻身份回收第二輪 +- **V10.410 Code Review timeout 梯度改為保護 111**: 部署後實測顯示 GCP-A 從 188 失聯時,Code Review 仍會先等 primary 45s,GCP-B 完整審查 prompt 又常因 25s 太短而 timeout,最後轉落 111。`CODE_REVIEW_OLLAMA_TIMEOUT` 預設收斂為 `15s`,`CODE_REVIEW_OLLAMA_SECONDARY_TIMEOUT` 放寬為 `60s`;Hermes LLM scan 若啟用則 primary `15s`、secondary `45s`。目標是 A 掛時更快讓位給 B,並給 B 足夠時間完成,避免過早壓到 111。 - **V10.409 MCP fetch target review gate**: 新增 `mcp_fetch_target_review` read-only builder、GET/POST endpoint、UI target review 審核面板與 deployment readiness smoke target,讓 manual fetch handoff 通過後,先審核 adapter registry 公開入口、每平台節流、樣本數、timeout 與 rollback plan;API/UI 不保存 payload、不發外部 request、不開 DB、不寫入、不掛 scheduler,也不會自動打開 manual fetch。 - **V10.408 OPI 指甲油 catalog review-only 回收**: marketplace matcher 針對 OPI 類光繚指甲油加入同系列 catalog focused identity,只在「白日夢遊」或「驕傲果凍」系列名雙方一致時進 `identity_review`;12色/11色視為可選色號數差異,不當作販售件數,跨系列仍維持 suppress。production pilot 已回刷 KATE 怪獸級持色唇膏限量款與兩個 OPI SKU 共 3/3,`matched` 1613→1616、`true_low_confidence` 766→763,三筆皆為 `alert_tier_identity_review` / `price_basis_manual_review`,不進 Hermes 直接價格告警。 - **V10.407 Hermes/OpenClaw runner 熱駐留收斂**: V10.406 後續觀測顯示 GCP-B 仍會被 Hermes/OpenClaw 的 `24h` keep-alive runner 壓高 load,導致 GCP-B generate timeout 後轉落 111。`HERMES_KEEP_ALIVE` 與 `OPENCLAW_STRATEGY_OLLAMA_KEEP_ALIVE` 改為 env 可控且預設 `5m`,並補測試禁止 OpenClaw strategy 再硬寫 `keep_alive="24h"`;GCP-A 目前從 188 仍逾時,需另行修復主機/防火牆。 diff --git a/services/code_review_pipeline_service.py b/services/code_review_pipeline_service.py index b8a263f..65d66a7 100644 --- a/services/code_review_pipeline_service.py +++ b/services/code_review_pipeline_service.py @@ -47,13 +47,13 @@ CODE_REVIEW_OLLAMA_MODEL = os.getenv( "CODE_REVIEW_OLLAMA_MODEL", os.getenv("OPENCLAW_OLLAMA_MODEL", "qwen2.5-coder:7b"), ) -CODE_REVIEW_OLLAMA_TIMEOUT = int(os.getenv("CODE_REVIEW_OLLAMA_TIMEOUT", "45")) +CODE_REVIEW_OLLAMA_TIMEOUT = int(os.getenv("CODE_REVIEW_OLLAMA_TIMEOUT", "15")) CODE_REVIEW_OLLAMA_SECONDARY_MODEL = os.getenv( "CODE_REVIEW_OLLAMA_SECONDARY_MODEL", "gemma3:4b", ) CODE_REVIEW_OLLAMA_SECONDARY_TIMEOUT = int( - os.getenv("CODE_REVIEW_OLLAMA_SECONDARY_TIMEOUT", "25") + os.getenv("CODE_REVIEW_OLLAMA_SECONDARY_TIMEOUT", "60") ) CODE_REVIEW_OLLAMA_FALLBACK_MODEL = os.getenv( "CODE_REVIEW_OLLAMA_FALLBACK_MODEL", @@ -78,9 +78,9 @@ CODE_REVIEW_HERMES_FALLBACK_MODEL = os.getenv( CODE_REVIEW_OLLAMA_FALLBACK_MODEL, ) CODE_REVIEW_HERMES_PRIMARY_TIMEOUT = int( - os.getenv("CODE_REVIEW_HERMES_PRIMARY_TIMEOUT", os.getenv("CODE_REVIEW_HERMES_TIMEOUT", "35")) + os.getenv("CODE_REVIEW_HERMES_PRIMARY_TIMEOUT", os.getenv("CODE_REVIEW_HERMES_TIMEOUT", "15")) ) -CODE_REVIEW_HERMES_SECONDARY_TIMEOUT = int(os.getenv("CODE_REVIEW_HERMES_SECONDARY_TIMEOUT", "25")) +CODE_REVIEW_HERMES_SECONDARY_TIMEOUT = int(os.getenv("CODE_REVIEW_HERMES_SECONDARY_TIMEOUT", "45")) CODE_REVIEW_HERMES_FALLBACK_TIMEOUT = int(os.getenv("CODE_REVIEW_HERMES_FALLBACK_TIMEOUT", "20")) CODE_REVIEW_HERMES_NUM_PREDICT = int(os.getenv("CODE_REVIEW_HERMES_NUM_PREDICT", "384")) CODE_REVIEW_HERMES_MAX_FILES = int(os.getenv("CODE_REVIEW_HERMES_MAX_FILES", "2")) diff --git a/tests/test_code_review_claude_routing.py b/tests/test_code_review_claude_routing.py index d555edf..1f4d527 100644 --- a/tests/test_code_review_claude_routing.py +++ b/tests/test_code_review_claude_routing.py @@ -218,18 +218,18 @@ def test_code_review_ollama_defaults_use_fast_local_model(monkeypatch): svc_mod = _reload_pipeline() assert svc_mod.CODE_REVIEW_OLLAMA_MODEL == "qwen2.5-coder:7b" - assert svc_mod.CODE_REVIEW_OLLAMA_TIMEOUT == 45 + assert svc_mod.CODE_REVIEW_OLLAMA_TIMEOUT == 15 assert svc_mod.CODE_REVIEW_OLLAMA_SECONDARY_MODEL == "gemma3:4b" - assert svc_mod.CODE_REVIEW_OLLAMA_SECONDARY_TIMEOUT == 25 + assert svc_mod.CODE_REVIEW_OLLAMA_SECONDARY_TIMEOUT == 60 assert svc_mod.CODE_REVIEW_OLLAMA_FALLBACK_MODEL == "hermes3:latest" assert svc_mod.CODE_REVIEW_OLLAMA_FALLBACK_TIMEOUT == 20 assert svc_mod.CODE_REVIEW_OLLAMA_NUM_PREDICT == 384 assert svc_mod.CODE_REVIEW_OLLAMA_KEEP_ALIVE == "5m" assert svc_mod.CODE_REVIEW_HERMES_TIMEOUT == 35 assert svc_mod.CODE_REVIEW_HERMES_PRIMARY_MODEL == "qwen2.5-coder:7b" - assert svc_mod.CODE_REVIEW_HERMES_PRIMARY_TIMEOUT == 35 + assert svc_mod.CODE_REVIEW_HERMES_PRIMARY_TIMEOUT == 15 assert svc_mod.CODE_REVIEW_HERMES_SECONDARY_MODEL == "gemma3:4b" - assert svc_mod.CODE_REVIEW_HERMES_SECONDARY_TIMEOUT == 25 + assert svc_mod.CODE_REVIEW_HERMES_SECONDARY_TIMEOUT == 45 assert svc_mod.CODE_REVIEW_HERMES_FALLBACK_MODEL == "hermes3:latest" assert svc_mod.CODE_REVIEW_HERMES_FALLBACK_TIMEOUT == 20 assert svc_mod.CODE_REVIEW_HERMES_NUM_PREDICT == 384 @@ -297,8 +297,8 @@ def test_openclaw_uses_secondary_local_model_before_gemini(monkeypatch): assert result == "SECONDARY-LOCAL" assert [call["model"] for call in calls] == ["qwen2.5-coder:7b", "gemma3:4b"] - assert calls[0]["timeout"] == 45 - assert calls[1]["timeout"] == 25 + assert calls[0]["timeout"] == 15 + assert calls[1]["timeout"] == 60 fake_claude.generate.assert_not_called() fake_genai.GenerativeModel.assert_not_called() fake_elephant.generate.assert_not_called()