diff --git a/TODO_NEXT_STEPS.txt b/TODO_NEXT_STEPS.txt index d1cc56c..016acd9 100644 --- a/TODO_NEXT_STEPS.txt +++ b/TODO_NEXT_STEPS.txt @@ -4,6 +4,7 @@ ================================================================================ 【已完成】 + - V10.576 補 PChome backfill backlog 的型錄 lane counts,讓 `/api/ai/pchome-match/backfill/status` 也能回傳 `catalog_variant_review`、`catalog_unit_review`、`catalog_identity_review` 三條操作隊列;同版修正 `OllamaService.generate(allow_111_fallback=False)`,當 lazy resolver 快取到 111 時會強制改試 GCP-A/GCP-B allowlist,不再直接 `all 0 hosts failed`,且仍不把長分析推給 111。 - V10.575 拆分 PChome 型錄可比覆核 lane:`catalog_comparable` 不再只是一個總數,正式拆成 `catalog_variant_review`(選項/色號/款式待核)、`catalog_unit_review`(入數/檔期/商業條件待核)與 `catalog_identity_review`(身份採用待核)。Coverage、review queue filter、Dashboard 分段、decision envelope、Webcrumbs host data 都共用同一套 SQL helper 與 metadata;仍維持 HITL、不自動寫正式價差,讓營運可批次清理最有機會轉成單位價或正式身份的候選。 - V10.574 接上 PChome 型錄/任選可比覆核隊列:沿用 V10.572 的 `catalog_comparable_count` 安全口徑,將高分、無 hard veto、具同品線身份證據但仍有任選/型錄/商業條件待確認的 `true_low_confidence` 候選,拆成獨立 `catalog_comparable` 篩選與 decision envelope。此隊列仍維持 HITL,不寫入正式 `competitor_prices`、不算 exact matched,並把「型錄可比」與真正「證據不足」分開,讓營運可以先批次處理最有機會轉成單位價或正式身份的候選。 - V10.574 新增市場情報 Source Governance → Fetch Target bridge:新增 `/api/market_intel/mcp_fetch_target_source_governance_review`、市場情報頁 bridge panel 與 deployment readiness smoke target,交叉審核 Professional Source Governance 與 MCP Fetch Target Review,要求每個 target `platform_code/source_key` 都能對上已通過治理的公開 source contract;仍不抓外站、不讀 robots/sitemap、不開 DB、不寫檔、不執行 CLI、不掛 scheduler。 diff --git a/config.py b/config.py index 74706d5..5e7038b 100644 --- a/config.py +++ b/config.py @@ -402,7 +402,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '') # ========================================== # 系統版本與路徑 # ========================================== -SYSTEM_VERSION = "V10.575" +SYSTEM_VERSION = "V10.576" LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log') public_url = PUBLIC_URL # 用於模板顯示 diff --git a/docs/memory/current_execution_queue_20260524.md b/docs/memory/current_execution_queue_20260524.md index 0103c23..db72739 100644 --- a/docs/memory/current_execution_queue_20260524.md +++ b/docs/memory/current_execution_queue_20260524.md @@ -104,6 +104,7 @@ - 2026-05-31 起,`V10.506` 新增市場情報 MCP Fetch Candidate Queue Writer Review Decision Approval gate:在 review decision 通過後只審核 operator human approval 摘要,要求 decision linkage、approval identity、target table、row count、dedupe keys、`approved_for_writer_preflight` approval result、decision/approval evidence refs、artifact paths、matched row exact-identity/variant/overwrite guard 與 operator confirmation 對齊;仍不讀 token、不執行 CLI、不開 DB、不寫 approval record、不寫 decision record、不更新 review_state、不寫 match result、不補 queue、不掛 scheduler,只放行到後續 writer preflight 設計。 - 2026-05-31 起,`V10.509` 新增市場情報 MCP Fetch Candidate Queue Writer Review Decision Approval Writer Preflight gate:在 human approval 通過後只審核 operator writer preflight 摘要,要求 approval linkage、writer_preflight_id、target operation、row count、dedupe keys、approved decision 到 target review_state 的逐列映射、decision/approval/preflight evidence refs、matched row exact-identity/variant/overwrite guard 與 operator boundary;仍不讀 token、不執行 CLI、不開 DB、不寫 preflight/approval/decision/match、不更新 review_state、不補 queue、不掛 scheduler,只放行到後續 CLI review / run package 設計。 - 2026-06-01 起,`V10.566` 新增市場情報 Professional Source Governance gate:將 robots/REP、sitemap/lastmod、JSON-LD / schema.org structured data、canonical URL、rate limit、公開資料邊界、provenance、snapshot hash 與 idempotency key 納入 source contract,並接上 `/api/market_intel/mcp_professional_source_governance`、UI preview panel、deployment readiness check 與 production smoke target;仍不抓外站、不讀 robots/sitemap、不開 DB、不寫檔、不掛 scheduler。 +- 2026-06-04 起,`V10.576` 修正 GCP-only Ollama retry:caller 禁用 111 fallback 時,resolver 若回到 111 會改試 GCP-A/GCP-B allowlist,不再讓 Hermes / Code Review 類任務因 resolver 快取到 111 而 `all 0 hosts failed`。 - 2026-06-04 起,`V10.575` 拆分 PChome 型錄可比覆核 lane:`catalog_comparable` 會依 diagnostic evidence 分成選項/色號、單位/入數與身份採用三條人工處理路徑,Dashboard、decision envelope、coverage 與 Webcrumbs host data 使用同一套統計與 HITL guardrail。 - 2026-06-03 起,`V10.574` 新增市場情報 Source Governance → Fetch Target bridge:`/api/market_intel/mcp_fetch_target_source_governance_review` 交叉審核 Professional Source Governance 與 MCP Fetch Target Review,要求 target `platform_code/source_key` 全部命中已治理 source contract;仍不抓外站、不讀 robots/sitemap、不開 DB、不寫檔、不執行 CLI、不掛 scheduler,只放行到後續人工 fetch run package review。 - 2026-06-02 起,`V10.567` 將 MCP 市場洞察 fallback 收斂為 GCP-A / GCP-B only,不再讓 111 承接非即時市場分析長任務;預設 timeout 25 秒、`num_predict` 500,GCP 不可用時直接保守降級,避免 Elephant Alpha 60 秒 timeout 與 111 負載尖峰。 diff --git a/docs/memory/history_logs.md b/docs/memory/history_logs.md index 556bdce..85ad127 100644 --- a/docs/memory/history_logs.md +++ b/docs/memory/history_logs.md @@ -13,6 +13,7 @@ ## 📅 詳細更新日誌 (考古存檔) ### 2026-06-01:PChome 比價新鮮度操作閉環 +- **V10.576 PChome backlog lane 與 GCP-only Ollama retry 修補**: `/api/ai/pchome-match/backfill/status` 的 coverage 與 operation backlog 同步輸出 `catalog_variant_review`、`catalog_unit_review`、`catalog_identity_review`,讓 Dashboard 操作建議可直接跳到三條人工隊列。同版修正 `OllamaService.generate(allow_111_fallback=False)`:若 resolver 已快取到 111,會改試尚未嘗試的 GCP-A/GCP-B allowlist,不再直接 `all 0 hosts failed`,同時仍避免長分析落到 111。 - **V10.575 PChome 型錄可比覆核 lane 分流**: `catalog_comparable` 進一步拆成 `catalog_variant_review`、`catalog_unit_review` 與 `catalog_identity_review`。Coverage SQL、review queue filter、Dashboard 分段、decision envelope 與 Webcrumbs host data 共用同一套 helper,將選項/色號/款式、入數/商業條件、身份採用三種人工閉環路徑分開統計與瀏覽;仍維持 HITL,不自動寫正式價差。 - **V10.574 PChome 型錄/任選可比覆核隊列**: 將 V10.572 的 `catalog_comparable_count` 派生口徑正式接進 PChome review queue。高分、無 hard veto、具同品線身份證據但仍有任選/型錄/商業條件待確認的 `true_low_confidence` 會進獨立 `catalog_comparable` 篩選、狀態標籤與 decision envelope;真正 `true_low_confidence` 會排除這批候選,避免重複出現在「證據不足」。此變更不放寬 `MIN_MATCH_SCORE`、不寫正式 `competitor_prices`、不算 exact matched,只把最有機會人工批次確認的候選變成可操作隊列。 - **V10.574 市場情報 Source Governance → Fetch Target bridge**: 新增 `/api/market_intel/mcp_fetch_target_source_governance_review`、preview service 與市場情報頁 bridge panel,交叉審核 Professional Source Governance 與 MCP Fetch Target Review。此 gate 要求每個 target `platform_code/source_key` 都能對上已通過治理的公開 source contract,並同步納入 deployment readiness preview-safe check 與 production smoke target;API/UI 仍不抓外站、不讀 robots/sitemap、不開 DB、不寫檔、不執行 CLI、不掛 scheduler。 diff --git a/services/ollama_service.py b/services/ollama_service.py index 22438ee..c4ae4de 100644 --- a/services/ollama_service.py +++ b/services/ollama_service.py @@ -638,9 +638,18 @@ class OllamaService: for attempt in range(max_attempts): current_host = _normalize_host(self.host) # property 每次 lazy resolve if not allow_111_fallback and _is_111_fallback_host(current_host): - last_error = "111 fallback disabled; no approved GCP Ollama host available" - logger.warning("[Ollama] %s", last_error) - break + next_host = next((host for host in allowed_hosts if host not in attempted_hosts), None) + if not next_host: + last_error = "111 fallback disabled; no approved GCP Ollama host available" + logger.warning("[Ollama] %s", last_error) + break + logger.info( + "[Ollama] resolver selected 111 but caller disabled fallback; forcing approved GCP host=%s", + next_host, + ) + if self._explicit_host is None: + _clear_resolved_host_cache() + current_host = next_host if current_host in attempted_hosts: # 已試過同主機時,若是標準三主機鏈且 caller 沒指定 host, # 改走尚未嘗試的下一台。避免 request timeout(60s) 大於 diff --git a/tests/test_ollama_retry_chain.py b/tests/test_ollama_retry_chain.py index 7dc5025..7d989f7 100644 --- a/tests/test_ollama_retry_chain.py +++ b/tests/test_ollama_retry_chain.py @@ -212,7 +212,7 @@ def test_generate_model_404_does_not_mark_host_unhealthy(): def test_generate_can_disable_111_fallback_for_batch_llm_work(): - """批量 LLM 任務可選擇只跑 GCP-A/GCP-B,避免 111 承接長分析。""" + """批量 LLM 任務只跑 GCP-A/GCP-B,resolver 落到 111 時也不直接空跑。""" import requests from services import ollama_service as oss from services.ollama_service import OllamaService @@ -230,9 +230,9 @@ def test_generate_can_disable_111_fallback_for_batch_llm_work(): posted_hosts = [call.args[0].split('/api/generate')[0] for call in mock_post.call_args_list] assert resp.success is False - assert posted_hosts == [oss.OLLAMA_HOST_SECONDARY] + assert posted_hosts == [oss.OLLAMA_HOST_SECONDARY, oss.OLLAMA_HOST_PRIMARY] assert oss.OLLAMA_HOST_FALLBACK not in posted_hosts - assert '111 fallback disabled' in (resp.error or '') + assert 'timeout' in (resp.error or '') def test_generate_skips_111_when_circuit_breaker_blocks_fallback():