在银行流水分析中,一笔交易被分错类时,最容易做的事是修改页面文案。这也往往是最危险的事:页面看起来正确了,但后端统计、AI 分析和 Word 报告仍然使用旧结果。

真正有效的排查,需要先画出一条完整数据链路。

一笔交易会经过哪些层

常见的链路可以概括为:

PDF / Excel
  → 原始行解析
  → 统一 Transaction 模型
  → 排除条件与请求配置
  → 分类规则与统计器
  → API 序列化 / AI 摘要
  → 页面与 Word 报告

如果只在最后一层修改名称,前面的统计对象并不会随之改变。所以第一步不是猜一个可能相关的函数,而是选择一笔可复现的真实交易,记录它在每一层的值。

规则命中之前,先检查配置是否真正进入后端

很多分类错误不是规则写错,而是用户在页面上选了新配置,请求却没有带上;或者后端接收到参数,又被默认值覆盖。

可以按固定顺序检查:

  1. 前端状态中的值是什么。
  2. 序列化后的请求体是什么。
  3. 后端路由实际收到什么。
  4. 配置对象进入分析器前是否又被合并或转换。
  5. 规则函数最终使用的是哪个字段。

这个顺序能快速区分“页面显示成功”和“配置实际生效”。

优先级要写成可证明的规则

一条摘要可能同时命中多个关键词。如果优先级仅依赖 if 的排列顺序,后来的维护者很难理解为什么得到这个结果。

更好的方式是把优先级显式化,并返回命中证据:

RULES = [
    {"id": "parking", "priority": 30, "keywords": ["停车"]},
    {"id": "property", "priority": 20, "keywords": ["物业"]},
    {"id": "rent", "priority": 10, "keywords": ["房租", "租金"]},
]

def classify(summary: str):
    for rule in sorted(RULES, key=lambda item: item["priority"], reverse=True):
        for keyword in rule["keywords"]:
            if keyword in summary:
                return {"rule_id": rule["id"], "matched_keyword": keyword}
    return None

这样一来,分类结果不再是一个无法追问的字符串,而是可以被测试和审计的决策记录。

测试要穿过整条链路

单测规则函数只能证明它自己正确。要防止回归,还需要一条从请求配置到报表输出的端到端样例,确认:

  • 新配置可以从前端进入后端。
  • 交易在核心分析层使用正确类别。
  • API 返回、页面统计和 Word 附表读取同一结果。
  • 报表中可以看到规则 ID 与命中关键词。

修复分类问题的核心,是让同一笔交易在所有下游产物中保持同一种含义。当页面、统计、AI 和报表共享同一个事实源时,修复才算真正完成。