Browse Source

test(aiclean): 回填模板匹配修复复测记录与证据

- 报告第 7 节记录 F-01/F-01B/F-03B/F-05/F-06/F-07 复测结果与外部模型端点阻塞
- 新增案件 27 复测样本、执行脚本与 retest_evidence.json
- F-01/F-01B 上传闸门与安全兜底 E2E 通过;F-03B/F-05 E2E 通过;F-06/F-07 单测通过
cc 4 days ago
parent
commit
ccb4be8a12

+ 53 - 6
docs/testing/ai-llm-template-match-bug-report-20261026.md

@@ -22,17 +22,17 @@
 
 | 编号 | 级别 | 问题 | 复现文件 / 任务 | 状态 |
 |---|---|---|---|---|
-| F-01 | **P0** | 交通银行同义表被错误判成「农商行交易流水」模板 48,出口 A 写业务表;因模板缺少必填「本方卡号」,8 行数据全部被拒,业务表 0 行 | `bills/BILL-09_交通银行_同义.xlsx`;案件 24,job `2114558438624731136` | **已修复**(文件侧覆盖率) |
-| F-01B | **P0** | 导出话单/通信记录变体在上传阶段被既有模糊匹配器误判为「通信登记信息」模板 3;话单数据被写进 `call_opening_info`,只保留姓名/号码,通话方向/时间/时长等全部丢失;AI 链路根本没被触发 | `calls/CALL-09_导出话单_同义.xlsx`;案件 25,批次 `2114559120123633664` | **已修复**(部分匹配覆盖率) |
+| F-01 | **P0** | 交通银行同义表被错误判成「农商行交易流水」模板 48,出口 A 写业务表;因模板缺少必填「本方卡号」,8 行数据全部被拒,业务表 0 行 | `bills/BILL-09_交通银行_同义.xlsx`;案件 24,job `2114558438624731136` | **已修复**(复测:上传闸门/兜底通过;模型裁决分支受端点阻塞) |
+| F-01B | **P0** | 导出话单/通信记录变体在上传阶段被既有模糊匹配器误判为「通信登记信息」模板 3;话单数据被写进 `call_opening_info`,只保留姓名/号码,通话方向/时间/时长等全部丢失;AI 链路根本没被触发 | `calls/CALL-09_导出话单_同义.xlsx`;案件 25,批次 `2114559120123633664` | **已修复**(复测:上传阶段通过;模型裁决分支受端点阻塞) |
 | F-01C | P2 | table_info 全量同表头覆盖:364 个模板中 345 正确、16 错配(子集模板先到先得)、3 失败(headers 与 table_field 不一致);12 个模板存在表头字段在 table_field 中不存在 | `full-template/`;`results/full-exact_20261026_113820.json` | 不修复(数据质量) |
 | F-02 | **P1** | 清洗完成统计把非数据行(标题/表头)算成“导入成功”:文件行显示成功 2、失败 8,但业务表 0 行;另一批次 UI 显示 32 条、实际 30 行 | 案件 24 同上;案件 19 批次 `1792983591254364400` | 不修复 |
-| F-03B | **P1** | AI 动态表的 `CALL_DIRECTION` 列把方向字典的整串别名写进单元格(如“主叫,短信发送话单,呼出,01,主叫话单”),不是“主叫/被叫”;账单 AI 表的借贷方向也保留 借/贷/D/C/收/付 原值未归一 | `calls/CALL-02/03/10/18`;`bills/BILL-02` AI 表 | **已修复**(字典反向 + 兜底归一) |
+| F-03B | **P1** | AI 动态表的 `CALL_DIRECTION` 列把方向字典的整串别名写进单元格(如“主叫,短信发送话单,呼出,01,主叫话单”),不是“主叫/被叫”;账单 AI 表的借贷方向也保留 借/贷/D/C/收/付 原值未归一 | `calls/CALL-02/03/10/18`;`bills/BILL-02` AI 表 | **已修复**(复测通过:零模型 HEADER_CACHE 验证) |
 | F-03 | **P1** | 既有清洗对带千分位/货币符号/负号的金额未识别,直接写 `0.00`(1,234.50、-100.00、¥2,300.50、¥88.88、5,000.00 全部变 0.00) | `bills/BILL-01_通用流水_标准.xlsx`;案件 19 `trans_record_all` | 不修复 |
 | F-04 | **P1** | 默认 `max-concurrent=3` 时,本地单会话模型 2/3 调用超过 180s 硬超时并重试,批次卡在 JUDGING;单并发后恢复正常 | 案件 20/21;日志 `logs/backend-test2.log`、`backend-test3.log` | 不修复(环境/配置) |
 | F-04B | **P1** | 文件 AI 识别调度器仍是 `file-ai.max-concurrent=3`;含 txt 的批次会与 AI 清洗争用同一单会话模型,导致 `HTTP header parser received no bytes`、AI 清洗 FAIL/重试 | 案件 26,`EDGE-04_说明.txt` + `EDGE-06`;日志 `logs/backend-test5.log` | 不修复 |
-| F-05 | P2 | 出口 B 新建 AI 表的中文名与既有模板同名(“银行交易流水”/“通信记录”),处理日志只写“已写入 N 行(表 xxx)”,无法区分是既有业务表还是 AI 动态表 | 案件 19 批次 `1792983591254364400` | **已修复**(AI_ 前缀 + 日志点名 AI 动态表) |
-| F-06 | P2 | 出口 A 的二次 `askLlm` 只送 1 个候选,但模型返回 `templateNo=69` 越界序号;该路径不校验序号,仍使用模型 binds | 案件 24 draft 见 `results/bill_20261026_112312.json` | **已修复**(单候选重编号 + 序号校验) |
-| F-07 | P2 | 同义/相似词改写后模型能语义选对模板,但出口 A 的确定性闸门(必填覆盖)不通过,最终建 AI 表而非写既有业务表;用户看到“命中模板”却得到新表 | 案件 19 `BILL-02`/`CALL-02` | **已修复**(日志/备注明确出口 A/B) |
+| F-05 | P2 | 出口 B 新建 AI 表的中文名与既有模板同名(“银行交易流水”/“通信记录”),处理日志只写“已写入 N 行(表 xxx)”,无法区分是既有业务表还是 AI 动态表 | 案件 19 批次 `1792983591254364400` | **已修复**(复测通过:新表名 AI_ 前缀 + 导入备注) |
+| F-06 | P2 | 出口 A 的二次 `askLlm` 只送 1 个候选,但模型返回 `templateNo=69` 越界序号;该路径不校验序号,仍使用模型 binds | 案件 24 draft 见 `results/bill_20261026_112312.json` | **已修复**(单测通过;E2E 受端点阻塞) |
+| F-07 | P2 | 同义/相似词改写后模型能语义选对模板,但出口 A 的确定性闸门(必填覆盖)不通过,最终建 AI 表而非写既有业务表;用户看到“命中模板”却得到新表 | 案件 19 `BILL-02`/`CALL-02` | **已修复**(单测通过;E2E 受端点阻塞) |
 
 ## 3. 详细复现
 
