优化奶龙字段语义理解
This commit is contained in:
@@ -362,7 +362,8 @@ def _agent_system_prompt(message: str) -> str:
|
||||
"8. 查询结果包含 summary 时,客户、产品和规则数量必须依据完整 summary,"
|
||||
"不能因为 items 被截断就回答只覆盖部分记录。\n"
|
||||
"9. 最终回答使用中文,简洁说明结论、依据和剩余风险,并提醒由风控专员人工复核。\n"
|
||||
f"{context}\n{filter_context}\n{_truncation_instruction()}"
|
||||
f"{context}\n{filter_context}\n{_truncation_instruction()}\n"
|
||||
f"{_field_meaning_instruction()}"
|
||||
)
|
||||
|
||||
|
||||
@@ -374,6 +375,14 @@ def _truncation_instruction() -> str:
|
||||
)
|
||||
|
||||
|
||||
def _field_meaning_instruction() -> str:
|
||||
return (
|
||||
"11. 工具结果中的 field_meanings 是字段中文含义词典。面向用户回答时必须使用"
|
||||
"这些业务含义组织内容,不要直接罗列 customer_no、ack_status、behavior_score "
|
||||
"等数据库字段名;只有用户明确要求查看原始字段时才保留字段名。"
|
||||
)
|
||||
|
||||
|
||||
def _is_disposition_query(message: str) -> bool:
|
||||
return any(keyword in message for keyword in (
|
||||
"误报",
|
||||
|
||||
+110
-4
@@ -16,6 +16,111 @@ from app.service.risk_judgement_service import (
|
||||
)
|
||||
from app.service.risk_query_service import scope_from_context
|
||||
|
||||
FIELD_MEANINGS: dict[str, str] = {
|
||||
"alert_no": "预警编号",
|
||||
"customer_id": "客户编号",
|
||||
"customer_no": "客户编号",
|
||||
"customer_name": "客户姓名(脱敏)",
|
||||
"product_code": "产品代码",
|
||||
"product_name": "产品名称",
|
||||
"alert_type": "预警类型",
|
||||
"risk_level": "风险等级",
|
||||
"rule_codes": "命中规则编号",
|
||||
"triggered_rules": "命中规则编号",
|
||||
"evidence_summary": "证据摘要",
|
||||
"event_status": "事件状态",
|
||||
"status": "业务状态",
|
||||
"ack_status": "预警确认状态",
|
||||
"created_at": "创建时间",
|
||||
"updated_at": "更新时间",
|
||||
"due_at": "处理截止时间",
|
||||
"ack_at": "确认时间",
|
||||
"escalated_at": "升级时间",
|
||||
"priority_score": "优先级分数",
|
||||
"is_escalated": "是否已升级",
|
||||
"evidence_archived": "证据是否已归档",
|
||||
"close_reason": "关闭原因",
|
||||
"disposition_hint": "列表级只读研判建议",
|
||||
"disposition_assessment": "详情级只读研判草案",
|
||||
"name": "客户姓名(脱敏)",
|
||||
"birth_date": "出生日期",
|
||||
"occupation": "职业",
|
||||
"mobile_masked": "手机号(脱敏)",
|
||||
"investor_type": "投资者风险承受等级",
|
||||
"investment_horizon": "投资期限",
|
||||
"preferred_asset_class": "偏好资产类别",
|
||||
"trading_frequency": "交易频率",
|
||||
"total_asset": "总资产",
|
||||
"behavior_score": "行为分",
|
||||
"risk_tags": "风险标签",
|
||||
"trade_account": "交易账号",
|
||||
"product_category": "产品类别",
|
||||
"risk_disclosure_required": "是否要求风险揭示",
|
||||
"second_confirmation_required": "是否要求二次确认",
|
||||
"recording_required": "是否要求双录",
|
||||
"transaction_no": "交易编号",
|
||||
"order_side": "买卖方向",
|
||||
"transaction_type": "交易类型",
|
||||
"amount": "金额",
|
||||
"channel": "交易渠道",
|
||||
"trade_status": "交易状态",
|
||||
"risk_disclosure_signed": "风险揭示签署状态",
|
||||
"second_confirmation": "二次确认状态",
|
||||
"confirmed_at": "确认时间",
|
||||
"executed_at": "成交时间",
|
||||
"flow_no": "资金流水编号",
|
||||
"flow_type": "资金流水类型",
|
||||
"settled_at": "到账时间",
|
||||
"occurred_at": "发生时间",
|
||||
"source_type": "资金来源",
|
||||
"match_status": "资金匹配状态",
|
||||
"shares": "持有份额",
|
||||
"cost_amount": "持仓成本",
|
||||
"current_value": "当前市值",
|
||||
"profit_loss": "浮动盈亏",
|
||||
"profit_loss_ratio": "盈亏比例",
|
||||
"holding_days": "持有天数",
|
||||
"holding_ratio": "持仓占资产比例",
|
||||
"login_at": "登录时间",
|
||||
"login_result": "登录结果",
|
||||
"ip_region": "登录地区",
|
||||
"device_id": "登录设备标识",
|
||||
"is_common_device": "是否常用设备",
|
||||
"failure_reason": "失败原因",
|
||||
"notification_no": "通知编号",
|
||||
"send_status": "发送状态",
|
||||
"receiver_email": "接收邮箱",
|
||||
"sent_at": "发送时间",
|
||||
"handler_id": "处理人编号",
|
||||
"related_transaction_id": "关联交易编号",
|
||||
"related_work_order_id": "关联工单编号",
|
||||
"evidence_truncated": "被截断的证据类型",
|
||||
"data_truncated": "数据是否被截断",
|
||||
"truncated": "结果是否被截断",
|
||||
}
|
||||
|
||||
|
||||
def with_field_meanings(value: dict[str, Any]) -> dict[str, Any]:
|
||||
"""附加当前结果实际出现字段的中文含义,供模型转换后回答。"""
|
||||
names: set[str] = set()
|
||||
|
||||
def collect(item: object) -> None:
|
||||
if isinstance(item, dict):
|
||||
for key, child in item.items():
|
||||
names.add(str(key))
|
||||
collect(child)
|
||||
elif isinstance(item, (list, tuple)):
|
||||
for child in item:
|
||||
collect(child)
|
||||
|
||||
collect(value)
|
||||
meanings = {
|
||||
name: FIELD_MEANINGS[name]
|
||||
for name in sorted(names)
|
||||
if name in FIELD_MEANINGS
|
||||
}
|
||||
return {**value, "field_meanings": meanings}
|
||||
|
||||
|
||||
async def search_risk_alerts_tool(
|
||||
arguments: RiskAlertQuery,
|
||||
@@ -61,7 +166,7 @@ def build_alert_search_result(
|
||||
hint = item.get("disposition_hint") or {}
|
||||
if isinstance(hint, dict) and hint.get("verdict"):
|
||||
disposition_counts[str(hint["verdict"])] += 1
|
||||
return {
|
||||
return with_field_meanings({
|
||||
"total": len(compact_items),
|
||||
"filters": filters or {},
|
||||
"summary": {
|
||||
@@ -76,7 +181,7 @@ def build_alert_search_result(
|
||||
"complete": True,
|
||||
},
|
||||
"items": compact_items,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
def _compact_alert_item(item: dict[str, Any]) -> dict[str, Any]:
|
||||
@@ -170,7 +275,8 @@ async def get_risk_overview_tool(
|
||||
) -> dict[str, Any]:
|
||||
del arguments
|
||||
async with SessionFactory() as session:
|
||||
return await RiskRepository(session, scope=scope_from_context(context)).overview()
|
||||
data = await RiskRepository(session, scope=scope_from_context(context)).overview()
|
||||
return with_field_meanings(data)
|
||||
|
||||
|
||||
async def get_alert_evidence_tool(
|
||||
@@ -186,4 +292,4 @@ async def get_alert_evidence_tool(
|
||||
return None
|
||||
detail = record.to_dict()
|
||||
detail["disposition_assessment"] = assess_alert_detail(detail)
|
||||
return detail
|
||||
return with_field_meanings(detail)
|
||||
|
||||
Reference in New Issue
Block a user