Files
ccdi/docs/design/2026-03-25-lsfx-mock-all-hit-sql-alignment-design.md

12 KiB
Raw Blame History

lsfx-mock all 模式 SQL 对齐强命中设计

1. 背景

当前 lsfx-mock-server--rule-hit-mode all 已支持为多类规则生成流水样本,但生成策略仍带有早期“语义化样本”特征,未完全对齐主工程真实 SQL 的命中口径。

在最新排查中,以下 5 条已落地真实 SQL 的规则仍无法稳定命中:

  • SPECIAL_AMOUNT_TRANSACTION
  • MONTHLY_FIXED_INCOME
  • SUSPICIOUS_INCOME_KEYWORD
  • FIXED_COUNTERPARTY_TRANSFER
  • LOW_INCOME_RELATIVE_LARGE_TRANSACTION

问题根因不是主工程打标链路异常,而是 Mock 样本和关联表数据与后端 XML SQL 条件不一致:

  • 特殊金额样本金额错误
  • 固定月收入样本月数不足
  • 收入关键词样本摘要不在 SQL 词表内
  • 固定对手转入样本主体落在家属证件号
  • 低收入亲属规则缺少满足阈值的关系表收入基线

本次设计目标是在不修改主工程打标逻辑的前提下,只通过调整 lsfx-mock-serverall 模式生成策略,让以上 5 条真实 SQL 规则稳定命中,并尽量抑制额外噪声命中。

2. 目标

  • 仅针对 --rule-hit-mode all 生效,subset 模式保持现状不变。
  • 仅覆盖后端 XML 中已落地真实 SQL 的规则,不处理占位 SQL。
  • 让上述 5 条规则在真实链路下稳定命中:
    • Mock 返回流水
    • 主工程入库 ccdi_bank_statement
    • 触发重打标
    • ccdi_bank_statement_tag_result 中看到命中结果
  • 允许通过补写最小关联表基线满足 SQL 前置条件。
  • 尽量压住因普通噪声流水导致的误命中或聚合口径污染。

3. 非目标

  • 不修改主工程 ccdi-project 中的 XML SQL、Service 或打标逻辑。
  • 不处理占位 SQL 规则:
    • ABNORMAL_CUSTOMER_TRANSACTION
    • INTEREST_PAYMENT_BY_OTHERS
    • 以及其他仍为 where 1 = 0 的规则
  • 不把 subset 模式升级成同样的强命中模型。
  • 不引入 DSL、规则解释器或额外配置中心。
  • 不做与本次 5 条规则无关的通用重构。

4. 范围

4.1 目标规则

  • SUSPICIOUS_RELATION / SPECIAL_AMOUNT_TRANSACTION
  • SUSPICIOUS_PART_TIME / MONTHLY_FIXED_INCOME
  • SUSPICIOUS_PART_TIME / SUSPICIOUS_INCOME_KEYWORD
  • SUSPICIOUS_PART_TIME / FIXED_COUNTERPARTY_TRANSFER
  • ABNORMAL_TRANSACTION / LOW_INCOME_RELATIVE_LARGE_TRANSACTION

4.2 涉及模块

  • lsfx-mock-server/services/file_service.py
  • lsfx-mock-server/services/statement_service.py
  • lsfx-mock-server/services/statement_rule_samples.py
  • lsfx-mock-server/services/phase2_baseline_service.py
  • lsfx-mock-server/tests/test_file_service.py
  • lsfx-mock-server/tests/test_statement_service.py
  • 视需要补充或调整集成测试

5. 方案对比

5.1 方案 ASQL 镜像驱动强命中

按后端 XML SQL 条件重写 all 模式样本和关联表基线。每条目标规则拥有专属、确定性的输入组,并对噪声数据施加约束。

优点:

  • 与真实 SQL 口径一致
  • 命中稳定,可重复验证
  • 便于定位问题,后续逐条扩展也清晰

缺点:

  • 需要逐条核对 SQL 条件并同步改写样本函数

5.2 方案 B最小命中修补

仅把当前明显不命中的样本做最小修修补补,不系统控制噪声和规则串扰。

优点:

  • 改动量较小

缺点:

  • 容易出现“目标规则命中了,但多出一批误命中”
  • 后续 SQL 小改动后容易再次失效

5.3 方案 C配置化规则生成器

抽象规则配置层,由统一生成器按配置组装样本。

优点:

  • 长期扩展性好

缺点:

  • 明显超出本次最短路径诉求
  • 需要引入新的抽象和维护成本

6. 推荐方案

采用方案 A。

