fix(ai): 價格調整轉人工覆核
All checks were successful
CD Pipeline / deploy (push) Successful in 2m16s

This commit is contained in:
OoO
2026-05-01 14:09:54 +08:00
parent 62f8f1d52d
commit b5de8d5d61
6 changed files with 121 additions and 5 deletions

View File

@@ -2,7 +2,7 @@
> 本文件定義專案開發的核心準則與不可違反的規範
> **建立日期**: 2026-01-12
> **當前版本**: V10.50 (Vendor stockout query service extraction)
> **當前版本**: V10.51 (Price adjustment actions require human review)
> **最後更新**: 2026-05-01
---

4
app.py
View File

@@ -95,8 +95,8 @@ except Exception as e:
sys_log.error(f"無法檢測磁碟空間: {e}")
# 🚩 系統版本定義 (備份與顯示用)
# 🚩 2026-05-01 V10.50: Vendor stockout query service extraction
SYSTEM_VERSION = "V10.50"
# 🚩 2026-05-01 V10.51: Price adjustment actions require human review
SYSTEM_VERSION = "V10.51"
# ==========================================
# 🔒 SQL Injection 防護函數

View File

@@ -66,6 +66,7 @@ SQL漏斗(~300筆)
- `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`,等待人工核准。
可觀測性:

View File

@@ -103,10 +103,20 @@ _ACTION_ZH = {
"generate_market_analysis": "市場分析",
"generate_pricing_strategy": "定價策略建議",
"generate_meta_analysis": "AI 系統自我審視",
"execute_price_adjustment": "價格調整覆核",
"adjust_price": "調整定價",
"send_alert": "發送告警",
}
_PRICE_ADJUSTMENT_REVIEW_ACTIONS = frozenset({
"execute_price_adjustment",
"adjust_price",
"apply_price_change",
"update_price",
"dispatch_price_update",
"dispatch_price_updates",
})
def _zh_trigger(trigger_type: str) -> str:
return _TRIGGER_ZH.get(trigger_type, trigger_type)
@@ -559,7 +569,7 @@ class ElephantAlphaAutonomousEngine:
async def _execute_step(self, step: Dict[str, Any]) -> None:
agent_type = step.get("agent", "").lower()
action = step.get("action", "")
params = step.get("parameters", {})
params = step.get("parameters") or step.get("params") or {}
if agent_type == "hermes" and action == "analyze_price_competition":
return await self._run_with_timeout(
@@ -579,7 +589,10 @@ class ElephantAlphaAutonomousEngine:
return
if agent_type == "openclaw" and action in (
"generate_strategic_analysis", "generate_weekly_strategy", "generate_market_analysis"
"generate_strategic_analysis",
"generate_weekly_strategy",
"generate_market_analysis",
"generate_pricing_strategy",
):
return await self._run_with_timeout(
self._generate_strategy_report,
@@ -608,6 +621,13 @@ class ElephantAlphaAutonomousEngine:
timeout=SSH_COMMAND_TIMEOUT,
)
if action in _PRICE_ADJUSTMENT_REVIEW_ACTIONS:
return await self._run_with_timeout(
self._record_price_adjustment_review,
step,
timeout=SSH_COMMAND_TIMEOUT,
)
raise ValueError(f"Unrecognized step: agent={agent_type} action={action}")
# ---- Sub-services ----
@@ -638,6 +658,64 @@ class ElephantAlphaAutonomousEngine:
payload.setdefault("error_type", error_type)
return auto_heal_service.handle_exception(error_type=error_type, context=payload)
def _record_price_adjustment_review(self, step: Dict[str, Any]) -> Dict[str, Any]:
"""
Price changes are business-critical. Elephant Alpha may recommend them,
but this system records the proposal for HITL review instead of applying it.
"""
params = step.get("parameters") or step.get("params") or {}
sku = (
params.get("sku")
or params.get("product_sku")
or params.get("i_code")
or params.get("item_id")
or "unknown"
)
action = step.get("action", "price_adjustment")
content = (
f"[Elephant Alpha 價格調整覆核] AI 建議執行 {action}"
f"商品 {sku} 已攔截直接執行並轉入人工審核。"
)
session = get_session()
try:
row = session.execute(
text("""
INSERT INTO ai_insights
(insight_type, content, confidence, created_by, status, metadata_json)
VALUES (:type, :content, :confidence, :created_by, :status, :metadata)
RETURNING id
"""),
{
"type": "human_review",
"content": content,
"confidence": 0.8,
"created_by": "elephant_alpha",
"status": "pending",
"metadata": json.dumps({
"source": "price_adjustment_review",
"step": step,
"sku": sku,
"reason": "price_adjustment_requires_human_approval",
}, ensure_ascii=False),
},
).fetchone()
session.commit()
insight_id = row[0] if row else None
if insight_id:
try:
from services.openclaw_learning_service import enqueue_insight_embedding
enqueue_insight_embedding(insight_id, "human_review", content)
except Exception as embed_err:
self._log.warning("Embedding enqueue failed for price adjustment review: %s", embed_err)
self._log.warning("Price adjustment intercepted for HITL review: action=%s sku=%s", action, sku)
return {"status": "pending_review", "insight_id": insight_id, "sku": sku, "action": action}
except Exception:
session.rollback()
raise
finally:
session.close()
# ---- Notification ----
async def _notify_telegram_executed(
self,

View File

@@ -146,6 +146,22 @@ DECISION FRAMEWORK:
6. Create detailed execution plans
7. Monitor and adapt based on outcomes
ALLOWED EXECUTION ACTIONS:
- hermes / analyze_price_competition
- nemotron / dispatch_alert
- openclaw / generate_strategic_analysis
- openclaw / generate_weekly_strategy
- openclaw / generate_market_analysis
- openclaw / generate_pricing_strategy
- openclaw / generate_meta_analysis
- elephant_alpha / auto_heal
- elephant_alpha / code_fix
價格調整紅線:
- 禁止輸出 execute_price_adjustment、adjust_price、apply_price_change、update_price。
- 若需要調價,請改輸出 openclaw / generate_pricing_strategy並在 description 說明「需要人工核准後才能調價」。
- 本系統不得由 AI 直接修改商品價格,只能產生建議與人工覆核項目。
BUSINESS CONTEXT:
- E-commerce platform (momo-pro-system)
- Real-time price competition monitoring

View File

@@ -42,6 +42,27 @@ def test_execute_step_routes_code_fix_to_autoheal(monkeypatch):
assert calls == [("python_exception", {"target_file": "services/example.py", "error_message": "Traceback"})]
def test_execute_step_routes_price_adjustment_to_human_review(monkeypatch):
from services.elephant_alpha_autonomous_engine import ElephantAlphaAutonomousEngine
calls = []
engine = ElephantAlphaAutonomousEngine()
monkeypatch.setattr(
engine,
"_record_price_adjustment_review",
lambda step: calls.append(step) or {"status": "pending_review", "sku": "SKU-9"},
)
result = asyncio.run(engine._execute_step({
"agent": "nemotron",
"action": "execute_price_adjustment",
"parameters": {"sku": "SKU-9", "recommended_price": 1280},
}))
assert result == {"status": "pending_review", "sku": "SKU-9"}
assert calls[0]["parameters"]["recommended_price"] == 1280
def test_autoheal_derives_python_exception_from_traceback():
from services.auto_heal_service import AutoHealService