Files
ewoooc/docs/AI_INTELLIGENCE_MODULE_SOT.md
OoO 76a89a7098
All checks were successful
CD Pipeline / deploy (push) Successful in 1m2s
fix: tolerate missing quantities for review candidates
2026-06-19 02:48:23 +08:00

79 KiB
Raw Permalink Blame History

PChome 業績成長自動化作戰系統 — AI 競價情報模組 Single Source of Truth

最後更新: 2026-06-18 (台北時間) 狀態: 🟢 四 AI Agent 自動化閉環已落地LLM 路由紅線升級為 Ollama-first 三主機級聯PChome 後台業績匯入韌性已補強產品定位正名為「PChome 業績成長自動化作戰系統」外部市場來源正規化層、自動同步、作戰清單與價格參考表優先讀取、CSV 備援預檢、前台操作入口、高可見頁面繁中化守門、比價/作戰 UI 工作台化、GCP embedding 熔斷延後處理、110 proxy rescue 與 direct host health skip 已建立 適用版本: V10.627


零、LLM 路由紅線2026-05-12

  • 所有 AI Agent、LLM 推理與 embedding 預設必須走 Ollama 三主機級聯GCP-A 34.87.90.216:11434 → GCP-B 34.21.145.224:11434 → 111 192.168.0.111:11434
  • services/ollama_service.resolve_ollama_host() 是主機解析契約;OLLAMA_HOSTHERMES_URLEMBEDDING_HOSTOLLAMA_API_BASE 只接受 GCP-A / GCP-B / 111 或 110 的核准轉發端口。
  • 188 直連 GCP-A / GCP-B timeout 時resolver 可先使用同順位 110 proxy rescueGCP-A direct → 192.168.0.110:11435 → GCP-B direct → 192.168.0.110:11436 → 111。proxy rescue 只是同一順位的可用入口,不代表 GCP direct host 已恢復。
  • OLLAMA_RESOLVE_HOST_HEALTH_SKIP_ENABLED=trueresolver 會讀最近 host_health_probes;若 direct GCP-A/GCP-B 在視窗內已被判定不健康,會直接略過該 direct endpoint先試同順位 proxy rescue避免每 120 秒 cache refresh 都等待 direct timeout。此 skip 只套用 direct GCP不套用 110 proxy。
  • config.OLLAMA_HOSTconfig.HERMES_URLconfig.EMBEDDING_HOST 只保留為舊 caller 相容常數import-time 不得 probe network也不得因 GCP-A/GCP-B 短暫不可用而 freeze 到 111。需要即時路由時一律呼叫 get_ollama_host()get_hermes_url()get_embedding_host()OllamaService
  • Gemini 只能作為 Ollama 主路徑失敗後的備援MCP Grounding、PPT/vision、週/月報、Code Review、EA HITL、複雜 SKU 升級等舊鎖定場景也必須先走 GCP-A → GCP-B → 111。
  • 188 192.168.0.188 僅是 App / DB / scheduler / Telegram bot 容器宿主與 AutoHeal target不可作為 Ollama 節點。
  • 通用 AI 文案、關鍵字、商品洞察與 Telegram Q&A 第一響應不得 Gemini-first。
  • Hermes intent / analyst 路徑不得手刻 /api/generate 或只 resolve 單次 host必須走 OllamaService。預設 HERMES_ALLOW_111_FALLBACK=false,同一請求只跑 GCP-A → GCP-B兩台都失敗時回規則引擎或 DB 證據 fallback不把批量價格分析轉嫁到 111。救急時才可顯式設 true 允許 111 接手。
  • NemoTron qwen3 dispatch 的 /api/chat tool-calling 路徑也必須同一請求最多嘗試三台 Ollama第一台失敗要 mark_unhealthy() 後再試下一台,最後才 fallback NIM。
  • PPT vision、PPT 文案 final fallback、MCP 離線 final fallback 等特殊 Ollama 路徑也不得只打單一 host如需 /api/generate,一律透過 OllamaService.generate()
  • Code Review pipeline 也必須 Ollama-firstHermes scan 與 OpenClaw assessment 都走 OllamaService 三主機 retryGemini 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:4bCODE_REVIEW_ALLOW_111_FALLBACK=true 時才允許落到 111並由 OllamaService 降級到 llama3.2:latest。不啟用 Gemini 備援,本地掃描失敗時只回空 findings 並交由 OpenClaw 本地矩陣續跑。
  • Code Review OpenClaw assessment 預設只跑 GCP-A → GCP-BGCP-A qwen2.5-coder:7b、GCP-B gemma3:4bprimary timeout 預設 15s、secondary timeout 預設 60s,讓 A 掛時快速讓位給 B且 B 有足夠時間完成審查 prompt。111 是最後救急節點,但部署後重分析預設不打 111只有 CODE_REVIEW_ALLOW_111_FALLBACK=true 才允許 111 接手,並降級到 llama3.2:latest。Code Review 的 Ollama keep_alive 預設為 5m,不得再用 24h 長駐 runner 壓住 GCP-B/111。GCP-A/GCP-B 都失敗且 Claude/Gemini 未顯式開啟時,必須回 deterministic 本地降級摘要,不呼叫 Gemini、不落 111、不走其他雲端模型。
  • Embedding / semantic RAG 背景任務預設只跑 GCP-A → GCP-BOpenClawLearningService embedding worker 與 RAGService 查詢 embedding 呼叫 OllamaService.generate_embedding(..., allow_111_fallback=False)111 只可作人工明確指定的救急路徑,不承接 bge-m3 背景批次。OLLAMA_EMBED_TIMEOUT / OLLAMA_EMBED_MAX_TIMEOUT 預設 30sOLLAMA_EMBED_KEEP_ALIVE=1mOLLAMA_EMBED_MAX_CHARS=4000;此上限依 GCP-B bge-m3 實測 623s 波動調整,避免慢但成功的 embedding 被 15s cap 誤殺。
  • allow_111_fallback=False 時,若 resolver 因 unhealthy cache 回傳 111不得直接結束 embedding必須強制改試尚未嘗試的 GCP-A / GCP-B避免正式 log 出現 tried=[] 或只試單台 GCP-B。
  • allow_111_fallback=False 且 GCP-A / GCP-B 皆失敗時,背景 embedding 會開啟短暫 GCP failure circuit預設 60 秒),期間不重複打兩台 GCP、不落 111避免 worker 與 log 被連續失敗拖慢GCP 恢復後會自然再試。
  • 背景 embedding 的 GCP-only 熔斷屬於可降級背景能力,應記錄為明確 WARNING 與 circuit 狀態,不應每次污染 ERROR 通道;真正允許三主機 fallback 的同步 embedding 全失敗仍保留 ERROR。
  • OpenClaw embedding worker 遇到 GCP-only failure circuit 時,必須把已 claim 任務退回 pending 並延後處理,不得扣 attempts、不得把同批任務刷成 failed;熔斷期間也不得繼續 claim 新任務。
  • Scheduler host health probe 不只看 /api/tagsGCP-A / GCP-B 節點必須再通過 bge-m3 /api/embed 實作探針,才算 healthy。探針 timeout 預設 30s111 預設不納入這個背景 embedding 探針,避免監測任務把 fallback Mac 載入 bge-m3
  • 背景 embedding 會讀取最近 host_health_probes runtime 結果;若 GCP-A / GCP-B 在 OLLAMA_EMBED_HOST_HEALTH_SKIP_WINDOW_MINUTES=20 視窗內已被標為 unhealthyOllamaService.generate_embedding(..., allow_111_fallback=False) 會先跳過該節點並開啟短暫 GCP circuit不再等待 30 秒 timeout也仍不落 111。此功能由 OLLAMA_EMBED_HOST_HEALTH_SKIP_ENABLED=true 控制DB 讀取失敗時 fail-open 回到原本網路 retry。
  • BGE-M3 一致性檢查是監測任務,不是 fallback 壓測;預設只比對 GCP-A / GCP-B。111 Mac fallback 只有 EMBED_CONSISTENCY_INCLUDE_111=true 時才納入,避免每週背景檢查把 bge-m3 載入 111。
  • 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 → 111Gemini 只允許以 openclaw_bot_image_gemini caller 作為失敗後備援。
  • OpenClaw 週報、月報、Meta analysis、日報洞察、Telegram PPT 分析與 MCP fallback 也必須 Ollama-firstGemini caller 只能帶 _gemini_fallback 或明確 fallback caller 語意,且不得先於 Ollama/NIM 被呼叫。OpenClaw strategy 的 Ollama keep_alive 預設為 5m,避免報告型任務把 GCP-B/111 runner 長駐 24h。
  • OpenClaw 週報、月報、Meta analysis、日報洞察與每日報告的 Gemini/NIM 備援 caller 必須登錄在 caller registry、AI 觀測台 agent group 與 Telegram 狀態統計,避免 fallback 用量被歸類為未知或漏算。
  • ai_calls.provider='ollama_other' 只允許作為 unresolved/unknown Ollama telemetry bucket例如全 host 失敗、尚未選定實際 GCP-A/GCP-B/111 host 或舊 caller 未帶 host不得把 ollama_other 當成實際路由目標或新增非核准 Ollama host。
  • GCP-B 若缺 caller 指定的 coder/large 模型,OllamaService 必須先在 GCP-B 改用 OLLAMA_SECONDARY_MODEL_FALLBACK(預設 gemma3:4b),不可因 model 404 把整台 GCP-B 標成 unhealthy 後直接推到 111真正 timeout / HTTP 5xx 才標 host unhealthy。
  • Gemini API 出站有第二道 kill switchGEMINI_FALLBACK_ENABLED 預設為 false。即使 GEMINI_API_KEY 存在,通用 AI fallback、OpenClaw 報告/QA/PPT/圖片、MCP Grounding 與 Code Review L3 都不得呼叫 Gemini只有操作員明確設為 trueGemini 才能作緊急備援。
  • docker-compose.ymlmomo-appschedulertelegram-bot 必須明確設定 GEMINI_API_HARD_DISABLED=${GEMINI_API_HARD_DISABLED:-true}GEMINI_FALLBACK_ENABLED=${GEMINI_FALLBACK_ENABLED:-false}.env 可保留 GEMINI_API_KEY,但不得因 key 存在就讓核心容器產生 Gemini 付費出站。
  • OpenClaw 日/週/月/Meta 等敘事報告屬長任務Ollama 只能走 GCP-A → GCP-B不得使用 111 final fallback 承接長文生成。GCP 兩台都不可用時,應走既有 Gemini hard-disabled guard 後的 NIM / deterministic degraded path避免 111 被非即時分析壓高負載。
  • Gemini 不可被任何狀態面板或 router 推薦為主提供者:AIProviderService._get_recommended_provider() 不得回傳 gemini,只能顯示為 fallback 狀態;llm_model_routerea_engine 若收到 gemini-* default 必須改回 hermes3:latest,需要深推理時才升本地 deepseek-r1:14b
  • ElephantAlpha prompt / agent registry 不得再把 OpenClaw 描述為 Gemini 主模型OpenClaw 是 qwen2.5-coder:7b / qwen3:14b Ollama-first 策略師Gemini 僅能在 guard 顯式解鎖後作 emergency fallback。
  • 111 192.168.0.111 只是最後一道 Mac fallback不承接 7B+、vision、long-context 模型長駐;OllamaService.generate() 落到 111 時會將 qwen3deepseek-r1hermes3qwen2.5*gemma3llavaminicpm-v 與 7B+ 模型依 OLLAMA_111_MODEL_DOWNGRADE_PATTERNS 降級到 OLLAMA_111_MODEL_FALLBACK=llama3.2:latest,並以 OLLAMA_111_KEEP_ALIVE=5mOLLAMA_111_MAX_TIMEOUT=20OLLAMA_111_NUM_CTX=4096OLLAMA_111_NUM_PREDICT=512 封頂。OpenClaw 報告型路徑的業務 keep-alive 預設 5mCode Review 以 CODE_REVIEW_ALLOW_111_FALLBACK=false、Hermes 以 HERMES_ALLOW_111_FALLBACK=false 預設跳過 111避免 16GB RAM 主機與 GCP-B 被長駐 runner、長輸出與 24h keep-alive 壓到高 load。
  • Scheduler 每 15 分鐘執行 run_ollama_111_usage_guard_check(),只讀 ai_calls 統計最近視窗的 GCP-A / GCP-B / 111 呼叫量;預設 60 分鐘內 Ollama 呼叫至少 20 次、111 至少 3 次且占比 >= 5% 才推 Telegram。這是觀測護欄不改路由、不寫 DB、不自動重啟服務。
  • OllamaService 對 111 final fallback 有 circuit breaker預設最近 60 分鐘 Ollama 呼叫至少 20 次、111 至少 5 次且占比 >= 5% 時,短暫跳過 111OLLAMA_111_CIRCUIT_CACHE_SEC=60),避免 111 在已偏高時繼續承接長任務DB 觀測失敗時 fail-open不讓主要 GCP-A/GCP-B 路由被觀測層中斷。
  • 111 的 LAN 入口必須經 scripts/ops/ollama111_allow_proxy.py allowlist proxy真實 Ollama 綁 127.0.0.1:11434proxy 綁 192.168.0.111:11434,預設只允許 111 本機與 188 生產宿主110 / 121 / 其他 LAN client 不能直接打 111避免跨專案 CI 或 VM 繞過 momo-pro router 載入 7B+ runner。111 上以 scripts/ops/install_ollama111_allow_proxy.sh 安裝 user LaunchAgent安裝器會把 proxy script 複製到 ~/.local/share/momo-pro-system/ollama111_allow_proxy.py,讓 LaunchAgent 不依賴 iCloud repo 掛載路徑,並讓 proxy 與 OLLAMA_HOST=127.0.0.1:11434 在登入/重啟後自動恢復。拒絕日誌以 OLLAMA111_PROXY_REJECT_LOG_DEDUP_SEC=60 去重,避免 121 這類旁路探測刷爆 111 磁碟日誌。
  • ElephantAlpha 的 price_drop_alert / market_opportunity Telegram HITL 告警必須把同款證據獨立呈現,至少包含 match_typeprice_basisalert_tiermatch_score;沒有高信心同款與總價可比證據時,不得把 PChome/MOMO 價差寫成可直接跟價建議。

