10 KiB
ADR-021: EA HITL Pre-fetch + 競價告警必填金額影響量化
- Status: Accepted
- Date: 2026-05-03
- Deciders: 統帥
- Related: 補強 ADR-012(Agent Action Ladder L3 HITL)對 escalation 訊息內容的要求;不取代任何既有 ADR
- Affects:
services/elephant_alpha_autonomous_engine.py、services/nemoton_dispatcher_service.py、services/hermes_analyst_service.py、services/telegram_bot_service.py
Context
2026-05-02 統帥收到一條 EA 升級審核 Telegram 告警(commit b5a2b094 時段),內容為:
自主決策信心度 0.83 低於門檻,需人工批准 AI 摘要:競爭對手價格溢價 >5% 且有庫存充足… 步驟 1:[OpenClaw] 基於市區拉貨區市場特性,生成包含動態定價模型與競爭對手分析的策略建議 步驟 2:[Hermes] 識別具體競爭商品並量化價格差異(目標確認至少 20 個高價溢價 SKU) 步驟 3:[NemoTron] 將生成的定價策略與競爭分析結果同步至人工審核管道
統帥指出此告警毫無決策價值,原因:
- 沒有具體 SKU、沒有金額影響、沒有可批准/駁回的具體動作
- 三步驟「建議行動」實為「申請開始分析」的元流程描述(OpenClaw 生成策略 → Hermes 識別 SKU → NemoTron 同步),人類審核者沒有判斷依據
- HITL 攔截點放錯位置:應在「具體動作出爐後、執行前」攔,而非「分析計畫產出但尚未跑」
程式碼層證據
根因 A — _escalate_to_human 的 ai_actions 來源是 plan 階段:services/elephant_alpha_autonomous_engine.py:528-557 的 _execute_autonomous_decision 在 elephant_orchestrator.analyze_and_coordinate 產出 StrategicDecision 後,信心度不足即 escalate——此時 decision.execution_plan 還只是 Gemini 寫的 plan 文字,Hermes/NemoTron 從未實際跑過取得具體 SKU。_escalate_to_human 把 plan 的前 3 個 step description 直接灌進 triaged_alert.ai_actions 是空泛元流程的根源。
根因 B — Hermes/NemoTron 已有具體告警,但缺金額影響量化:services/nemoton_dispatcher_service.py:683-700 的 _exec_trigger_price_alert 已經能輸出「[SKU] 商品|MOMO $X / PChome $Y|價差 ±%|銷量 ±%」,但缺絕對金額影響——人類看到「價差 22.4%、銷量 -35%」仍需自己換算「我這週實際少賺多少」才能決策。
根因 C — momo:eig: callback 按鈕從未實作:services/telegram_templates.py:466-467 的 triaged_alert 鍵盤產出「🛑 忽略此事件」按鈕(callback_data = momo:eig:{event_id}),但 services/telegram_bot_service.py:512 的 handle_callback 只 dispatch menu:/cmd:/await: 三個 prefix,momo: prefix 完全沒處理——統帥點擊忽略按鈕後永遠沒反應,HITL 流程閉環缺一環。
Decision
對 EA L3 HITL 升級審核訊息與 NemoTron 競價告警採取三項根治措施:
規則 1 — EA 升級審核 pre-fetch Hermes 具體威脅清單
對 _PRICE_RELATED_TRIGGERS = {price_drop_alert, market_opportunity, threat_escalation} 三類觸發,_escalate_to_human 送 Telegram 前先呼叫 Hermes 取得具體 SKU 清單,將前 5 筆格式化為:
[SKU] 商品名稱|MOMO $X vs PChome $Y (±%)|近 7 日流失 NT$ Z|建議跟進 NT$ W
蓋掉原本的 plan 元流程文字。強制配套限制:
asyncio.wait_for(timeout=5)短超時:Hermes 熱駐留 < 10s,但冷啟動會拖到 30s+,HITL 訊息延遲不可大於 10s- Pre-fetch 失敗(timeout / 0 threats / 全部缺金額)→ 不送 Telegram、不寫 pending human_review,只記錄 suppressed escalation telemetry 與 cooldown,避免把無實證 plan 當成可審核告警
- 「全部行皆缺金額」也視同無料 fallback,避免「乾巴巴兩行 MOMO/PChome 比價」比 plan 文字更空泛
規則 1.1 — 非價格類低信心 escalation 必須有可審核內容
2026-05-19 補充:resource_optimization 不是 SKU/價格事件,不能套用 Hermes/SKU fallback 模板。當 EA 對 resource_optimization 只產出低信心決策且沒有具體可審核行動時,系統只記錄 telemetry 與 cooldown,不發 Telegram,也不建立 ai_insights.status='pending' 的人工審核。這避免「資源調配優化」告警顯示「Hermes 即時威脅清單不可用」這類錯誤診斷。
規則 2 — NemoTron 告警必填金額影響量化
新增模組級 helper _compute_business_impact(threat) -> {revenue_loss_7d, recommended_price}:
revenue_loss_7d=max(0, sales_7d_prev_amount - sales_7d_curr_amount)且僅在gap_pct > 0時計算- 語意:「我方比競品貴,且過去 7 日銷量金額下滑 → 推估價格因素導致的流失」
gap_pct ≤ 0(我方便宜或持平)即使銷量下滑亦歸 0,避免把季節性/商品壽命終結等非價格因素誤標為「流失」誘導降價
recommended_price=round(pchome_price)當gap_pct > 0;否則None- 語意:「跟進競品的最低調價金額」;統帥可基於此再依毛利策略加溢價
_fmt_price_alert / _fmt_human_review 加入「📉 過去 7 日營收流失:NT$ X」「🎯 跟進競品建議價:NT$ Y(毛利策略可再加溢價)」區塊。dispatch() 主路徑、防線二強制覆核、_hermes_rule_fallback 三條路徑全部走 Python 獨裁注入(同 Bug-1 防線二原則:客觀數字不過 LLM)。
為支援此計算,PriceThreat dataclass 新增 sales_7d_curr_amount / sales_7d_prev_amount 兩個欄位,由 _batch_analyze 從 SQL 結果直接帶出(不餵給 LLM 推理,避免 token 爆炸與 LLM 嘗試引用幻覺)。
規則 3 — 補實 momo:eig: callback handler
telegram_bot_service.py.handle_callback 在既有 menu:/cmd:/await: dispatch 之前加 momo:eig: 處理,呼叫 _handle_event_ignore_callback:
- 解析
event_id,空 id 立即拒絕(防 audit 污染) - 寫入
ai_insights:status='ignored', insight_type='human_review', metadata_json含event_id / decided_by / decided_at(ADR-012 §③ audit trail) - 編輯原訊息加「🛑 已忽略 by
<user>@<ts>」尾註 user_label/ts_label寫入 HTML 前必須html.escape()(user-controlled Telegram username 透過<a href>/<pre>注入超連結與破版的 XSS 防線)- 任何例外都 best-effort,不阻斷 UI
Critic 審查(必修)
| 編號 | 嚴重度 | 內容 | 修復 |
|---|---|---|---|
| Critical-1 | CRITICAL | user_label 直接 HTML 拼接 → username 注入 <a>/<pre> 破版 |
html.escape() 雙重 escape |
| High-1 | HIGH | Pre-fetch Hermes 同步阻塞 escalation cooldown 視窗(30-60s) | asyncio.wait_for(timeout=5) |
| High-2 | HIGH | Hermes 有 threats 但全部缺金額時 → 兩行乾巴巴比價反而更空泛 | any_concrete 判斷,全缺則 return None 觸發 plan fallback |
| Medium-2 | MEDIUM | 空 event_id callback 寫入 'unknown' 污染 audit |
prefix 解析後即拒絕 |
| Medium-3 | MEDIUM | gap_pct ≤ 0 但 prev > curr 仍顯示「流失」誤導降價 |
revenue_loss_7d 條件改為 if gap_pct > 0 |
Alternatives Considered
| 方案 | 為何不選 |
|---|---|
A. 廢掉 market_opportunity 觸發類型,全交 NemoTron pipeline |
EA 同時負責 price_drop_alert / threat_escalation / resource_optimization / code_exception 多類觸發,不可單刪一類;且 EA orchestrator 是 SOT,廢觸發類型需大改 |
| B. 把 EA 信心度門檻降到 0.5,讓「market_opportunity」全部自主執行 | 違反 ADR-012 L3 HITL 對「實際修改價格」的安全網;統帥未授權自動調價 |
| C. Pre-fetch 改為背景 task,escalation 訊息分兩次發 | 兩次告警分裂語境,使用者體驗差;且 Hermes 結果晚到時 escalation 已 cooldown |
D. 不 pre-fetch,要求人類自己用 /menu 查 SKU |
違反「告警必須 actionable」精神,且增加人類認知負荷 |
Consequences
正面
- EA 升級審核 Telegram 內容從元流程描述變為「具體 SKU + 價格 + 金額流失 + 建議調價」,HITL 真正可決策
- 無實證的價格類與資源調配低信心 escalation 不再打擾人工,避免 Telegram 出現不可批准、不可駁回、不可操作的空告警
- NemoTron 既有告警再升級,每筆都帶可批准/駁回的金額判斷依據
momo:eig:按鈕首次有對應 handler,HITL 流程閉環完整- pre-fetch 改用 5s 短超時 + fallback,最壞情況退回原 plan 文字,不破壞既有行為
負面 / 風險
- 每次價格類 escalation 多花 ≤ 5s(Hermes 熱駐留實測 < 10s 但有 timeout),整體告警延遲略增
- Hermes 在 5s 內若沒回應,價格類 escalation 會被壓制並記錄 telemetry;若後續需要追查,需從
ai_calls.meta.suppressed_escalation與 scheduler log 觀察 gap_pct ≤ 0案例的銷量下滑(非價格因素)將完全不顯示流失金額——若統帥需追蹤「非價格流失」需另開告警類型(待後續 ADR)
監控指標
- Telegram 「EA 升級審核」訊息含「📉 過去 7 日營收流失」比例(部署後應 → 每筆價格類觸發都有,除非 5s timeout)
_handle_event_ignore_callbackaudit 寫入頻率(觀察人類實際使用 HITL 比例)- Hermes pre-fetch timeout rate(>10% 代表 Ollama 冷啟動嚴重,需檢查 keep_alive)
實作 checklist
services/hermes_analyst_service.pyPriceThreat 新增絕對金額欄位services/nemoton_dispatcher_service.py_compute_business_impacthelper + 三條 dispatch 路徑注入services/elephant_alpha_autonomous_engine.py_fetch_hermes_threats_summary+ 5s timeout + fallbackservices/telegram_bot_service.py_handle_event_ignore_callback+ HTML escape + 空 id 拒絕- 2026-05-19:無實證價格類 /
resource_optimization低信心 escalation 改為 suppressed telemetry,不再送空泛 Telegram - Critic 審查通過(Critical-1 / High-1 / High-2 / Medium-2 / Medium-3 全修)
- Smoke test:
_compute_business_impact對 gap≤0 / gap=0 / 銷量回升 / bogus type 四案例驗證 docs/adr/README.md索引加 ADR-021- 部署到 188 + 觀察首日 EA escalation 內容(人工驗證)