Files
ccdi/docs/design/2026-03-20-lsfx-mock-phase2-random-hit-design.md

9.5 KiB
Raw Blame History

兰溪流水 Mock 第二期稳定随机命中设计

1. 背景

当前仓库已经具备两条基础能力:

本次目标不是重写主工程打标逻辑,而是在保留第一期稳定随机命中方案的前提下,为第二期补齐可联调、可重复、可命中真实 SQL 的输入数据。

2. 目标

  • 保留现有第一期 logId -> 稳定随机规则子集 行为不变。
  • 为第二期规则新增稳定随机命中计划。
  • 让“拉取本行信息 / 获取流水列表 -> 入库到本地 -> 执行重打标”后,最终标签结果中可以查到抽中的第二期规则命中。
  • 对依赖采购、资产等外部事实表的规则,补最小且幂等的本地数据库基线。

3. 非目标

  • 不新增主工程打标补丁逻辑。
  • 不把采购类、资产类规则伪造成纯银行流水规则。
  • 不引入“指定特殊 logId 固定命中全部第二期规则”的双轨模式。
  • 不扩展第二期范围外的新规则。

4. 方案对比

4.1 方案 A稳定随机命中 + 第二期基线编排

保留现有 FileService -> StatementService -> 缓存分页 主链路;对可由银行流水驱动的第二期规则继续通过 Mock 流水样本触发;对依赖采购、资产等外部事实表的规则,通过本地数据库最小基线补齐真实 SQL 输入。

优点:

  • 与主工程真实 SQL 数据来源一致。
  • 能同时覆盖“Mock 取数正确”和“真实规则可命中”。
  • 保持现有第一期链路结构不变,扩展成本最低。

缺点:

  • 需要同时维护流水样本和数据库基线两类输入。

4.2 方案 B只改 Mock 流水

只扩充 lsfx-mock-server 返回的流水数据,不补采购、资产等业务表。

缺点:

  • 第二期中存在真实依赖 ccdi_purchase_transactionccdi_asset_info 的规则,最终会出现 Mock 看似有数据、真实 SQL 仍然无法命中的偏差。

4.3 方案 C只补数据库基线

Mock 仅返回普通流水,把第二期命中主要交给数据库灌数。

缺点:

  • 无法证明“兰溪本地接口获取流水列表并入库”的链路本身正确。
  • 偏离本次验收口径。

5. 推荐方案

采用方案 A。

原因:

  • 第二期联调必须同时证明两件事Mock 取数入库链路没问题,真实 SQL 也确实能命中。
  • 采购类和资产类规则本来就不是纯流水规则,直接补最小事实基线才符合真实业务口径。
  • 继续使用“同一 logId 稳定随机命中一部分规则”可以复用现有测试与排障习惯。

6. 模块边界与数据流

6.1 FileService

继续负责生成并持久化规则命中计划。

在现有字段基础上新增两组规则计划:

  • phase2_statement_hit_rules
  • phase2_baseline_hit_rules

职责边界:

  • 只负责决定“这个 logId 抽中了哪些第二期规则”。
  • 不直接构造流水明细,也不直接写数据库业务基线。

6.2 StatementServicestatement_rule_samples.py

继续负责把命中计划转成最小流水样本,并与噪声流水合并后返回。

职责边界:

  • 只生成能通过 ccdi_bank_statement 真实入库后触发的第二期样本。
  • 不为采购、资产等外部事实规则伪造流水替代。

6.3 第二期基线服务

lsfx-mock-server/services/ 下新增一个轻量服务,负责根据 phase2_baseline_hit_rules 幂等写入本地 MySQL 最小事实数据。

职责边界:

  • 只补真实 SQL 所需输入。
  • 不直接写标签结果表,不参与打标逻辑计算。

6.4 主工程

主工程 CcdiFileUploadServiceImpl -> CcdiBankStatement -> CcdiBankTagServiceImpl 链路保持不变。

验收以真实链路为准:

  1. 拉取本行信息或通过兰溪接口获取流水。
  2. 流水成功入库到 ccdi_bank_statement
  3. 执行项目重打标。
  4. ccdi_bank_statement_tag_result 或结果接口中看到抽中的第二期规则命中。

7. 第二期规则分层

7.1 流水样本直接驱动

以下规则以 ccdi_bank_statement 为核心输入,使用 Mock 流水样本驱动:

  • LOW_INCOME_RELATIVE_LARGE_TRANSACTION
  • MULTI_PARTY_GAMBLING_TRANSFER
  • MONTHLY_FIXED_INCOME
  • FIXED_COUNTERPARTY_TRANSFER
  • SALARY_QUICK_TRANSFER
  • SALARY_UNUSED

要求:

  • 样本必须落在同一个真实员工域或其亲属域上。
  • 时间窗口、金额区间、对手方稳定性等聚合条件必须在同一对象范围内闭环。
  • 互斥规则不得使用同一员工样本组。

7.2 数据库基线驱动

以下规则需要外部事实表配合:

  • HOUSE_REGISTRATION_MISMATCH
  • PROPERTY_FEE_REGISTRATION_MISMATCH
  • TAX_ASSET_REGISTRATION_MISMATCH
  • SUPPLIER_CONCENTRATION