零之零、產品定位正名2026-06-15

  • 本專案的營運定位正名為「PChome 業績成長自動化作戰系統」。
  • 主要目標是提升 PChome 銷售業績MOMO 是目前已接入的外部價格參考來源,不再把 PChome 視為附屬競品語意。
  • 使用者可見 UI、Telegram 與報表文案必須白話、可行動,優先使用「商品對應」「可直接比價」「待補對應」「放大價格優勢」「檢查售價與活動」等營運語言,避免把 identity_v2match_scorecandidate queue 等工程詞直接丟給使用者。
  • services/pchome_revenue_growth_service.py 是第一版只讀作戰清單:讀 PChome 後台業績與已驗證 MOMO 外部價格參考,輸出 /api/ai/pchome-growth/opportunities。此服務不呼叫 LLM、不抓外站、不寫 DB。
  • 2026-06-15 只讀盤點確認:daily_sales_snapshot."商品ID"competitor_prices.competitor_product_id 在正式資料中直接重疊為 0。因此第一版作戰清單不得硬接兩邊 ID若沒有可驗證對應只能輸出「先補商品對應」任務。
  • 蝦皮與酷澎暫停接入,不進作戰清單、不發告警;後續只可透過 official API / provider API / manual CSV 進 external_offers 類正規化層,並清楚標示資料品質。
  • V10.607 新增 external_market_sources / external_offers 正規化層與 /api/ai/pchome-growth/source-contract 只讀 API。MOMO 先以既有比價快取橋接進來源狀態;蝦皮與酷澎只保留 official API、provider API、manual CSV contract預設暫停且不進告警。
  • V10.608 新增 /api/ai/pchome-growth/external-offers/csv-dry-run 與 AI 情報頁「外部報價預檢」。CSV 預檢只讀、不寫 DB逐列回報「可使用」「需人工確認」「不能使用」並支援中文表頭避免格式小錯造成整批匯入失敗。
  • V10.609 明確把外部報價主路徑改為自動化:run_external_offer_sync_task 每 4 小時將已確認同款的既有比價快取同步進 external_offers。CSV 只保留為 API / crawler / provider 失敗時的備援預檢入口,不是日常營運主流程。
  • V10.610 起 /api/ai/pchome-growth/opportunities 優先讀取 external_offers 的自動同步資料;只有新資料層缺資料時才 fallback 舊 competitor_prices。API stats 會回傳資料來源計數,方便確認作戰清單是否已走新資料層。
  • V10.611 起 /ai_intelligence 是營運使用者主入口V10.617 已將舊「今日作戰入口 / 外部報價預檢」改為「今日重點總覽 / 備援資料檢查」,主流程不得再把人工 CSV 放在前段。
  • V10.612 起 /api/ai/icaim/dashboard 的「MOMO 外部價格參考」表格也優先讀 external_offers,缺資料才 fallback competitor_prices;價差與風險改採 PChome 視角,正數代表 PChome 比 MOMO 外部參考價高。
  • V10.613 起高可見前台頁面必須以繁體中文呈現程式碼審查、AI 自動化健康檢查、PPT 產線與商品看板操作標籤不得使用英文工程標題或簡體字;測試需防止頁面文案退回英文。
  • V10.614 起部署監控、基礎設施生命線與 PPT 產線狀態也納入繁中守門:前台不得顯示 DashboardPipelineRuntime 等工程詞,動態階段需轉成「測試 / 建置 / 部署」。
  • V10.615 起 AI 智慧推薦頁必須把 Ollama 顯示為「Ollama 主路徑」Gemini 只能顯示為「Gemini 備援」且手動選項停用;使用者可見錯誤與搜尋流程不得出現 Web SearchToken:、半形英文冒號等工程文案。
  • V10.616 起主商品看板 / 的統計與補強區塊也納入繁中守門:不得顯示 ACTIVEPICK COUNTAVG CONFIDENCEEVIDENCE GAPPCHOME MATCH BACKFILL 等工程標籤畫面需使用「有效商品」「挑品數」「平均信心」「待補證據」「PChome 比價補強」等白話營運文案。
  • V10.617 起 /ai_intelligence 必須採「先給下一步」的作戰導向 UI首屏需先回答「今天先做什麼」再呈現商品處理進度、外部價格來源與操作捷徑今日處理清單需用表格呈現優先級、建議動作、商品、近 7 天業績、比價結果、資料可信度與下一步MOMO 外部價格參考需顯示價格風險分佈,且表格需以 PChome 價格優先明確顯示「PChome 貴 / PChome 便宜」與可信度,不得只用大段文字說明使用方式。
  • V10.618 起 /price_comparison 也必須採「先給下一步」的比價決策 UI首屏需顯示目前卡在哪一步、PChome / MOMO 資料準備狀態與下一個按鈕;比價結果需先呈現「需檢查價格 / 可主推曝光 / 價格接近」分佈,再用表格列出每筆商品的下一步,不得只呈現 Step 流程或原始價差表。
  • V10.619 起 MOMO 比價候選來源新增「PChome 商品導向搜尋」:當比價 API 已有 PChome 商品但缺 MOMO 清單時,必須用每筆 PChome 商品名稱產生精準搜尋詞反查 MOMO保留品牌、品名、容量與組合線索新版 MOMO 搜尋頁需解析 Next.js goodsInfoList payload。此路徑只擴大候選池不放寬同款 matcher 門檻。
  • V10.620 起 unit_comparable 不再一律丟人工確認:若 build_unit_price_comparison() 可產生明確容量/數量、MOMO 單位價、PChome 單位價與差距百分比,候選需標為「自動單位價比較」並回傳 auto_compare_type=unit_price。此類候選可自動呈現價格壓力,但不得混入舊總價同款比價表,也不得直接寫入正式價差或自動改價;無法產生單位證據時才維持「需人工確認」。
  • V10.621 起 /price_comparison 的「自動找 MOMO 候選」會把可直接總價比價與自動單位價候選同步到 external_offersingestion_method='targeted_momo_search',人工確認候選不得寫入。external_offers.raw_payload_json.price_basis='unit_price' 時,作戰清單必須使用 unit_price_comparison 的 MOMO / PChome 單位價與 unit_gap_pct 判斷價格壓力;不得把 MOMO 組合總價與 PChome 單品總價直接相減。此同步只影響外部價格參考與作戰清單,不寫 competitor_prices,也不自動改價。
  • V10.622 起任何 external_offers 自動同步成功寫入後,必須呼叫 mark_pchome_growth_cache_stale() 寫入共享 cache epoch/api/ai/pchome-growth/opportunities 讀快取前必須比對 get_pchome_growth_cache_epoch()。這是跨 Gunicorn worker 的可見性保護,避免自動候選已進外部價格參考,但 AI 情報頁仍回 120 秒舊作戰清單。
  • V10.623 起 /price_comparison/ai_intelligence 不得只靠大段文字說明流程:比價頁第一屏必須有主 KPI、目前卡點、四步流程與結果決策摘要作戰頁第一屏必須有今日任務、可立即處理、待補比價與最新業績日。所有狀態都要由實際 API/前端狀態驅動,讓使用者一眼知道下一步要按哪個動作。
  • V10.638 起 PChome 導向 MOMO 補抓會把「找到但不能自動比價」的候選以 match_status='needs_review'data_quality_status='needs_review' 保存到 external_offers;這些候選不得進價格壓力判斷,也不得發告警,但 /api/ai/pchome-growth/opportunities 可回傳待確認候選數,讓 UI 顯示「已有候選待確認」而不是只顯示無法比價。
  • V10.639 起待確認候選排序必須容忍缺少單位數量;沒有 momo_total_quantity / competitor_total_quantity 時仍可保存為 needs_review,不得中斷 PChome 導向 MOMO 回填。

