feat: 扩展风险规则体系、审批动态路由与预算中心列表化改造
- 新增 25+ 条风险规则(预算/报销/申请/通用类),完善风险规则模拟与反馈发布机制 - 引入费用审批动态路由、平台风险分级、预审与风险阶段管理 - 预算中心列表化改造,优化票据夹仪表盘与数字员工工作看板 - 新增 Hermes 风险线索收集器、Agent 链路追踪中心 - 扩展数字员工能力库(18 个领域 Skill)与交通费用自动预估 - 完善报销申请快速预览、权限控制与前端测试覆盖
This commit is contained in:
@@ -146,6 +146,38 @@ class AgentAssetRiskRuleRegenerateRequest(BaseModel):
|
||||
requires_attachment: bool | None = None
|
||||
|
||||
|
||||
class AgentAssetRiskRuleTemplateFieldRead(BaseModel):
|
||||
key: str
|
||||
label: str
|
||||
display: str
|
||||
source: str
|
||||
type: str
|
||||
|
||||
|
||||
class AgentAssetRiskRuleTemplateRead(BaseModel):
|
||||
template_id: str
|
||||
group: str
|
||||
group_label: str
|
||||
title: str
|
||||
description: str = ""
|
||||
business_domain: str = "expense"
|
||||
business_stage: str = "reimbursement"
|
||||
business_stage_label: str = "费用报销"
|
||||
expense_category: str | None = None
|
||||
expense_category_label: str = ""
|
||||
requires_attachment: bool = False
|
||||
natural_language: str
|
||||
fields: list[AgentAssetRiskRuleTemplateFieldRead] = Field(default_factory=list)
|
||||
dsl_example: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class AgentAssetRiskRuleTemplateGroupRead(BaseModel):
|
||||
group: str
|
||||
group_label: str
|
||||
order: int
|
||||
templates: list[AgentAssetRiskRuleTemplateRead] = Field(default_factory=list)
|
||||
|
||||
|
||||
class AgentAssetRiskRuleSampleCase(BaseModel):
|
||||
case_id: str | None = Field(default=None, max_length=60)
|
||||
name: str = Field(default="测试样例", min_length=1, max_length=80)
|
||||
@@ -211,6 +243,9 @@ class AgentAssetRiskRuleSimulationRead(BaseModel):
|
||||
trace: dict[str, Any] = Field(default_factory=dict)
|
||||
attachments: list[dict[str, Any]] = Field(default_factory=list)
|
||||
recognized_fields: list[dict[str, Any]] = Field(default_factory=list)
|
||||
ocr_raw_fields: list[dict[str, Any]] = Field(default_factory=list)
|
||||
hermes_normalized_fields: list[dict[str, Any]] = Field(default_factory=list)
|
||||
executor_input_fields: list[dict[str, Any]] = Field(default_factory=list)
|
||||
missing_fields: list[dict[str, Any]] = Field(default_factory=list)
|
||||
recognition_summary: list[dict[str, Any]] = Field(default_factory=list)
|
||||
execution_mode: str = "risk_rule_simulation"
|
||||
@@ -229,6 +264,38 @@ class AgentAssetRiskRuleLevelUpdate(BaseModel):
|
||||
risk_level: str = Field(pattern="^(low|medium|high|critical)$")
|
||||
|
||||
|
||||
class AgentAssetRiskRuleFeedbackCreate(BaseModel):
|
||||
version: str | None = Field(default=None, max_length=30)
|
||||
feedback_type: str = Field(pattern="^(false_positive|false_negative|unclear|improvement)$")
|
||||
subject_type: str | None = Field(default=None, max_length=50)
|
||||
subject_key: str | None = Field(default=None, max_length=160)
|
||||
subject_label: str | None = Field(default=None, max_length=200)
|
||||
actual_result: dict[str, Any] = Field(default_factory=dict)
|
||||
expected_result: dict[str, Any] = Field(default_factory=dict)
|
||||
comment: str = Field(min_length=1, max_length=1000)
|
||||
payload: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class AgentAssetRiskRuleFeedbackRead(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
feedback_id: str
|
||||
asset_id: str
|
||||
version: str
|
||||
feedback_type: str
|
||||
status: str
|
||||
subject_type: str = ""
|
||||
subject_key: str = ""
|
||||
subject_label: str = ""
|
||||
actual_result_json: dict[str, Any] = Field(default_factory=dict)
|
||||
expected_result_json: dict[str, Any] = Field(default_factory=dict)
|
||||
comment: str | None = None
|
||||
payload_json: dict[str, Any] = Field(default_factory=dict)
|
||||
created_by: str
|
||||
created_at: datetime
|
||||
|
||||
|
||||
class AgentAssetRiskRuleTestRunRead(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
63
server/src/app/schemas/agent_trace.py
Normal file
63
server/src/app/schemas/agent_trace.py
Normal file
@@ -0,0 +1,63 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
from app.schemas.agent_run import AgentRunRead, AgentToolCallRead, SemanticParseRead
|
||||
from app.schemas.orchestrator import ConversationMessageRead
|
||||
|
||||
|
||||
class AgentTraceEventRead(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
run_id: str
|
||||
conversation_id: str | None = None
|
||||
sequence: int
|
||||
stage: str
|
||||
event_name: str
|
||||
title: str
|
||||
summary: str | None = None
|
||||
status: str
|
||||
input_json: dict[str, Any] = Field(default_factory=dict)
|
||||
output_json: dict[str, Any] = Field(default_factory=dict)
|
||||
error_message: str | None = None
|
||||
started_at: datetime
|
||||
finished_at: datetime | None = None
|
||||
duration_ms: int = 0
|
||||
created_at: datetime
|
||||
|
||||
|
||||
class AgentTraceListItem(BaseModel):
|
||||
run_id: str
|
||||
conversation_id: str | None = None
|
||||
agent: str
|
||||
source: str
|
||||
status: str
|
||||
scenario: str | None = None
|
||||
intent: str | None = None
|
||||
title: str
|
||||
summary: str | None = None
|
||||
event_count: int = 0
|
||||
tool_call_count: int = 0
|
||||
failed_tool_call_count: int = 0
|
||||
started_at: datetime
|
||||
finished_at: datetime | None = None
|
||||
duration_ms: int = 0
|
||||
|
||||
|
||||
class AgentTraceDetailRead(BaseModel):
|
||||
run: AgentRunRead
|
||||
conversation_id: str | None = None
|
||||
events: list[AgentTraceEventRead] = Field(default_factory=list)
|
||||
semantic_parse: SemanticParseRead | None = None
|
||||
tool_calls: list[AgentToolCallRead] = Field(default_factory=list)
|
||||
conversation_messages: list[ConversationMessageRead] = Field(default_factory=list)
|
||||
fallback_generated: bool = False
|
||||
|
||||
|
||||
class AgentConversationTraceRead(BaseModel):
|
||||
conversation_id: str
|
||||
runs: list[AgentTraceDetailRead] = Field(default_factory=list)
|
||||
16
server/src/app/schemas/digital_employee_dashboard.py
Normal file
16
server/src/app/schemas/digital_employee_dashboard.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class DigitalEmployeeDashboardRead(BaseModel):
|
||||
window_days: int
|
||||
generated_at: str
|
||||
has_real_data: bool
|
||||
totals: dict[str, Any] = Field(default_factory=dict)
|
||||
daily_work: list[dict[str, Any]] = Field(default_factory=list)
|
||||
task_distribution: list[dict[str, Any]] = Field(default_factory=list)
|
||||
category_distribution: list[dict[str, Any]] = Field(default_factory=list)
|
||||
recent_runs: list[dict[str, Any]] = Field(default_factory=list)
|
||||
@@ -130,6 +130,9 @@ class ExpenseClaimRead(BaseModel):
|
||||
employee_position: str | None = None
|
||||
employee_grade: str | None = None
|
||||
manager_name: str | None = None
|
||||
budget_approver_name: str | None = None
|
||||
budget_approver_grade: str | None = None
|
||||
budget_approver_role_code: str | None = None
|
||||
role_labels: list[str] = Field(default_factory=list)
|
||||
project_code: str | None
|
||||
expense_type: str
|
||||
@@ -202,6 +205,7 @@ class ExpenseClaimAttachmentActionResponse(BaseModel):
|
||||
item_location: str | None = None
|
||||
item_amount: Decimal | None = None
|
||||
claim_amount: Decimal | None = None
|
||||
claim_risk_flags: list[Any] = Field(default_factory=list)
|
||||
attachment: ExpenseClaimAttachmentRead | None = None
|
||||
|
||||
|
||||
|
||||
@@ -117,9 +117,11 @@ class RiskObservationDashboardRead(BaseModel):
|
||||
window_days: int
|
||||
total_observations: int
|
||||
pending_count: int
|
||||
risk_clue_count: int = 0
|
||||
high_or_above_count: int
|
||||
confirmed_count: int
|
||||
false_positive_count: int
|
||||
feedback_sample_count: int = 0
|
||||
total_amount: float = 0.0
|
||||
average_score: float
|
||||
level_distribution: dict[str, int] = Field(default_factory=dict)
|
||||
|
||||
Reference in New Issue
Block a user