diff --git a/apps/api/src/services/agent_orchestrator.py b/apps/api/src/services/agent_orchestrator.py index 912ebb30..ac21a23f 100644 --- a/apps/api/src/services/agent_orchestrator.py +++ b/apps/api/src/services/agent_orchestrator.py @@ -117,6 +117,31 @@ async def run_agent_debate( status=package.session_status.value, elapsed_ms=elapsed, ) + + # ADR-083 Phase 3: 辯證結果學習訊號接線(L7×D2) + # best-effort — 學習失敗不阻塞主流程 + # 2026-04-15 ogt + Claude Sonnet 4.6(亞太) + try: + from src.services.learning_service import get_learning_service + _critic_challenges = ( + package.critic_report.challenge_count + if package.critic_report else 0 + ) + await get_learning_service().record_agent_session( + session_id=session_id, + incident_id=incident_id, + final_confidence=package.confidence, + requires_human_approval=package.requires_human_approval, + all_agents_degraded=package.all_agents_degraded, + critic_challenge_count=_critic_challenges, + ) + except Exception as _lerr: + logger.warning( + "agent_session_learning_failed", + session_id=session_id, + error=str(_lerr), + ) + return package except asyncio.TimeoutError: diff --git a/apps/api/src/services/learning_service.py b/apps/api/src/services/learning_service.py index 5603283a..8bae62b5 100644 --- a/apps/api/src/services/learning_service.py +++ b/apps/api/src/services/learning_service.py @@ -749,6 +749,71 @@ class LearningService: matched_playbook_id=matched_playbook_id, ) + async def record_agent_session( + self, + session_id: str, + incident_id: str, + final_confidence: float, + requires_human_approval: bool, + all_agents_degraded: bool, + critic_challenge_count: int, + matched_playbook_id: str | None = None, + ) -> None: + """ + 記錄 5-Agent 辯證 Session 的學習訊號。 + + ADR-083 Phase 3: AgentSession 學習接線(L7×D2)。 + DB 持久化由 agent_orchestrator._write_agent_turn() 負責, + 此方法負責從辯證結果提取學習訊號(Redis analytics + Playbook EWMA)。 + + 信號邏輯: + - all_agents_degraded=True → 系統品質警報(記錄到 Redis governance) + - critic_challenge_count > 0 AND matched_playbook_id → 輕度負向 EWMA(Critic 質疑 Playbook) + - requires_human_approval=True → 信心不足,系統整體品質下降紀錄 + + Args: + session_id: 辯證 Session ID + incident_id: 關聯 Incident ID + final_confidence: Coordinator 最終信心分數(0-1) + requires_human_approval: 是否升級人工審核 + all_agents_degraded: 是否全部 Agent 降級 + critic_challenge_count: Critic 提出的質疑數量 + matched_playbook_id: 本次決策匹配的 Playbook(若有) + + 2026-04-15 ogt + Claude Sonnet 4.6(亞太): Phase 3 AgentSession 學習接線 + """ + # 1. 記錄辯證品質到 Redis(供 SLO 監控 + Governance 分析) + try: + await self._repository.record_repair( + anomaly_key=f"debate:{incident_id}", + repair_action=f"session:{session_id[:8]}", + success=not requires_human_approval, + fix_description=f"confidence={final_confidence:.2f},degraded={all_agents_degraded},critic_challenges={critic_challenge_count}", + ) + except Exception as e: + logger.warning( + "record_agent_session_to_repo_failed", + session_id=session_id, + error=str(e), + ) + + # 2. Critic 有重大質疑 + 有匹配 Playbook → 輕度負向 EWMA(Playbook 可能不準確) + if critic_challenge_count > 0 and matched_playbook_id: + await self._update_playbook_stats( + playbook_id=matched_playbook_id, + success=False, + ) + + logger.info( + "agent_session_recorded", + session_id=session_id, + incident_id=incident_id, + final_confidence=final_confidence, + requires_human_approval=requires_human_approval, + all_agents_degraded=all_agents_degraded, + critic_challenge_count=critic_challenge_count, + ) + async def get_recommended_fix(self, anomaly_key: str) -> dict: """ 根據歷史學習,推薦最佳修復方案