@@ -539,3 +539,50 @@ module/dm/pre/PreDataListenerMatchTest                   # F-01B 上传匹配(
 > (`PreDataListenerRawTest#previewTableFeedsAiLoader` 在整包运行时 `SpringUtil` 解析到真实的
 > `CaseRoutingDataSource`,初始化预览表抛「请先打开案件后再操作数据」;用改动前的代码跑整包同样复现,
 > 该类单独运行通过),本轮未处理。
+
+## 7. 修复复测记录(2026-10-26 12:30–12:37)
+
+> 代码:`6396cac`;后端重启加载最新构建;本地模型单并发。
+> 单测:`mvn -pl ai-server clean test -Dtest='HeaderScorerTest,AiTemplateMatcherTest,AiRecordCleanerTest,AiCleanTableNamingTest,AiSmartCleanServiceTest,PreDataListenerMatchTest'`
+> → **62 tests, 0 failures, 0 errors**(`logs/retest-unit.log`)。
+> 复测样本/结果:`docs/testing/fixtures/ai-llm-match-20261026/retest/`(案件 27)。
+
+| 编号 | 复测方式 | 结果 |
+|---|---|---|
+| F-01 | 新案件上传 BILL-09 同义表 + 智能清洗 | 上传阶段 `SHEET_TEMPLATE_MATCHED_FAIL`(不再直中模板 48);job `SELF_HEADER`、出口 B、8/8 行写入 `AI_交行流水`,业务表未写入。**PASS(修复的错配/丢数据路径已关闭)** |
+| F-01B | 新案件上传 CALL-09/CALL-17/CALL-19/IND-03 | 四者上传全部 `SHEET_TEMPLATE_MATCHED_FAIL`,不再命中模板 3 / 子模板 2084276161 / 596849484;CALL-09/17/19 各自建 AI 表并全列入库 10/10/12 行。**PASS(上传闸门修复生效)**;IND-03 因模型端点异常 `FAIL`,但未写错表。 |
+| F-03B | 复用修复前的 CALL-18 / BILL-02 AI 模板(HEADER_CACHE,零模型) | CALL-18 `CALL_DIRECTION` distinct = `[主叫, 被叫]`;BILL-02 `DEBIT_CREDIT_FLAG` distinct = `[支出, 收入]`。**PASS** |
+| F-05 | 新表命名 + 导入文件备注 | 复测新建表:`AI_交行流水`、`AI_导出话单`、`AI_通信记录日期时间`、`AI_通信记录`、`AI_银行流水`;导入备注均为「AI 新建动态表:AI_xxx」。**PASS** |
+| F-06 | 单测 `AiTemplateMatcherTest#singleCandidateMustAnswerNumberOne` | 通过;模型端点异常,未能在 E2E 中自然复现 `templateNo=69`。**单测 PASS** |
+| F-07 | 单测 `AiSmartCleanServiceTest#exitBLogExplainsExistingTemplateDowngrade` | 通过;模型端点异常,未能在 E2E 中触发“模型命中既有模板但闸门未过”。**单测 PASS** |
+
+### 7.1 复测期间的外部阻塞
+
+复测重启后,本地模型端点出现新异常:
+
+```text
+短提示(如“回复OK”、50 字以内)→ 200 正常流式返回
+长提示(约 150–270 字以上)→ 连接被远端重置:
+  HTTP transport error during streaming: SSE/NDJSON stream failed:
+  java.io.IOException: HTTP/1.1 header parser received no bytes
+```
+
+- 复测批次 7 个文件:6 个因此走 `SELF_HEADER` 安全兜底,1 个(IND-03)`FAIL: 模型未返回可解析的规则草稿`。
+- **这不是本轮修复引入的回归**:同一模型端点在修复前的长提示(6k tokens)可正常返回;本轮复测时短提示正常、长提示断连,属于外部模型服务状态异常。
+- 因此 F-01/F-01B 的**上传闸门、安全兜底、零错表**已 E2E 验证;**模型正确选择模板的 E2E 分支**未能完成,需模型端点恢复后补跑。
+- F-06/F-07 的安全行为已由单测覆盖;E2E 同样受该外部阻塞影响。
+
+### 7.2 复测结论
+
+- 已修复项中,**F-03B、F-05 复测通过(含真实数据页核验)**;**F-01、F-01B 的故障路径(错表/吞文件)已关闭**;**F-06、F-07 单测通过**。
+- 本轮未发现修复引入的新问题:新 AI 表命名、方向值、上传状态、导入备注均符合预期。
+- 待模型端点恢复后,建议补跑 F-01/F-01B 的“模型命中正确模板 → 出口 A”分支,以及 F-07 的 E2E 日志展示。
+- 复测证据:
+  - 已入库:`retest/retest_evidence.json`、`retest/retest_fixes.py`、`retest/RT_*.xlsx`;
+  - 本机日志(`.gitignore` 忽略,不随提交):`retest/retest_run.log`、`logs/backend-retest.log`、`logs/retest-unit.log`。
+
+### 7.3 复测中的残留观察(未列入本轮修复范围)
+
+- **SELF_HEADER 自建表的方向类型未推断**:模型端点异常时,`CALL-18`/`BILL-02` 的新建 AI 表把「呼叫类型/借贷方向」推断为 `TEXT`,数据里仍是 `主叫/被叫/呼入`、`借/贷/D`,没有归一成 `主叫/被叫`、`收入/支出`;而带 `CALL_DIRECTION`/`DEBIT_CREDIT_FLAG` 类型的 HEADER_CACHE 表已正确归一(F-03B 复测通过)。
+- 这是「无模型兜底时按表头名推断类型」的粒度问题,不是 F-03B 字典反向修复本身;是否要扩展到自建表类型推断,建议单独评估。
+- F-05 的 `AI_` 前缀只作用于新建模板;修复前已存在的 AI 模板(HEADER_CACHE 复用)保留原名,这是设计约定,复测中已确认。

