fix(ea): Hermes-first short-circuit + 消除 EA escalation LLM 幻覺訊息
Some checks are pending
CD Pipeline / deploy (push) Has started running

統帥 2026-05-03 23:30 反饋:「EA escalation 訊息空洞、浪費 Gemini API」
根因:
  1. 燒錢:每個 trigger 先跑 Gemini orchestration,再 prefetch Hermes
     Hermes 0 threats 時 → Gemini 已燒,訊息卻空泛幻覺
  2. 空泛:fallback 路徑灌 OpenClaw plan 文字 + decision.reasoning
     全是「312 SKU / 23% / 14 項任務」LLM 自由發揮,無 DB 鉤住

修補:
  A. _execute_autonomous_decision 加 Hermes-first short-circuit
     - 價格類 trigger 先跑 Hermes (5s timeout, 免費 Ollama)
     - 0 threats → 直接 return,不燒 Gemini orchestration
     - 預期 >70% trigger 在此階段攔截,月省 ~3-5M Gemini tokens
     - prefetch 結果存入 trigger.conditions 給 orchestrator 用
       (避免 orchestrator 又自己編 SKU 數字)
     - log_ai_call 記 short_circuit=true 供 token report 統計
  B. _escalate_to_human fallback 路徑改極簡訊息
     - concrete=Hermes 實證 vs concrete=None 兩條路徑徹底分離
     - 有實證 → 完整訊息(含 SKU 流失金額)
     - 無實證 → 極簡訊息「⚠️ Hermes 即時數據不可用」+ SQL 查詢指引
       不再灌 OpenClaw plan 文字 / decision.reasoning(幻覺源頭)

Operation Ollama-First v5.0 / Phase 6.5 hotfix / ADR-021 遵循收尾

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
OoO
2026-05-03 23:26:18 +08:00
parent 2b218589bd
commit 56504ed7c1

View File

