41 KiB
风控业务第二版迁移清单
目标仓库:
group_fqcd_jr_rm2基线分支:
origin/qyqy_develop,基线提交:6516ccb开发分支:
RM2_develop迁移原则:只迁移风控业务能力,复用第二版公共底座;不复制第一版鉴权、同步数据库、私有兼容接口和演示数据。
唯一业务来源:
C:\Users\Windows\PycharmProjects\python0626zsProject\nanfangjijin_demo禁止来源:
D:\项目\项目2代码\group_fqcd_jr。该目录是被放弃的第一次迁移,只允许用于查看历史问题,不再复制任何代码。
一、不可违反的边界
- 数据库以
docs/00-新数据库基线设计.md和docs/02-数据库建表设计.md为准;允许新增表、新增字段和新增 Alembic 迁移,不修改、重命名或删除已有表名和字段定义。 - 已有业务代码只读:不修改、不重命名、不删除。迁移代码优先新增文件;接入主路由或 Agent 工厂时只允许追加不改变原逻辑的注册行。
- HTTP 接口以
docs/05-接口文档.md为准,使用/api/v1、{data, meta}信封、统一错误码和调用方提供的 trace。 - 时间和日期存储统一按 UTC;对外时间使用 RFC 3339。
- 金额、价格、数量和概率使用十进制字符串;BIGINT 主键对外使用字符串。
- Controller 只调用 Service;Repository 负责数据库访问;Controller 不导入 ORM 或 SQLAlchemy Session。
- 业务 Agent 必须继承
BaseAgent、由AgentFactory创建,并经过鉴权、配置、记忆、意图、模型、工具、合规、审计和 Outbox。 - 风控 Agent 只读业务数据,不得确认、调查、排除、结案、升级预警或修改交易数据。
- 不把
private_frontend、私有登录、私有兼容路由和演示数据脚本复制到公共代码。
二、旧迁移资产复用规则
| 原项目资产 | 第二版处理方式 |
|---|---|
app/model/entities.py |
作为字段和业务关系参考;第二版优先复用 app/model/fund.py,缺失表再新增独立只读映射 |
app/service/risk_service.py |
迁移状态机、行为分和查询规则,按第二版 MVC+S 重写 |
app/service/risk_scan_service.py |
迁移规则算法、合并和防重,统一使用第二版 Session、UTC 和审计 |
app/tool/rule_engine.py |
迁移规则定义和证据生成逻辑,不迁移同步会话 |
app/service/evidence_list_service.py |
迁移八类证据列表查询和过滤,接入第二版只读 Repository |
app/service/evidence_service.py |
迁移预警证据详情聚合和脱敏 |
app/service/evidence_archive_service.py |
迁移文件签名、扩展名、大小和归档安全逻辑 |
app/service/notification_service.py |
迁移通知创建、分页和预警编号展示 |
app/service/daily_report_service.py |
迁移九段式日报统计和降级建议 |
app/service/daily_report_mail_service.py |
迁移多邮箱和邮件失败处理,接入第二版开关与 dry-run |
app/service/agent_chat_service.py |
作为对话行为参考,按第二版 Agent Run、工具治理和 SSE 重写 |
app/service/agent_service.py |
迁移研判、话术、工单摘要和日报业务内容 |
app/prompt/agent_chat.py、app/prompt/daily_report.py |
迁移业务提示词和边界,模型调用统一走第二版模型服务 |
app/api/risk.py、app/api/evidence.py、app/api/chat.py、app/api/admin.py |
作为业务接口清单参考;正式接口全部重新映射到第二版 /api/v1 契约 |
app/static/index.html、app/static/app.js、app/static/style.css |
迁移正式工作台页面,适配第二版 JWT、响应信封、分页和 Agent Run SSE |
app/service/risk_scan_scheduler.py |
迁移调度语义,后台执行接入第二版 Worker 和租约 |
三、执行阶段
R0 新基线核对
- 从
origin/qyqy_develop创建RM2_develop。 - 确认第二版接口文档、错误码、信封、UTC、游标分页和 Agent 接入规范。
- 确认第二版已有
app/model/fund.py,完整映射风控使用的fin_*只读表。 - 对照
qyqy_develop现有 Fund 模型确认风控查询所需字段缺口。 - 对照第二版基线确认所有风控表、字段、唯一键和主键生成方式。
- 建立第二版风控专项测试目录和测试夹具。
验收:能够回答风控数据的来源、写入点、权限校验、事务边界和审计位置,且不改数据库结构。
R1 风控只读模型与 Repository
状态:[-] 进行中
- 复用
app/model/fund.py,不再重复映射已有 Fund 模型。 - 为数据库已存在的
sys_user、sys_login_record、biz_work_order新增最小只读 ORM 映射。 - R1.1 模型字段专项测试通过:
3 passed。 - 新增
RiskRepository,统一客户范围、脱敏、分页和稳定排序。 - 支持风险概览、未闭环预警列表、预警详情。
- R1.2 Repository 专项测试通过:
5 passed。 - 支持八类证据查询:客户、产品、交易、资金、持仓、登录、预警、通知。
- 所有列表遵循第二版
{data, meta}和分页规范;预警队列业务限制每页 5 条,其余证据每页 10 条。 - 不向 Agent 或接口泄露非必要内部主键。
验收:Repository 在授权范围内只返回允许数据;越权、空范围和无数据场景均失败关闭或返回空集。
R2 风控公共查询接口
- 新增风控 Controller、请求参数和响应 Mapper。
- 实现风险概览。
- 实现预警队列和详情。
- 实现八类证据分页查询。
- 行为分、风险等级、规则编号、客户、产品、时间筛选。
- 使用
AuthorizationService校验权限和客户范围。 - 所有响应符合
{data, meta}、错误码和X-Trace-ID。
验收:Controller 不访问 Model/Repository;非法分页、非法筛选和越权请求有明确错误;接口测试通过。
R3 规则扫描、人工处置和行为分
- 迁移当前实际启用的 RW 规则和证据生成逻辑。
- 迁移同交易合并、重复扫描防重和事务边界。
- 迁移手动扫描接口。
- 迁移确认接收、调查、误报关闭、结案和升级标记。
- 结案时按低 3、中 5、高 20 扣减行为分,最低为 0。
- 误报和未闭环不扣分。
- 所有状态和行为分变化写入审计。
验收:非法状态跳转失败;重复请求幂等;预警、行为分和审计一致。
R4 证据归档、通知和日报
- 迁移证据文件上传,校验扩展名、签名、大小和文件名。
- 文件成功写入后再更新预警证据快照;失败回滚并清理文件。
- 迁移高风险通知创建和通知分页。
- 通知开关和邮件开关接入第二版配置中心。
- 迁移九段式日报,历史未闭环事项完整统计。
- 日报建议模型调用统一走第二版模型服务,失败时规则降级。
- 支持多邮箱校验和 dry-run,不建立额外邮件业务留痕。
验收:文件、通知和日报失败不会误写主业务状态;开关关闭时不调用外部服务。
R5 奶龙风控智能助手
- 按第二版
BaseAgent实现RiskAgent。 - 在
register_business_agents()注册agent_type=risk。 - 声明只读工具:风险概览、预警查询、预警证据。
- 支持客户、产品、风险等级、规则编号和时间筛选。
- 生成研判、话术和工单摘要时使用不同输出合同。
- 增加功能边界、免责声明、空内容校验和分类降级。
- 发布
agent_tools和agent_intent_config配置。 - 使用真实 Agent Run、Worker、结果查询和 SSE 验收。
验收:没有发布配置时工具失败关闭;模型异常不能绕过合规审查;Agent 不能执行任何处置。
R6 定时扫描与后台任务
- 将定时扫描接入第二版 Worker 和租约机制。
- 扫描开关、周期、重试和并发策略使用环境变量配置。
- 手动扫描和定时扫描共用同一 Service。
- 默认关闭,不在 Web 进程启动后台线程。
验收:多次并发扫描不重复生成预警;关闭开关不执行;失败可重试。
R7 正式单页工作台
- 将完整 HTML、CSS 和 JavaScript 迁入主项目静态资源目录。
- 适配正式 JWT、统一错误信封、
/api/v1/risk和 Agent Run SSE。 - 保留概览、八类证据、预警队列、详情弹窗、处置、日报和 Agent 对话。
- 预警队列每页 5 条,其余表每页 10 条。
- 桌面和常用窄屏无文字重叠、无布局跳变。
验收:从登录到证据查询、预警处置、Agent 对话和日报发送均可通过正式接口完整操作。
R8 回归、清理和交付
- 风控单元测试、接口测试和数据库集成测试通过。
- Agent 正常路径、越权、工具拒绝、模型失败和 SSE 恢复通过。
- 主项目全量测试、Ruff、MyPy、架构检查和 schema audit 通过。
- 删除私有兼容依赖,私有页面不再参与正式迁移。
- 更新需求文档、接口文档、字段映射和回滚说明。
四、当前下一步
R0.1 第二版模型缺口核对
状态:[x] 已完成
- 确认第二版已有
app/model/fund.py。 - 确认风险预警、通知、客户画像、交易、资金、持仓等表已有模型。
- 确认
sys_user数据库表已存在;当前由IdentityRepository和SuitabilityService通过原生 SQL 访问,仅有通用 ORM 映射缺口。 - 确认
sys_login_record数据库表已存在,当前缺少 ORM 映射。 - 确认
biz_work_order数据库表已存在,当前缺少 ORM 映射。 - 确认 R1 只新增上述三张已有表的最小只读 ORM 映射,不新增数据库表。
结论:app/model/fund.py 已覆盖大部分 fin_* 风控查询表;不得重复映射。R1 需要新增一个风控专用 ORM 模块,只容纳上述三张当前缺失映射的已有表,或优先通过现有 Repository 查询方式接入。此步骤不执行数据库迁移、不改变表结构。
R0.2 风控查询仓储设计
状态:[x] 已完成
- 明确哪些查询复用
FundQueryRepository。 - 明确哪些查询需要新增风控专用 Repository。
- 明确客户范围和字段脱敏的调用链。
- 输出最小实现方案和测试清单。
确认点:R0.2 方案完成并测试后停下,等待确认再进入 R1。
可直接复用
以下实体已由 app/model/fund.py 映射,并由 FundQueryRepository 提供静默拒绝的客户范围:
fin_productfin_customer_profilefin_risk_assessmentfin_transactionfin_capital_flowfin_holdingfin_risk_alertfin_risk_notification
以下查询可以直接使用 FundQueryRepository:
- 风险测评分页。
- 交易、资金、持仓基础分页。
- 预警和通知基础分页。
- 按客户范围限制的简单单表查询。
需要新增
新增 app/model/risk.py,只映射以下数据库已存在、但当前缺少 ORM 的只读表,不执行建表或改字段:
sys_user:客户编号、用户名、用户类型、客户分层、投资人类型、状态。sys_login_record:登录时间、结果、地区、设备、常用设备和失败原因。biz_work_order:工单编号、客户、产品、渠道、状态、风险揭示、二次确认、录音编号、提交和处理时间。
新增 app/repository/risk_repository.py,原因如下:
- 预警列表需要联表客户、画像、交易和产品,并在输出前统一脱敏。
- 客户证据列表需要关联
sys_user + fin_customer_profile + fin_risk_assessment。 - 交易证据需要关联客户、产品、工单和风险留痕字段。
- 登录证据和工单证据需要访问第二版尚未映射的表。
- 预警详情需要一次聚合预警、客户、交易、产品、工单和相关证据。
- 风险概览需要风险等级、待处理数量、超时数量和重点事件。
最小文件计划
新增文件,不修改已有业务代码:
app/model/risk.py
app/repository/risk_repository.py
app/api/schemas/risk.py
app/service/risk_query_service.py
app/api/controllers/risk.py
tests/unit/repository/test_risk_repository.py
tests/unit/api/test_risk_controller.py
接入正式路由时,app/main.py 只允许追加一行 import 和一行 include_router,不改变已有中间件、异常处理和其他路由。
序列化和分页约定
- 主键和数据库 BIGINT 对外返回字符串。
- 金额、价格、数量和概率返回十进制字符串。
- 时间在数据库内按 UTC,输出 RFC 3339。
- 客户姓名只显示首字,其余替换为
*。 - 预警队列业务默认 limit=5,其他证据默认 limit=10。
- 公共列表接口使用
{data, meta};游标和过滤条件绑定,非法游标返回INVALID_CURSOR。
R1 测试清单
- 未授权角色、缺少权限和空客户范围返回拒绝或空集。
- 客户姓名、手机号和敏感编号脱敏。
- 风险概览统计与未闭环状态一致。
- 预警队列按风险等级和主键稳定排序。
- 八类证据查询分别覆盖有数据、空数据和越权范围。
- 金额、时间、布尔值和 BIGINT 序列化符合第二版契约。
- 非法游标、非法排序和非法筛选返回明确错误。
五、逐步执行门禁
后续每一项都必须严格按以下顺序执行:
- 思考:阅读原项目对应文件、第二版目标模块、调用链、数据来源、写入点和权限来源。
- 方案:写出最小迁移范围、不修改的边界、影响模块和验证方式。
- 迁移:只实现当前一个步骤,不顺手迁移下一步。
- 测试:运行当前步骤的专项测试;失败先修复,不带问题进入下一步。
- 确认:汇报修改文件、测试结果、剩余风险和下一步,等待用户确认。
未完成当前步骤的“测试 + 确认”,不得开始下一步。
六、执行记录
R1.1 补充只读 ORM 映射
状态:[x] 已完成,已确认
新增文件:
app/model/risk.pytests/unit/model/test_risk_models.py
验证结果:使用 Python 3.13.5 运行专项测试,3 passed。
下一步:R1.2 新增 RiskRepository,实现风险概览、未闭环预警列表和预警详情查询。等待确认后执行。
R1.2 风控核心查询 Repository
状态:[x] 已完成,已确认
新增文件:
app/repository/risk_repository.pytests/unit/repository/test_risk_repository.py
已实现:
overview():未闭环总数、等级分布、待处理、超时和重点预警。list_alerts():客户、产品、风险等级、规则编号、关键字和时间筛选。get_alert_detail():聚合预警、客户、交易、产品、工单和证据快照。- 客户与交易账号范围校验,范围缺失时失败关闭。
- 客户姓名脱敏和高风险优先排序。
验证结果:使用 Python 3.13.5 运行专项测试,5 passed。
下一步:R1.3 检查 Repository 只读契约和现有 FundQueryRepository 的复用边界。等待确认后执行。
R1.3 Repository 只读契约与复用边界
状态:[x] 已完成,已确认
新增文件:
tests/unit/repository/test_risk_repository_contract.py
已确认:
RiskRepository不导入 insert/update/delete/merge 等写 SQL。- 不调用
session.add/commit/flush/rollback/with_for_update等写事务方法。 - 对外只暴露
overview、list_alerts、get_alert_detail三类只读用例。 - 风险概览、预警列表和预警详情需要多表联表,保留在
RiskRepository。 - 后续单表或简单实体查询必须复用
FundQueryRepository,不得在RiskRepository重复实现。
验证结果:使用 Python 3.13.5 运行契约测试,3 passed。
下一步:R1.4 实现八类证据查询。优先复用 FundQueryRepository;只有需要客户身份、登录记录、工单联表或跨表拼装时才扩展 RiskRepository。等待确认后执行。
R1.4 八类证据查询
状态:[x] 已完成,已确认
已在 RiskRepository 实现:
list_customers():客户画像、最新风测、行为和状态。list_products():直接复用FundQueryRepository。list_transactions():交易、客户、产品、工单和留痕字段。list_capital_flows():资金流水。list_holdings():持仓、持有天数和持仓占比。list_login_records():登录结果、地区和设备。list_alerts():预警队列和筛选。list_notifications():通知和预警编号。
验证结果:八类证据查询和只读契约专项测试共 13 passed。
下一步:R2.1 新增风控查询 Schema 与 Service,把 Repository 记录转换为第二版 {data, meta} 响应投影。等待确认后执行。
R2.1 风控查询 Schema、游标和 Service
状态:[x] 已完成,待确认
新增文件:
app/core/risk_cursor.pyapp/api/schemas/risk.pyapp/service/risk_query_service.pytests/unit/service/test_risk_query_service.py
已实现:
- 预警队列和证据列表参数校验,队列最多 5 条,证据最多 10 条。
- 不透明偏移游标及非法游标错误。
- 客户数据范围转换和失败关闭。
- Repository 记录到第二版响应字段的统一投影。
- BIGINT、Decimal、datetime、tuple 的序列化。
- 风险概览、预警列表、预警详情和八类证据 Service 方法。
验证结果:Schema、游标和 Service 专项测试共 6 passed。
下一步:R2.2 新增风控 Controller 和正式路由,只负责参数绑定、调用 Service 并包装 {data, meta}。等待确认后执行。
R2.2 风控只读 Controller 与正式路由
状态:[x] 已完成,待确认
新增和接入:
- 新增
app/api/controllers/risk.py。 app/main.py仅追加一条 import 和一条include_router。- 新增
tests/unit/api/test_risk_controller.py。
正式接口:
GET /api/v1/risk/overviewGET /api/v1/risk/alertsGET /api/v1/risk/alerts/{alert_no}GET /api/v1/risk/evidence/{source}
验证结果:风控模型、Repository、Service 和 Controller 合并专项测试共 26 passed。
下一步:R3.1 迁移规则扫描,先实现扫描 Service 和重复预警防重测试。等待确认后执行。
R3.1 规则扫描 Service 与 RW-003
状态:[x] 已完成,待确认
新增文件:
app/service/risk_scan_service.pytests/unit/service/test_risk_scan_service.py
已实现:
- 异步
RiskScanService和RiskRuleEngine。 - 扫描权限校验、进程内并发保护、事务提交和失败回滚。
- 显式生成
fin_risk_alert.id业务主键。 - 同交易多规则预警合并。
- 按交易和规则编号防重。
- RW-003、RW-007、RW-012、RW-015、RW-018 五条规则代码。
- RW-003 事实型摘要、防重、合并和扫描事务专项测试。
验证结果:当前风控迁移全部专项测试共 31 passed。
下一步:R3.2 为 RW-007、RW-012、RW-015、RW-018 补齐正例、反例和边界测试。等待确认后执行。
R3.2 剩余规则边界测试
状态:[x] 已完成,待确认
补充覆盖:
- RW-007:C2/R5 高风险、C4/R5 中风险、留痕完整不触发、等级匹配不触发。
- RW-012:高龄大额赎回触发、历史均值三倍边界触发、超过三倍不触发、常用设备不触发。
- RW-015:凌晨零点且刚好 10000 元触发、非凌晨不触发、超过 10000 元不触发。
- RW-018:渠道“定投”和“自动定投”触发、普通手机渠道不触发。
验证结果:当前全部风控专项测试共 37 passed。
下一步:R3.3 新增扫描 Controller 和正式接口,将手动扫描映射到 POST /api/v1/risk/alerts/scan。等待确认后执行。
R3.3 手动扫描接口
状态:[x] 已完成,待确认
已接入:
POST /api/v1/risk/alerts/scan- Controller 调用
RiskScanService,只包装{data, meta}。 - 未认证请求返回统一 401。
- 请求体为空,扫描权限由 Service 层校验。
验证结果:扫描 Controller 与 Service 联合专项测试共 16 passed。
下一步:R4.1 迁移人工处置状态机,覆盖确认接收、调查、误报关闭、结案、升级和行为分。等待确认后执行。
R4.1 人工处置状态机与行为分
状态:[x] 已完成,待确认
新增文件:
app/service/risk_action_service.pytests/unit/service/test_risk_action_service.py
已实现:
- 确认接收。
- 进入调查。
- 关闭误报并记录理由。
- 完成结案并记录处置结论。
- 升级处理,升级不是终态。
- 结案行为分扣减:低 3、中 5、高 20,最低为 0。
- 误报和未闭环不扣分。
- 每次状态变化写入
interaction_audit。 - 重复确认、未确认进入调查、重复升级和非法状态转换拒绝。
验证结果:当前全部风控专项测试共 46 passed。
下一步:R4.2 新增人工处置 Schema、Controller 和正式接口,将状态机映射到 /api/v1/risk/alerts/{alert_no} 子资源。等待确认后执行。
R4.2 人工处置 Controller 与接口
状态:[x] 已完成,待确认
新增接口:
POST /api/v1/risk/alerts/{alert_no}/acknowledgementsPOST /api/v1/risk/alerts/{alert_no}/investigationsPOST /api/v1/risk/alerts/{alert_no}/exclusionsPOST /api/v1/risk/alerts/{alert_no}/resolutionsPOST /api/v1/risk/alerts/{alert_no}/escalations
已实现:
- 处置请求参数校验。
- JWT、限流和
{data, meta}响应信封。 - 误报理由、处置结论和升级理由不能为空。
- Controller 只调用
RiskActionService。
验证结果:当前全部风控专项测试共 48 passed。
下一步:R5.1 迁移证据文件归档,覆盖类型、签名、大小、重复上传和失败回滚。等待确认后执行。
R5.1 证据文件归档 Service
状态:[x] 已完成,待确认
新增文件:
app/service/risk_evidence_archive_service.pytests/unit/service/test_risk_evidence_archive_service.py
已实现:
- 仅允许 JPG、PNG、WEBP、PDF、Word、Excel、PPT 和 UTF-8 TXT。
- 扩展名、文件签名、Office ZIP 结构和 TXT 编码校验。
- 文件大小限制,默认 10 MB。
- 文件名统一替换为预警编号加原扩展名。
- 项目目录内路径校验,禁止目录穿越。
- 同一预警禁止重复归档或覆盖。
- 文件先写临时文件再原子替换。
- 数据库提交失败时回滚并删除目标文件。
- 归档信息写入
evidence_snapshot.evidence_archive。 - 归档动作写入
interaction_audit。
验证结果:当前全部风控专项测试共 54 passed。
下一步:R5.2 新增证据上传 Controller 和正式接口。等待确认后执行。
R5.2 证据上传 Controller 与接口
状态:[x] 已完成,待确认
新增接口:
POST /api/v1/risk/alerts/{alert_no}/evidence
已实现:
- multipart 文件上传。
- Controller 只调用
RiskEvidenceArchiveService。 - 上传对象在请求结束后关闭。
{data, meta}响应信封。- Service 校验和失败回滚继续生效。
验证结果:证据上传接口与归档 Service 联合专项测试共 14 passed。
下一步:R6.1 迁移通知记录创建和分页查询,通知内容必须包含预警编号。等待确认后执行。
R6.1 通知记录创建与分页
状态:[x] 已完成,待确认
新增文件:
app/service/risk_notification_service.pytests/unit/service/test_risk_notification_service.py
已实现:
- 站内通知记录创建。
- 邮件通知记录创建;迁移阶段当时尚未接入 SMTP。
- 通知主键和通知编号显式生成。
- 通知内容自动包含“预警编号:xxx”。
- 高风险批量通知记录。
- 通知分页复用
RiskQueryService和RiskRepository。
2026-09-12 更新:本节“本阶段不外发 SMTP”只描述 R6.1 当时状态。当前手动扫描和定时扫描命中高风险后已恢复真实邮件发送,通知状态会回写
已发送或发送失败。当前高风险预警邮件只支持一个收件人。
验证结果:当前全部风控专项测试共 58 passed。
下一步:R6.2 将高风险通知创建接入扫描事务,并验证通知失败不破坏预警主事务。等待确认后执行。
R6.2 高风险通知接入扫描
状态:[x] 已完成,待确认
已实现:
- 扫描生成高风险预警后自动创建站内通知记录。
- 高风险邮件通知记录和真实 SMTP 外发,发送失败不回滚预警。
- 高风险预警邮件当前只支持一个收件人,多个邮箱值只取第一个。
- 通知创建使用嵌套保存点隔离。
- 通知创建失败只记录日志,不回滚预警扫描主事务。
- 扫描结果增加
notification_count。
验证结果:当前全部风控专项测试共 60 passed。
下一步:R6.3 新增通知分页查询接口,复用统一游标和响应信封。等待确认后执行。
R6.3 通知分页查询接口
状态:[x] 已完成,待确认
新增接口:
GET /api/v1/risk/notifications
已实现:
- 通知专用分页参数。
- 关键字、发送状态、时间范围和游标筛选。
- 每页最多 10 条。
{data, meta}响应信封。- 复用通知 Service、Repository 和统一序列化。
验证结果:通知查询接口与 Service 联合专项测试共 12 passed。
下一步:R7.1 迁移九段式日报和日报邮件 Service。等待确认后执行。
R7.1 九段式日报和邮件 Service
状态:[x] 已完成,待确认
新增文件:
app/service/risk_daily_report_service.pyapp/service/risk_daily_report_mail_service.pytests/unit/service/test_risk_daily_report_service.py
已实现:
- 九段式日报统计模板。
- 当日预警、历史未闭环、误报、处置结果和规则效果统计。
- 历史未闭环不受分页限制。
- 模型建议走第二版模型服务,失败、空内容或越权表述时规则降级。
- 日报生成审计。
- 日报异步流式事件。
- 邮件 Service 默认禁用、支持 dry-run、不主动连接 SMTP。
验证结果:当前全部风控专项测试共 65 passed。
下一步:R7.2 新增日报 Controller 和正式接口,覆盖结构化生成、流式生成和邮件发送。等待确认后执行。
R7.2 日报 Controller 与接口
状态:[x] 已完成,待确认
新增接口:
POST /api/v1/risk/daily-reportPOST /api/v1/risk/daily-report/streamPOST /api/v1/risk/daily-report/mail
已实现:
- 结构化日报生成。
- SSE 流式日报事件。
- 日报邮件发送。
- 多收件人去重和邮箱校验。
{data, meta}响应信封。- 邮件默认禁用或 dry-run,不主动连接 SMTP。
验证结果:当前全部风控专项测试共 66 passed。
下一步:R8.1 迁移奶龙风控智能助手,按第二版 BaseAgent 和 AgentFactory 注册。等待确认后执行。
R8.1 奶龙风控智能助手
状态:[x] 已完成,待确认
新增和接入:
app/core/risk_contracts.pyapp/service/risk_tools.pyapp/service/agent/implementations/risk_agent.pyapp/service/agent/bootstrap.py追加 RiskAgent 和三个只读工具注册tests/contract/test_risk_agent_contract.py
已实现:
agent_type=risk,展示名称为“奶龙风控智能助手”。- 四个意图:风险概览、风险查询、预警证据、通用边界。
- 三个只读工具:风险概览、预警查询、预警证据。
- 工具权限
risk:alert:read,允许角色risk_operator/admin。 - Agent 不执行确认、调查、误报关闭、结案或升级。
- 未发布工具白名单时失败关闭。
- 返回功能边界和只读说明。
验证结果:当前全部风控专项测试和 Agent 契约测试共 71 passed。
下一步:R8.2 发布 risk Agent 的 agent_tools 和 agent_intent_config 配置,并执行真实 Agent Run/SSE 验收。等待确认后执行。
R8.2 配置发布与真实 Agent 验收
状态:[x] 已完成,待确认
已执行:
- 生成并验证本地 RS256 JWT 公私钥。
- 对空库执行 Alembic 基线迁移,51 张表结构审计通过。
- 写入 9001/9002/9003 测试身份和基础 RBAC。
- 补充并授予风控读取、写入、扫描权限。
- 写入并激活 DeepSeek
deepseek-flash模型端点。 - 发布 risk Agent 工具白名单。
- 发布四条 risk 意图配置。
- 新增
tools/seed_risk_agent_config.py和tools/risk_agent_e2e.py。
真实验收结果:
- Agent Run 受理成功。
- Worker 执行终态为
succeeded。 - 工具调用为
get_risk_overview/succeeded。 - 工具审计已写入。
- SSE 返回
text/event-stream并包含done。 - Milvus 不可用、Redis 模块不可用时按设计降级,没有阻塞风险概览查询。
下一步:R9 正式前端工作台迁移。等待确认后执行。
R9.1 正式工作台静态资源迁移
状态:[x] 已完成,待确认
已迁移:
app/static/index.htmlapp/static/style.cssapp/static/app.js
已接入:
app/main.py追加/static静态资源挂载。- 新增静态资源测试
tests/unit/api/test_risk_workbench_static.py。
验证结果:页面、CSS 和 JavaScript 均可由第二版应用提供,专项测试 1 passed。
下一步:R9.2 适配前端 JWT、/api/v1/risk 接口、统一响应信封和 Agent Run SSE。等待确认后执行。
R9.2 私有前端 REST、JWT 和日报 SSE 适配
状态:[x] 已完成,待确认
只在 private_frontend 中完成:
- 增加浏览器 Bearer 令牌管理和本地保存。
/api/risk/**迁移到/api/v1/risk/**。- 统一拆包
{data, meta}响应。 - 适配游标分页的上一页/下一页。
- 适配八类证据、预警、通知、详情和处置子资源。
- 适配证据上传、扫描、日报生成、日报流和日报邮件。
- 流式解析同时支持 NDJSON 和 SSE。
- 新增私有静态代理服务器
private_server.py。 - 新增短期令牌生成脚本
generate_token.py。
验证结果:JavaScript 和 Python 语法检查通过,短期令牌生成成功。
剩余:Agent 对话仍使用原项目 /api/risk/agent/chat/stream,将在 R9.3 改为第二版 Agent Run/SSE 编排。
R9.3 私有前端 Agent Run 对话
状态:[x] 已完成,待确认
私有前端对话已改为:
POST /api/v1/agent-runs创建agent_type=risk的真实运行。- 使用浏览器生成的 session_id 和 idempotency_key。
- 订阅
/api/v1/agent-runs/{run_id}/eventsSSE。 - 展示工具调用、replace/delta、done/error。
- 当前预警自动将预警编号拼入 Agent 消息。
运行依赖:
- Web 服务。
- 独立 Worker:
python -m app.worker。 - 9002 访问令牌。
验证结果:私有前端 JavaScript 语法检查通过,旧对话接口已移除。
R10.1 结构化输出恢复
状态:[x] 已完成,已确认
新增或修改:
app/service/risk_analysis_service.pyapp/service/agent/implementations/risk_agent.py追加结构化分析路由tests/unit/service/test_risk_analysis_service.pytests/contract/test_risk_agent_contract.py
已实现:
- 恢复预警研判、回访话术、工单摘要三种独立输出。
- 三种输出使用不同的模型任务、提示词和模板降级内容。
- 模型返回空内容、超长内容或包含越权处置声明时自动降级。
- 生成结果写入
fund_risk_alert.ai_analysis,并追加交互审计。 - 生成前校验
risk:alert:read权限和数据范围。 - 自然语言携带预警编号时,可路由到对应结构化输出。
验证结果:语法检查通过,结构化输出与 Agent 契约专项测试 10 passed。
遗留告警:Pydantic 对公共配置中 model_ 前缀字段给出命名警告,不属于本次业务逻辑故障。
下一步:R10.2 模型自主选择工具和多轮工具调用。等待确认后执行。
R10.2 模型自主选择工具与多轮工具调用
状态:[x] 已完成,已确认
新增或修改:
app/service/risk_agent_model_client.pyapp/service/agent/implementations/risk_agent.pyapp/service/risk_tools.pytests/unit/service/test_risk_agent_model_client.pytests/contract/test_risk_agent_contract.py
已实现:
- 奶龙风控智能助手由模型自主选择风险概览、预警查询和预警证据工具。
- 支持最多 4 轮模型调用和累计 6 次工具调用。
- 工具名、工具类型、调用编号和 JSON 参数均执行严格校验。
- 只允许调用当前 Agent 配置中已授权的只读工具。
- 工具仍通过公共
ToolExecutor执行,权限校验、超时和审计规则不变。 - 工具结果移除内部数据库主键,并限制单次返回长度。
- 模型最终回复校验空内容、超长内容、越权处置声明和工具协议残留。
- 模型或工具编排失败时切换到既有确定性查询降级路径。
search_risk_alerts改为按每页 10 条循环读取全部未闭环预警,不再只取首批 10 条。
验证结果:R10.2 专项测试 10 passed,完整风控专项测试 77 passed。
遗留告警:Pydantic 对公共配置中 model_ 前缀字段给出命名警告,不属于本次业务逻辑故障。
下一步:R10.3 恢复误报、可放行、疑似误判等业务研判意图。等待确认后执行。
R10.3 误报、可放行与疑似误判研判
状态:[x] 已完成,已确认
新增或修改:
app/service/risk_judgement_service.pyapp/service/risk_tools.pyapp/repository/risk_repository.pyapp/service/agent/implementations/risk_agent.pytests/unit/service/test_risk_judgement_service.pytests/contract/test_risk_agent_contract.pytests/unit/repository/test_risk_repository.py
已实现:
- 预警列表增加只读
disposition_hint复核方向。 - 预警证据增加只读
disposition_assessment研判草案。 - 恢复有效定投场景的可放行候选识别。
- 恢复低风险小金额非正常时段操作的疑似误报识别。
- RW-007 会重新核对客户等级、产品等级和风险揭示、二次确认、录音留痕。
- RW-003 会重新核对大额门槛和赎回比例。
- RW-012 会核对年龄、赎回金额、历史门槛和登录设备常用性。
- 预警证据详情补充资金流、持仓和登录记录。
- 模型不可用时可使用规则化只读研判草案降级。
- 所有结论均明确标注为复核草案,Agent 不执行误报关闭、放行、结案或升级。
验证结果:R10.3 专项测试 14 passed,完整风控专项测试 83 passed。
遗留告警:Pydantic 对公共配置中 model_ 前缀字段给出命名警告,不属于本次业务逻辑故障。
下一步:R10.4 恢复自然语言客户、产品、规则和时间筛选,并补齐完整回答场景。等待确认后执行。
R10.4 自然语言筛选与完整回答
状态:[x] 已完成,已确认
新增或修改:
app/service/risk_natural_language.pyapp/service/risk_tools.pyapp/service/agent/implementations/risk_agent.pytests/unit/service/test_risk_natural_language.pytests/unit/service/test_risk_search_result.pytests/contract/test_risk_agent_contract.py
已实现:
- 支持自然语言客户编号筛选。
- 支持产品代码和产品名称筛选。
- 支持风险等级和 RW 规则编号筛选。
- 支持今天、本月、最近 N 天、明确起止日期、日期以来和截至日期。
- 中文本地时间统一在 Asia/Shanghai 解析,再转换为 UTC 查询时间。
- 模型调用工具前会收到系统预解析的筛选条件,降低日期和编号解析偏差。
- 预警查询返回完整分组汇总和精简明细。
- 汇总包含全部客户、产品、风险等级、规则和研判分布,不会因明细截断而声称只覆盖部分记录。
- 模型不可用且问题属于预警列表查询时,可使用本地筛选和完整汇总规则化回答。
验证结果:R10.4 专项测试 14 passed,完整风控专项测试 88 passed。
遗留告警:Pydantic 对公共配置中 model_ 前缀字段给出命名警告,不属于本次业务逻辑故障。
下一步:R10.5 对话历史、会话归属、审计和分类降级。等待确认后执行。
R10.5 对话历史、会话归属与长期留存
状态:[-] 暂缓,全部迁移完成后再做
已确认的边界:
- 当前 MySQL
svc_conversation_session、conversation_message、agent_run和审计写入继续保留。 - 不在本阶段改为 Redis-only。
- 不在本阶段修改公共 Run、Worker、消息持久化和记忆抽取链路。
- 后续优先采用 MySQL 权威保存、Redis 缓存最近会话、原始消息分级保留的方案。
- 长期留存、脱敏、归档和删除策略作为独立迁移任务处理。
下一步:R10.6 真实 Agent Run、Worker、结果查询、SSE 和业务对话端到端验收。
R10.6 真实 Agent Run 与业务对话端到端验收
状态:[x] 已完成,已确认
新增:
tools/risk_agent_business_e2e.py
验收场景:
- 风险概览对话。
- 低风险客户和产品完整筛选回答。
- 误报、可放行和疑似误判研判对话。
通过正式链路验证:
POST /api/v1/agent-runs受理为queued。WorkerRuntime实际执行 Run。- 模型自主调用
get_risk_overview、search_risk_alerts和get_alert_evidence。 - 查询结果通过
summary表示完整分组,未因明细截断声称只覆盖部分记录。 GET /api/v1/agent-runs/{run_id}返回succeeded。- SSE 返回
text/event-stream并包含done。 - 工具调用审计和运行完成审计均可追溯。
- Agent 未执行确认、误报关闭、放行、结案或升级动作。
验收结果:
- 风险概览:
PASSED,运行编号40190585-2aad-4af5-b600-d3bf72471830。 - 完整筛选回答:
PASSED,运行编号b314ad10-1926-4ada-8b1c-a5facf96beca。 - 误报研判:
PASSED,运行编号cbcb3758-0b8c-4967-9582-ff7ab66de256。
环境降级:
- Milvus 未启动,语义记忆关闭,结构化流程继续运行。
- Redis 缓存读取降级,不影响 Agent Run 结果。
.env第 12 行存在 dotenv 解析警告,不影响本次业务验收。
下一步:R11 全量回归、代码质量检查、数据库结构审计和迁移收口。等待确认后执行。
R11 全量回归与迁移收口
状态:[x] 业务侧与静态检查已完成;公共底座 3 项类型问题确认不修改
全量测试:
python -m pytest -q --basetemp=.pytest_rm2_tmp -p no:cacheprovider- 结果:
567 passed, 1 skipped。
类型检查:
- 已修复本次风控迁移代码中的 30 项 MyPy 严格类型错误。
- 当前
python -m mypy app仍报告 3 项公共底座既有错误:app/service/model_gateway.py两个端点适配器类型错误。app/worker/runtime.py一个请求元数据类型错误。
- 经确认,公共基座不修改,上述 3 项作为已知类型例外接受。
- 该例外不影响当前业务功能、真实 Agent Run、工具调用和 SSE。
静态检查:
python -m pip check通过。python -m ruff check app tests tools alembic通过。- 使用 Ruff
0.16.6修复导入排序、未使用变量、调用默认值标记、超长行和未使用统计变量。
数据库结构:
python tools/audit_schema.py:51 张业务表通过,无缺失或多余业务表。python tools/audit_constraints.py:唯一键和 ORM 映射与基线一致。python tools/migration_state_check.py:数据库版本为 head20260910_drop_review_separation,51 张业务表。python -m alembic check无法执行,原因是公共alembic/env.py未提供 MetaData。
剩余环境项:
.env第 12 行存在 dotenv 解析警告。- Pydantic 对公共配置中
model_前缀字段给出命名警告。 - 本地 Milvus 未启动;Redis 缓存读取降级。
- R10.5 对话历史与长期留存继续暂缓,全部迁移完成后再处理。
结论:R11 业务迁移和质量门禁已完成。公共底座 3 项 MyPy 例外保持现状,Ruff、全量测试、数据库结构和迁移状态均已通过。
R6.4 定时规则扫描补迁移
状态:[x] 已完成,待确认
新增:
app/service/risk_scan_schedule_config.pyapp/worker/risk_scan_scheduler.pytests/unit/service/test_risk_scan_schedule_config.pytests/unit/worker/test_risk_scan_scheduler.py
已实现:
- 独立定时扫描 Worker,不在 Web 进程启动后台线程。
- 从
.env环境变量读取开关、周期、立即执行、重试次数和轮询间隔。 - 默认关闭。
- 使用 MySQL 咨询锁防止多进程重复扫描。
- 手动和定时扫描共用同一
RiskScanService。 - 扫描成功和失败写入系统审计。
- 支持
--once和--force本地验证参数。
环境变量:
RISK_SCAN_SCHEDULE_ENABLEDRISK_SCAN_INTERVAL_MINUTESRISK_SCAN_RUN_IMMEDIATELYRISK_SCAN_RETRY_LIMITRISK_SCAN_POLL_SECONDS
验证结果:专项测试 6 passed,Ruff 通过,MyPy 通过,全量测试 573 passed, 1 skipped。
本地运行方式:
python -m app.worker.risk_scan_scheduler
python -m app.worker.risk_scan_scheduler --once --force
下一步:将定时扫描配置写入当前 active 配置发布,并同步推送代码。等待确认后执行。