Files
Mutual_Fund/风控Agent需求文档.md
T
zhangyongcai 69db5c46bd docs:补充风控Agent需求文档与规则初始化SQL
- 新增《风控Agent需求文档》:规则引擎、前置拦截、人工处置、工单闭环
- 新增 sql/risk_rule_seed.sql:20条风控规则种子数据(INSERT IGNORE)
2026-09-12 21:15:42 +08:00

16 KiB
Raw Blame History

风控 Agent 需求文档

版本:v1.0 | 日期:2026-09-12 | 状态:待评审 依据:《开发计划.md》§2.5 风控控制台、§5 风控Agent、Phase 4 关联:《风控Agent设计方案.md》


1. 背景与目标

为系统接入风控 Agent:每一笔申购/赎回在下单落账前,先经过风控规则引擎检测,命中规则的订单被「挂起」等待人工处置,未命中的正常成交。

核心目标:形成「检测 → 阻断 → 人工处置 → 回写」的合规闭环。

合规铁律:机器只负责告警 + 阻断;放行/拦截/冻结的处置权永远在人工。


2. 术语与核心概念

术语 表 定位
交易申请单 trade_order 风控拦截对象,状态机主表(事前)
成交流水 fin_transaction 账务凭证,只含真正成交的单(事后)
风控预警 fin_risk_alert 命中记录 + 人工处置留痕
风控规则 risk_rule 规则引擎的表驱动配置(参数)
业务工单 biz_work_order 拦截/冻结后开启的独立审批链

两张链的关系:预警链(fin_risk_alert)在人工处置后结束;工单链(biz_work_order)只在「拦截/冻结」时额外开启,是处置的下游产物。


3. 现状与差距

  • 当前 service/purchase.py / service/redeem.py 为即时成交(直接扣款+加仓 / 减仓+入账),不产生任何交易留痕。
  • trade_order / fin_transaction / fin_risk_alert / risk_rule / biz_work_order 五张表只有 DDL,无 model/repo/schema 实现。
  • 结论:风控 Agent 当前无数据可检测,需先补齐交易留痕。

4. 核心需求

FR1 · 前置拦截(交易留痕)

申购/赎回由「即时成交」改为「先建单 → 检测 → 通过才落账」。

请求(申购/赎回)
  ↓
FastAPI 鉴权(get_current_user)→ 获取当前用户
  ↓
适当性校验(硬拦截,申购专用):
    客户风险等级 ≥ 产品风险等级,否则 1005 直接拒绝,不生成订单
  ↓
创建 trade_order,status = '待确认'
    - 生成唯一 order_no(前缀+日期+序列,如 PO20260912xxxx)
    - 填入 order_type / amount / shares / nav(申请口径)
    - ★ 不碰账户余额、不碰持仓
  ↓
同步进入风控规则引擎检测(FR2)
  ↓
├─ 未命中 ──► status='已确认' + 落账(扣款+加仓 / 减仓+入账)
│              + 写 fin_transaction + confirm_time=now
│
└─ 命中 ────► 生成 fin_risk_alert(未处理)
               + trade_order.status='风控挂起' + risk_alert_id 关联
               账户、持仓保持不动,等待人工处置(FR4)

关键约束:

  • 建单 → 检测 → 落账/挂起 在单个事务内原子完成(无外部调用,全为 DB + 纯计算)。
  • 落账逻辑复用现有 deduct_balance/holdings.upsert、holdings.redeem/credit_balance,不重写。

FR2 · 规则引擎检测(纯代码,不用大模型)

  • 同步执行:在下单请求内当场完成,结果驱动状态流转。
  • 纯规则引擎:阈值比较 + 历史流水统计,全程 if/else + SQL,不调用 LLM。
  • 表驱动:risk_rule 表存参数(阈值/级别/权重/启停),代码存判断逻辑。

检测输入:当前 trade_order + 该客户历史流水 + 客户画像/账户/注册时间。 检测输出:命中规则列表(规则 ID + 规则名 + 命中详情)。