+ 1 - 0
docs/testing/ai-llm-template-match-strict-20261026.md

@@ -241,6 +241,7 @@ fixtures/ai-llm-match-20261026/
 ## 6. 执行结果(本轮已跑部分)
 
 > 详细问题、复现文件与日志见 [ai-llm-template-match-bug-report-20261026.md](ai-llm-template-match-bug-report-20261026.md)。
+> 2026-10-26 修复后的复测记录见该报告第 7 节(F-01/F-01B/F-03B/F-05/F-06/F-07)。
 > 本地 27B 模型只支持单并发,单次判定约 40–120s;为保证覆盖优先执行了高价值场景,未跑条目见 §7。
 
 | 组 | 用例 | 结果 |

BIN
docs/testing/fixtures/ai-llm-match-20261026/retest/RT_F01B_CALL-09_导出话单同义.xlsx


BIN
docs/testing/fixtures/ai-llm-match-20261026/retest/RT_F01B_CALL-17_日期时间同义.xlsx


BIN
docs/testing/fixtures/ai-llm-match-20261026/retest/RT_F01B_CALL-19_时长格式.xlsx


BIN
docs/testing/fixtures/ai-llm-match-20261026/retest/RT_F01B_IND-03_开户同义.xlsx


BIN
docs/testing/fixtures/ai-llm-match-20261026/retest/RT_F01_BILL-09_交行同义.xlsx


BIN
docs/testing/fixtures/ai-llm-match-20261026/retest/RT_F03B_F05_CALL-18_方向_新增列.xlsx


BIN
docs/testing/fixtures/ai-llm-match-20261026/retest/RT_F03B_F07_BILL-方向_新增列.xlsx


+ 1304 - 0
docs/testing/fixtures/ai-llm-match-20261026/retest/retest_evidence.json