零之一、12 Agent 決策信封2026-05-24

  • 12 角色分工不作為 12 個常駐模型;在產品層統一收斂成 decision_envelope,由 Hermes / NemoTron / OpenClaw / ElephantAlpha 與人工審核、PPT QA、競品 review queue 共用。
  • decision_envelope 必須至少能表達:decision_typeseverityevidence[]recommended_actionexpected_impactconfidenceguardrailstrace
  • guardrails.can_auto_execute=false 是預設價格調整、正式比價覆寫、PPT 發送與修復執行都必須遵守 HITL 或既有 service guard不得因 Agent 信心高就繞過 matcher / feeder / review service。
  • 證據不足時不得輸出空泛效益預測;必須標記 data_quality=missing|partial|stale,並把建議行動降級成 human_reviewneeds_researchsilence_alert
  • Telegram triaged_alert() 已支援渲染 decision_envelope,讓告警固定呈現嚴重度、證據、建議行動、預期影響、信心度與追蹤 ID後續觀測台與 PPT 也應共用同一份欄位語意。
  • NemoTron price_alert / human_review 派發會把同款證據、價差、七日銷量變化、營收流失、HITL 邊界與資料品質寫入同一份 decision_envelope,並同步放入 EventRouter event 與 KM metadata12 Agent 後續只能沿用此信封補充分析,不得繞過 matcher / feeder / review service 直接改價或覆寫比價資料。
  • EventRouter / Telegram 的 HITL callback 必須優先使用 decision_envelope.decision_id 作為事件追蹤 ID若上游未帶 event.idtriaged_alert() 仍會用 decision_id 產生 momo:eig:* callback避免價格決策審核落成 unknown。所有 momo:eig:* callback 必須以 UTF-8 byte-safe 截斷,確保 callback_data 不超過 Telegram 64-byte 限制。
  • 競品比價相關的 Agent 建議只能讀 competitor_match_attempts / review queue / competitor_prices 的既有證據;不得直接寫 competitor_prices 或覆蓋 _should_upsert_competitor_price() 的保護規則。
  • 已帶 decision_envelope 的價格/覆核事件必須由 EventRouter 直接渲染證據模板,不再進 L1/L2 AI 重新摘要Telegram 決策信封需顯示標的 SKU、商品名稱、PChome 候選、evidence、guardrails 與 HITL 動作,避免已有實證的比價告警被二次生成文字稀釋或造成額外模型成本。
  • PChome 覆核隊列本身也必須輸出 decision_envelopefetch_competitor_review_queue()fetch_competitor_review_queue_page()/api/pchome-review/queue 的每筆候選需帶相同的 subjectevidencerecommended_actionexpected_impactguardrails,供 Dashboard、Agent、Telegram 與 PPT 共用;任何下游不得另寫一套比價狀態翻譯或繞過 HITL guardrails。
  • Dashboard 覆核卡與 /api/export/excel/pchome-review 也必須顯示/匯出 decision_envelope 的等級、資料品質、建議代碼、HITL、trace 與 can_auto_execute=false 邊界;操作員離開系統畫面或下載 Excel 後,仍要看得到「不可自動寫正式價差」的 guardrails。
  • OpenClaw 週報/日報/月報與 competitor PPT 不得再各自重算或翻譯 PChome 覆核狀態;必須透過 competitor_intel_repository.summarize_review_decision_envelopes() 讀取同一份 decision_envelope 摘要,並在 prompt / data_summary / KPI slide 保留 HITL 與 can_auto_execute=false 邊界。
  • Webcrumbs / Shared UI host data 也必須透過 summarize_review_decision_envelopes() 輸出 reviewDecisionBrief,並在 metadata 保留 review queue、HITL、auto-execute-blocked、decision_support_ratecatalog_comparable_count 與 catalog review lane counts不得另寫一套 PChome 覆核摘要或在前端 runtime 重新推論價格行動。
  • ElephantAlpha 的 resource_optimization 與低信心 ea_escalation 也必須輸出 decision_envelope:資源壓力信封只能使用 action_plans、CPU 實測、hygiene 結果與 insight/action trace不得加入 LLM 預測效益;triaged_alert()ea_escalation 亦需渲染信封並以 decision_id 作為 callback 追蹤 ID。

一、四 AI Agent 路由架構

SQL漏斗(~300筆)
     ↓
[Hermes 3 8B] — 分析師 (Ollama 三主機級聯, 零成本)
  模型: hermes3:latest @ GCP-A → GCP-B → 111
  任務: 競價威脅分類 → TOP 20 HIGH/MED/LOW
     ↓
[NemoTron / qwen3] — 派發器
  主路徑: qwen3:14b @ GCP-A/GCP-B落到 111 時自動降級 llama3.2
  備援: NVIDIA NIM meta/llama-3.1-8b-instruct
  任務: Tool Calling → Telegram 告警 / DB 寫入
     ↓
[OpenClaw] — 策略師 (Ollama-firstGemini 僅備援 / 鎖定場景)
  任務: 週策略報告、洞察報告、L3 HITL 建議
     ↓
[ElephantAlpha] — 編排者 (L3 Orchestrator)
  任務: 跨 Agent orchestration、HITL、AutoHeal bridge、受控 log scan

1.1 PChome 挑品 Agent2026-05-01

