12 KiB
lsfx-mock all 模式 SQL 对齐强命中设计
1. 背景
当前 lsfx-mock-server 的 --rule-hit-mode all 已支持为多类规则生成流水样本,但生成策略仍带有早期“语义化样本”特征,未完全对齐主工程真实 SQL 的命中口径。
在最新排查中,以下 5 条已落地真实 SQL 的规则仍无法稳定命中:
SPECIAL_AMOUNT_TRANSACTIONMONTHLY_FIXED_INCOMESUSPICIOUS_INCOME_KEYWORDFIXED_COUNTERPARTY_TRANSFERLOW_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_TRANSACTIONINTEREST_PAYMENT_BY_OTHERS- 以及其他仍为
where 1 = 0的规则
- 不把
subset模式升级成同样的强命中模型。 - 不引入 DSL、规则解释器或额外配置中心。
- 不做与本次 5 条规则无关的通用重构。
4. 范围
4.1 目标规则
SUSPICIOUS_RELATION / SPECIAL_AMOUNT_TRANSACTIONSUSPICIOUS_PART_TIME / MONTHLY_FIXED_INCOMESUSPICIOUS_PART_TIME / SUSPICIOUS_INCOME_KEYWORDSUSPICIOUS_PART_TIME / FIXED_COUNTERPARTY_TRANSFERABNORMAL_TRANSACTION / LOW_INCOME_RELATIVE_LARGE_TRANSACTION
4.2 涉及模块
lsfx-mock-server/services/file_service.pylsfx-mock-server/services/statement_service.pylsfx-mock-server/services/statement_rule_samples.pylsfx-mock-server/services/phase2_baseline_service.pylsfx-mock-server/tests/test_file_service.pylsfx-mock-server/tests/test_statement_service.py- 视需要补充或调整集成测试
5. 方案对比
5.1 方案 A:SQL 镜像驱动强命中
按后端 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_samplesbuild_monthly_fixed_income_samplesbuild_suspicious_income_keyword_samplesbuild_fixed_counterparty_transfer_samplesbuild_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精确设置为:0null- 或低于
36000
约束:
- 不依赖项目库现存家属收入
- 每次 all 模式生成时都要确保目标家属收入状态被重置到可命中口径
10. 噪声控制设计
当前 StatementService 中的随机噪声会对聚合类规则造成干扰。本次只做最小必要控制:
all模式下继续保留背景噪声,但员工本人使用更收敛的对手方集合- 对目标员工:
- 避免随机制造跨季度重复转入
- 避免随机制造大量同月对公收入
- 避免随机制造会抬高
MONTHLY_FIXED_INCOME波动率的异常大额流入
- 对家属样本:
- 避免随机覆盖低收入亲属规则的专属家属域
实现上优先采用“all 模式下缩窄噪声候选集”而不是彻底禁掉噪声。
11. 数据流
FileService在all模式下构建强命中规则计划。phase2_baseline_service根据计划写入最小关联表基线。StatementService根据规则计划生成专属流水样本,并补受控噪声。- 主工程按原流程拉取、入库并执行打标。
- 目标规则在结果表中稳定出现命中记录。
12. 测试与验证
12.1 Mock 单元测试
至少补以下断言:
SPECIAL_AMOUNT_TRANSACTION样本金额为520/1314MONTHLY_FIXED_INCOME样本月份数不少于6SUSPICIOUS_INCOME_KEYWORD摘要或交易类型命中 SQL 关键词FIXED_COUNTERPARTY_TRANSFER样本主体为员工本人而非家属LOW_INCOME_RELATIVE_LARGE_TRANSACTION所需家属基线收入满足低收入条件
12.2 联调验证
沿用真实链路验证:
- 启动 Mock:
main.py --rule-hit-mode all - 拉取流水并导入项目
- 触发重打标
- 查询
ccdi_bank_statement_tag_result
验收通过标准:
- 上述 5 条规则全部存在命中记录
- 命中主体与预期主体一致
- 没有明显失控的额外噪声命中
13. 风险与控制
风险:
- 规则间共享主体导致聚合口径互相污染
- 噪声流水再次引入额外固定对手或异常月收入
- 关系表覆盖不当污染其他联调项目
控制:
- 每条目标规则尽量使用独立样本簇
- all 模式下对目标员工域启用受控噪声
- 基线服务只覆盖当前命中域,不做全表灌数
14. 实施建议
按以下顺序执行最稳妥:
- 先改 5 条样本函数
- 再补低收入家属基线写入
- 再收紧 all 模式噪声
- 最后补单元测试和联调验证
这样可以分层确认:
- 样本本身对不对
- 主数据前置条件够不够
- 噪声是否把聚合口径冲坏
15. 结论
本次采用“只改 all 模式、只改真实 SQL 对应规则、按 XML 口径重写样本与最小基线”的方案,是满足当前需求的最短路径。
设计完成后,后续实施只需围绕 5 条目标规则逐条落地,不需要修改主工程,也不需要引入额外抽象层。