@@ -0,0 +1,1304 @@
+{
+ "tested_at": "2026-10-26 12:30-12:37",
+ "case_id": 27,
+ "commit": "6396cac",
+ "unit_tests": "62 passed (HeaderScorerTest/AiTemplateMatcherTest/AiRecordCleanerTest/AiCleanTableNamingTest/AiSmartCleanServiceTest/PreDataListenerMatchTest)",
+ "model_endpoint_issue": "本地模型端点在本轮复测时对长提示词(>约150-270字符)直接断连,短提示正常;导致 6/7 AI 判定走 SELF_HEADER、1 个 FAIL。F-01/F-01B 的 AI 裁决分支未完成 E2E,上传闸门与安全兜底已验证。",
+ "upload_batches": {
+  "2114575363429961728": [
+   {
+    "fileName": "2114575365564862464_RT_F03B_F07_BILL-方向_新增列.xlsx",
+    "cleanMode": "AI清洗",
+    "cleanNote": "AI 新建动态表:AI_银行流水",
+    "sheets": [
+     {
+      "sheetName": "银行流水",
+      "status": "SHEET_TEMPLATE_MATCHED_FAIL",
+      "templateId": null,
+      "successNum": 10,
+      "failNum": 0,
+      "cleanNote": "AI 新建动态表:AI_银行流水"
+     }
+    ]
+   },
+   {
+    "fileName": "2114575365350952960_RT_F03B_F05_CALL-18_方向_新增列.xlsx",
+    "cleanMode": "AI清洗",
+    "cleanNote": "AI 新建动态表:AI_通信记录",
+    "sheets": [
+     {
+      "sheetName": "通信记录",
+      "status": "SHEET_TEMPLATE_MATCHED_FAIL",
+      "templateId": null,
+      "successNum": 12,
+      "failNum": 0,
+      "cleanNote": "AI 新建动态表:AI_通信记录"
+     }
+    ]
+   },
+   {
+    "fileName": "2114575365141237760_RT_F01B_IND-03_开户同义.xlsx",
+    "cleanMode": "AI清洗",
+    "cleanNote": "清洗失败:模型未返回可解析的规则草稿",
+    "sheets": [
+     {
+      "sheetName": "开户信息",
+      "status": "SHEET_TEMPLATE_MATCHED_FAIL",
+      "templateId": null,
+      "successNum": 0,
+      "failNum": 0,
+      "cleanNote": "清洗失败:模型未返回可解析的规则草稿"
+     }
+    ]
+   },
+   {
+    "fileName": "2114575364918939648_RT_F01B_CALL-19_时长格式.xlsx",
+    "cleanMode": "AI清洗",
+    "cleanNote": "AI 新建动态表:AI_通信记录",
+    "sheets": [
+     {
+      "sheetName": "通信记录",
+      "status": "SHEET_TEMPLATE_MATCHED_FAIL",
+      "templateId": null,
+      "successNum": 12,
+      "failNum": 0,
+      "cleanNote": "AI 新建动态表:AI_通信记录"
+     }
+    ]
+   },
+   {
+    "fileName": "2114575364713418752_RT_F01B_CALL-17_日期时间同义.xlsx",
+    "cleanMode": "AI清洗",
+    "cleanNote": "AI 新建动态表:AI_通信记录日期时间",
+    "sheets": [
+     {
+      "sheetName": "通信记录日期时间",
+      "status": "SHEET_TEMPLATE_MATCHED_FAIL",
+      "templateId": null,
+      "successNum": 10,
+      "failNum": 0,
+      "cleanNote": "AI 新建动态表:AI_通信记录日期时间"
+     }
+    ]
+   },
+   {
+    "fileName": "2114575364461760512_RT_F01B_CALL-09_导出话单同义.xlsx",
+    "cleanMode": "AI清洗",
+    "cleanNote": "AI 新建动态表:AI_导出话单",
+    "sheets": [
+     {
+      "sheetName": "导出话单",
+      "status": "SHEET_TEMPLATE_MATCHED_FAIL",
+      "templateId": null,
+      "successNum": 10,
+      "failNum": 0,
+      "cleanNote": "AI 新建动态表:AI_导出话单"
+     }
+    ]
+   },
+   {
+    "fileName": "2114575363434156032_RT_F01_BILL-09_交行同义.xlsx",
+    "cleanMode": "AI清洗",
+    "cleanNote": "AI 新建动态表:AI_交行流水",
+    "sheets": [
+     {
+      "sheetName": "交行流水",
+      "status": "SHEET_TEMPLATE_MATCHED_FAIL",
+      "templateId": null,
+      "successNum": 8,
+      "failNum": 0,
+      "cleanNote": "AI 新建动态表:AI_交行流水"
+     }
+    ]
+   }
+  ],
+  "2114577409721831424": [
+   {
+    "fileName": "2114577409944129536_BILL-02_通用流水_同义词.xlsx",
+    "cleanMode": "AI清洗",
+    "cleanNote": "AI 新建动态表:银行流水",
+    "sheets": [
+     {
+      "sheetName": "银行流水",
+      "status": "SHEET_TEMPLATE_MATCHED_FAIL",
+      "templateId": null,
+      "successNum": 10,
+      "failNum": 0,
+      "cleanNote": "AI 新建动态表:银行流水"
+     }
+    ]
+   },
+   {
+    "fileName": "2114577409721831425_CALL-18_主被叫方向.xlsx",
+    "cleanMode": "AI清洗",
+    "cleanNote": "AI 新建动态表:通信记录",
+    "sheets": [
+     {
+      "sheetName": "通信记录",
+      "status": "SHEET_TEMPLATE_MATCHED_FAIL",
+      "templateId": null,
+      "successNum": 12,
+      "failNum": 0,
+      "cleanNote": "AI 新建动态表:通信记录"
+     }
+    ]
+   }
+  ]
+ },
+ "jobs": [
+  {
+   "job_id": 2114575366282088448,
+   "file_name": "2114575363434156032_RT_F01_BILL-09_交行同义.xlsx",
+   "status": "SUCCESS",
+   "exit_code": "B",
+   "matched_by": "SELF_HEADER",
+   "match_tier": "NONE",
+   "ref_template_id": null,
+   "ai_template_id": 2114577148945174528,
+   "llm_calls": 1,
+   "confidence": null,
+   "row_total": 8,
+   "row_loaded": 8,
+   "row_rejected": 0,
+   "fail_reason": null
+  },
+  {
+   "job_id": 2114575366353391616,
+   "file_name": "2114575364461760512_RT_F01B_CALL-09_导出话单同义.xlsx",
+   "status": "SUCCESS",
+   "exit_code": "B",
+   "matched_by": "SELF_HEADER",
+   "match_tier": "NONE",
+   "ref_template_id": null,
+   "ai_template_id": 2114577150471901184,
+   "llm_calls": 1,
+   "confidence": null,
+   "row_total": 10,
+   "row_loaded": 10,
+   "row_rejected": 0,
+   "fail_reason": null
+  },
+  {
+   "job_id": 2114575366399528960,
+   "file_name": "2114575364713418752_RT_F01B_CALL-17_日期时间同义.xlsx",
+   "status": "SUCCESS",
+   "exit_code": "B",
+   "matched_by": "SELF_HEADER",
+   "match_tier": "NONE",
+   "ref_template_id": null,
+   "ai_template_id": 2114577151734386688,
+   "llm_calls": 1,
+   "confidence": null,
+   "row_total": 10,
+   "row_loaded": 10,
+   "row_rejected": 0,
+   "fail_reason": null
+  },
+  {
+   "job_id": 2114575366441472000,
+   "file_name": "2114575364918939648_RT_F01B_CALL-19_时长格式.xlsx",
+   "status": "SUCCESS",
+   "exit_code": "B",
+   "matched_by": "SELF_HEADER",
+   "match_tier": "NONE",
+   "ref_template_id": null,
+   "ai_template_id": 2114577153164644352,
+   "llm_calls": 1,
+   "confidence": null,
+   "row_total": 12,
+   "row_loaded": 12,
+   "row_rejected": 0,
+   "fail_reason": null
+  },
+  {
+   "job_id": 2114575366487609344,
+   "file_name": "2114575365141237760_RT_F01B_IND-03_开户同义.xlsx",
+   "status": "FAIL",
+   "exit_code": null,
+   "matched_by": "SCORE",
+   "match_tier": "STRONG",
+   "ref_template_id": null,
+   "ai_template_id": null,
+   "llm_calls": 1,
+   "confidence": null,
+   "row_total": null,
+   "row_loaded": null,
+   "row_rejected": null,
+   "fail_reason": "模型未返回可解析的规则草稿"
+  },
+  {
+   "job_id": 2114575366521163776,
+   "file_name": "2114575365350952960_RT_F03B_F05_CALL-18_方向_新增列.xlsx",
+   "status": "SUCCESS",
+   "exit_code": "B",
+   "matched_by": "SELF_HEADER",
+   "match_tier": "NONE",
+   "ref_template_id": null,
+   "ai_template_id": 2114577155312128000,
+   "llm_calls": 1,
+   "confidence": null,
+   "row_total": 12,
+   "row_loaded": 12,
+   "row_rejected": 0,
+   "fail_reason": null
+  },
+  {
+   "job_id": 2114575366563106816,
+   "file_name": "2114575365564862464_RT_F03B_F07_BILL-方向_新增列.xlsx",
+   "status": "SUCCESS",
+   "exit_code": "B",
+   "matched_by": "SELF_HEADER",
+   "match_tier": "NONE",
+   "ref_template_id": null,
+   "ai_template_id": 2114577156838854656,
+   "llm_calls": 1,
+   "confidence": null,
+   "row_total": 10,
+   "row_loaded": 10,
+   "row_rejected": 0,
+   "fail_reason": null
+  },
+  {
+   "job_id": 2114577410262896640,
+   "file_name": "2114577409721831425_CALL-18_主被叫方向.xlsx",
+   "status": "SUCCESS",
+   "exit_code": "B",
+   "matched_by": "HEADER_CACHE",
+   "match_tier": "STRONG",
+   "ref_template_id": null,
+   "ai_template_id": 2114559632961183744,
+   "llm_calls": 0,
+   "confidence": "0.9500",
+   "row_total": 12,
+   "row_loaded": 12,
+   "row_rejected": 0,
+   "fail_reason": null
+  },
+  {
+   "job_id": 2114577410325811200,
+   "file_name": "2114577409944129536_BILL-02_通用流水_同义词.xlsx",
+   "status": "SUCCESS",
+   "exit_code": "B",
+   "matched_by": "HEADER_CACHE",
+   "match_tier": "STRONG",
+   "ref_template_id": null,
+   "ai_template_id": 2114552983580147712,
+   "llm_calls": 0,
+   "confidence": "0.9500",
+   "row_total": 10,
+   "row_loaded": 10,
+   "row_rejected": 0,
+   "fail_reason": null
+  }
+ ],
+ "ai_templates": [
+  {
+   "id": "2114552983580147712",
+   "table_name_cn": "银行流水",
+   "headers": "银行名称,客户名称,客户证件号码,查询账号,银行卡号,交易对方名称,交易对方证件号码,交易对方卡号,交易类型,借贷方向,币种,发生额,交易余额,交易时点,交易流水号,对方余额,交易对方账号开户行,交易摘要,交易网点名称,交易网点代码,现金标志,终端号,交易发生地,商户名称,商户号,IP地址,MAC地址,交易柜员号,交易渠道,备注",
+   "status": "ONLINE",
+   "fields": [
+    {
+     "column_name": "c0",
+     "field_name_cn": "银行名称",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c1",
+     "field_name_cn": "客户名称",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c2",
+     "field_name_cn": "客户证件号码",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c3",
+     "field_name_cn": "查询账号",
+     "field_type": "ACCT_CARD_NO",
+     "required": 0
+    },
+    {
+     "column_name": "c4",
+     "field_name_cn": "银行卡号",
+     "field_type": "ACCT_CARD_NO",
+     "required": 1
+    },
+    {
+     "column_name": "c5",
+     "field_name_cn": "交易对方名称",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c6",
+     "field_name_cn": "交易对方证件号码",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c7",
+     "field_name_cn": "交易对方卡号",
+     "field_type": "ACCT_CARD_NO",
+     "required": 0
+    },
+    {
+     "column_name": "c8",
+     "field_name_cn": "交易类型",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c9",
+     "field_name_cn": "借贷方向",
+     "field_type": "DEBIT_CREDIT_FLAG",
+     "required": 1
+    },
+    {
+     "column_name": "c10",
+     "field_name_cn": "币种",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c11",
+     "field_name_cn": "发生额",
+     "field_type": "MONEY",
+     "required": 1
+    },
+    {
+     "column_name": "c12",
+     "field_name_cn": "交易余额",
+     "field_type": "MONEY",
+     "required": 0
+    },
+    {
+     "column_name": "c13",
+     "field_name_cn": "交易时点",
+     "field_type": "DATE_TIME",
+     "required": 1
+    },
+    {
+     "column_name": "c14",
+     "field_name_cn": "交易流水号",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c15",
+     "field_name_cn": "对方余额",
+     "field_type": "MONEY",
+     "required": 0
+    },
+    {
+     "column_name": "c16",
+     "field_name_cn": "交易对方账号开户行",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c17",
+     "field_name_cn": "交易摘要",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c18",
+     "field_name_cn": "交易网点名称",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c19",
+     "field_name_cn": "交易网点代码",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c20",
+     "field_name_cn": "现金标志",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c21",
+     "field_name_cn": "终端号",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c22",
+     "field_name_cn": "交易发生地",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c23",
+     "field_name_cn": "商户名称",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c24",
+     "field_name_cn": "商户号",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c25",
+     "field_name_cn": "IP地址",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c26",
+     "field_name_cn": "MAC地址",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c27",
+     "field_name_cn": "交易柜员号",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c28",
+     "field_name_cn": "交易渠道",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c29",
+     "field_name_cn": "备注",
+     "field_type": "TEXT",
+     "required": 0
+    }
+   ],
+   "direction_values": {
+    "借贷方向": [
+     "支出",
+     "收入"
+    ]
+   }
+  },
+  {
+   "id": "2114559632961183744",
+   "table_name_cn": "通信记录",
+   "headers": "使用人姓名,本机电话号码,对方号码,呼叫类型,呼叫开始时间,呼叫时长,本机LAC号,本机cellid,对方姓名,使用人证件号码,对方证件号码,本机号码归属地,对方号码归属地,本机归属运营商,通话类型,备注,通话所在地",
+   "status": "ONLINE",
+   "fields": [
+    {
+     "column_name": "c0",
+     "field_name_cn": "使用人姓名",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c1",
+     "field_name_cn": "本机电话号码",
+     "field_type": "PHONE",
+     "required": 1
+    },
+    {
+     "column_name": "c2",
+     "field_name_cn": "对方号码",
+     "field_type": "PHONE",
+     "required": 1
+    },
+    {
+     "column_name": "c3",
+     "field_name_cn": "呼叫类型",
+     "field_type": "CALL_DIRECTION",
+     "required": 1
+    },
+    {
+     "column_name": "c4",
+     "field_name_cn": "呼叫开始时间",
+     "field_type": "DATE_TIME",
+     "required": 1
+    },
+    {
+     "column_name": "c5",
+     "field_name_cn": "呼叫时长",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c6",
+     "field_name_cn": "本机LAC号",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c7",
+     "field_name_cn": "本机cellid",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c8",
+     "field_name_cn": "对方姓名",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c9",
+     "field_name_cn": "使用人证件号码",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c10",
+     "field_name_cn": "对方证件号码",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c11",
+     "field_name_cn": "本机号码归属地",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c12",
+     "field_name_cn": "对方号码归属地",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c13",
+     "field_name_cn": "本机归属运营商",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c14",
+     "field_name_cn": "通话类型",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c15",
+     "field_name_cn": "备注",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c16",
+     "field_name_cn": "通话所在地",
+     "field_type": "TEXT",
+     "required": 0
+    }
+   ],
+   "direction_values": {
+    "呼叫类型": [
+     "主叫",
+     "被叫"
+    ]
+   }
+  },
+  {
+   "id": "2114577148945174528",
+   "table_name_cn": "AI_交行流水",
+   "headers": "银行卡号,借贷方向,发生额,交易日期,交易时间,姓名,对方户名,对方帐号,余额,对方金融机构网点名称,备注",
+   "status": "ONLINE",
+   "fields": [
+    {
+     "column_name": "c0",
+     "field_name_cn": "银行卡号",
+     "field_type": "ACCT_CARD_NO",
+     "required": 0
+    },
+    {
+     "column_name": "c1",
+     "field_name_cn": "借贷方向",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c2",
+     "field_name_cn": "发生额",
+     "field_type": "MONEY",
+     "required": 0
+    },
+    {
+     "column_name": "c3",
+     "field_name_cn": "交易日期",
+     "field_type": "DATE",
+     "required": 0
+    },
+    {
+     "column_name": "c4",
+     "field_name_cn": "交易时间",
+     "field_type": "TIME",
+     "required": 0
+    },
+    {
+     "column_name": "c5",
+     "field_name_cn": "姓名",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c6",
+     "field_name_cn": "对方户名",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c7",
+     "field_name_cn": "对方帐号",
+     "field_type": "ACCT_CARD_NO",
+     "required": 0
+    },
+    {
+     "column_name": "c8",
+     "field_name_cn": "余额",
+     "field_type": "MONEY",
+     "required": 0
+    },
+    {
+     "column_name": "c9",
+     "field_name_cn": "对方金融机构网点名称",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c10",
+     "field_name_cn": "备注",
+     "field_type": "TEXT",
+     "required": 0
+    }
+   ],
+   "direction_values": {}
+  },
+  {
+   "id": "2114577150471901184",
+   "table_name_cn": "AI_导出话单",
+   "headers": "本机号码,对方号码,通话类型,通话时间,使用人姓名,通话时长,本方基站大区号,本方基站小区号,本方证件号码,本方号码归属地,对方号码归属地",
+   "status": "ONLINE",
+   "fields": [
+    {
+     "column_name": "c0",
+     "field_name_cn": "本机号码",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c1",
+     "field_name_cn": "对方号码",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c2",
+     "field_name_cn": "通话类型",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c3",
+     "field_name_cn": "通话时间",
+     "field_type": "DATE_TIME",
+     "required": 0
+    },
+    {
+     "column_name": "c4",
+     "field_name_cn": "使用人姓名",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c5",
+     "field_name_cn": "通话时长",
+     "field_type": "NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c6",
+     "field_name_cn": "本方基站大区号",
+     "field_type": "NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c7",
+     "field_name_cn": "本方基站小区号",
+     "field_type": "NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c8",
+     "field_name_cn": "本方证件号码",
+     "field_type": "ID_CARD_NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c9",
+     "field_name_cn": "本方号码归属地",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c10",
+     "field_name_cn": "对方号码归属地",
+     "field_type": "PHONE",
+     "required": 0
+    }
+   ],
+   "direction_values": {}
+  },
+  {
+   "id": "2114577151734386688",
+   "table_name_cn": "AI_通信记录日期时间",
+   "headers": "使用人姓名,本机号码,对方号码,话单类型,通话日期时间,通话时间,呼叫时长,本机LAC号,本机cellid,对方姓名,使用人证件号码,对方证件号码,本机号码归属地,对方号码归属地,本机归属运营商,通话类型,备注,通话所在地",
+   "status": "ONLINE",
+   "fields": [
+    {
+     "column_name": "c0",
+     "field_name_cn": "使用人姓名",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c1",
+     "field_name_cn": "本机号码",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c2",
+     "field_name_cn": "对方号码",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c3",
+     "field_name_cn": "话单类型",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c4",
+     "field_name_cn": "通话日期时间",
+     "field_type": "DATE",
+     "required": 0
+    },
+    {
+     "column_name": "c5",
+     "field_name_cn": "通话时间",
+     "field_type": "TIME",
+     "required": 0
+    },
+    {
+     "column_name": "c6",
+     "field_name_cn": "呼叫时长",
+     "field_type": "NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c7",
+     "field_name_cn": "本机LAC号",
+     "field_type": "NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c8",
+     "field_name_cn": "本机cellid",
+     "field_type": "NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c9",
+     "field_name_cn": "对方姓名",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c10",
+     "field_name_cn": "使用人证件号码",
+     "field_type": "ID_CARD_NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c11",
+     "field_name_cn": "对方证件号码",
+     "field_type": "ID_CARD_NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c12",
+     "field_name_cn": "本机号码归属地",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c13",
+     "field_name_cn": "对方号码归属地",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c14",
+     "field_name_cn": "本机归属运营商",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c15",
+     "field_name_cn": "通话类型",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c16",
+     "field_name_cn": "备注",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c17",
+     "field_name_cn": "通话所在地",
+     "field_type": "TEXT",
+     "required": 0
+    }
+   ],
+   "direction_values": {}
+  },
+  {
+   "id": "2114577153164644352",
+   "table_name_cn": "AI_通信记录",
+   "headers": "使用人姓名,本机号码,对方号码,呼叫类型,呼叫开始时间,通话时长,本机LAC号,本机cellid,对方姓名,使用人证件号码,对方证件号码,本机号码归属地,对方号码归属地,本机归属运营商,通话类型,备注,通话所在地",
+   "status": "ONLINE",
+   "fields": [
+    {
+     "column_name": "c0",
+     "field_name_cn": "使用人姓名",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c1",
+     "field_name_cn": "本机号码",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c2",
+     "field_name_cn": "对方号码",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c3",
+     "field_name_cn": "呼叫类型",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c4",
+     "field_name_cn": "呼叫开始时间",
+     "field_type": "DATE_TIME",
+     "required": 0
+    },
+    {
+     "column_name": "c5",
+     "field_name_cn": "通话时长",
+     "field_type": "NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c6",
+     "field_name_cn": "本机LAC号",
+     "field_type": "NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c7",
+     "field_name_cn": "本机cellid",
+     "field_type": "NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c8",
+     "field_name_cn": "对方姓名",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c9",
+     "field_name_cn": "使用人证件号码",
+     "field_type": "ID_CARD_NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c10",
+     "field_name_cn": "对方证件号码",
+     "field_type": "ID_CARD_NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c11",
+     "field_name_cn": "本机号码归属地",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c12",
+     "field_name_cn": "对方号码归属地",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c13",
+     "field_name_cn": "本机归属运营商",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c14",
+     "field_name_cn": "通话类型",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c15",
+     "field_name_cn": "备注",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c16",
+     "field_name_cn": "通话所在地",
+     "field_type": "TEXT",
+     "required": 0
+    }
+   ],
+   "direction_values": {}
+  },
+  {
+   "id": "2114577155312128000",
+   "table_name_cn": "AI_通信记录",
+   "headers": "使用人姓名,本机电话号码,对方号码,呼叫类型,呼叫开始时间,呼叫时长,本机LAC号,本机cellid,对方姓名,使用人证件号码,对方证件号码,本机号码归属地,对方号码归属地,本机归属运营商,通话类型,备注,通话所在地,数据来源",
+   "status": "ONLINE",
+   "fields": [
+    {
+     "column_name": "c0",
+     "field_name_cn": "使用人姓名",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c1",
+     "field_name_cn": "本机电话号码",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c2",
+     "field_name_cn": "对方号码",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c3",
+     "field_name_cn": "呼叫类型",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c4",
+     "field_name_cn": "呼叫开始时间",
+     "field_type": "DATE_TIME",
+     "required": 0
+    },
+    {
+     "column_name": "c5",
+     "field_name_cn": "呼叫时长",
+     "field_type": "NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c6",
+     "field_name_cn": "本机LAC号",
+     "field_type": "NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c7",
+     "field_name_cn": "本机cellid",
+     "field_type": "NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c8",
+     "field_name_cn": "对方姓名",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c9",
+     "field_name_cn": "使用人证件号码",
+     "field_type": "ID_CARD_NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c10",
+     "field_name_cn": "对方证件号码",
+     "field_type": "ID_CARD_NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c11",
+     "field_name_cn": "本机号码归属地",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c12",
+     "field_name_cn": "对方号码归属地",
+     "field_type": "PHONE",
+     "required": 0
+    },
+    {
+     "column_name": "c13",
+     "field_name_cn": "本机归属运营商",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c14",
+     "field_name_cn": "通话类型",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c15",
+     "field_name_cn": "备注",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c16",
+     "field_name_cn": "通话所在地",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c17",
+     "field_name_cn": "数据来源",
+     "field_type": "TEXT",
+     "required": 0
+    }
+   ],
+   "direction_values": {}
+  },
+  {
+   "id": "2114577156838854656",
+   "table_name_cn": "AI_银行流水",
+   "headers": "银行名称,客户名称,客户证件号码,查询账号,银行卡号,交易对方名称,交易对方证件号码,交易对方卡号,交易类型,借贷方向,币种,发生额,交易余额,交易时点,交易流水号,对方余额,交易对方账号开户行,交易摘要,交易网点名称,交易网点代码,现金标志,终端号,交易发生地,商户名称,商户号,IP地址,MAC地址,交易柜员号,交易渠道,备注,数据来源",
+   "status": "ONLINE",
+   "fields": [
+    {
+     "column_name": "c0",
+     "field_name_cn": "银行名称",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c1",
+     "field_name_cn": "客户名称",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c2",
+     "field_name_cn": "客户证件号码",
+     "field_type": "ID_CARD_NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c3",
+     "field_name_cn": "查询账号",
+     "field_type": "ACCT_CARD_NO",
+     "required": 0
+    },
+    {
+     "column_name": "c4",
+     "field_name_cn": "银行卡号",
+     "field_type": "ACCT_CARD_NO",
+     "required": 0
+    },
+    {
+     "column_name": "c5",
+     "field_name_cn": "交易对方名称",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c6",
+     "field_name_cn": "交易对方证件号码",
+     "field_type": "ID_CARD_NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c7",
+     "field_name_cn": "交易对方卡号",
+     "field_type": "ACCT_CARD_NO",
+     "required": 0
+    },
+    {
+     "column_name": "c8",
+     "field_name_cn": "交易类型",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c9",
+     "field_name_cn": "借贷方向",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c10",
+     "field_name_cn": "币种",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c11",
+     "field_name_cn": "发生额",
+     "field_type": "MONEY",
+     "required": 0
+    },
+    {
+     "column_name": "c12",
+     "field_name_cn": "交易余额",
+     "field_type": "MONEY",
+     "required": 0
+    },
+    {
+     "column_name": "c13",
+     "field_name_cn": "交易时点",
+     "field_type": "DATE_TIME",
+     "required": 0
+    },
+    {
+     "column_name": "c14",
+     "field_name_cn": "交易流水号",
+     "field_type": "ID_CARD_NUMBER",
+     "required": 0
+    },
+    {
+     "column_name": "c15",
+     "field_name_cn": "对方余额",
+     "field_type": "MONEY",
+     "required": 0
+    },
+    {
+     "column_name": "c16",
+     "field_name_cn": "交易对方账号开户行",
+     "field_type": "ACCT_CARD_NO",
+     "required": 0
+    },
+    {
+     "column_name": "c17",
+     "field_name_cn": "交易摘要",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c18",
+     "field_name_cn": "交易网点名称",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c19",
+     "field_name_cn": "交易网点代码",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c20",
+     "field_name_cn": "现金标志",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c21",
+     "field_name_cn": "终端号",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c22",
+     "field_name_cn": "交易发生地",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c23",
+     "field_name_cn": "商户名称",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c24",
+     "field_name_cn": "商户号",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c25",
+     "field_name_cn": "IP地址",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c26",
+     "field_name_cn": "MAC地址",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c27",
+     "field_name_cn": "交易柜员号",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c28",
+     "field_name_cn": "交易渠道",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c29",
+     "field_name_cn": "备注",
+     "field_type": "TEXT",
+     "required": 0
+    },
+    {
+     "column_name": "c30",
+     "field_name_cn": "数据来源",
+     "field_type": "TEXT",
+     "required": 0
+    }
+   ],
+   "direction_values": {}
+  }
+ ],
+ "conclusions": {
+  "F-01": "PASS(上传不再命中模板48;BILL-09 以 SELF_HEADER 建 AI_交行流水 8/8 行,无业务表写入;模型裁决分支受端点阻塞)",
+  "F-01B": "PASS(上传阶段 CALL-09/CALL-17/CALL-19/IND-03 全部 SHEET_TEMPLATE_MATCHED_FAIL,不再命中模板3/子模板;3 个话单自建表全列入库;IND-03 AI 分支受端点阻塞 FAIL)",
+  "F-03B": "PASS(HEADER_CACHE 零模型:CALL_DIRECTION=[主叫,被叫],DEBIT_CREDIT_FLAG=[支出,收入])",
+  "F-05": "PASS(新 AI 表名全部 AI_ 前缀;导入备注 AI 新建动态表:AI_xxx)",
+  "F-06": "PASS(单测);E2E 受模型端点阻塞",
+  "F-07": "PASS(单测);E2E 受模型端点阻塞"
+ }
+}