services/ai_product_pick_agent.py 新增 PChome 銷售用挑品 Agent

  • 只讀真實資料表:productsprice_recordscompetitor_pricescompetitor_price_history,若 daily_sales_snapshot 可用則納入近 7 天銷售額、數量、毛利或成本推算毛利率。
  • 將 PChome 比 MOMO 有價格優勢、比對信心足夠、且有歷史快照或銷售動能的品項寫入 ai_price_recommendations。信心度不以固定倍率灌高,而是由商機分數與證據完整度共同決定,證據包含 PChome match score、歷史快照、銷售/毛利、PChome 商品 ID/名稱、抓取時間與促銷/評價/庫存標籤。每次重算只保留最新 50 品為 status='pending',未進榜舊品標為 superseded,避免統計與清單超量。
  • 寫入策略使用 strategy='product_pick',保留在既有 AI 決策表,不新增假頁面或暫存 JSON。
  • 後台入口:POST /api/ai/product-picks/generate/ai_intelligence 可手動產生清單。
  • 配對來源仍以 PChome crawler 真實搜尋結果為準;無競品資料時不生成挑品。
  • 比對覆蓋率補強入口:POST /api/ai/pchome-match/backfill,優先補抓仍無有效 PChome 配對的高價 ACTIVE 商品,完成後自動重算 AI 挑品清單。
  • 過期價格刷新入口:POST /api/ai/pchome-match/refresh-stale,只針對已建立 identity_v2expires_at 過期的 PChome product_id 執行 run_expired_identity_refresh();不得跑 fresh search recovery不得呼叫 LLM完成後重算 AI 挑品並清除 Dashboard / competitor intel cache。
  • 過期 identity 搜尋救援入口:POST /api/ai/pchome-match/recover-stale 預設必須關閉主操作入口,僅保留只讀 preview正式 smoke 顯示小批次成功率不足且耗時偏高時,不得在 Dashboard 顯示日常操作按鈕。若需操作員手動執行,必須先明確設定 PCHOME_STALE_RECOVERY_ENABLED=true,再對已過期 identity_v2 先走既有 PChome product_id refresh只有舊 ID 查無商品或重評低於門檻時,才允許受控 fresh search recovery。救援隊列必須先排除 variant、catalog、commercial condition、count、bundle、unit-price 與任選 / 多款 / 香味 / 色號 / 即期 / 融燭燈 / 香氛蠟燭 / + / xN / *N / 具名香味或膚感版本等高風險名稱訊號。這條路徑可抓 PChome但不得呼叫 LLM正式寫入仍必須通過 matcher、hard veto、auto price write safety 與 overwrite protection。
  • 補抓狀態入口:GET /api/ai/pchome-match/backfill/status 除背景任務狀態外,必須回傳 read-only coverage snapshotactive_with_price / valid_matches / match_rate / fresh_matches / fresh_match_rate / decision_ready_matches / decision_ready_rate / stale_matches / pending / actionable_review_count,供 Dashboard 顯示目前該刷新過期價格或補抓未搜尋商品;此端點不寫 DB、不呼叫 LLM、不抓外站。match_rate 是身份覆蓋率,fresh_match_rate 是已配對 identity 內的新鮮比例,decision_ready_rate 才是可直接進入決策、圖表與簡報的 ACTIVE 商品比價覆蓋率。
  • 排程閉環:run_pchome_match_backfill_task 每日 10:30 執行,補抓 PChome 待比對商品、寫入歷史價格,再重算 strategy='product_pick' 清單。
  • PChome / MOMO 競價摘要出口 services/competitor_intel_repository.py 使用 30 分鐘共享快取(COMPETITOR_INTEL_CACHE_TTL_SECONDS 可調),避免 /growth_analysis/daily_sales、PPT/AI 報表每次請求重跑昂貴覆蓋率與價差趨勢查詢;run_competitor_price_feeder_task 與 PChome backfill 完成後會主動清除快取。快取只包摘要輸出,不改 matcher 的高信心門檻與 identity_v2 準確性規則。
  • 商品看板第一屏:/ 的 V2 看板直接以 productsprice_recordscompetitor_pricescompetitor_match_attemptscompetitor_match_reviewsai_price_recommendations 顯示比對覆蓋率、PChome 優勢、MOMO 威脅、AI 挑品、待比對優先清單與 PChome 覆核隊列;filter=ai_picks 可查看 50 品 AI 挑品列表,filter=pchome_review 可直接查看需人工處理的比價覆核 SKU並以 DB 分頁支援 search/category/status 後的完整隊列,不得只截前 50 筆。覆核狀態篩選必須至少包含全部、需單位價、已排除、低信心、價格過期、找不到同款與人工閉環,讓人工可依 matcher 診斷類型分批處理。列內顯示候選 PChome 商品、候選價、match score、單位價換算摘要、人工動作與 matcher 診斷原因標籤(品牌不符、商品線不符、容量差異、組合差異、需單位價、價差極端等),不得只顯示籠統「待比對」。/api/export/excel/pchome-review 必須匯出同一套覆核隊列、人工處置、候選 PChome、單位價比較與原始診斷讓人工覆核、簡報與後續 AI 分析共用同一份證據。/api/pchome-review/<sku>/decision 是人工閉環入口:accept_identity 才可把候選寫入 competitor_pricescompetitor_price_history 並打上 manual_review/manual_accept/identity_v2reject_identityunit_price_requiredneeds_research 只寫 competitor_match_reviews 並追加 manual attempt不得把不同販售組合或否決候選灌入正式價差。PChome feeder 後續搜尋同一候選時必須讀取 competitor_match_reviews:已否決候選寫 manual_rejected 並跳過正式寫入,且必須繼續評估下一個候選,不能讓已否決候選長期阻塞同 SKU已標記單位價候選寫 manual_unit_price_required;已要求補搜尋候選寫 manual_needs_research 並停留在覆核隊列;已採用候選可保守補到最低門檻並保留 manual_review/manual_accept 標籤。搜尋候選池只有強同款分數達 0.90 才可提前停止,避免 0.76 灰區候選卡掉後續更精準搜尋詞。人工 reject_identityunit_price_requiredneeds_research 若命中當前正式候選,必須將同候選 competitor_prices 過期,不得繼續顯示正式總價差。商品列表必須將 manual_rejectedmanual_unit_price_requiredmanual_needs_research 顯示為明確人工閉環狀態,不可回落成籠統「待比對」。fetch_competitor_coverage() 必須輸出人工採用、人工否決、人工單位價與採用率daily/growth/PPT 共用 payload 必須顯示人工閉環成效,避免只呈現待審數。商品看板深度快取同時寫入 data/dashboard_full_cache.pkl,供多個 Gunicorn worker 共用,避免部署後各 worker 重複重建 7,000+ 商品統計造成開頁變慢;所有資料異動與 AI 挑品重算都透過 clear_dashboard_cache() 同步清除記憶體與共享快取,手動重算 API 會立即預熱商品看板快取,避免第一位使用者承擔重建成本。
  • PChome re-score 回收線:rescore_accepted_current 只能表示最新版 matcher 判定「值得人工覆核身份」,不可直接寫入正式 competitor_pricesno_matchprice_basis=nonealert_tier=suppressvariant_selection_review 不得進入此隊列。fetch_competitor_coverage() 必須輸出 rescore_accepted_countDashboard、daily/growth 與 OpenClaw 競品摘要都要把「重算待人工覆核」獨立呈現,避免和一般低信心/單位價覆核混在一起。
  • PChome 低信心操作分流Dashboard 與 read-only /api/pchome-review/queue 必須把近門檻可救、證據不足、低信心舊候選拆成 recoverable_low_scoretrue_low_confidencelegacy_low_score 三個可篩選桶;廣義 low_score 僅作 repository/export 相容查詢,不可在 UI 中冒充單一操作分流。
  • PChome coverage 的 attempt_status / rescore_accepted_count / actionable_review_count 口徑必須與 review queue 對齊:統計「沒有新鮮有效 identity」的商品而不是只統計「完全沒有 identity」的商品已過期但可重算採用的 stale identity 仍應出現在待審數字中,避免 API 與 Dashboard 漏報。
  • run_retryable_candidate_revalidation() 的自動回刷主戰場仍限 low_score / refresh_low_score / recoverable_low_scoretrue_low_confidence 只有在已補 focused exact 規則的窄範圍品線、舊分數 >= 0.95、comparison_mode='exact_identity'、含 strong_exact_spec_match 且不含 commercial / variant / count / bundle / refill 等阻擋理由時,才可進入重評,不得全面打開人工審核池。rescore_accepted_current 只允許命中具名 focused exact 品線、舊分數 >= 0.76、且仍無 hard veto / 阻擋理由時進窄門回刷;最後仍由最新版 matcher 判定是否可寫正式價差,像不同指甲油型號 / 色號必須 hard veto。
  • 高分 true_low_confidence 的自動救回只能用具名 focused exact 線逐批擴充;同品牌、同品線、同規格/同組合的花美水 Relax、St.Clare 私密呼呼、BIOPEUTIC 果酸、台塑生醫嬰兒沐浴洗髮、Elizabeth Arden 八小時護唇膏與理膚寶水全面修復潤唇膏可走 total-price色號、香味、款式、即期品與 catalog selection 仍維持 review / veto。
  • true_low_confidence focused exact 線必須同步接入 run_retryable_candidate_revalidation() 的 SQL 窄門,讓舊候選可被批次回收;該窄門只允許具名品線豁免 variant_selection_review,其他 hard veto / 型別、款式、香味、件數、組合、refill、commercial condition 阻擋仍不得回刷。
  • 任選 catalog focused exact 只允許雙方都明確是同品線任選賣場且規格一致的窄範圍案例,例如 FLORTTE 眼線液筆 0.5ml、露得清護手霜 56g 無香/有香、Kanebo ALLIE 持采亮化 UV 防曬水凝乳 60g若有 commercial_condition_gap即期品、短效、航空版等狀態差異focused bypass 不得移除 variant_selection_review,不得自動寫正式價差。
  • O.P.I 指彩救回只允許同品牌、同 類光繚 / 如膠似漆 指甲油或指彩線,且共享 ISL... 精準型號 token 的案例自動走 total-price不同型號/色號仍維持人工或 veto。此規則可接入 true_low_confidence revalidation 窄門,但不得變成「同品線即通過」。
  • 其他正式覆核池 focused exact 線只能針對「已在正式頁面反覆出現且有硬規格」的窄範圍族群,例如 The Ordinary 咖啡因 EGCG、Natures Care 綿羊油同入數、TOMOON 指甲剪同尺寸、HH 雙 200ml 組、SEBAMED 200ml x2、YES 9cm 剪刀;同尺寸、同入數、同組合或單側漏規格必須可由 matcher 明確判斷,不能只因同品牌同品線通過。
  • /api/ai/pchome-match/backfill/status 必須把近門檻重評池與過期 identity 救援池以只讀 revalidation_preview / stale_recovery_preview 曝光給操作員;預覽只復用正式候選 SQL 並受 limit / 60 秒快取限制,不啟動 PChome 搜尋、不呼叫 LLM、不寫 competitor_match_attempts / competitor_prices。重評 preview 必須先從最新 competitor_match_attempts 縮小候選,再用 JOIN LATERAL 取單一最新 MOMO 價;救援 preview 必須從過期 competitor_prices 小集合出發並用 JOIN LATERAL 取最新 MOMO 價,兩者都不得掃全量 price_recordsDashboard 只能顯示「可救援」觀測值,不得在未開啟 PCHOME_STALE_RECOVERY_ENABLED 時提供 recover-stale 執行按鈕;其中 review_gated_count 僅代表窄門 true_low_confidence exact 候選,不得被解讀為全量人工池可自動回刷。
  • PChome re-score audit 預設必須先取每個 SKU 的最新 competitor_match_attempts 狀態,再套用 status / reason 篩選;舊低信心歷史候選只能透過 --include-historical-candidates 明確進入考古掃描,避免已入隊、已否決或已修正 SKU 被舊紀錄重新推回報表。
  • production re-score --apply-accepted 僅可追加 rescore_accepted_current attempt 給人工覆核;執行後需清除 Dashboard / competitor intel cache且必須抽查 competitor_prices / competitor_price_history 未新增正式價差。
  • production re-score 若曾把 variant_selection_review 追加成 rescore_accepted_current,必須用 audit_competitor_match_attempt_rescore.py --retract-variant-accepted 追加最新 true_low_confidence 退回列;此路徑只寫 competitor_match_attempts,不得刪歷史紀錄,也不得寫 competitor_prices / competitor_price_history
  • PChome matcher replay 必須先守住假陽性:EX8 等型號不可被誤解析成 x8 入數;香氛固體凝膠 / 空氣芳香劑若一側為泛稱、一側含明確香味或 No. 款式,必須走 aroma_scent_variant_conflict veto不得因同品牌同重量直接寫正式價差。
  • PChome matcher 對「同規格同數量」的多件組可以安全回收,但必須同時滿足:商品型別完全對齊、品牌同線、規格與數量對齊、沒有 variant / count / bundle / commercial / unit-price / price-ratio 阻擋理由,才可打 safe_multi_component_exact_total_price 並進 exact / total_price / price_alert_exact混合組、香味款、色號款、catalog 任選仍需留在 identity_review 或 veto。護唇品 focused total-price 僅允許已明確建規則的 DHC 純欖 1.5g、FRUDIA 蜂蜜藍莓 10g、SEBAMED 嬰兒護唇膏 4.8g x2、理膚寶水滋養修護潤唇膏 4.7ml,不得把所有 lip/cosmetic catalog 一次放行。
  • PChome feeder 正式寫入必須再套一層價格資料閘門:只有 match_type='exact'price_basis='total_price'alert_tier='price_alert_exact' 且無 variant_selection_review 的結果可以自動寫入 competitor_pricesmanual_review / identity_review 只能留在覆核隊列或人工採用流程,不得由 retryable replay 或 known identity refresh 自動升成正式價差。Rescore audit 若遇到 variant_selection_review,也不得產生 accepted_current
角色 模型 主機 成本 每日限額
Hermes 分析師 hermes3:latest / bge-m3 GCP-A → GCP-B → 111 Ollama 無限
NemoTron 派發器 qwen3:14b111 fallback 降級 llama3.2NIM fallback GCP-A → GCP-B → 111NVIDIA NIM 備援 Ollama 零NIM 配額內免費 NIM 80
OpenClaw 策略師 qwen2.5-coder:7b / qwen3:14b111 fallback 降級 llama3.2 Ollama-firstGemini emergency fallback only Ollama 零Gemini 預設封鎖
ElephantAlpha 編排者 ElephantAlpha 依部署環境 受控 HITL / 任務制

一之一、AI 自動化閉環實況2026-04-29

事件 / 排程失敗 / code review finding
  → EventRouter 分流、去重、降級
  → Hermes L1 摘要或 NemoTron L2 tool calling
  → L2 SAFE_ACTIONS / AutoHeal / OpenClaw memory
  → Telegram 通知,失敗則 file queue成功後 replay
  → ai_insights + embedding_retry_queue
  → OpenClaw / ElephantAlpha 後續策略與 HITL