FR3 · 预警生成

  • 聚合粒度:一笔订单命中多条规则,只生成一条预警;alert_type 取主规则,trigger_detail 记录全部命中规则,alert_level 取最高档。
  • 分级:级别取命中规则中 risk_level 最高档(低→蓝 / 中→黄 / 高→红)。
  • 置信度:confidence = 1 − Π(1 − weight_i)(命中规则越多、权重越高,置信度越高)。

FR4 · 人工处置(挂起自动,处置人工)

三个处置动作均为风控专员手动,系统绝不自动放行/自动作废:

动作 订单 预警 客户 工单
放行 已确认 + 落账 已排除 正常成交 无
拦截 失败(作废) 已确认 站内信通知 生成「可疑交易上报」
冻结 失败(作废) 已确认 sys_user.status=冻结 + 站内信通知 生成「冻结复核」

约束:

  • 处置接口的 handler_id 由后端从当前登录用户获取,不信任前端传入。
  • 处置接口需校验角色:风控专员(user_type=EMPLOYEE 且 employee_role=风控专员,或 ADMIN)。
  • 处置结果回写订单与预警表(handler_id/handle_result/handle_time),全程留痕可追责。
  • 放行时重新校验余额:挂起期间余额可能变化,申购放行若余额不足则放行失败、订单转「失败」。

FR5 · 工单链

  • 生成时机:仅在「拦截」或「冻结」处置时自动创建,系统自动挂起阶段不产生工单。
  • 创建方式:系统自动 INSERT,预填 order_type(可疑交易上报/冻结复核)、customer_id、submitter_id(当前专员)、priority(按预警级别)、biz_content(打包命中规则+订单号+预警 id);status 默认「待处理」、current_node 默认「初审」。
  • 流转(后端接口驱动):
            认领              提交审核            复核通过
 待处理 ──────────► 处理中 ──────────► 待审核 ──────────► 已完成
  (handler_id=自己)                          │
                                             └──────► 已驳回(复核驳回,终态)
  • 职责分离:复核人 ≠ 处理人,先做软校验(仅提示,不强制阻断)。
  • 终点:工单「已完成」即项目内终点,不上报人行(监管报送为系统外动作,不在本项目范围)。
  • 每次流转写 audit_log(谁、何时、从什么态改到什么态)。

5. 状态机

5.1 trade_order 订单状态机

待确认 ──(未命中)──────► 已确认 ──► 落账 + 写 fin_transaction
   │
   └──(命中)──────────► 风控挂起
                          │
                          ├──(放行)──► 已确认 ──► 落账 + 写 fin_transaction
                          ├──(拦截)──► 失败(作废)+ 通知客户 + 生成工单
                          └──(冻结)──► 失败(作废)+ 客户冻结 + 通知客户 + 生成工单

5.2 fin_risk_alert 预警状态机(无「处理中」中间态)

未处理 ──(放行)────► 已排除
   │
   ├──(拦截)──────► 已确认
   └──(冻结)──────► 已确认

防并发:处置接口用条件更新 WHERE id=? AND status='未处理',更新不到(rowcount=0)即视为已被他人处置,返回提示,不重复落账/工单/通知。

5.3 biz_work_order 工单状态机

待处理 ──认领──► 处理中 ──提交审核──► 待审核 ──复核通过──► 已完成
                                           └──复核驳回──► 已驳回(终态)

6. 数据表设计

五张表 DDL 已在 sql/schema.sql,本次需补 ORM model + repository + schema。

6.1 trade_order 字段映射

字段 来源
order_no 生成唯一单号 PO+日期+序列
customer_id 当前用户 id
product_id 入参 product_id
advisor_id 客户自购为 null
order_type 申购 / 赎回
amount / shares 申购金额+折算份额;赎回份额+折算金额
nav 产品当前净值
fee 0(暂无手续费)
status 待确认 / 风控挂起 / 已确认 / 失败
risk_alert_id 挂起时关联预警 id
confirm_time 确认时间

6.2 fin_transaction 成交流水

仅在风控通过、落账成交时写一笔:transaction_no、order_id(关联申请单)、customer_id、product_id、transaction_type(申购/赎回)、amount、shares、nav、fee、status='已确认'。

6.3 fin_risk_alert 预警

