
金融 Agent 风控设计每一笔操作都要有审计日志一、个性化深度引言普通 Agent 的操作错误可能只是一次搞笑的回复金融 Agent 的操作错误可能是一次资金损失。我们设计过一个量化交易 Agent晚上 11 点自动触发了一次大额买入——原因是爬虫抓取到一条过期的“利好消息”。调查后发现Agent 没有时间校验、来源校验、人工确认中的任何一环节。它像一辆没有刹车的自动驾驶汽车一旦启动就不受控制。见证奇迹的时刻在于当我们把风控从外部监控改造成 Agent 内嵌的“条件触发”机制后同样的错误被拦截在了执行前 0.3 秒。二、个性化原理剖析金融 Agent 风控五环架构审计日志的五大原则不可删除任何操作记录一旦生成不能被删除或修改Append-only因果关系每条操作记录必须包含触发它的上游事件 ID时间戳防篡改使用服务端时间戳不接受 Agent 本地时间全量记录包括成功的操作和被拦截的操作可追溯任何一条日志都可以追溯到决策链条的每一步五环的协作逻辑这五个环不是简单的串行通过而是一个逐步收紧的漏斗环1输入校验过滤最明显的错误——过期数据、格式错误、来源不明环2权限控制限制 Agent 的操作边界——只能操作指定账户、指定金额范围环3业务规则执行具体的风控参数——单笔上限、日累计上限、黑名单环4人工确认对超出自动处理范围的操作触发人工审批环5执行审计最终执行操作并记录完整的决策链路三、个性化代码实践from typing import List, Dict, Optional, Any from dataclasses import dataclass, field from datetime import datetime, timedelta from enum import Enum import hashlib import json class ActionType(Enum): 操作类型 QUERY 查询 TRADE 交易 TRANSFER 转账 WITHDRAWAL 提现 class AuditStatus(Enum): 审计状态 PASSED 通过 REJECTED 拒绝 PENDING_REVIEW 待审核 EXECUTED 已执行 ROLLED_BACK 已回滚 dataclass class AuditEntry: 审计日志条目 entry_id: str timestamp: datetime # 服务端时间戳 action_type: ActionType agent_id: str user_id: str operation_detail: Dict decision_chain: List[Dict] # 各环决策记录 final_status: AuditStatus upstream_event_id: Optional[str] # 上游触发事件 hash_signature: str # 防篡改哈希 class FinancialAgentGuard: 金融 Agent 风控守卫 # 设计原因风控参数的默认值可通过配置中心动态调整 DEFAULT_RISK_PARAMS { single_trade_max: 100000, # 单笔交易上限元 daily_trade_max: 500000, # 日累计交易上限 time_window_start: 9, # 允许交易时间开始小时 time_window_end: 15, # 允许交易时间结束下午3点 max_consecutive_losses: 5, # 连续亏损上限 cool_down_minutes: 30, # 连续亏损后的冷却时间 price_deviation_threshold: 0.05, # 价格偏离阈值 5% } def __init__(self, risk_params: Optional[Dict] None): self.risk_params risk_params or self.DEFAULT_RISK_PARAMS # 设计原因审计日志使用 append-only 列表 self.audit_log: List[AuditEntry] [] # 设计原因日内操作统计用于累计检查 self.daily_stats: Dict[str, Dict] {} def ring1_input_validation( self, operation: Dict ) - Tuple[bool, str, Dict]: 环1输入校验 # 设计原因时间校验是第一道防线 # 过期的数据可能来自缓存或爬虫延迟 if data_timestamp in operation: data_time operation[data_timestamp] now datetime.now() # 数据超过 5 分钟视为过期 if (now - data_time) timedelta(minutes5): return False, 数据过期, { data_age: (now - data_time).seconds, threshold: 300, } # 设计原因来源校验——只接受白名单内的数据源 if source in operation: trusted_sources {official_api, authorized_feed, user_input} if operation[source] not in trusted_sources: return False, 来源不受信任, { source: operation[source], trusted: list(trusted_sources), } return True, 通过, {} def ring2_permission_control( self, operation: Dict, agent_config: Dict ) - Tuple[bool, str, Dict]: 环2权限控制 action_type operation.get(action_type) # 设计原因每个 Agent 有明确的操作范围 # 查询类 Agent 不能执行交易 allowed_actions agent_config.get(allowed_actions, [ActionType.QUERY]) if action_type not in [a.value for a in allowed_actions]: return False, 操作超出权限范围, { requested: action_type, allowed: [a.value for a in allowed_actions], } # 设计原因金额上限检查 if amount in operation: amount operation[amount] max_amount agent_config.get( max_single_amount, self.risk_params[single_trade_max], ) if amount max_amount: return False, 金额超限, { amount: amount, max: max_amount, } return True, 通过, {} def ring3_business_rules( self, operation: Dict, agent_id: str ) - Tuple[bool, str, Dict]: 环3业务规则检查 details {} # 设计原因交易时间窗口检查 now datetime.now() current_hour now.hour now.minute / 60 start self.risk_params[time_window_start] end self.risk_params[time_window_end] if not (start current_hour end): return False, 非交易时间, { current_time: now.strftime(%H:%M), trading_window: f{start}:00-{end}:00, } # 设计原因日累计交易额检查 if amount in operation: today now.strftime(%Y-%m-%d) key f{agent_id}_{today} daily_total self.daily_stats.get(key, {}).get(total, 0) new_total daily_total operation[amount] if new_total self.risk_params[daily_trade_max]: return False, 日交易额超限, { current_daily: daily_total, new_amount: operation[amount], max_daily: self.risk_params[daily_trade_max], } details[daily_total] new_total # 设计原因价格偏离检查防止异常价格 if price in operation and reference_price in operation: deviation abs( operation[price] - operation[reference_price] ) / operation[reference_price] if deviation self.risk_params[price_deviation_threshold]: return False, 价格偏离过大, { price: operation[price], reference: operation[reference_price], deviation: f{deviation:.2%}, threshold: f{self.risk_params[price_deviation_threshold]:.2%}, } return True, 通过, details def ring4_human_review( self, operation: Dict ) - Tuple[bool, str, Dict]: 环4人工确认判断 # 设计原因判断是否需要人工审核 # 规则超过一定金额、首次操作、非标产品 needs_review False reasons [] amount operation.get(amount, 0) if amount self.risk_params[single_trade_max] * 0.5: needs_review True reasons.append(高金额操作) if operation.get(is_abnormal, False): needs_review True reasons.append(非标准操作) if needs_review: return False, 需要人工审核, { reasons: reasons, timeout_seconds: 300, fallback: 超时自动拒绝, } return True, 无需审核, {} def ring5_execution( self, operation: Dict, audit_entry: AuditEntry ) - AuditEntry: 环5执行操作并记录审计日志 # 设计原因操作前先记录审计日志预提交模式 audit_entry.final_status AuditStatus.EXECUTED # 设计原因计算防篡改哈希 # 包含所有关键字段任何修改都会被检测到 content json.dumps({ entry_id: audit_entry.entry_id, timestamp: audit_entry.timestamp.isoformat(), operation: operation, decision_chain: audit_entry.decision_chain, }, sort_keysTrue) audit_entry.hash_signature hashlib.sha256( content.encode() ).hexdigest() # 追加到审计日志设计原因append-only 不可删除 self.audit_log.append(audit_entry) return audit_entry def execute_with_audit( self, operation: Dict, agent_config: Dict ) - AuditEntry: 完整的五环执行流程 entry_id fAUDIT-{datetime.now().strftime(%Y%m%d%H%M%S%f)} decision_chain [] # 环1输入校验 passed, msg, detail self.ring1_input_validation(operation) decision_chain.append({ ring: 1, passed: passed, message: msg, detail: detail, timestamp: datetime.now().isoformat(), }) if not passed: entry AuditEntry( entry_identry_id, timestampdatetime.now(), action_typeActionType(operation.get(action_type, QUERY)), agent_idoperation.get(agent_id, unknown), user_idoperation.get(user_id, unknown), operation_detailoperation, decision_chaindecision_chain, final_statusAuditStatus.REJECTED, upstream_event_idoperation.get(event_id), hash_signature, ) return entry # 环2-5依次检查类似结构 # 环2 passed, msg, detail self.ring2_permission_control( operation, agent_config ) decision_chain.append({ ring: 2, passed: passed, message: msg, detail: detail, }) if not passed: return AuditEntry( entry_identry_id, timestampdatetime.now(), action_typeActionType(operation.get(action_type, QUERY)), agent_idoperation.get(agent_id, unknown), user_idoperation.get(user_id, unknown), operation_detailoperation, decision_chaindecision_chain, final_statusAuditStatus.REJECTED, upstream_event_idoperation.get(event_id), hash_signature, ) # ...环3-4类似处理... # 环5执行 entry AuditEntry( entry_identry_id, timestampdatetime.now(), action_typeActionType(operation.get(action_type, QUERY)), agent_idoperation.get(agent_id, unknown), user_idoperation.get(user_id, unknown), operation_detailoperation, decision_chaindecision_chain, final_statusAuditStatus.PENDING_REVIEW, upstream_event_idoperation.get(event_id), hash_signature, ) return self.ring5_execution(operation, entry)四、个性化边界权衡风控策略安全性延迟误拦截率工程复杂度无风控0低0%低仅输入校验30%低5%低加权限控制60%低8%中加业务规则85%低12%中加人工审核五环完整98%高15%高关键权衡安全 vs 延迟人工审核是安全保障的最高级别但会引入分钟级的延迟。在高频交易场景中这个延迟是不可接受的。建议根据操作金额分级小额自动放行大额人工审核。通用性 vs 定制性通用的风控参数如单笔上限 10 万容易设置但效果有限。需要按用户画像、产品类型、市场状态动态调整参数。审计日志的存储成本全量审计日志包括被拦截的操作会产生大量数据。但金融合规要求通常不允许选择性记录——所有的操作记录都是必要的。五、总结金融 Agent 的风控设计必须遵循“五环漏斗”模型输入校验、权限控制、业务规则、人工审核、执行审计。每一环都应该是可配置、可独立开关的策略节点。审计日志是风控体系的基石——必须满足 append-only、因果可追溯、防篡改三大原则。工程上建议将风控参数外部化为配置中心管理的动态规则而非代码中的硬编码常量支持运行时热更新人工审核环节需要设计超时退路超时自动拒绝而非放行审计日志需要独立于业务数据库存储以隔离故障域。风控不是附属功能而是金融 Agent 的主干设计。