硬性邊界:

  • EventRouter 是告警與 L2 safe action 的入口。
  • AutoHeal 是自癒副作用入口。
  • momo-db / momo-postgres 不可被 AI 自動 restart / stop / recreate。
  • raw ai_insights insert 必須接 enqueue_insight_embedding() 或可被 backfill。
  • ElephantAlpha 只做編排與 bridge不可繞過 ADR-011 / ADR-012 / ADR-013。
  • ElephantAlpha / NemoTron 不可直接執行商品價格調整;execute_price_adjustmentadjust_price 等動作必須攔截並寫入 human_review,等待人工核准。

可觀測性:

  • /metrics 匯出 momo_ai_event_router_dispatch_total
  • /metrics 匯出 momo_ai_event_router_latency_ms_count/sum/max
  • /metrics 匯出 momo_ai_event_router_safe_action_total
  • /metrics 匯出 momo_ai_event_router_replay_total
  • /metrics 匯出 momo_ai_autoheal_action_totalmomo_ai_autoheal_duration_ms_count/sum/max
  • /metrics 在尚無事件時仍輸出 momo_ai_* zero-baseline series讓 Prometheus/Grafana 重啟後可立即看到 metric names。
  • /ai_automation_smoke 提供登入後 AI 自動化健康檢查頁。
  • /api/ai-automation/smoke 提供 read-only JSON 狀態,不做外部網路呼叫。
  • 健康檢查 API 會將最近檢查結果保存到 JSONL頁面顯示最近狀態趨勢。
  • 健康檢查歷史支援 JSONL 匯出、清理與每日「正常 / 注意 / 嚴重」摘要。
  • 健康檢查每日摘要支援手動 Telegram 推播,並由 momo-scheduler 每日 09:10 呼叫 run_ai_smoke_daily_summary_task()
  • Grafana provisioning 新增 docker/grafana/provisioning/dashboards/json/ai-automation-overview.json,觀測 EventRouter dispatch/latency、safe action、Telegram replay 與 AutoHeal action/duration。
  • Active monitoring stack 使用 monitoring/prometheus.ymlmomo-app job scrape momo-pro-system:80/metricsPrometheus container 需加入 momo-network
  • Active Blackbox HTTP targets 必須探測 /health188 stack 目前 https://mo.wooo.work/healthhttp://momo-pro-system:80/health110 gateway stack 目前 https://mo.wooo.work/health),不可探測 Dashboard 首頁 /,避免監控流量觸發重型 DB 查詢。
  • /metricsrealtime_sales_monthly 只用 raw SELECT COUNT(*) 取得總筆數,避免 ORM schema drift 讓 Prometheus scrape 產生 warning。
  • momo-app 必須 bind mount ./gunicorn.conf.py:/app/gunicorn.conf.py:ro,讓 CD sync/rebuild 後的 Gunicorn runtime 設定與 repo 保持一致。
  • Gunicorn runtime 預設 worker_class = gthreadGUNICORN_THREADS=4preload_app = False;此組合讓 HUP 熱重載可用,也避免 Dashboard 長查詢完全阻塞 /health
  • CD rebuild 模式必須先 build image 成功,再短暫 stop/rm/recreate 三應用容器,避免 no-cache build 造成長時間 502。
  • ElephantAlpha 使用 NVIDIA NIM hosted APIproduction 預設模型為 nvidia/llama-3.3-nemotron-super-49b-v1.5ELEPHANT_ALPHA_FALLBACK_MODELS 需保留至少一個可呼叫備援403/404、408/409/425/429、5xx、timeout 與 connection error 必須嘗試下一個模型。
  • ElephantAlpha L3 HITL 只允許發送有實證、可審核、可行動的升級告警;價格類 trigger 無 Hermes 具體威脅時,只記錄 suppressed escalation telemetry 與 cooldown不寫 pending human_review,不發 Telegram 空告警。
  • ElephantAlpha 價格類 trigger 的 HITL / 決策 prefetch 必須先使用觸發 SQL 與 competitor_prices / price_records 的 DB 實證生成 SKU、MOMO / PChome 價差與建議 action lines完整 Hermes LLM prefetch 預設關閉(ELEPHANT_ALPHA_HERMES_LLM_PREFETCH_ENABLED=false),避免 5s timeout 後落入無實證摘要或雲端備援。若無 DB 實證,只記錄 suppressed telemetry / cooldown不發 Telegram 空告警。
  • ElephantAlpha price_drop_alert / market_opportunity trigger 不得對整張 price_records 做全表最新價聚合;必須先篩最近有效 identity_v2 PChome 候選,再用 per-SKU JOIN LATERAL 讀最新 MOMO 價格,並把 match_scoretagsmatch_diagnostic_json 帶入 evidence。
  • ElephantAlpha 協調器收到非純 JSON、fenced JSON 或混文字 JSON 時,必須先做容錯抽取;仍無法解析時,只能使用 DB/Hermes 實證生成保守 HITL fallback。fallback 不得放入 OpenClaw generate_* 類舊策略步驟,也不得暗示已自動調價。
  • V10.624 起 ElephantAlpha 價格類 trigger 即使信心度達自主門檻,也只能發送 HITL 價格覆核通知;必須跳過 orchestrator execution_plan 內的 Hermes/NemoTron/OpenClaw 長任務 step。這是價格決策護欄避免 60 秒 execution timeout 卡住 scheduler也避免把價格策略誤描述為已自動執行。
  • ElephantAlpha 執行器若遇到舊版 OpenClaw strategy 類步驟(含 generate_market_strategy / generate_dynamic_pricing_strategy / generate_resource_optimization_strategy),只能記錄為 advisory skipped不得觸發 circuit breaker也不得轉成實際排程、外部呼叫或價格行動。
  • resource_optimization 不再交給 LLM 生成「預期效益 / 已執行」敘事,顯示名稱統一為「資源壓力治理」。此 trigger 必須先由程式量測 action_plans backlog、P1/P2 數、pending_review、逾時項目與 CPU load只有 CPU 達門檻、P1/P2 積壓或逾時積壓才發 Telegram「資源壓力告警」。單純 queue 大但 CPU 正常只記錄 telemetry不派發 Hermes/NemoTron、不宣稱 48 小時效益Telegram 段落使用「系統處置紀錄」而非泛稱「已執行」,避免暗示 AI 已完成未經驗證的外部動作。
  • resource_optimization 的 Telegram 必須包含 decision_envelope 區塊,標明 source_agent=elephant_alpha、資料品質、量測證據、can_auto_execute=false 與 deterministic trace此路徑不呼叫 Gemini、不呼叫 Hermes/NemoTron也不得把 queue backlog 翻譯成主機資源耗盡。
  • resource_optimization 會先執行 ActionPlanHygieneService 清理過期噪音:只關閉超過 72 小時的 code_review_fix / openclaw_recommendation 類 advisory action_plans以及 NemoTron direct_response/reply_simple 舊聊天回覆計畫;將狀態改為 auto_disabledrejected 並寫入 metadata_json.hygiene_history。不刪資料,也不碰 NemoTron human_review / pricing / tool action 類業務行動。
  • momo-scheduler 每 6 小時固定執行 run_action_plan_hygiene_task(),讓過期 advisory action_plans 的關閉不再依賴 resource_optimization 告警觸發;排程失敗會經 EventRouter 發送 action_plan_hygiene_failure
  • action_plans 產生端必須防重Code Review 同一檔案已有 active code_review_fix 時不重建OpenClaw recommendation 會寫入文字 fingerprint 並跳過同一建議AIOrchestrator 不再把 NemoTron direct_response/reply_simple 聊天回覆存成 action plan真正需工具、審核或執行的 NemoTron action 才能進 queue。
  • OpenClaw/Hermes embedding 優先呼叫 Ollama /api/embed,只在舊節點不支援時 fallback /api/embeddingstimeout 由 EMBEDDING_TIMEOUT / OLLAMA_EMBED_TIMEOUT 控制,並受 OLLAMA_EMBED_MAX_TIMEOUT 封頂。背景 worker / RAG 查詢不得落 111除非 caller 顯式允許 allow_111_fallback=True
  • PPT 自動產線由 momo-scheduler 依節奏執行 run_ppt_auto_generation_task(schedule_kind):每日 20:30 產日報、週一 20:40 產週報/市場情報、每月 1 日 20:50 產月報與管理型簡報、季初 21:00 產季報、半年初 21:10 產半年報、年初 21:20 產年報,再交給 22:00 ppt_vision_audit 做視覺審核;每次嘗試會寫入 ppt_generation_runs/observability/ppt_audit_history 以精準參數檢查目標版本是否已產生,並可用 /observability/ppt_audit/generate_missing 手動補齊缺漏,總開關為 PPT_AUTO_GENERATION_ENABLED。PPT vision 需 PPT_VISION_ENABLED=true 與容器內 LibreOffice/observability/ppt_audit_file/<filename> 會把 PPTX 轉成 PDF 快取供站內線上預覽,原始 PPTX 仍保留下載。QA 失敗項目的「重跑」必須從檔名推回原 report_type並只失效相同 report_type + parameters 的 active ppt_reports cache避免拿到舊 PPT 或誤重跑 daily。

二、真實資料庫 Schema已校對確認

2.1 productsSQLAlchemy ORMSQLite/PostgreSQL 通用)

欄位 型別 說明
id Integer PK 主鍵
i_code String(50) UNIQUE MOMO 商品代碼(爬蟲來源,即商品 SKU
name String(255) 商品名稱
url String(500) MOMO 商品頁 URL
image_url Text 商品圖片 URL
category String(100) 分類名稱(直接欄位)
status String(20) 預設 'ACTIVE'
created_at DateTime 建立時間
updated_at DateTime 更新時間
category_id Integer FK → categories.id 分類關聯(可選)

重要: i_code = MOMO 網站上的商品 ID例如 I132467614

2.2 price_records

欄位 型別 說明
id Integer PK 主鍵
product_id Integer FK → products.id 商品關聯
price Float MOMO 自家售價(爬蟲抓取)
timestamp DateTime indexed 抓取時間戳

⚠️ 架構限制: price_records 只存 MOMO 自家售價,無 source 欄位無競品PChome價格。 PChome 比價資料必須由外部爬蟲即時抓取,以 pchome_prices: dict 形式注入 HermesAnalystService.run()

2.3 daily_sales_snapshotPChome 後台業績匯出,動態表)

