# 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 入口清理版 --- ## 一、四 AI Agent 路由架構 ``` SQL漏斗(~300筆) ↓ [Hermes 3 8B] — 分析師 (本地 Ollama, 零成本) 模型: hermes3:latest @ 192.168.0.111:11434 任務: 競價威脅分類 → TOP 20 HIGH/MED/LOW ↓ [NemoTron NIM] — 派發器 (雲端, 免費配額) 模型: meta/llama-3.1-8b-instruct @ NVIDIA NIM 任務: Tool Calling → Telegram 告警 / DB 寫入 ↓ [OpenClaw / Gemini] — 策略師 (費用審批制) 任務: 週策略報告、洞察報告、L3 HITL 建議 ↓ [ElephantAlpha] — 編排者 (L3 Orchestrator) 任務: 跨 Agent orchestration、HITL、AutoHeal bridge、受控 log scan ``` ### 1.1 PChome 挑品 Agent(2026-05-01) `services/ai_product_pick_agent.py` 新增 PChome 銷售用挑品 Agent: - 只讀真實資料表:`products`、`price_records`、`competitor_prices`、`competitor_price_history`,若 `daily_sales_snapshot` 可用則納入近 7 天銷售額與數量。 - 將 PChome 比 MOMO 有價格優勢、比對信心足夠、且有歷史快照或銷售動能的品項寫入 `ai_price_recommendations`。 - 寫入策略使用 `strategy='product_pick'`,保留在既有 AI 決策表,不新增假頁面或暫存 JSON。 - 後台入口:`POST /api/ai/product-picks/generate`,`/ai_intelligence` 可手動產生清單。 - 配對來源仍以 PChome crawler 真實搜尋結果為準;無競品資料時不生成挑品。 - 比對覆蓋率補強入口:`POST /api/ai/pchome-match/backfill`,優先補抓仍無有效 PChome 配對的高價 ACTIVE 商品,完成後自動重算 AI 挑品清單。 - 排程閉環:`run_pchome_match_backfill_task` 每日 10:30 執行,補抓 PChome 待比對商品、寫入歷史價格,再重算 `strategy='product_pick'` 清單。 - 商品看板第一屏:`/` 的 V2 看板直接以 `products`、`price_records`、`competitor_prices`、`ai_price_recommendations` 顯示比對覆蓋率、PChome 優勢、MOMO 威脅、AI 挑品與待比對優先清單。 | 角色 | 模型 | 主機 | 成本 | 每日限額 | |------|------|------|------|---------| | 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 | 雲端 | 需審批 | — | | ElephantAlpha 編排者 | ElephantAlpha | 依部署環境 | 受控 | HITL / 任務制 | --- ## 一之一、AI 自動化閉環實況(2026-04-29) ```text 事件 / 排程失敗 / 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_adjustment`、`adjust_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_total` 與 `momo_ai_autoheal_duration_ms_count/sum/max`。 - `/metrics` 在尚無事件時仍輸出 `momo_ai_*` zero-baseline series,讓 Prometheus/Grafana 重啟後可立即看到 metric names。 - `/ai_automation_smoke` 提供登入後 smoke dashboard。 - `/api/ai-automation/smoke` 提供 read-only JSON 狀態,不做外部網路呼叫。 - Smoke API 會將最近快檢結果保存到 JSONL,dashboard 顯示最近狀態趨勢。 - Smoke history 支援 JSONL 匯出、清理與每日 OK / Warning / Critical 摘要。 - Smoke 每日摘要支援手動 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.yml` 的 `momo-app` job scrape `momo-pro-system:80/metrics`;Prometheus container 需加入 `momo-network`。 - Active Blackbox HTTP targets 必須探測 `/health`(188 stack 目前 `https://mo.wooo.work/health` 與 `http://momo-pro-system:80/health`;110 gateway stack 目前 `https://mo.wooo.work/health`),不可探測 Dashboard 首頁 `/`,避免監控流量觸發重型 DB 查詢。 - `/metrics` 對 `realtime_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 = gthread`、`GUNICORN_THREADS=4`、`preload_app = False`;此組合讓 HUP 熱重載可用,也避免 Dashboard 長查詢完全阻塞 `/health`。 - CD rebuild 模式必須先 build image 成功,再短暫 stop/rm/recreate 三應用容器,避免 no-cache build 造成長時間 502。 - ElephantAlpha 使用 NVIDIA NIM hosted API;production 預設模型為 `nvidia/llama-3.3-nemotron-super-49b-v1.5`,`ELEPHANT_ALPHA_FALLBACK_MODELS` 需保留至少一個可呼叫備援;403/404、408/409/425/429、5xx、timeout 與 connection error 必須嘗試下一個模型。 - OpenClaw/Hermes embedding 優先呼叫 Ollama `/api/embed`,只在舊節點不支援時 fallback `/api/embeddings`;timeout 由 `EMBEDDING_TIMEOUT` / `OLLAMA_EMBED_TIMEOUT` 控制。 --- ## 二、真實資料庫 Schema(已校對確認) ### 2.1 `products` 表(SQLAlchemy ORM,SQLite/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_snapshot` 表(動態表,從 Excel 匯入) > **重要**: 此表由 `import_service.py` 使用 `df.to_sql()` 動態建立。 > 欄位名稱**完全繼承自匯入的 MOMO Excel 報表原始欄位**,加上程式碼追加的 `snapshot_date`。 #### 已確認的關鍵欄位(實際 MOMO 報表欄位名稱) | 欄位 | 型別 | 說明 | 備注 | |------|------|------|------| | `snapshot_date` | Date | 資料所屬日期(程式追加) | 由 `import_service.py` 從「日期」欄位解析 | | `商品ID` | VARCHAR | **商品識別碼**(= `products.i_code`) | ⚠️ 非 `商品編號`!| | `商品名稱` | TEXT | 商品名稱 | | | `銷售金額` | NUMERIC | 銷售業績金額 | 系統以 find_col 模糊比對,優先 `銷售金額` | | `數量` | NUMERIC | 銷售數量 | | | `總成本` | NUMERIC | 成本 | | | `廠商名稱` | VARCHAR | 廠商名稱 | | | `商品館` / `館別` | VARCHAR | 分類 | | #### 欄位自動偵測邏輯(`find_col`) 系統使用 keyword 模糊比對,**不要求欄位名完全固定**: ```python 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_prices` 表(Migration 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.45 不寫入 | | `tags` | JSONB | 語意標籤,如 `["on_sale","discount_20pct"]` | | `crawled_at` | TIMESTAMP | 爬取時間 | | `expires_at` | TIMESTAMP | TTL = crawled_at + 6h,過期後 Hermes 忽略 | **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_recommendations` 表(Migration 003 — 已建立) 此表需執行 `migrations/003_ai_price_recommendations.sql` 才能完整寫入 DB: ```sql 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 漏斗設計(已修正欄位名稱) `hermes_analyst_service.py` → `fetch_candidates()` 的核心 SQL: ```sql 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 ``` **漏斗效果**: 226萬筆 price_records → ~300 筆(近7天銷量跌幅 > 10% 的活躍商品) **JOIN 邏輯**: - `products.i_code` ↔ `daily_sales_snapshot."商品ID"` — 均為 MOMO 商品代碼,格式相同 --- ## 四、競品價格補給線架構(已實裝) ### 生產者-消費者解耦設計 ``` [competitor_price_feeder.py Worker] ←← 每 4 小時獨立運行 ↓ 搜尋 PChome(search_products) ↓ 模糊比對(price_comparison.py) ↓ 提取語意標籤 ↓ UPSERT competitor_prices(TTL 6h) ↓ [HermesAnalystService.fetch_candidates()] ←← AI Pipeline 消費端 ↓ LEFT JOIN competitor_prices(零網路等待) ↓ 有效期內(expires_at > NOW())+ match_score ≥ 0.45 才 JOIN ↓ pchome_price + competitor_tags 一起傳給 Hermes ``` ### 關鍵設計決策 | 決策 | 選擇 | 原因 | |------|------|------| | 解耦方式 | DB 表快取(非 Redis) | PostgreSQL 已是核心,無需額外依賴;支援 JOIN | | TTL | 6 小時 | 與 AI Pipeline 排程週期對齊 | | 比對算法 | 品牌(0.4) + 規格(0.3) + 關鍵字(0.3) | 依賴現有 `price_comparison.py` | | 最低比對門檻 | 0.45 | 低於此分數不寫入,避免張冠李戴影響 AI 決策 | | 語意標籤 | JSONB 陣列 | 傳給 Hermes 提升情境感知品質 | ### 競品比對邏輯(`competitor_price_feeder.py`) ``` MOMO 商品名稱[:20字] → PChomeCrawler.search_products(keyword, limit=10) → _find_best_match(momo_name, results) → ProductNameParser(品牌 + 規格 + 關鍵字) → _structural_similarity() → score → score ≥ 0.45 → _upsert_competitor_price() ``` ### `fetch_candidates()` v2 漏斗(已更新) ```sql LEFT JOIN competitor_prices cp ON cp.sku = lmp.sku AND cp.source = 'pchome' AND cp.expires_at > NOW() AND cp.match_score >= 0.45 ``` → 無競品資料的商品仍回傳,`pchome_price=NULL`,`_batch_analyze` 自動跳過 ### 執行方式 ```bash # 手動觸發一輪抓取 python3 services/competitor_price_feeder.py # 未來整合為 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.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 (本地 111) | 耗時: 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 (本地 111) | 耗時: 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 (本地 111) | 耗時: 34.2s | Tokens: 512 | $0 成本 • ⚡ 決策: NemoTron NIM | 185 Tokens | $0 (配額內 2/80) ``` #### 類別四(未來):Gemini 雲端推理週報 ``` ... (前文省略) ... ───────────────────── ⚙️ 運算足跡: • 🔍 彙整: Hermes 3 8B (本地 111) | 耗時: 12s | $0 成本 • 🧠 推理: Gemini 1.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: `8610496165:AAFOlcWV4oRUSC2TI-fYux7JV97fjNzsYR8` ### 單 Bot 多身份策略(One Bot, Multiple Headers) | 模組 | Telegram 標頭 | |------|--------------| | Hermes 分析師 | `[Hermes 分析師]` | | NemoTron 派發器 | `[NemoTron 派發器]` | | Gemini 策略師 | `[Gemini 策略師]` (未來) | ### 三種告警類型 | Tool | 觸發條件 | Telegram 格式 | |------|---------|--------------| | `trigger_price_alert` | HIGH 風險 (gap>15% + 銷量跌>20%) | 🔴/🟡 競價威脅告警 | | `add_to_recommendation` | 我方價格低於競品且銷量正成長 | ⭐ 推薦商品候選 | | `flag_for_human_review` | 信心 < 0.6 或情況複雜 | ⚠️ 需要人工審核 | --- ## 六、已驗證的服務參數 ### Hermes 分析師 | 參數 | 值 | |------|---| | 模型 | `hermes3:latest` | | Ollama URL | `http://192.168.0.111:11434` | | Timeout | 120s | | Temperature | 0.1 | | 實測推理時間 | **19.3s(3筆,實彈 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 佔用 5001,docker-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 短期內重複告警未防範 | | P1 | `daily_sales_snapshot` 欄位防禦 | 若 Excel 欄位名變更,JOIN 條件會靜默失效 | | P2 | Scheduler 整合 | 每6小時自動觸發 Hermes→NIM→Telegram 管線 | | P2 | Gemini 策略師 | 週報生成(需費用審批後實作) | --- ## 八、部署拓撲(2026-04-17 確認) ### 實體機器對應 | 服務 | 主機 | 容器名 | 說明 | |------|------|--------|------| | 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 可達 | | E2E 驗證容器 | 192.168.0.188 | `momo-e2e-test` | 臨時容器,含新服務模組 | ### 188 `/home/ollama/momo-pro/.env` 正確設定 ```bash TELEGRAM_BOT_TOKEN=8610496165:AAFOlcWV4oRUSC2TI-fYux7JV97fjNzsYR8 # ← 唯一正確 token TELEGRAM_CHAT_IDS=["-1003940688311"] # 小龍蝦群組 NVIDIA_API_KEY=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 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"`(與 MOMO Excel 實際欄位名一致) | | 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_text`(Telegram 顯示)與 `footprint_data`(DB 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 mount,`docker cp` 臨時解 | 重建 image(`COPY . .` bake 進新代碼);port 5001 衝突記錄為技術債 | | 2026-04-17 | 188 .env Telegram token 不正確(split-brain)| 修正為 `8610496165`,188→Telegram message_id=282 確認 | | 2026-04-17 | NIM Tool Calling E2E | 真實 NVIDIA_API_KEY 驗證:dispatched=3, errors=[] |