@@ -534,6 +534,49 @@ class ElephantAlphaAutonomousEngine:
return default
async def _execute_autonomous_decision(self, trigger: AutonomousTrigger) -> None:
# ─── Operation Ollama-First v5.0 修補2026-05-03───
# 統帥反饋:每個 EA trigger 都先跑 Gemini orchestrate燒錢才 prefetch Hermes
# 結果 Hermes 0 threats 時送出空泛幻覺訊息 + Gemini 帳單照付。
# 修法:價格類 trigger Hermes-first short-circuit
# 1. 先跑 Hermes5s timeout免費 Ollama
# 2. 0 threats → 直接 return**不燒 Gemini**
# 3. 有 threats → 才走原 Gemini orchestration
# 預期:>70% 的 trigger 在 Hermes 階段就被攔截,月省 Gemini ~3-5M tokens
if trigger.trigger_type in _PRICE_RELATED_TRIGGERS:
try:
hermes_threats = await self._fetch_hermes_threats_summary(top_n=5)
except Exception as e:
self._log.warning("Hermes pre-flight check 失敗 (non-blocking): %s", e)
hermes_threats = None
if not hermes_threats:
# 0 threats 或 prefetch timeout → 直接 drop trigger不燒 Gemini
self._log.info(
"EA short-circuit: trigger=%s 無 Hermes 實證 threats"
"跳過 Gemini orchestration 省成本",
trigger.trigger_type
)
# 紀錄 short-circuit 事件供 token report 統計(不影響主流程)
try:
from services.ai_call_logger import log_ai_call
with log_ai_call(
caller='ea_engine',
provider='gcp_ollama', # 只跑了 Hermes沒燒 Gemini
model='hermes3:latest',
meta={'short_circuit': True, 'trigger': trigger.trigger_type,
'reason': 'no_hermes_threats'},
) as ctx:
ctx.set_tokens(input=0, output=0) # Hermes 已自己記
ctx.status = 'cache_only' # 不算 ok 也不算 error
except Exception:
pass # logger 失敗不影響主流程
return
# Hermes 有實證 threats → 把它存進 trigger.conditions 給 orchestrator 用
# 避免 orchestrator 又自己編 SKU 數字
trigger.conditions = trigger.conditions or {}
trigger.conditions['_prefetched_hermes_threats'] = hermes_threats
context = await self._build_trigger_context(trigger)
try:
decision = await self._run_with_timeout(
@@ -881,32 +924,62 @@ class ElephantAlphaAutonomousEngine:
self._log.warning("Pre-fetch threats raised (non-blocking): %s", e)
concrete_actions = None
# ─── Operation Ollama-First v5.0 修補:消除空泛幻覺訊息 ───
# 統帥反饋2026-05-03fallback 路徑帶 OpenClaw Gemini plan 文字 +
# decision.reasoning 全是「312 SKU / 23% / 14 項任務」幻覺數字,無 DB 鉤住,
# 嚴重誤導決策。修法concrete=Hermes 實證 vs concrete=None 兩條路徑徹底分離。
# - 有實證 → 完整訊息(含 SKU 流失金額)
# - 無實證 → 極簡訊息「Hermes 即時數據不可用」+ 不再灌 LLM 幻覺
from services.telegram_templates import triaged_alert, _send_telegram_raw
if concrete_actions:
# 有實證數據路徑:保留完整訊息
ai_actions_payload = concrete_actions
ai_summary_text = (decision.reasoning or "")[:300]
ai_cause_text = (
f"觸發類型:{_zh_trigger(trigger.trigger_type)} | "
f"信心度:{decision.confidence:.2f} | "
f"參與模組:{', '.join(_AGENT_LABEL.get(a.lower(), a) for a in decision.agents_required)}"
)
else:
# 無實證數據路徑:極簡訊息,明確標註無數據
self._log.warning(
"EA escalation 落入 no-concrete-data fallback (trigger=%s)"
"送極簡訊息避免 LLM 幻覺數字誤導統帥",
trigger.trigger_type
)
ai_actions_payload = [
f"步驟 {s.get('step', i+1)}{_zh_step(s)}"
for i, s in enumerate(decision.execution_plan[:3])
] or ["無具體執行計畫"]
"⚠️ Hermes 即時威脅清單不可用5s timeout 或無 SKU 命中)",
"📋 建議:手動下 SQL 查詢過去 24h competitor_price_history 確認狀況",
"🔧 或SSH 188 跑 docker exec momo-pro-system python -c "
"'from services.hermes_analyst_service import HermesAnalystService;"
" print(HermesAnalystService().run().threats[:5])'",
]
ai_summary_text = (
f"⚠️ 本訊息為**無實證**告警Hermes pre-fetch 失敗,"
f"以下原始決策內容含 LLM 自由發揮數字(非 DB 數據),請審慎參考。"
)
ai_cause_text = (
f"觸發類型:{_zh_trigger(trigger.trigger_type)} | "
f"信心度:{decision.confidence:.2f} | "
f"⚠️ 無 Hermes SKU 數據(不顯示 LLM 幻覺 plan 文字)"
)
try:
from services.telegram_templates import triaged_alert, _send_telegram_raw
msg, keyboard = triaged_alert(
base_event={
"event_type": "ea_escalation",
"title": f"🐘 EA 升級審核 · {_zh_trigger(trigger.trigger_type)}",
"summary": (
f"自主決策信心度 {decision.confidence:.2f} 低於門檻,需人工批准"
+ ("" if concrete_actions else "(⚠️ 無實證數據)")
),
"id": f"ea_review_{int(datetime.now().timestamp())}",
},
tier_label="🐘 Elephant Alpha · L3 HITL",
ai_summary=(decision.reasoning or "")[:300],
ai_cause=(
f"觸發類型:{_zh_trigger(trigger.trigger_type)} | "
f"信心度:{decision.confidence:.2f} | "
f"參與模組:{', '.join(_AGENT_LABEL.get(a.lower(), a) for a in decision.agents_required)}"
),
ai_summary=ai_summary_text,
ai_cause=ai_cause_text,
ai_actions=ai_actions_payload,
)
await self._run_with_timeout(_send_telegram_raw, msg, timeout=10, reply_markup=keyboard)