feat: 阶段C 风控对话线(C1 四只读 Tool + C2 risk 分支意图 + C3 A-6 验收与边界)

- C1: app/service/risk/chat_tools.py 新增 alert_query/customer_context/suitability_check/aml_lookup 四只读 Tool,挂 RISK_TOOL_REGISTRY(与 core_tools.ToolSpec 同构)
- C1: tool_service.run_tool 改查 core+risk 统一注册表并恒传 risk_repo;_normalize_params 读 spec 白名单;core_tools 三函数加 risk_repo=None;summarize 补四工具分支
- C2: match_intent 按 agent 分组扩 risk 关键词;agent_service.tool_node 守卫放宽(requires_customer=False 的 Tool 允许无绑定客户运行,支撑 A-6 全局待审)
- C3: A-6 验收(risk_officer 问待审预警→alert_query 全量→回复含待审数)+ 诱导处置边界(无处置 Tool、系统提示禁自动处置、诱导只触发只读且预警状态不变)
- 测试 tests/test_risk_chat_tools.py(21 例);全量 pytest 342 绿(原 321 + 21)
This commit is contained in:
2026-09-07 10:26:54 +08:00
parent d56f73ff73
commit 930ea9db56
5 changed files with 720 additions and 32 deletions
+9 -2
View File
@@ -58,7 +58,7 @@ def _jsonable(value: Any) -> Any:
def query_customer_profile(
customer_id: str, core_ro: CoreReadOnlyRepository | None = None
customer_id: str, core_ro: CoreReadOnlyRepository | None = None, risk_repo=None
) -> dict[str, Any]:
"""客户档案与风险测评(L0):core_customer + core_customer_risk。"""
repo = core_ro or CoreReadOnlyRepository()
@@ -69,7 +69,7 @@ def query_customer_profile(
def query_holdings(
customer_id: str, core_ro: CoreReadOnlyRepository | None = None
customer_id: str, core_ro: CoreReadOnlyRepository | None = None, risk_repo=None
) -> dict[str, Any]:
"""持仓明细(按市值降序)+ 合计(sum_market_value)。
@@ -96,6 +96,7 @@ def query_recent_trades(
customer_id: str,
days: int = DEFAULT_TRADE_DAYS,
core_ro: CoreReadOnlyRepository | None = None,
risk_repo=None,
) -> dict[str, Any]:
"""近 N 天 confirmed 申赎流水(时间升序截断至 DETAIL_LIMIT)。"""
repo = core_ro or CoreReadOnlyRepository()
@@ -120,16 +121,22 @@ TOOL_REGISTRY: dict[str, ToolSpec] = {
func=query_customer_profile,
description="查询客户档案与风险测评等级(L0)",
requires_customer=True,
param_whitelist=TOOL_PARAM_WHITELIST["query_customer_profile"],
int_bounds={},
),
"query_holdings": ToolSpec(
func=query_holdings,
description="查询客户持仓明细与合计市值",
requires_customer=True,
param_whitelist=TOOL_PARAM_WHITELIST["query_holdings"],
int_bounds={},
),
"query_recent_trades": ToolSpec(
func=query_recent_trades,
description="查询客户近期申赎交易流水",
requires_customer=True,
param_whitelist=TOOL_PARAM_WHITELIST["query_recent_trades"],
int_bounds={k: v for k, v in INT_PARAM_BOUNDS.items() if k in TOOL_PARAM_WHITELIST["query_recent_trades"]},
),
}