+ 130 - 0
docs/testing/fixtures/ai-llm-match-20261026/retest/retest_fixes.py

@@ -0,0 +1,130 @@
+# -*- coding: utf-8 -*-
+"""F-01/F-01B/F-03B/F-05/F-07 真实链路复测(F-06 由单测覆盖)。"""
+import json
+import os
+import sys
+import time
+
+import requests
+
+BASE = os.path.dirname(os.path.abspath(__file__))
+FIXTURES = os.path.dirname(BASE)
+sys.path.insert(0, FIXTURES)
+import run_tests as rt  # noqa: E402
+
+CASE_ID = 27
+rt.CASE_ID = CASE_ID
+sys.stdout.reconfigure(encoding="utf-8")
+
+
+def log(msg):
+    print(msg, flush=True)
+
+
+FILES = [
+    # (测试点, 文件名)
+    ("F-01", "RT_F01_BILL-09_交行同义.xlsx"),
+    ("F-01B", "RT_F01B_CALL-09_导出话单同义.xlsx"),
+    ("F-01B", "RT_F01B_CALL-17_日期时间同义.xlsx"),
+    ("F-01B", "RT_F01B_CALL-19_时长格式.xlsx"),
+    ("F-01B", "RT_F01B_IND-03_开户同义.xlsx"),
+    ("F-03B/F-05", "RT_F03B_F05_CALL-18_方向_新增列.xlsx"),
+    ("F-03B/F-07", "RT_F03B_F07_BILL-方向_新增列.xlsx"),
+]
+
+
+def ai_data_page(c, tpl_id, size=30):
+    r = c.request("GET", "/aiClean/data/page",
+                  params={"aiTemplateId": tpl_id, "page": 1, "size": size}, timeout=60)
+    j = r.json() or {}
+    return (j.get("data") or {})
+
+
+def main():
+    c = rt.Client()
+    c.open_case()
+    batch_id = None
+    roots = []
+    recs = []
+    log("== 上传 ==")
+    for point, name in FILES:
+        path = os.path.join(BASE, name)
+        with open(path, "rb") as f:
+            r = c.request("POST", "/dm/preFileUpload", params=({"batchId": batch_id} if batch_id else {}),
+                          files={"file": (name, f)}, timeout=120)
+        data = (r.json() or {}).get("data")
+        if not data:
+            log(f"  {name}: DATA_NULL {(r.json() or {}).get('message')}")
+            recs.append(dict(point=point, file=name, upload="DATA_NULL"))
+            continue
+        batch_id = batch_id or data.get("batchId")
+        roots.append(data)
+        sheets = []
+        for ch in data.get("children") or []:
+            sheets.append(dict(sheet_id=ch.get("id"), sheet_name=ch.get("sheetName"),
+                               status=ch.get("fileStatus"), template_id=ch.get("templateId"),
+                               data_num=ch.get("dataNum")))
+        log(f"  {name}: {[(s['sheet_name'], s['status'], s['template_id']) for s in sheets]}")
+        recs.append(dict(point=point, file=name, file_id=data.get("id"),
+                         batch_id=data.get("batchId"), sheets=sheets))
+
+    log(f"batch={batch_id}; 发起智能清洗")
+    sc = c.smart_clean(roots)
+    log(f"smartClean: {sc.get('code')} {sc.get('message')} data={sc.get('data')}")
+    if sc.get("code") != 200 or not sc.get("data"):
+        json.dump(recs, open(os.path.join(BASE, "retest_result.json"), "w", encoding="utf-8"),
+                  ensure_ascii=False, indent=1, default=str)
+        return
+
+    t0 = time.time()
+    final = None
+    while time.time() - t0 < 1800:
+        st = c.status(batch_id)
+        if st and st.get("stage") in ("DONE", "PARTIAL", "FAILED"):
+            final = st
+            break
+        time.sleep(3)
+    log(f"batch final={final}")
+
+    sheet_ids = [s["sheet_id"] for r in recs for s in r.get("sheets") or []]
+    jobs = rt.db_jobs(sheet_ids)
+    for rec in recs:
+        rec["jobs"] = []
+        for s in rec.get("sheets") or []:
+            job = jobs.get(int(s["sheet_id"])) if s.get("sheet_id") else None
+            s["job"] = job
+            if job:
+                rec["jobs"].append(job)
+        rec["ai_templates"] = []
+        for j in rec["jobs"]:
+            tid = j.get("ai_template_id")
+            if tid:
+                rec["ai_templates"].append(rt.db_ai_template(tid))
+        log(f"\n[{rec['point']}] {rec['file']}")
+        for j in rec["jobs"]:
+            log(f"  job={j['job_id']} status={j['status']} exit={j['exit_code']} by={j['matched_by']} "
+                f"tier={j['match_tier']} ref={j['ref_template_id']} ai={j['ai_template_id']} "
+                f"llm={j['llm_calls']} conf={j['confidence']} rows={j['row_total']}/{j['row_loaded']} "
+                f"fail={j['fail_reason']}")
+            tpl_id = j.get("ai_template_id")
+            tpl = next((t for t in rec["ai_templates"] if t and str(t["id"]) == str(tpl_id)), None)
+            if tpl:
+                log(f"  AI表名={tpl['table_name_cn']!r} headers={tpl['headers'][:80]!r}")
+                # 方向字段核验
+                dir_cols = [f for f in tpl.get("fields") or []
+                            if f.get("field_type") in ("CALL_DIRECTION", "DEBIT_CREDIT_FLAG")]
+                if dir_cols:
+                    data = ai_data_page(c, tpl["id"], 30)
+                    recs_data = (data.get("pages") or {}).get("records") or []
+                    for f in dir_cols:
+                        vals = sorted({str(r.get(f["column_name"])) for r in recs_data if r.get(f["column_name"]) is not None})
+                        log(f"  direction field {f['field_name_cn']} ({f['field_type']}) distinct={vals[:10]}")
+                        rec.setdefault("direction_values", {})[f["field_name_cn"]] = vals[:10]
+
+    json.dump(recs, open(os.path.join(BASE, "retest_result.json"), "w", encoding="utf-8"),
+              ensure_ascii=False, indent=1, default=str)
+    log("\nresult -> retest_result.json")
+
+
+if __name__ == "__main__":
+    main()