处理方式:

  • 三条资产不匹配规则:
    • Mock 生成对应交易流水。
    • 基线服务在 ccdi_asset_info 中补“故意缺失或不匹配”的最小资产事实。
  • SUPPLIER_CONCENTRATION
    • 直接补 ccdi_purchase_transaction 聚合命中基线。
    • 不伪造银行流水替代。

8. 第二期样本设计

8.1 LOW_INCOME_RELATIVE_LARGE_TRANSACTION

  • 选择一个真实员工及其亲属身份证范围。
  • 亲属收入基线维持低收入事实。
  • 生成大额累计转入或转出流水,确保超过低收入亲属的大额交易阈值。

8.2 MULTI_PARTY_GAMBLING_TRANSFER

  • 同一员工对象、同一天、多名不同对手方。
  • 每笔金额落在 MULTI_PARTY_AMT_MIN ~ MULTI_PARTY_AMT_MAX 区间。
  • 命中依赖“多人 + 多次 + 同日 + 区间金额”,不依赖敏感词。

8.3 MONTHLY_FIXED_INCOME

  • 为同一员工构造连续 3 至 4 个月的固定收入转入。
  • 排除工资代发主体和工资关键词。
  • 每月金额稳定高于 MONTHLY_FIXED_INCOME

8.4 FIXED_COUNTERPARTY_TRANSFER

  • 为同一员工与固定对手方构造季度稳定转入。
  • 每季累计金额落在 FIXED_COUNTERPARTY_TRANSFER_MIN ~ FIXED_COUNTERPARTY_TRANSFER_MAX 区间。

8.5 SALARY_QUICK_TRANSFER

  • 先生成可识别工资入账。
  • 再在 24 小时内生成大额转出,满足比例条件。

8.6 SALARY_UNUSED

  • 先生成工资入账。
  • 后续 30 天不生成可计入“工资使用”的消费或转账支出。
  • SALARY_QUICK_TRANSFER 不共用同一员工对象。

8.7 资产不匹配三条规则

  • HOUSE_REGISTRATION_MISMATCH:生成购房交易流水,但不提供可匹配房产登记。
  • PROPERTY_FEE_REGISTRATION_MISMATCH:生成物业缴费流水,但不提供对应房产登记。
  • TAX_ASSET_REGISTRATION_MISMATCH:生成大额纳税流水,但不提供与税费相符的资产登记。

8.8 SUPPLIER_CONCENTRATION

  • 为同一申请人写入多笔采购记录。
  • 使单一供应商采购额占比显著超过 70%。
  • 使用固定业务主键和稳定供应商集合,确保可重复验证。

9. 实现落点

  • Modify: lsfx-mock-server/services/file_service.py
  • Modify: lsfx-mock-server/services/statement_service.py
  • Modify: lsfx-mock-server/services/statement_rule_samples.py
  • Add: lsfx-mock-server/services/phase2_baseline_service.py
  • Add/Modify: lsfx-mock-server/tests/test_file_service.py
  • Add/Modify: lsfx-mock-server/tests/test_statement_service.py
  • Add/Modify: lsfx-mock-server/tests/integration/test_full_workflow.py
  • Add: sql/migration/2026-03-20-lsfx-mock-phase2-hit-baseline.sql

10. 幂等策略

  • 规则命中计划继续由 logId 决定,不新增第二随机源。
  • 流水样本继续由 StatementService 缓存,同一 logId 重复分页读取结果一致。
  • 采购基线使用固定业务主键,按固定主键删后重建。
  • 资产基线使用固定特征组合,确保可精确清理与重建。
  • 所有基线写入都必须只作用于本次选中的员工域,避免污染无关人员。

11. 验证设计

11.1 Mock 单元测试

  • 第二期规则池抽样稳定性。
  • 第二期流水样本只装配被抽中的规则。
  • 第二期数据库基线写入的幂等性。

11.2 Mock 集成测试

  • getJZFileOrZjrcuFile -> getBSByLogId 同一 logId 下结果稳定。
  • 抽中第二期规则时,流水样本与基线写入同步成立。

11.3 主工程端到端验证

  • 拉取本行信息后流水成功入库。
  • 执行项目重打标后,第二期目标规则出现在结果中。
  • 明细型规则可通过流水详情接口回查。
  • 对象型规则可在标签结果表中看到正确 objectType/objectKey/reasonDetail

12. 风险与边界

  • 不为了联调成功去修改主工程真实 SQL。
  • 不把 SUPPLIER_CONCENTRATION 伪造成纯流水命中。
  • 不引入兜底、补丁或兼容性双轨逻辑。
  • 若第二期真实 SQL 与现有基线字段口径不一致,按验证失败暴露,不在 Mock 侧偷偷修正业务规则。

13. 结论

本方案采用“保留第一期稳定随机命中方案 + 为第二期补齐稳定随机命中计划、最小流水样本和幂等数据库基线”的最短路径实现。

这样可以同时保证:

  • 兰溪本地接口能够正确返回并入库存量流水;
  • 第二期新增模型所需输入事实完整;
  • 主工程重打标后能够命中新增模型的真实规则结果。