強化 EA JSON fallback 與 EDM cache 自癒
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
This commit is contained in:
@@ -15,6 +15,7 @@ Position: Super Orchestrator above Hermes/NemoTron/OpenClaw
|
||||
import os
|
||||
import json
|
||||
import asyncio
|
||||
from json import JSONDecodeError
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, List, Any, Optional
|
||||
from dataclasses import dataclass
|
||||
@@ -241,8 +242,22 @@ BUSINESS OBJECTIVE: Optimize e-commerce performance through intelligent automati
|
||||
if not response.success:
|
||||
raise RuntimeError(response.error)
|
||||
|
||||
# Parse and validate response
|
||||
decision_data = json.loads(response.content)
|
||||
# Parse and validate response. Some NIM-compatible models still wrap
|
||||
# JSON in fenced blocks or prepend reasoning text even with json_mode.
|
||||
try:
|
||||
decision_data = self._extract_json_object(response.content)
|
||||
except ValueError as parse_error:
|
||||
logger.warning(
|
||||
"[ElephantAlpha] Coordination JSON parse failed; using evidence fallback. "
|
||||
"model=%s error=%s preview=%r",
|
||||
response.model,
|
||||
parse_error,
|
||||
(response.content or "")[:240],
|
||||
)
|
||||
return self._fallback_decision(
|
||||
business_context,
|
||||
reason="Elephant Alpha 回應不是可解析 JSON,已改用實證 fallback。",
|
||||
)
|
||||
decision = self._parse_strategic_decision(decision_data)
|
||||
|
||||
# Log decision for learning
|
||||
@@ -253,7 +268,46 @@ BUSINESS OBJECTIVE: Optimize e-commerce performance through intelligent automati
|
||||
except Exception as e:
|
||||
logger.error(f"[ElephantAlpha] Coordination failed: {e}")
|
||||
# Fallback to conservative decision
|
||||
return self._fallback_decision(business_context)
|
||||
return self._fallback_decision(
|
||||
business_context,
|
||||
reason=f"Elephant Alpha 協調失敗:{type(e).__name__}",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _extract_json_object(raw: str) -> Dict[str, Any]:
|
||||
"""Extract one JSON object from tolerant LLM output."""
|
||||
text_value = (raw or "").strip()
|
||||
if not text_value:
|
||||
raise ValueError("empty response")
|
||||
|
||||
if text_value.startswith("```"):
|
||||
lines = text_value.splitlines()
|
||||
if lines and lines[0].strip().startswith("```"):
|
||||
lines = lines[1:]
|
||||
if lines and lines[-1].strip().startswith("```"):
|
||||
lines = lines[:-1]
|
||||
text_value = "\n".join(lines).strip()
|
||||
|
||||
try:
|
||||
parsed = json.loads(text_value)
|
||||
if isinstance(parsed, dict):
|
||||
return parsed
|
||||
raise ValueError("JSON root is not an object")
|
||||
except JSONDecodeError:
|
||||
pass
|
||||
|
||||
decoder = json.JSONDecoder()
|
||||
for idx, char in enumerate(text_value):
|
||||
if char != "{":
|
||||
continue
|
||||
try:
|
||||
parsed, _end = decoder.raw_decode(text_value[idx:])
|
||||
except JSONDecodeError:
|
||||
continue
|
||||
if isinstance(parsed, dict):
|
||||
return parsed
|
||||
|
||||
raise ValueError("no JSON object found")
|
||||
|
||||
def _build_coordination_prompt(self, context: Dict[str, Any]) -> str:
|
||||
"""Build detailed coordination prompt for Elephant Alpha"""
|
||||
@@ -431,22 +485,56 @@ Provide your strategic decision in the specified JSON format.
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def _fallback_decision(self, context: Dict[str, Any]) -> StrategicDecision:
|
||||
@staticmethod
|
||||
def _context_concrete_actions(context: Dict[str, Any]) -> List[str]:
|
||||
conditions = context.get("conditions") if isinstance(context, dict) else {}
|
||||
if not isinstance(conditions, dict):
|
||||
return []
|
||||
for key in ("_prefetched_hermes_threats", "_db_evidence_actions"):
|
||||
actions = conditions.get(key)
|
||||
if isinstance(actions, list):
|
||||
cleaned = [str(action).strip() for action in actions if str(action).strip()]
|
||||
if cleaned:
|
||||
return cleaned[:5]
|
||||
return []
|
||||
|
||||
def _fallback_decision(self, context: Dict[str, Any], *, reason: str = "Elephant Alpha unavailable") -> StrategicDecision:
|
||||
"""Fallback decision if Elephant Alpha fails"""
|
||||
concrete_actions = self._context_concrete_actions(context)
|
||||
trigger_type = str((context or {}).get("trigger_type") or "unknown")
|
||||
if concrete_actions:
|
||||
return StrategicDecision(
|
||||
priority="high",
|
||||
agents_required=["hermes", "elephant_alpha"],
|
||||
reasoning=(
|
||||
f"{reason} 已保留 {len(concrete_actions)} 筆 DB/Hermes 價格比對實證;"
|
||||
"僅送人工覆核,不執行自動調價。"
|
||||
),
|
||||
expected_outcome="產生可稽核的人工覆核告警,避免使用無法解析的 LLM 推論文字。",
|
||||
confidence=0.74,
|
||||
execution_plan=[],
|
||||
resource_requirements={
|
||||
"compute_cost": "$0.00",
|
||||
"time_estimate": "人工覆核",
|
||||
"human_oversight": "required",
|
||||
},
|
||||
)
|
||||
|
||||
return StrategicDecision(
|
||||
priority="medium",
|
||||
agents_required=["openclaw"],
|
||||
reasoning="Elephant Alpha unavailable, using conservative OpenClaw strategy",
|
||||
expected_outcome="Basic strategic analysis",
|
||||
agents_required=["elephant_alpha"],
|
||||
reasoning=(
|
||||
f"{reason} trigger={trigger_type},且沒有可稽核的 DB/Hermes 實證;"
|
||||
"不產生策略型行動計畫,避免把推測當成事實。"
|
||||
),
|
||||
expected_outcome="不執行自動動作;需要先確認資料來源或等待下一輪具體實證。",
|
||||
confidence=0.6,
|
||||
execution_plan=[{
|
||||
"step": 1,
|
||||
"agent": "openclaw",
|
||||
"action": "generate_market_analysis",
|
||||
"parameters": context,
|
||||
"expected_duration": "2-3 minutes"
|
||||
}],
|
||||
resource_requirements={"compute_cost": "$0.00", "time_estimate": "5 minutes"}
|
||||
execution_plan=[],
|
||||
resource_requirements={
|
||||
"compute_cost": "$0.00",
|
||||
"time_estimate": "等待實證",
|
||||
"human_oversight": "required",
|
||||
},
|
||||
)
|
||||
|
||||
# Singleton instance
|
||||
|
||||
@@ -304,6 +304,8 @@ SEARCH_NOISE_TOKENS = {
|
||||
}
|
||||
|
||||
SEARCH_IDENTITY_ANCHORS = (
|
||||
"潤浸保濕清爽身體乳液",
|
||||
"閃亮珍珠眼影棒",
|
||||
"智能光感應無線自動除臭芳香噴霧機",
|
||||
"usb精油薰香機",
|
||||
"超音波水氧機",
|
||||
@@ -520,6 +522,8 @@ BRAND_ALIAS_OVERRIDES = {
|
||||
"xiaomi": ("小米有品", "小米", "xiaomi"),
|
||||
"mac": ("m.a.c", "mac", "m a c"),
|
||||
"opi": ("o.p.i", "opi", "o p i"),
|
||||
"curel": ("curel", "珂潤"),
|
||||
"karadium": ("karadium",),
|
||||
"st雞仔牌": ("日本雞仔牌st", "日本st雞仔牌", "st雞仔牌", "雞仔牌st", "雞仔牌"),
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user