feat: 新增风险图谱算法与系统仪表盘及操作反馈体系

后端新增风险图谱算法模块、风险观察与反馈服务、规则 DSL
校验器和可解释性引擎,完善系统仪表盘和财务仪表盘统计,
优化 agent 运行和编排执行链路,清理旧开发文档,前端新增
系统趋势、负载热力图等多种仪表盘图表组件,完善操作反馈
对话框和工作台日期选择器,优化报销创建和审批详情交互,
补充单元测试覆盖。
This commit is contained in:
caoxiaozhu
2026-05-30 15:46:51 +08:00
parent 4c59941ec6
commit 7989f3a159
314 changed files with 30073 additions and 20626 deletions

View File

@@ -0,0 +1,149 @@
from __future__ import annotations
from datetime import UTC, datetime, timedelta
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
from sqlalchemy.pool import StaticPool
from app.db.base import Base
from app.models.agent_feedback import AgentOperationFeedback
from app.models.agent_run import AgentRun, AgentToolCall
from app.models.user_session_metric import UserSessionMetric
from app.services.system_dashboard import SystemDashboardService
def build_session() -> Session:
engine = create_engine(
"sqlite+pysqlite:///:memory:",
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
Base.metadata.create_all(bind=engine)
session_factory = sessionmaker(bind=engine, autoflush=False, autocommit=False)
return session_factory()
def test_system_dashboard_service_aggregates_real_runtime_metrics() -> None:
now = datetime.now(UTC)
with build_session() as db:
db.add(
AgentRun(
run_id="run-dashboard-001",
agent="orchestrator",
source="user_message",
user_id="chen.yuqing@example.com",
status="succeeded",
started_at=now - timedelta(hours=3),
finished_at=now - timedelta(hours=3, minutes=-1),
tool_calls=[
AgentToolCall(
run_id="run-dashboard-001",
tool_type="llm",
tool_name="expense_claim.review",
request_json={"prompt_tokens": 120},
response_json={"completion_tokens": 80},
status="succeeded",
duration_ms=1800,
created_at=now - timedelta(hours=3),
),
AgentToolCall(
run_id="run-dashboard-001",
tool_type="ocr",
tool_name="invoice.ocr",
request_json={"image_count": 1},
response_json={"message": "识别失败"},
status="failed",
duration_ms=2600,
error_message="low confidence",
created_at=now - timedelta(hours=2),
),
],
)
)
db.add(
AgentRun(
run_id="run-dashboard-002",
agent="hermes",
source="schedule",
user_id="gu.chengyu@example.com",
status="failed",
started_at=now - timedelta(hours=1),
finished_at=now,
tool_calls=[
AgentToolCall(
run_id="run-dashboard-002",
tool_type="knowledge",
tool_name="policy.rag",
request_json={"total_tokens": 90},
response_json={},
status="succeeded",
duration_ms=900,
created_at=now - timedelta(hours=1),
),
],
)
)
db.add_all(
[
UserSessionMetric(
session_id="session-dashboard-001",
username="chen.yuqing@example.com",
display_name="陈雨晴",
email="chen.yuqing@example.com",
login_at=now - timedelta(hours=4),
logout_at=now - timedelta(hours=3),
duration_ms=60 * 60 * 1000,
activity_event_count=16,
status="closed",
),
UserSessionMetric(
session_id="session-dashboard-002",
username="gu.chengyu@example.com",
display_name="顾成宇",
email="gu.chengyu@example.com",
login_at=now - timedelta(minutes=25),
last_activity_at=now - timedelta(minutes=5),
activity_event_count=9,
status="active",
),
]
)
db.add_all(
[
AgentOperationFeedback(
run_id="run-dashboard-001",
user_id="chen.yuqing@example.com",
agent="orchestrator",
rating=5,
created_at=now - timedelta(hours=2),
),
AgentOperationFeedback(
run_id="run-dashboard-002",
user_id="gu.chengyu@example.com",
agent="hermes",
rating=2,
created_at=now - timedelta(hours=1),
),
]
)
db.commit()
dashboard = SystemDashboardService(db).build_dashboard(days=7)
assert dashboard.has_real_data is True
assert dashboard.totals["toolCalls"] == 3
assert dashboard.totals["modelTokens"] >= 290
assert dashboard.totals["onlineUsers"] == 1
assert dashboard.totals["executionSuccessRate"] == 50.0
assert dashboard.totals["positiveFeedback"] == 1
assert dashboard.totals["negativeFeedback"] == 1
assert dashboard.user_token_usage[0]["tokens"] >= 200
assert "陈雨晴" in {item["name"] for item in dashboard.user_token_usage}
assert dashboard.accuracy_comparison["correct"][
dashboard.accuracy_comparison["categories"].index("报销预审")
] == 1
assert dashboard.accuracy_comparison["wrong"][
dashboard.accuracy_comparison["categories"].index("异常诊断")
] == 1