原因:

  • 这是当前最短且逻辑闭环的实现路径。
  • 目标是“真实 SQL 下稳定命中”,因此 Mock 端必须直接对齐 XML 条件,而不是继续依靠语义相近的样本。
  • 只在 all 模式启用该策略,可以在不破坏现有 subset 习惯的前提下完成强命中能力。

7. 设计原则

  • all 模式中的目标规则样本必须是 deterministic 的,不依赖随机碰运气。
  • 每条目标规则都要有独立的命中样本簇,尽量避免多条规则共享同一组核心流水。
  • 规则所需的主体类型必须与 SQL 首层 join 一致:
    • 仅员工本人:样本 cret_no 必须落在 ccdi_base_staff.id_card
    • 依赖家属:样本 cret_no 必须落在 ccdi_staff_fmy_relation.relation_cert_no
  • 对存在聚合或收口条件的规则,必须同时控制背景噪声,避免误触发额外对手方、额外月份或额外支出。
  • 关联表基线只写“命中真实 SQL 所需的最小数据”,并且应可重复写入、可覆盖旧状态。

8. 模块设计

8.1 file_service.py

职责保持为“生成命中计划并记录文件级上下文”,但 all 模式逻辑调整为:

  • 继续保留现有大额交易、第一期、第二期规则计划字段,避免影响调用方结构。
  • 对本次 5 条目标规则,在 all 模式下强制加入计划。
  • 占位 SQL 规则不进入 all 模式强命中计划。
  • 在记录中保留足够的身份上下文,供基线服务和样本服务共享使用。

subset 模式不改。

8.2 statement_rule_samples.py

保留“每条规则一个构造函数”的现有结构,不引入新 DSL。

本次只重写以下函数:

  • build_special_amount_transaction_samples
  • build_monthly_fixed_income_samples
  • build_suspicious_income_keyword_samples
  • build_fixed_counterparty_transfer_samples
  • build_low_income_relative_large_transaction_samples

同时对 all 模式下的噪声样本约束做最小增强,避免干扰:

  • 不制造过多重复 CUSTOMER_ACCOUNT_NAME
  • 不制造额外稳定季度转入
  • 不制造会破坏“工资后无支出”或“固定月收入稳定性”的额外流水

8.3 phase2_baseline_service.py

继续作为关联表最小基线服务使用,但扩展为支持本次规则所需的关系表精确写入。

职责:

  • 针对 LOW_INCOME_RELATIVE_LARGE_TRANSACTION 写入低收入家属基线
  • 针对 SPECIAL_AMOUNT_TRANSACTION 保证目标对手不被识别成配偶/子女
  • 只覆盖规则命中的必要字段,不额外灌入无关主数据

幂等策略:

  • 对既有关系数据,按目标人员主键做“精确覆盖”而不是追加污染
  • 保持同一员工域下重复执行结果一致

9. 规则级生成策略

9.1 SPECIAL_AMOUNT_TRANSACTION

对应 SQL 特征:

  • 员工本人 inner join ccdi_base_staff
  • 对手不是配偶/子女
  • 金额必须为 5201314

生成策略:

  • 样本主体使用员工本人证件号
  • 生成 1 至 2 笔支出或收入流水,金额固定取 5201314
  • 对手方名称使用专属固定名称
  • 基线服务不为该对手建立“配偶/子女”关系

约束:

  • 不再使用 88888.88
  • 不复用现有家庭关系中的配偶、子女姓名,避免误入排除条件

9.2 MONTHLY_FIXED_INCOME

对应 SQL 特征:

  • 员工本人 inner join ccdi_base_staff
  • 近 12 个月至少 6 个月月收入大于阈值
  • 排除工资代发主体和工资摘要
  • 月度波动率不高于 0.3

生成策略:

  • 样本主体切到员工本人
  • 构造连续 6 个月固定转入,每月 1 笔
  • 对手方固定
  • 月金额保持完全一致或极小波动
  • 对手方名称不是本行工资代发主体
  • 摘要不包含工资相关关键词

约束:

  • all 模式噪声流水不能再向该员工叠加大额杂散流入,避免抬高波动率

9.3 SUSPICIOUS_INCOME_KEYWORD

对应 SQL 特征:

  • 员工本人 inner join ccdi_base_staff
  • 收入流水
  • 摘要或交易类型命中收入关键词词表

生成策略:

  • 样本主体使用员工本人
  • 生成 1 笔收入流水
  • 摘要直接使用 SQL 关键词集合中的明确命中词,例如“劳务费发放”或“奖金发放”
  • 交易类型可同步设置为“劳务费”或“代发收入”一类,形成双重保险

