新增lsfx-mock全命中SQL对齐设计文档

This commit is contained in:
wkc
2026-03-25 09:41:57 +08:00
parent 98430b4c8d
commit 3e8e44ae30

View File

@@ -0,0 +1,364 @@
# 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-server``all` 模式生成策略,让以上 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`
- 对手不是配偶/子女
- 金额必须为 `520``1314`
生成策略:
- 样本主体使用员工本人证件号
- 生成 1 至 2 笔支出或收入流水,金额固定取 `520``1314`
- 对手方名称使用专属固定名称
- 基线服务不为该对手建立“配偶/子女”关系
约束:
- 不再使用 `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. `FileService``all` 模式下构建强命中规则计划。
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. 启动 Mock`main.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 条目标规则逐条落地,不需要修改主工程,也不需要引入额外抽象层。