字段 填什么
customer_id 交易客户
order_id 触发预警的申请单
alert_type 主命中规则名
alert_level 低(蓝)/中(黄)/高(红),取命中规则最高档
trigger_detail 全部命中规则 + 触发详情
transaction_ids 关联历史交易 ID 列表(聚合规则用)
confidence 预警置信度
status 未处理 → 已确认 / 已排除
handler_id / handle_result / handle_time 处置留痕

6.4 risk_rule 规则(表驱动)

20 条规则配置见 §7,字段:rule_id / rule_name / trigger_condition / threshold(JSON) / risk_level / weight / status。

6.5 biz_work_order 工单

见 §4 FR5,work_order_no 生成 WO+日期+序列。


7. 规则清单(20 条)

A 类 · 单笔规则(只看当前订单)

编号 规则名 触发条件 阈值 JSON 级别 权重
R001 大额申购-红 单笔申购金额 ≥ 100万 {"amount":1000000} 高 0.90
R002 大额赎回-红 单笔赎回金额 ≥ 100万 {"amount":1000000} 高 0.90
R003 大额申购-黄 单笔申购金额 ≥ 50万 {"amount":500000} 中 0.70
R004 大额赎回-黄 单笔赎回金额 ≥ 50万 {"amount":500000} 中 0.70
R014 适当性异常 客户风险等级 < 产品风险等级 {} 高 0.95
R020 夜间交易 下单时间 00:00–06:00 {"start":"00:00","end":"06:00"} 低 0.35

B 类 · 聚合规则(查客户历史流水)

编号 规则名 触发条件 阈值 JSON 级别 权重
R005 高频交易 近 7 天申赎 ≥ 10 笔 {"days":7,"count":10} 中 0.65
R006 当日密集交易 近 1 天申赎 ≥ 5 笔 {"days":1,"count":5} 中 0.60
R007 密集小额申购 近 3 天 ≥ 5 笔、每笔 < 1万 {"days":3,"count":5,"max_amount":10000} 低 0.50
R008 短炒赎回 同产品申购后 7 天内赎回 {"days":7} 中 0.65
R009 快进快出 同产品申购后 3 天内全额赎回 {"days":3} 高 0.85
R010 资金快进快出 入账后 24 小时内赎回 {"hours":24} 高 0.90
R011 短期累计大额 近 7 天累计申赎 ≥ 200万 {"days":7,"amount":2000000} 高 0.85
R012 中期累计大额 近 30 天累计申赎 ≥ 500万 {"days":30,"amount":5000000} 中 0.65
R013 拆分规避大额 同 1 天多笔合计 ≥ 100万、单笔 < 50万 {"days":1,"total":1000000,"each_lt":500000} 中 0.70
R018 全额清仓赎回 赎回后该产品持仓归 0 且金额 ≥ 10万 {"amount":100000} 低 0.45
R019 对倒交易 近 7 天多产品互买互卖 {"days":7} 中 0.70

C 类 · 客户维度规则(看画像/账户/注册时间)

编号 规则名 触发条件 阈值 JSON 级别 权重
R015 新客户大额 注册 < 30 天且单笔 ≥ 50万 {"days":30,"amount":500000} 中 0.65
R016 休眠账户激活 90 天无交易后首笔 ≥ 10万 {"days":90,"amount":100000} 低 0.55
R017 整数金额 金额为整万且 ≥ 10万 {"amount":100000} 低 0.40

统计:高 6 条、中 8 条、低 6 条。

规则启用状态:R019 对倒交易初始 status=停用(实现最复杂、Mock 下难触发),其余 19 条默认启用。


8. 接口清单

8.1 交易接口(改造)

接口 说明
POST /api/purchase 改造为前置拦截:适当性校验 → 建单 → 检测 → 落账/挂起
POST /api/redeem 同上(赎回无适当性校验)

8.2 处置接口(新增,风控专员)

接口 动作 副作用
POST /api/risk/alert/{id}/release 放行 订单已确认 + 落账;预警已排除
POST /api/risk/alert/{id}/block 拦截 订单失败 + 通知;预警已确认 + 生成工单
POST /api/risk/alert/{id}/freeze 冻结 订单失败 + 客户冻结 + 通知;预警已确认 + 生成工单