约束:

  • 不再使用“咨询返现收入”“合作收入”这类 SQL 不识别的语义词

9.4 FIXED_COUNTERPARTY_TRANSFER

对应 SQL 特征:

  • 员工本人 inner join ccdi_base_staff
  • 近 12 个月内,固定对手方至少 2 个季度累计转入位于区间 [3000,15000]
  • 满足条件的固定对手数量 < 3

生成策略:

  • 样本主体改为员工本人
  • 固定 1 个专属对手方
  • 至少覆盖 2 个季度,建议 2 到 3 个季度
  • 每季度累计转入控制在区间中部,避免靠边界
  • 每季度仅保留 1 笔或少量固定笔数,便于验证

噪声控制:

  • all 模式噪声流水中,员工本人不得再出现过多重复对手方季度转入
  • 避免出现第二、第三个误满足区间条件的稳定对手

9.5 LOW_INCOME_RELATIVE_LARGE_TRANSACTION

对应 SQL 特征:

  • 家属证件号与 ccdi_staff_fmy_relation.relation_cert_no 关联
  • 家属年收入为空、为 0或折月小于 3000
  • 家属累计交易金额大于 100000

生成策略:

  • 使用目标员工的家属证件号作为流水主体
  • 生成 2 笔以上累计超过 100000 的交易
  • 基线服务把该家属 annual_income 精确设置为:
    • 0
    • null
    • 或低于 36000

约束:

  • 不依赖项目库现存家属收入
  • 每次 all 模式生成时都要确保目标家属收入状态被重置到可命中口径

10. 噪声控制设计

当前 StatementService 中的随机噪声会对聚合类规则造成干扰。本次只做最小必要控制:

  • all 模式下继续保留背景噪声,但员工本人使用更收敛的对手方集合
  • 对目标员工:
    • 避免随机制造跨季度重复转入
    • 避免随机制造大量同月对公收入
    • 避免随机制造会抬高 MONTHLY_FIXED_INCOME 波动率的异常大额流入
  • 对家属样本:
    • 避免随机覆盖低收入亲属规则的专属家属域

实现上优先采用“all 模式下缩窄噪声候选集”而不是彻底禁掉噪声。

11. 数据流

  1. FileServiceall 模式下构建强命中规则计划。
  2. phase2_baseline_service 根据计划写入最小关联表基线。
  3. StatementService 根据规则计划生成专属流水样本,并补受控噪声。
  4. 主工程按原流程拉取、入库并执行打标。
  5. 目标规则在结果表中稳定出现命中记录。

12. 测试与验证

12.1 Mock 单元测试

至少补以下断言:

  • SPECIAL_AMOUNT_TRANSACTION 样本金额为 520/1314
  • MONTHLY_FIXED_INCOME 样本月份数不少于 6
  • SUSPICIOUS_INCOME_KEYWORD 摘要或交易类型命中 SQL 关键词
  • FIXED_COUNTERPARTY_TRANSFER 样本主体为员工本人而非家属
  • LOW_INCOME_RELATIVE_LARGE_TRANSACTION 所需家属基线收入满足低收入条件

12.2 联调验证

沿用真实链路验证:

  1. 启动 Mockmain.py --rule-hit-mode all
  2. 拉取流水并导入项目
  3. 触发重打标
  4. 查询 ccdi_bank_statement_tag_result

验收通过标准:

  • 上述 5 条规则全部存在命中记录
  • 命中主体与预期主体一致
  • 没有明显失控的额外噪声命中

13. 风险与控制

风险:

  • 规则间共享主体导致聚合口径互相污染
  • 噪声流水再次引入额外固定对手或异常月收入
  • 关系表覆盖不当污染其他联调项目

控制:

  • 每条目标规则尽量使用独立样本簇
  • all 模式下对目标员工域启用受控噪声
  • 基线服务只覆盖当前命中域,不做全表灌数

14. 实施建议

按以下顺序执行最稳妥:

  1. 先改 5 条样本函数
  2. 再补低收入家属基线写入
  3. 再收紧 all 模式噪声
  4. 最后补单元测试和联调验证

这样可以分层确认:

  • 样本本身对不对
  • 主数据前置条件够不够
  • 噪声是否把聚合口径冲坏

15. 结论

本次采用“只改 all 模式、只改真实 SQL 对应规则、按 XML 口径重写样本与最小基线”的方案,是满足当前需求的最短路径。

设计完成后,后续实施只需围绕 5 条目标规则逐条落地,不需要修改主工程,也不需要引入额外抽象层。