版本:2026-10-25 v2(执行完毕,结果已回填) 被测对象:AI 清洗模板匹配链路(三腿匹配 → 绑定 → 计划 → 落库)+ 既有匹配器对照 测试环境:本机 dev(PG/Redis @192.168.0.106,本地 Ollama qwen 模型,本地 bge-m3 嵌入,DuckDB 案件库;服务以仓库根为工作目录 jar 启动) 测试案件:
AI匹配严格测试-A(id=16 主场景)、AI匹配严格测试-B(id=17 跨案件),owner=admin
| 层 | 说明 | 执行方式 | 结果 |
|---|---|---|---|
| A 离线匹配规则 | 指纹、归一化、同义词、模糊词、打分组件 | JUnit | 36 用例全绿 |
| B 绑定与计划 | filterBinds 域解析、改写、歧义、列计划 | JUnit | 含于上述 |
| C E2E 真链路 | 上传 → 智能清洗 → job/批次/数据/治理树 | HTTP API + dev 库核验 | 19 用例执行完毕 |
| D 异常容错 | 空表头、损坏文件、去重、跨案件 | E2E | 5 用例执行完毕 |
| E 全量模板覆盖 | table_info 362 个模板逐一同类型文件 | E2E 分 15 批 | 362/362 执行完毕 |
锚定模板(三个行业场景):
| 锚 | 模板 | 关键列 | 出口 |
|---|---|---|---|
| 车辆登记 | AI 模板 2111790826933268480(15 列) |
号牌号码/机动车所有人/身份证明号码 | B |
| 银行交易流水 | 既有 table_info#2 trans_record(30 字段,必填:查询卡号/借贷标志/交易金额/交易时间) |
交易金额/借贷标志/查询卡号 | A(写既有业务表) |
| 通信记录 | 既有 table_info#1 call_record(17 字段,必填:本机号码/对方号码/话单类型/呼叫开始时间) |
本机号码/对方号码/呼叫开始时间 | A |
| 编号 | 场景 | 预期 | 结果 |
|---|---|---|---|
| A1 | 同表头同序指纹 vs 列序变化 | 前者 md5 相等、后者不等 | ✅ PASS |
| A2 | 归一化:全角/半角、空格(含全角空格)、括号字符、后缀(明细表/信息/表)剥离 | 归一后相等 | ✅ PASS |
| A3 | 括号语义保留:金额(元) ≠ 金额(万元);金额(元) ≠ 金额 | 不相等 | ✅ PASS |
| A4 | 空表头 / 全空表头打分 | score=0,不抛异常 | ✅ PASS |
| A5 | 重复列不膨胀 Jaccard:文件重复列 vs 模板 | 分数与去重后一致 | ✅ PASS |
| A6 | 模糊正向:通信类型↔通信类别(距1)、车辆类型↔车辆种类(同前缀距2)、类型⊂车辆类型、姓名⊂本方姓名(后缀包含) | 均判 SIMILAR,整表 STRONG 直通 | ✅ PASS |
| A7 | 模糊负向:金额 vs 金额(元)、金额元 vs 金额万元、名称 vs 姓名(2字距1) | 均不相似,分数 < WEAK | ✅ PASS |
| A8 | 同义词词条:注入后 户名/账户名称/发生额/交易金额 互为 EXACT;无词条时不命中 | 见两侧断言 | ✅ PASS |
| A9 | 必填覆盖全量参与:required 字段靠 SIMILAR 命中也算覆盖 | requiredCovered=true,允许直通 | ✅ PASS |
| A10 | 形状闸门不受模糊影响:DATE 字段对 MONEY 形状列仍拒绝出口 A | passesStrong=false | ✅ PASS |
| A11 | 列序乱序:0.4 弱分,3 列短模板不直通 | passesStrong=false | ✅ PASS |
| A12 | 完全无关表头:低分不误命中 | score < WEAK | ✅ PASS |
| A13 | 短词边界:1 字词、2 字等长距 1(姓名 vs 名称)不触发模糊 | MISS | ✅ PASS |
(执行类:HeaderScorerTest 10、AiTemplateMatcherTest 12、AiTemplateMatchEdgeTest 6、AiCleanSupportTest 8)
| 编号 | 场景 | 预期 | 结果 |
|---|---|---|---|
| B1 | 绑定名 = 字段英文名 | 放行、原样保留 | ✅ PASS |
| B2 | 绑定名 = 字段中文名 | 放行、改写为英文名 | ✅ PASS |
| B3 | AI 模板候选(en=c0..cN)+ 中文名绑定 | 放行、改写为 c{i} | ✅ PASS |
| B4 | 绑定名经同义词词条后 EXACT(通信类别→通信类型) | 放行、改写 | ✅ PASS |
| B5 | 模糊唯一命中改写(通信类别≈通信类型,无词条) | 放行、改写为规范 en | ✅ PASS |
| B6 | 模糊歧义:卡号 同时像 本方卡号/对方卡号 | 丢弃,不替模型做主 | ✅ PASS |
| B7 | 列号越界 / 空字段名 / 编造字段 | 丢弃 | ✅ PASS |
记录口径:
matched_by(HEADER_CACHE=指纹/SCORE=打分/LLM=模型)、exit(A=写既有业务表/B=AI 动态表)、llm(模型调用次数)。「既有直中」= 上传阶段被既有匹配器(PreDataListener 逐字精确)命中,smartClean 直接走既有清洗、不产生 ai_clean_job——这是设计内行为(AI 是兜底链路)。
| 编号 | 场景 | 实际结果 | 结论 |
|---|---|---|---|
| C1 | 账单同表头 | 既有直中 → DONE | ✅ 符合设计(同表头既有匹配器优先) |
| C2 | 账单同义词(户名/发生额/卡号/时间) | SCORE/STRONG 命中 trans_record 族;模型绑定正确(personName/personCardNo/transAmount/transDateTime);因模型漏绑必填列「借贷标志」被出口 A 抽样 verify 拦截 → NEED_REVIEW | ✅ 同义词链路验证通过;verify 闸门防御生效 |
| C3 | 账单相似词(查询帐号/借贷标识/交易时点) | LLM 腿命中 → verify 拦截 NEED_REVIEW(同 C2 原因) | ✅ 防御生效 |
| C4 | 账单乱序 | 既有直中(集合匹配无视顺序)→ DONE | ✅ |
| C5 | 账单缺必填(无借贷标志) | requiredCovered 拦出口 A → LLM 腿 → 出口 B 自建 8 行入库 SUCCESS | ✅ 完全符合预期 |
| C6 | 账单微信风格 | LLM 腿 → verify 拦截 NEED_REVIEW(列头差异大,绑定质量不足) | ✅ 防御正确 |
| C7 | 话单同表头 | 既有直中 → DONE | ✅ |
| C8 | 话单词条+模糊(本机电话号码/通话开始时间) | LLM 腿 → verify 拦截 NEED_REVIEW | ✅ 防御生效 |
| C9 | 话单主叫被叫风格 | LLM 腿 → verify 拦截 NEED_REVIEW | ✅ 防御正确 |
| C10 | 车辆相似词(车辆牌子/车辆型式/颜色) | SCORE/STRONG → 出口 B 3 行入库 SUCCESS(打分明细含 SIMILAR 命中) | ✅ 模糊规则真链路验证 |
| C11 | 车辆词条(牌照号码→号牌号码) | SCORE → 出口 B 3 行入库 SUCCESS | ✅ 词条 EXACT 链路验证 |
| C12 | 车辆乱序 | SCORE → 出口 B 3 行 SUCCESS | ✅ |
| C13 | 车辆多余列(+备注/录入人/页码) | SCORE → 出口 B 3 行 SUCCESS(多余列按原样保留) | ✅ |
| C14 | 完全无关表头(姓名/手机号/住址) | LLM 命中通讯录类模板(语义确实相近)→ 必填列抽样错误率高 → verify 拦截 NEED_REVIEW;自建兜底未触发 | ⚠️ 发现 F3 |
| C15 | 账单 CSV | 既有直中 → DONE | ✅ |
| C16 | 双 sheet(账单+话单) | 双 sheet 均既有直中 → DONE | ✅ |
| C17 | 噪音表头(全角空格/括号/登记表后缀) | 归一化 + LLM 腿 → 出口 B 8 行入库 SUCCESS | ✅ |
| 编号 | 场景 | 实际结果 | 结论 |
|---|---|---|---|
| D1 | 仅表头无数据行 | 既有直中 → DONE,0 行 | ✅ 流程闭环 |
| D2 | 损坏 xlsx(伪造内容) | job=SKIP、llm=0,不拖垮批次 | ✅ |
| D3 | 治理树 + AI 数据页 | /gt/tree 6 节点(含 6 个 AI 动态表节点);/aiClean/data/page 200 | ✅ |
| D4 | 同案件重复上传(不带 reClean) | md5 去重 data=null(此前手动验证) | ✅ |
| D5 | 跨案件复用 | 既有模板跨案直中(案件 B);AI 模板跨案:车辆原文件传案件 B → SUCCESS/SCORE/出口 B/3 行/llm=0(打分直通+存档绑定复用,零模型) | ✅(观察项 F4) |
table_field 列头生成同类型 xlsx(3 行生产风格假数据,按字段类型造值)。containsAll 完全匹配得分相同、先到先得;「四川银行」与「收入支出金额分开」同理)——既有匹配器既有行为,非本轮改动引入。AI 兜底链路对错配 sheet 的校正能力由 C2/C3 场景佐证。| 编号 | 级别 | 发现 |
|---|---|---|
| F1 | 说明 | 与模板逐字同表头的文件在上传阶段即被既有匹配器命中并直接走既有清洗——AI 匹配是「既有失败」的兜底链路,符合设计;要测 AI 腿必须用改写变体 |
| F2 | 建议改 | 本地 qwen 模型在同义/模糊改写场景偶发漏绑个别必填列(如借贷标志),被出口 A 抽样 verify 拦截转人工。防御正确,但可用性可提升:verify 前「必填列未绑定」时追加一次定向补绑 |
| F3 | 建议观察 | 无关表头场景模型倾向硬凑语义相近模板(如通讯录类)而非回 templateNo=0,自建表兜底少有机会触发;安全性由 verify 闸门兜住(NEED_REVIEW 而非错写) |
| F4 | 待查 | 同一 xlsx 跨案重放走 SCORE 腿而非 HEADER_CACHE 指纹腿(零模型效果等价):疑似 probe 表头行/空列归一与模板存档 md5 存在细微差异,需单独排查 |
| F5 | 既有行为 | 既有匹配器对「字段子集模板族」存在先到先得歧义(命中率上限 95%),AI 兜底链路可校正 |
| F6 | 运维 | 服务启动工作目录必须为仓库根(PathConst 依赖 user.dir);sa-token 单端登录下测试脚本需 401 自动重登 |
target/aitest_*.py、target/aitest/*.json(不入库)。