重要: 此表由 import_service.py 使用 df.to_sql() 動態建立。 欄位名稱完全繼承自 PChome 後台匯出的業績 Excel 原始欄位,加上程式碼追加的 snapshot_date。 V10.605 起,匯入器會掃描所有 worksheet 與前 15 列表頭,優先選擇含「日期 / 商品名稱 / 總業績或銷售金額」的明細工作表;格式或日期真的不合格的檔案會移到 Google Drive 匯入失敗,避免每 30 分鐘重複告警。

已確認的關鍵欄位PChome 後台報表欄位名稱)

欄位 型別 說明 備注
snapshot_date Date 資料所屬日期(程式追加) import_service.py 從「日期」欄位解析
商品ID VARCHAR PChome 後台 / 訂單目錄商品識別碼 ⚠️ 不可假設等於 products.i_code
商品名稱 TEXT 商品名稱
總業績 / 銷售金額 NUMERIC 銷售業績金額 匯入器以欄位群組模糊比對,兩者皆可
數量 NUMERIC 銷售數量
總成本 NUMERIC 成本
廠商名稱 VARCHAR 廠商名稱
商品館 / 館別 VARCHAR 分類

欄位自動偵測邏輯(find_col

系統使用 keyword 模糊比對,不要求欄位名完全固定

SKU/商品ID   = find_col(['商品ID', 'Product ID', 'ID', 'i_code', 'Item Code'])
商品名稱     = find_col(['商品名稱', '品名', 'Name', 'Product'])
銷售金額     = find_col(['銷售金額', '業績', '金額', 'Amount', 'Sales', 'Total'])
成本         = find_col(['成本', 'Cost', '進價', '總成本'])
數量         = find_col(['銷售數量', '銷量', '數量', 'Qty', 'Quantity'])
日期         = find_col(['日期', '訂單日期', '交易日期', 'Date'])
分類         = find_col(['商品館', '館別', '分類', 'Category'])

2.4 competitor_pricesMigration 004 — 已建立)

競品價格快取表,由 competitor_price_feeder.py Worker 寫入AI Pipeline LEFT JOIN 消費。

欄位 型別 說明
id SERIAL PK 主鍵
sku VARCHAR(50) MOMO 商品代碼(= products.i_code
source VARCHAR(30) 競品來源:'pchome'(預留 shopee 等)
price NUMERIC(10,2) 競品售價
original_price NUMERIC(10,2) 競品原價
discount_pct INTEGER 折扣 %NULL=未折扣)
competitor_product_id VARCHAR(100) PChome 商品 ID
competitor_product_name TEXT PChome 商品名稱(核對用)
match_score NUMERIC(4,3) 商品身份比對分數0~1< 0.76 不寫入正式快取
tags JSONB 語意標籤,如 ["on_sale","discount_20pct"]
crawled_at TIMESTAMP 爬取時間
expires_at TIMESTAMP TTL = crawled_at + 48h可由 PCHOME_FEEDER_TTL_HOURS 調整),過期後 Hermes 忽略UI 身份覆蓋率不因價格 TTL 過期歸零

UNIQUE: (sku, source) — 同一 SKU+來源只有一筆ON CONFLICT UPDATE

語意標籤字典

標籤 觸發條件
on_sale PChome is_on_sale = True
discount_10pct 折扣 10-19%
discount_20pct 折扣 20-29%
discount_30pct 折扣 ≥ 30%
low_stock 庫存 < 10
high_rating 評分 ≥ 4.5

2.5 ai_price_recommendationsMigration 003 — 已建立)

此表需執行 migrations/003_ai_price_recommendations.sql 才能完整寫入 DB

CREATE TABLE IF NOT EXISTS ai_price_recommendations (
    id          SERIAL PRIMARY KEY,
    sku         VARCHAR(50) UNIQUE NOT NULL,
    name        TEXT NOT NULL,
    reason      TEXT,
    status      VARCHAR(20) DEFAULT 'pending',  -- pending / approved / rejected
    created_at  TIMESTAMP DEFAULT NOW(),
    updated_at  TIMESTAMP DEFAULT NOW()
);

現狀: nemoton_dispatcher_service.py_exec_add_to_recommendation() 在 engine 注入且表存在時才寫入,否則只發 Telegram 通知,不會 crash。


三、SQL 漏斗設計PChome 業績 ID 邊界)

daily_sales_snapshot 來自 PChome 後台業績匯出,商品IDproducts.i_code 不保證同一套 ID。任何跨表分析必須先經過可驗證的 mapping / identity contract不能只用字串相等把 PChome 後台銷售資料與 MOMO 商品主檔硬接。

歷史上曾以如下漏斗概念描述近 7 天銷售額下滑,但此 SQL 只能在 ID 已確認同源時使用:

WITH latest_momo_price AS (
    -- 從爬蟲商品庫取最新 MOMO 售價
    SELECT
        p.i_code      AS sku,      -- MOMO 商品代碼
        p.name,
        p.category,
        pr.price      AS momo_price,
        ROW_NUMBER() OVER (PARTITION BY p.id ORDER BY pr.timestamp DESC) AS rn
    FROM products p
    JOIN price_records pr ON pr.product_id = p.id
    WHERE p.status = 'ACTIVE'
),
recent_sales AS (
    -- 從每日業績快照計算近7天 vs 前7天銷售額
    SELECT
        "商品ID"     AS sku,      -- ⚠️ 實際欄位名為「商品ID」(非「商品編號」)
        SUM(CASE WHEN snapshot_date >= CURRENT_DATE - 7
                 THEN COALESCE("銷售金額"::numeric, 0) ELSE 0 END) AS sales_7d_curr,
        SUM(CASE WHEN snapshot_date >= CURRENT_DATE - 14
                  AND snapshot_date < CURRENT_DATE - 7
                 THEN COALESCE("銷售金額"::numeric, 0) ELSE 0 END) AS sales_7d_prev
    FROM daily_sales_snapshot
    GROUP BY "商品ID"
)
SELECT lmp.sku, lmp.name, lmp.category, lmp.momo_price,
       rs.sales_7d_curr, rs.sales_7d_prev
FROM latest_momo_price lmp
JOIN recent_sales rs ON rs.sku = lmp.sku
WHERE lmp.rn = 1
  AND rs.sales_7d_prev > 0
  AND (rs.sales_7d_curr - rs.sales_7d_prev) / rs.sales_7d_prev < -0.10
ORDER BY (rs.sales_7d_curr - rs.sales_7d_prev) / rs.sales_7d_prev ASC
LIMIT 300

ID 邊界:

  • products.i_code 是 MOMO 商品主檔 / 價格爬蟲 SKU。
  • daily_sales_snapshot."商品ID" 是 PChome 後台業績匯出中的商品識別碼。
  • 兩者不可被文件、Agent 或報表預設視為相同。需要合併分析時,必須先建立可審核 mapping 或沿用已驗證的 PChome identity / 商品名稱證據。

四、競品價格補給線架構(已實裝)

生產者-消費者解耦設計

[competitor_price_feeder.py Worker]  ←← 每 4 小時獨立運行
  ↓ 搜尋 PChomesearch_products
  ↓ 商品身份比對marketplace_product_matcher.py
  ↓ 提取語意標籤
  ↓ UPSERT competitor_prices預設 TTL 48h
                ↓
[HermesAnalystService.fetch_candidates()]  ←← AI Pipeline 消費端
  ↓ LEFT JOIN competitor_prices零網路等待
  ↓ 有效期內expires_at > NOW()+ match_score ≥ 0.76 + tags 含 identity_v2 才 JOIN
  ↓ pchome_price + competitor_tags 一起傳給 Hermes

關鍵設計決策

