[V10.318] 收緊 EA HITL 告警證據與排版治理
All checks were successful
CD Pipeline / deploy (push) Successful in 1m23s
All checks were successful
CD Pipeline / deploy (push) Successful in 1m23s
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
================================================================================
|
||||
|
||||
【已完成】
|
||||
- V10.318 收緊 Elephant Alpha HITL 告警治理:`ea_escalation` 只有真正含 SKU/價格比較的 actions 才排成 TOP 待審 SKU 卡片;非 SKU 診斷改為「待確認事項」,並用測試鎖住價格類低信心但無 DB/Hermes 實證時只 suppress、不寫 human_review、不發 Telegram,避免空泛告警打擾人工審核。
|
||||
- V10.317 修正 PChome 比價覆蓋率分子:`fetch_competitor_coverage()` 的 valid_matches 改成 `ACTIVE + 有 MOMO 最新價` 商品與有效 PChome `identity_v2` 價格的交集,不再把非活躍或無 MOMO 現價的舊 competitor_prices 列入覆蓋率,避免 daily/growth/PPT/AI 報表高估比價資料品質。
|
||||
- V10.315 修正競品簡報/報表指定日期取價:`fetch_competitor_comparison_results()` 在有 start/end date 時改讀 `competitor_price_history` 的期間快照,MOMO 價格也取期間結束前最新價;沒有指定日期才使用目前有效 `competitor_prices`,避免把今天的 PChome 快取價塞回歷史 daily/growth/PPT 判讀。
|
||||
- V10.314 擴大 PChome 候選池與搜尋韌性:PChome 搜尋 API 改為依 limit 掃多頁並對 429/5xx/timeout 做有限重試;feeder 預設每個商品最多 5 組搜尋詞、每詞 20 候選、2 頁,且搜尋清理不再刪掉括號/方括號內的品牌與規格,讓正確候選更有機會進 matcher,而不是長期停在「待對比」。
|
||||
|
||||
@@ -320,7 +320,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
|
||||
# ==========================================
|
||||
# 系統版本與路徑
|
||||
# ==========================================
|
||||
SYSTEM_VERSION = "V10.317"
|
||||
SYSTEM_VERSION = "V10.318"
|
||||
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
|
||||
public_url = PUBLIC_URL # 用於模板顯示
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> **最後更新**: 2026-05-20 (台北時間)
|
||||
> **狀態**: 🟢 四 AI Agent 自動化閉環已落地;LLM 路由紅線升級為 Ollama-first 三主機級聯,Gemini 僅備援 / 鎖定場景
|
||||
> **適用版本**: V10.307
|
||||
> **適用版本**: V10.318
|
||||
|
||||
---
|
||||
|
||||
@@ -609,3 +609,4 @@ POSTGRES_HOST=momo-db
|
||||
| 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 |
|
||||
|
||||
@@ -542,6 +542,15 @@ def _format_ea_risk_summary(actions: List[Dict[str, Any]]) -> List[str]:
|
||||
return lines
|
||||
|
||||
|
||||
def _is_ea_sku_action(item: Dict[str, Any]) -> bool:
|
||||
return bool(
|
||||
item.get("sku")
|
||||
or item.get("comparison")
|
||||
or item.get("momo_price")
|
||||
or item.get("pchome_price")
|
||||
)
|
||||
|
||||
|
||||
def _format_ea_action_card(item: Dict[str, Any], index: int) -> List[str]:
|
||||
sku = escape(str(item.get("sku") or ""))
|
||||
name = escape(_short_text(item.get("name") or item.get("title") or "", 58))
|
||||
@@ -575,6 +584,11 @@ def _format_ea_action_card(item: Dict[str, Any], index: int) -> List[str]:
|
||||
return lines
|
||||
|
||||
|
||||
def _format_ea_generic_action(item: Dict[str, Any], index: int) -> str:
|
||||
text = item.get("raw") or item.get("title") or ""
|
||||
return f"{index}. {escape(_short_text(text, 140))}"
|
||||
|
||||
|
||||
def _format_ea_escalation_alert(
|
||||
*,
|
||||
base_event: Dict[str, Any],
|
||||
@@ -592,8 +606,10 @@ def _format_ea_escalation_alert(
|
||||
if part and part.strip()
|
||||
]
|
||||
parsed_actions = [_parse_ea_action(action) for action in (ai_actions or [])]
|
||||
shown_actions = parsed_actions[:5]
|
||||
hidden_count = max(0, len(parsed_actions) - len(shown_actions))
|
||||
sku_actions = [item for item in parsed_actions if _is_ea_sku_action(item)]
|
||||
generic_actions = [item for item in parsed_actions if not _is_ea_sku_action(item)]
|
||||
shown_actions = sku_actions[:5]
|
||||
hidden_count = max(0, len(sku_actions) - len(shown_actions))
|
||||
|
||||
lines = [
|
||||
f"⚡ <b>{escape(str(tier_label))}</b>",
|
||||
@@ -614,11 +630,11 @@ def _format_ea_escalation_alert(
|
||||
f"• {escape(_short_text(ai_summary, 280))}",
|
||||
]
|
||||
|
||||
if parsed_actions:
|
||||
if sku_actions:
|
||||
lines += [
|
||||
"",
|
||||
"📊 <b>風險摘要</b>",
|
||||
*_format_ea_risk_summary(parsed_actions),
|
||||
*_format_ea_risk_summary(sku_actions),
|
||||
"",
|
||||
"📋 <b>TOP 待審 SKU</b>",
|
||||
]
|
||||
@@ -635,6 +651,20 @@ def _format_ea_escalation_alert(
|
||||
"• 同款:評估跟價、組合促銷或加強 MOMO 價格優勢曝光",
|
||||
"• 非同款:標記待審,避免進入自動調價或簡報決策",
|
||||
]
|
||||
elif generic_actions:
|
||||
lines += [
|
||||
"",
|
||||
"📋 <b>待確認事項</b>",
|
||||
*[
|
||||
_format_ea_generic_action(item, idx)
|
||||
for idx, item in enumerate(generic_actions[:5], start=1)
|
||||
],
|
||||
"",
|
||||
"✅ <b>建議處置</b>",
|
||||
"• 先確認資料來源、最近錯誤紀錄與觀測台狀態",
|
||||
"• 補齊可審核證據後再批准執行",
|
||||
"• 未取得實證前,不執行自動調價、修復或策略派發",
|
||||
]
|
||||
else:
|
||||
lines += [
|
||||
"",
|
||||
|
||||
@@ -231,6 +231,55 @@ def test_escalate_resource_optimization_without_evidence_is_suppressed(monkeypat
|
||||
assert suppressed == [("resource_optimization", "no_concrete_evidence")]
|
||||
|
||||
|
||||
def test_escalate_price_alert_without_evidence_is_suppressed(monkeypatch):
|
||||
import services.elephant_alpha_autonomous_engine as engine_module
|
||||
from services.elephant_alpha_autonomous_engine import (
|
||||
AutonomousTrigger,
|
||||
ElephantAlphaAutonomousEngine,
|
||||
)
|
||||
from services.elephant_alpha_orchestrator import StrategicDecision
|
||||
|
||||
engine = ElephantAlphaAutonomousEngine()
|
||||
suppressed = []
|
||||
cooldown = []
|
||||
|
||||
async def _no_concrete_actions(top_n=5):
|
||||
return None
|
||||
|
||||
def _raise_if_db_opened():
|
||||
raise AssertionError("no-concrete price escalation should not write human_review")
|
||||
|
||||
monkeypatch.setattr(engine, "_fetch_hermes_threats_summary", _no_concrete_actions)
|
||||
monkeypatch.setattr(engine_module, "get_session", _raise_if_db_opened)
|
||||
monkeypatch.setattr(engine, "_store_escalation", lambda trigger_type: cooldown.append(trigger_type))
|
||||
monkeypatch.setattr(
|
||||
engine,
|
||||
"_record_suppressed_escalation",
|
||||
lambda decision, trigger, reason: suppressed.append((trigger.trigger_type, reason)),
|
||||
)
|
||||
|
||||
decision = StrategicDecision(
|
||||
priority="medium",
|
||||
agents_required=["openclaw"],
|
||||
reasoning="價格調整建議信心不足",
|
||||
expected_outcome="待人工確認",
|
||||
confidence=0.62,
|
||||
execution_plan=[],
|
||||
resource_requirements={},
|
||||
)
|
||||
trigger = AutonomousTrigger(
|
||||
trigger_type="price_drop_alert",
|
||||
conditions={},
|
||||
threshold=0.8,
|
||||
enabled=True,
|
||||
)
|
||||
|
||||
asyncio.run(engine._escalate_to_human(decision, trigger))
|
||||
|
||||
assert cooldown == ["price_drop_alert"]
|
||||
assert suppressed == [("price_drop_alert", "no_concrete_evidence")]
|
||||
|
||||
|
||||
def test_resource_pressure_classifier_does_not_equate_backlog_with_cpu_load():
|
||||
from services.elephant_alpha_autonomous_engine import ElephantAlphaAutonomousEngine
|
||||
|
||||
|
||||
@@ -41,3 +41,26 @@ def test_ea_escalation_uses_structured_incident_brief():
|
||||
assert "PChome:<code>DABC53-A9009OEF</code>" in msg
|
||||
assert " • [5900068]" not in msg
|
||||
assert keyboard["inline_keyboard"][0][0]["callback_data"] == "momo:eig:ea_review_test"
|
||||
|
||||
|
||||
def test_ea_escalation_generic_actions_do_not_render_as_sku_cards():
|
||||
msg, _ = triaged_alert(
|
||||
base_event={
|
||||
"event_type": "ea_escalation",
|
||||
"title": "🐘 EA 升級審核 · 程式碼異常偵測",
|
||||
"summary": "低信心且缺少可格式化的具體行動",
|
||||
"id": "ea_review_generic",
|
||||
},
|
||||
tier_label="🐘 Elephant Alpha · L3 HITL",
|
||||
ai_summary="已隱藏 LLM plan 文字,避免把推測當成事實。",
|
||||
ai_cause="觸發類型:程式碼異常偵測 | 信心度:0.62 | 缺少可直接審核的實證資料",
|
||||
ai_actions=[
|
||||
"檢查觸發條件:{\"scan_containers\": [\"momo-pro-system\"]}",
|
||||
"不執行自動動作;請先在觀測台確認對應資料來源與最近錯誤紀錄。",
|
||||
],
|
||||
)
|
||||
|
||||
assert "📋 <b>待確認事項</b>" in msg
|
||||
assert "📋 <b>TOP 待審 SKU</b>" not in msg
|
||||
assert "• 待審 SKU" not in msg
|
||||
assert "未取得實證前,不執行自動調價、修復或策略派發" in msg
|
||||
|
||||
Reference in New Issue
Block a user