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

365 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 条目标规则逐条落地,不需要修改主工程,也不需要引入额外抽象层。