決策 選擇 原因
解耦方式 DB 表快取(非 Redis PostgreSQL 已是核心,無需額外依賴;支援 JOIN
TTL 6 小時 與 AI Pipeline 排程週期對齊
比對算法 品牌 + 核心 token + 容量/重量/包數 + 品類 + 價格 sanity check marketplace_product_matcher.py 統一供 feeder、legacy crawler、AI/PPT 鏈路使用
最低比對門檻 0.76 核心比價寧可待審,不允許低信心錯配影響 AI 決策
已有不同 PChome 商品覆蓋門檻 0.84 新候選與既有正式配對不同時,除非超高信心,否則寫入 needs_review attempt 不覆蓋
單位價可比模式 unit_comparable 同核心商品但買送/套組/件數不同時,不寫正式總價差;只寫入 attempt並以單位價證據供 Dashboard / PPT / AI 報表與人工覆核
Browse.sh 診斷 optional wrapper 只用於 selector / XHR / network trace 探勘;不得取代正式 crawler也不得直接把輸出寫成正式競品價格
語意標籤 JSONB 陣列 傳給 Hermes 提升情境感知品質

競品比對邏輯(competitor_price_feeder.py

MOMO 商品名稱
  → marketplace_product_matcher.build_search_terms()
  → PChomeCrawler.search_products(keyword, limit=12)
  → marketplace_product_matcher.score_marketplace_match()
    → 品牌衝突 / 容量衝突 / 包數衝突 hard veto
    → 同核心但買送/套組/件數不同標記 unit_comparable不進正式總價差
    → 同款高信心 score ≥ 0.76 才進 competitor_prices
    → 低信心、規格衝突、既有配對衝突寫入 competitor_match_attempts

fetch_candidates() v2 漏斗(已更新)

LEFT JOIN competitor_prices cp
       ON cp.sku = lmp.sku
      AND cp.source = 'pchome'
      AND cp.expires_at > NOW()
      AND cp.match_score >= 0.76
      AND COALESCE(cp.tags, '[]'::jsonb) ? 'identity_v2'

→ 無競品資料的商品仍回傳,pchome_price=NULL_batch_analyze 自動跳過

下游消費規範2026-05-19 更新)

  • Dashboard、AI pick、Hermes、Excel export、daily/growth 圖表與 competitor PPT 必須以 competitor_prices + competitor_price_history + competitor_match_attempts 為短期唯一生產真相源,且只消費 identity_v2 matcher 驗證過的配對;舊版僅靠 match_score 的快取不可直接進入決策或簡報。
  • pchome_matches 與 live pchome_batch() 僅保留 legacy compatibility不得作為新簡報或 AI 決策主來源。
  • services/competitor_intel_repository.py 是下游頁面、圖表、簡報的共用查詢出口;新增消費端不得各自硬寫不同 match threshold。所有競品報表的價差方向統一為 MOMO - PChome:正值代表 MOMO 較貴 / PChome 低價壓力,負值代表 MOMO 價格優勢daily、growth、OpenClaw、PPT 不得使用反向定義。
  • competitor PPT 不可只輸出 matched rows 造成覆蓋率假象;fetch_competitor_comparison_results() 必須用 LEFT JOIN valid_competitor 保留高營收/高價但尚未有效配對的 MOMO 商品,並帶出 match_statuscandidate_countbest_match_scorematch_diagnostic,讓簡報與 AI 文案明確區分「高信心比對」與「待補身份/價格」。
  • services/competitor_identity_revalidator.py 可對既有 competitor_prices legacy row 離線重跑 identity_v2:只有新版 matcher 分數 >= 0.76 且無 hard veto 才補 identity_v2 / legacy_revalidated tags預設不刷新 expires_at,避免過期價格進入決策。
  • CompetitorPriceFeeder.run_expired_identity_refresh() 會優先刷新已通過 identity_v2 但 TTL 過期的 PChome row直接用既有 competitor_product_id 批次呼叫 PChome 商品 API再用新版 matcher 重新驗證名稱/規格/價格 sanity通過後寫回 competitor_pricescompetitor_price_history。這條路徑提升新鮮價格覆蓋率,但不降低 match threshold也不讓過期價格直接進入決策佇列排序必須先處理既有 price_basis_total_price / alert_tier_price_alert_exact 或 diagnostic 等價欄位的安全價差 row再處理需要 review 的舊 row。若既有 competitor_product_id 已查不到或回傳候選低於門檻expired refresh 只寫 refresh_no_result / 低信心 attempt 並標記 fresh_search_recovery_deferred,不得在同一條價格刷新路徑 fresh search 替換正式 identity。fresh search recovery 只保留給 retryable candidate revalidation / unmatched priority 等補抓路徑。
  • 過期 identity refresh 排序必須優先 price_basis_total_price / alert_tier_price_alert_exactmatch_diagnostic_json.price_basis='total_price' / alert_tier='price_alert_exact' 的正式價差配對,再依 expires_at 與 MOMO 價格排序,避免高風險可決策價差長期排在低價或非告警型 stale row 後面。
  • marketplace_product_matcher.py 的擴充只能走「正向證據 + 反向 veto」品牌一致、商品線/型號訊號強、價格合理且無 hard veto 時才允許 strong_product_line_match 加分;補充瓶/補充包/refill 與一般正裝不互相配對,分享組/加量組/明星組等組合包不得誤配單品。
  • 近門檻規則必須成對補「召回 + 防錯配」測試:可召回者需有品牌、商品線、規格或具名 identity anchor例如 MUJI 精油芬香護手霜、Mustela 慕之幼爽身潤膚乳、Herbacin 小甘菊護手霜;防錯配者需成為 hard veto例如 M·A·C Macximal 柔霧/緞光唇膏質地、ERBE 指甲清垢棒/指甲緣刨刀功能、Schick 舒芙/舒綺女用除毛刀品線。不得用單一同規格或同品牌放寬全域門檻。
  • 套組/買送/件數不同但品牌、核心商品線與單一基礎規格一致時matcher 必須回傳 comparison_mode='unit_comparable'unit_comparable reasonFeeder 只能寫入 competitor_match_attempts.attempt_status='unit_comparable'refresh_unit_comparable,不得寫入 competitor_prices。Dashboard 與 competitor_intel_repository 必須用 build_unit_price_comparison() 產生每 ml / 每 g / 每入單位價證據,讓 PPT / AI 報表可說明「需單位價比較」而不是把總價當同款價差。商品看板在正式配對尚未成立時,仍必須顯示最佳候選 PChome 商品名稱、候選價與「候選價需單位換算」說明讓人工覆核可直接看見下一步daily/growth、PPT 與 OpenClaw 摘要不得自建查詢,需消費 fetch_competitor_review_queue() 與 coverage 的 unit_comparable_count。若任一側含多個不同容量/重量規格,視為多品項套組,不可進 unit_comparable
  • PChome feeder 的外部 request timeout 由 PCHOME_FEEDER_TIMEOUT 控制,預設 12 秒;排程不得因單一 PChome 搜尋 API timeout 被拖到數分鐘。
  • 品牌 alias 屬於正向身份證據,不是門檻放寬;DR.WU / DR WU / DRWU / 達爾膚 這類同品牌中英混寫必須正規化後再進 matcher避免同規格真同款被誤降成 brandless identity review。
  • 近門檻 rescore pilot 必須支援明確 SKU 篩選;audit_competitor_match_attempt_rescore.py --sku <sku> 可只重算指定 SKU避免為了小批次驗證而掃整批 true_low_confidence
  • 商品看板的 PChome 狀態必須把 matcher 診斷原因翻成可行動語意:品牌不符已排除、規格不符已排除、補充包不相容、組合規格不相容、系列不符已排除、需單位價比較、低信心待補強等,不可只顯示籠統「待比對」或「身份否決」。
  • PChome 補抓產線與 priority list 若尚未進入搜尋/補抓必須顯示「PChome 補抓產線」、「尚未搜尋」與「尚未進入 PChome 補抓」,不得使用「待比對」這類會被誤解成已有候選待人工審核的字眼。
  • 商品看板、PChome review queue 與 /api/export/excel/pchome-review 必須優先讀取 match_diagnostic_json.reasons 並轉成操作員可讀標籤;文字版 error_message 只作 legacy fallback。商品列的 PChome 狀態摘要也必須使用同一套專業標籤,避免 overview 顯示「妝效質地不同」但列表仍顯示籠統身份不符。新增 matcher reason 時需同步更新 MATCH_DIAGNOSTIC_REASON_LABELS 與 dashboard 狀態翻譯,避免 UI 顯示 makeup_finish_conflict 這類 machine code。PChome 標題缺品牌但有窄範圍 exact identity anchor 的商品,只能透過具名 brandless recovery 進 manual-review identity多色任選 / 單一色號 gap 必須標記 variant_selection_review,並從 recoverable_low_score 降回 true_low_confidence,不得自動批次寫正式價差。
  • Dashboard 必須把「待比對」拆成可診斷狀態:價格過期待刷新舊版配對待重驗低分配對待補強已排除需單位價比較找不到同款抓取異常尚未搜尋。硬性不相容候選應顯示為已排除/不相容,不得讓使用者誤以為每筆都需要人工待審。

執行方式

# 手動觸發一輪抓取
python3 services/competitor_price_feeder.py

# 預覽 legacy PChome 快取 identity_v2 重驗證(不寫入)
python3 -m services.competitor_identity_revalidator --limit 500

# 寫入安全通過的 identity_v2 tag不刷新過期價格
python3 -m services.competitor_identity_revalidator --limit 500 --apply

# 未來整合為 K3s CronJob每 4 小時)
# k8s/jobs/competitor-price-feeder-cronjob.yaml

五、Telegram 語意化訊息規範ChatOps 標準)

5.1 核心原則

  1. 語意化排版 (Semantic Formatting) — Emoji 作為視覺標籤0.5 秒判斷嚴重性
  2. 倒金字塔結構 — 結論先行 → 核心數據 → AI 洞察 → 建議行動 → 運算足跡
  3. 收斂行動呼籲 (Call to Action) — 每則訊息只有一個明確的 👉 建議行動
  4. 底部運算足跡 — FinOps + Observability用分隔線隔開主訊息
  5. EA HITL 專業 briefea_escalation 必須分成決策狀態、背景摘要、風險摘要、TOP 待審 SKU 與建議處置;價格類行動不得用長 bullet 串接,必須拆出 MOMO/PChome 價格、價差、人工處置與 PChome ID。
  6. 價格類決策信封專業 briefprice_alertpchome_match_reviewcompetitor_price_review 等含 PChome / 價格證據的 decision_envelopeEventRouter 必須直送 evidence template不得進 L1/L2 重摘要Telegram 內容必須拆成「標的、價格證據、比對證據、人工下一步」,並從信封讀取 momo_pricecompetitor_pricecandidate_gap_pctmatch_scoreunit_price_insightexisting_match_conflict
  7. Shared UI 信封摘要共用 — Webcrumbs host data 與其他共用 UI runtime 必須讀 reviewDecisionBrief / decision_envelope 的結構化證據,不在瀏覽器端重組比價判斷;這些 payload 只能讀 DB 既有覆核資料,不呼叫 LLM、不抓外站、不寫資料。

5.2 語意化 Emoji 字典

類別 Emoji 語意
身份識別 ⚡ NemoTron 派發器 Dispatcher 身份
身份識別 🔍 Hermes 3 8B Analyst 身份(僅出現在足跡)
風險級別 🚨 高危險,立即行動
風險級別 ⚠️ 中風險,人工覆核
風險級別 💡 低風險,策略建議
例行報告 📊 核心數據區塊標頭
業務屬性 💰 價格/毛利
業務屬性 📦 庫存/銷量
業務屬性 🏆 競品情報
AI 洞察 🧠 AI 分析結果
運算足跡 ⚙️ FinOps 底部區塊

5.3 三大類訊息模板(標準格式)

類別一:緊急告警(trigger_price_alert 觸發)

🚨 [⚡ NemoTron 派發器] 競價高危險預警

⚠️ 核心問題:[A003 舒特膚 AD 乳液] 價格大幅落後競品,訂單流失中!

📊 關鍵數據:
• 我方價格:$1,200
• 競品價格:$980 (價差 22.4%)
• 銷量變化:近七天銷量 -35.0%

🧠 AI 洞察 (信心度 85%)
價差已突破 20% 警戒線,且伴隨實質銷量下滑,高度判定為競品大力促銷攔截。

👉 建議行動:建議立即降價至 $1,000 迎戰,或發放 $200 專屬折價券

─────────────────────
⚙️ 運算足跡:
• 🔍 分析: Hermes 3 8B (GCP-A/GCP-B/111 Ollama) | 耗時: 34.2s | Tokens: 512 | $0 成本
• ⚡ 決策: NemoTron NIM | 185 Tokens | $0 (配額內 2/80)

類別二:人工覆核(flag_for_human_review 觸發)

⚠️ [⚡ NemoTron 派發器] 異常波動需人工覆核

🔍 待查商品:[A001 玻尿酸面膜10片裝]

📊 矛盾數據:
• 價格狀態:無明顯價差 (與競品齊平)
• 異常現象:過去 3 天銷量突然掛零 (平日日均 15 件)
• 庫存狀態:目前庫存充足 (500+ 件)

🧠 AI 洞察 (信心度 45%)
數據出現矛盾訊號AI 信心不足以自主決策,需人工走查確認。

👉 建議行動:請營運人員立即進行人工走查。