8.3 工单接口(新增)

接口 动作 状态变化
GET /api/work-order/list 列表 —
GET /api/work-order/{id} 详情 —
POST /api/work-order/claim 认领 待处理 → 处理中
POST /api/work-order/submit-review 提交审核 处理中 → 待审核
POST /api/work-order/review 复核 待审核 → 已完成 / 已驳回

8.4 规则引擎(内部服务,非 HTTP 接口)

  • detect(order, customer) -> 命中规则列表:加载启用规则 → 按 rule_id 路由到判断函数 → 传入交易数据 + threshold 执行 → 汇总命中。

9. 关键设计约束(汇总)

  1. 单事务原子:建单 → 检测 → 落账/挂起在单个事务内完成。
  2. 落账复用:复用现有扣款/加仓、减仓/入账逻辑,不重写。
  3. 纯代码检测:规则匹配用 if/else + SQL,不用 LLM。
  4. 人工处置:挂起自动,放行/拦截/冻结人工,系统不自动处置。
  5. 防并发:处置接口条件更新 status='未处理',防重复处置。
  6. handler_id 后端取:不信任前端传入;处置/工单接口均校验角色权限。
  7. 放行重新校验余额:防挂起期间余额变化导致落账失败。
  8. 预警聚合:一笔订单一条预警;级别取最高;置信度按权重合成。
  9. 工单后置:仅拦截/冻结时生成,为处置的下游产物。
  10. 审计留痕:处置与工单流转均写 audit_log。

10. 实施分期

Step 1  建 5 张表的 model + repo + schema
Step 2  改 purchase/redeem:适当性校验 → 建单(待确认) → 调风控引擎
Step 3  写规则引擎(读 risk_rule + 查历史流水,输出命中列表)
Step 4  命中分支:挂起 + 生成预警;未命中:落账 + 写流水
Step 5  处置接口(放行/拦截/冻结)+ 权限 + 防并发 + 审计
Step 6  工单链(自动建单 + claim/review 接口)  ← 可后置

11. 验收标准

  1. 正常申购/赎回:未命中规则 → 订单「已确认」、账户/持仓变动、fin_transaction 生成一条成交流水。
  2. 命中挂起:大额申购(如 ≥100万)→ 订单「风控挂起」、生成一条 fin_risk_alert(未处理)、账户与持仓不变。
  3. 放行:风控专员放行 → 订单「已确认」+ 落账、预警「已排除」。
  4. 拦截:风控专员拦截 → 订单「失败」、预警「已确认」、生成「可疑交易上报」工单、客户收到站内信。
  5. 冻结:风控专员冻结 → 订单「失败」、预警「已确认」、客户 sys_user.status=冻结、生成「冻结复核」工单。
  6. 防并发:同一预警被两次处置,第二次返回"已被处理",不重复落账/工单/通知。
  7. 权限:非风控专员调用处置接口被拒绝。
  8. 工单链:拦截/冻结生成的工单能走完「待处理 → 处理中 → 待审核 → 已完成/已驳回」。
  9. 留痕:处置与工单流转均有 audit_log 记录(谁、何时、从什么态到什么态)。

12. 已确认决策清单

# 决策点 结论
1 风控时机 前置拦截(先建单 → 检测 → 通过才落账)
2 检测方式 同步 + 纯规则引擎,不用 LLM
3 落表 trade_order 为风控主表,fin_transaction 为成交凭证
4 预警粒度 一笔订单聚合一条预警
5 分级置信度 级别取最高;confidence = 1 − Π(1 − weight_i)
6 处置方式 挂起自动,放行/拦截/冻结人工
7 预警中间态 不加「处理中」,用条件更新防并发
8 工单时机 仅拦截/冻结时生成,人工处置之后
9 工单复核分离 软校验(仅提示),不强制
10 工单驳回 已驳回为终态,不回流
11 工单终点 「已完成」即终点,不上报人行
12 R019 对倒交易 初始停用
13 R014 适当性异常 保留作兜底
14 单号生成 前缀+日期+序列(PO... / WO...)