""" Agent 层回归测试:RiskAgent 配置集中可用性 + Orchestrator 每日流程步骤隔离。 """ import sys import os sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import numpy as np import pandas as pd import pytest from unittest.mock import patch from agents.risk_agent import RiskAgent from agents.orchestrator import AgentOrchestrator, TOTAL_STEPS def _flat_dm(): """给出平淡行情 → 风险 low。""" class _DM: def get_daily(self, code): idx = pd.date_range('2025-01-01', periods=300, freq='B').strftime('%Y%m%d') close = np.linspace(100, 100 + 0.03 * 300, 300) + np.random.default_rng(0).normal(0, 0.2, 300) return pd.DataFrame({'trade_date': idx, 'close': close}) return _DM() def _hot_dm(): class _DM: def get_daily(self, code): idx = pd.date_range('2025-01-01', periods=300, freq='B').strftime('%Y%m%d') close = 100 * np.exp(np.cumsum(np.random.default_rng(1).normal(0, 0.03, 300))) return pd.DataFrame({'trade_date': idx, 'close': close}) return _DM() def test_risk_config_low_level(): r = RiskAgent(dm=_flat_dm()).execute() assert r['risk_level'] in ('low', 'medium', 'high') assert r['target_exposure'] in (0.85, 0.60, 0.30) def test_risk_config_high_level(): r = RiskAgent(dm=_hot_dm()).execute() assert r['risk_level'] in ('high', 'medium') class _FailAgent: def execute(self, **kw): raise RuntimeError("boom") class _OkAgent: def execute(self, **kw): return {"report_path": "/tmp/x.md", "risk_level": "low", "target_exposure": 0.8, "top_picks": [], "date": "20260601"} class _FakeDM: def get_stock_list(self): return pd.DataFrame(index=['000001.SZ', '600519.SH']) def sync_daily(self, code): return 5 class _FakeSent: def get_scope_stocks(self): return ["000001.SZ", "600519.SH"] def compute(self, *a, **k): return pd.DataFrame({"news_sent_5": [0.1, 0.2]}) def test_run_daily_steps_isolated(): """risk/selection 抛错被隔离,report/sentiment/sync 仍成功。""" with patch('database.dao.get_latest_trade_date', side_effect=lambda c: "20260530"): orch = AgentOrchestrator(dm=_FakeDM(), sent=_FakeSent()) orch.agents = {"risk": _FailAgent(), "selection": _FailAgent(), "report": _OkAgent(), "research": _OkAgent()} res = orch.run_daily(date="20260601") assert "risk" in res and isinstance(res["risk"], dict) and "error" in res["risk"] assert "selection" in res and isinstance(res["selection"], dict) and "error" in res["selection"] # 失败不中断:report/sentiment 仍成功 assert "report" in res and "error" not in res["report"] assert isinstance(res.get("sentiment"), pd.DataFrame) def test_orchestrator_total_steps_is_5(): assert TOTAL_STEPS == 5