─────────────────────
⚙️ 運算足跡:
• 🔍 分析: Hermes 3 8B (GCP-A/GCP-B/111 Ollama) | 耗時: 34.2s | Tokens: 512 | $0 成本
• ⚡ 決策: NemoTron NIM | 185 Tokens | $0 (配額內 2/80)

類別三:策略執行通知(add_to_recommendation 觸發)

💡 [⚡ NemoTron 派發器] 潛力商品自動佈署

🏆 推薦品項:[A009 美白化妝水150ml] 已自動加入「首頁推薦區塊」

📊 決策依據:
我方價格低於市場 20%近7天銷量回升具備流量轉換潛力

🧠 AI 洞察 (信心度 82%)
具備價格競爭優勢NemoTron 主動提升曝光量以最大化業績。

👉 執行狀態:✅ 系統已自動寫入 ai_price_recommendations 推薦表

─────────────────────
⚙️ 運算足跡:
• 🔍 分析: Hermes 3 8B (GCP-A/GCP-B/111 Ollama) | 耗時: 34.2s | Tokens: 512 | $0 成本
• ⚡ 決策: NemoTron NIM | 185 Tokens | $0 (配額內 2/80)

類別四Gemini 備援 / 鎖定場景推理週報

... (前文省略) ...
─────────────────────
⚙️ 運算足跡:
• 🔍 彙整: Hermes 3 8B (GCP-A/GCP-B/111 Ollama) | 耗時: 12s | $0 成本
• 🧠 備援/鎖定場景: Gemini 2.5 Flash | 8,420 Tokens | 費用: 約 $0.003 USD

5.4 運算足跡資料來源

模型 API Response 欄位 說明
Hermes (Ollama) eval_count, total_duration 生成 tokens 數 + 推理耗時 (ns→s)
NemoTron (NIM) usage.total_tokens (OpenAI 格式) prompt + completion tokens 合計
Gemini usageMetadata.totalTokenCount 乘費率算 USD

程式碼位置: nemoton_dispatcher_service.py_build_footprint_block(hermes_stats, nim_stats)

5.5 Inline Keyboard 按鈕Level 2 互動,待實裝)

當收到類別一緊急告警時訊息底部附帶互動按鈕Telegram Bot API inline_keyboard

[ ✅ 批准降價 ]  [ ❌ 拒絕並忽略 ]  [ 🔗 查看報表 ]
  • ✅ 批准降價 → 呼叫 MOMO PRO 後台 API 改價 + 決策寫入知識庫
  • ❌ 拒絕並忽略 → 決策寫入知識庫(訓練未來在此品類保守點)
  • 🔗 查看報表 → 跳轉至 MOMO PRO 該商品數據分析頁

現狀: 尚未實裝Inline Keyboard 需搭配 Telegram Webhook + callback_query handler


六、Telegram 告警架構

告警群組

  • 群組: 小龍蝦 (業務情報專用,非 SRE 維運)
  • Chat ID: -1003940688311
  • Bot: <TELEGRAM_BOT_TOKEN>

單 Bot 多身份策略One Bot, Multiple Headers

模組 Telegram 標頭
Hermes 分析師 [Hermes 分析師]
NemoTron 派發器 [NemoTron 派發器]
Gemini 備援 [Gemini 備援](僅 Ollama 失敗或 ADR-028 鎖定場景)

三種告警類型

Tool 觸發條件 Telegram 格式
trigger_price_alert HIGH 風險 (gap>15% + 銷量跌>20%) 🔴/🟡 競價威脅告警
add_to_recommendation 我方價格低於競品且銷量正成長 推薦商品候選
flag_for_human_review 信心 < 0.6 或情況複雜 ⚠️ 需要人工審核

六、已驗證的服務參數

Hermes 分析師

參數
模型 hermes3:latest
Ollama URL GCP-A http://34.87.90.216: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
TOP_N 20每次最多輸出威脅數

NemoTron 派發器

參數
模型 meta/llama-3.1-8b-instruct
NIM API URL https://integrate.api.nvidia.com/v1
Timeout 60s
每日配額上限 80留 20 給 AWOOOI
配額耗盡 fallback 直接派發 HIGH 風險告警,跳過 NIM
實測 token 消耗 1206 tokens/輪(實彈 2026-04-17

七、已知技術債與待辦

優先 項目 說明
Migration 003 + 004 competitor_prices + ai_price_recommendations 已在 188 momo_analytics 執行
188 生產容器實彈驗證 Hermes + NIM + PostgreSQL + Telegram 全通 (2026-04-17)
momo-app port 5001→5002 docker-registry 佔用 5001docker-compose.yml 改為 127.0.0.1:5002:80,已 Up healthy
momo-app 雙網路連線 同時連 momo-network + momo-pro_default(後者含 momo-db alias momo-postgres
P1 PChome Feeder CronJob competitor_price_feeder.py 每 4 小時排程 (Scheduler 整合)
P1 告警去重 TTL 同一 SKU 短期內重複告警未防範
daily_sales_snapshot 欄位防禦 V10.605 已支援多 worksheet / 表頭列掃描 / 格式失敗隔離
P1 PChome 後台業績匯出前半段自動化 現有 importer 已自動吃 Google Drive仍需接 PChome 後台排程匯出、Email 附件或受控 browser 下載
P2 Scheduler 整合 每6小時自動觸發 Hermes→NIM→Telegram 管線
P2 Gemini 備援治理 僅保留 ADR-028 鎖定場景與 Ollama 失敗備援,新增 caller 必須走 ADR

八、部署拓撲2026-04-17 確認)

實體機器對應

服務 主機 容器名 說明
PostgreSQL 192.168.0.188 momo-db pgvector/pgvector:pg14含所有 AI 相關表
momo-app 192.168.0.188 momo-pro-system Up healthyport 5002:805001 被 docker-registry 佔用,已改 5002
momo-scheduler 192.168.0.188 momo-scheduler 常駐排程容器
Ollama Primary 34.87.90.216 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 正確設定

TELEGRAM_BOT_TOKEN=<TELEGRAM_BOT_TOKEN>  # ← 唯一正確 token
TELEGRAM_CHAT_IDS=["-1003940688311"]  # 小龍蝦群組
NVIDIA_API_KEY=<NVIDIA_API_KEY>
USE_POSTGRESQL=true
POSTGRES_HOST=momo-db
# POSTGRES_DB / USER / PASSWORD 使用 docker-compose.yml 預設值

⚠️ Split-brain 陷阱188 容器環境曾存在舊 bot token 8569720657(不同 bot不在小龍蝦群組 已於 2026-04-17 深夜修正為正確 token 8610496165


九、校對歷程

日期 問題 修正
2026-04-17 fetch_candidates() SQL 使用 "商品編號" 修正為 "商品ID"2026-06-15 追認此欄位來自 PChome 後台業績匯出,不可預設等於 MOMO products.i_code
2026-04-17 Hermes gap_pct 由 LLM 計算 → 誤差大 改為 Python 預算 (momo-pchome)/pchome*100
2026-04-17 推理時間 52s 預算 gap_pct 後降至 19.3s (3筆)
2026-04-17 model_footprint DB 欄位寫入 {} 分離 footprint_textTelegram 顯示)與 footprint_dataDB JSON
2026-04-17 SQLite 語法 NOW() / datetime('now') / ::jsonb 全部改為 CURRENT_TIMESTAMP / Python 計算(跨 DB 相容)
2026-04-17 本機 SQLite 測試通過但 188 未同步任何檔案 rsync 推送 6 核心檔案 + 全站 dry-run 對帳 + migrations 跑通
2026-04-17 188 容器無 volume mountdocker cp 臨時解 重建 imageCOPY . . bake 進新代碼port 5001 衝突記錄為技術債
2026-04-17 188 .env Telegram token 不正確split-brain 修正為 8610496165188→Telegram message_id=282 確認
2026-04-17 NIM Tool Calling E2E 真實 NVIDIA_API_KEY 驗證dispatched=3, errors=[]
2026-05-20 PChome 商品身份比對仍可能因單一規格重疊誤放行 V10.312 起 matcher 解析 mg/mcg 劑量、件組套組、多規格集合與同數字不同單位;劑量/容量/重量/件數/品類衝突會硬否決或導向單位價覆核,避免錯配污染 Dashboard、daily/growth、PPT 與 AI 競價分析
2026-05-20 正確 PChome 候選常因只掃第一頁或搜尋詞丟失品牌/規格而未進入 matcher V10.314 起搜尋 API 依 limit 掃多頁、對暫時性錯誤有限重試feeder 預設 5 組搜尋詞、20 候選、2 頁,並保留括號/方括號內品牌與規格,提升覆核隊列與正式比價的候選品質
2026-05-20 指定日期競品簡報可能混用目前 competitor_prices 快取價 V10.315 起 fetch_competitor_comparison_results() 有 start/end date 時改用 competitor_price_history 期間快照MOMO 價格取報表結束日前最新價;即時報表才使用目前有效 competitor_prices
2026-05-20 PChome 覆蓋率分子可能被非活躍或無 MOMO 現價 SKU 膨脹 V10.317 起 fetch_competitor_coverage()valid_matches 改為 active MOMO latest price 與有效 PChome identity_v2 價格交集,確保 daily/growth/PPT/AI 看到的比價資料品質不被舊快取列高估
2026-05-20 EA HITL 告警可能把非 SKU 診斷誤排成待審 SKU或在缺少 DB/Hermes 實證時打擾人工 V10.318 起 ea_escalation 僅對含 SKU/價格比較的 actions 使用競價卡片;非 SKU 診斷改為「待確認事項」。價格類低信心事件若無 DB/Hermes 實證,測試鎖定只 suppress、不寫 human_review、不發 Telegram
2026-05-21 ElephantAlpha NIM/LLM 回應偶爾不是純 JSON會觸發 json.loads() 失敗並落入舊式空泛策略 fallback V10.383 起協調器容忍 fenced/混文字 JSON無法解析時改用 DB/Hermes 實證 fallback且 fallback 不再包含 OpenClaw generate_* 舊步驟或自動調價暗示
2026-05-20 Telegram HTML parse mode 不支援 <br>,可能導致告警或報告送出 400 V10.321 起 Telegram template 發送前會把 <br> / <br/> / <BR /> 轉為換行;保留其他 HTML 標籤,非 HTML parse mode 不改寫
2026-05-20 部分舊 Telegram 入口繞過中央 sanitizer且 RAG awaiting review 使用錯誤 chat_id= 參數會讓人工審核推播失敗 V10.322 起 Bot API price decision 走 send_telegram_with_result()price_decision()report_url 相容並 escape 動態欄位RAG awaiting review 改用 chat_ids=[...] 呼叫 _send_telegram_raw()