# Bank Flow Reconciliation

> 银行流水合并与核对工具。支持多银行多格式流水文件的智能合并（标准化为统一12列格式）， 以及银行流水与序时账（总账）的自动化双向核对（9层递进匹配引擎）。 当用户提到"银行流水核对""流水核对""银行流水合并""合并流水""流水匹配""银行存款核对" "对账""核对银行流水""bank reconciliation""流水对账""多账号流水合并""银行流水审计" "核对银行存款""序时账核对"时触发。 即使用户只说"帮我核对下银行流水"或"把这几个银行的流水合到一起"也应触发。 审计场景中涉及银行存款测试、资金核对时优先使用此 skill。

- Skill: `nigo81/bank-flow-reconciliation` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add nigo81/bank-flow-reconciliation`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nigo81/bank-flow-reconciliation/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: nigo81 (https://skillmd.com/u/nigo81)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/nigo81/bank-flow-reconciliation

---


> **作者**：nigo（涂佳兵） | **微信公众号**：逆行的狗
>
> 审计实务 + 数字化工具，分享审计效率提升的实战经验。

# 银行流水合并与核对

## 概述

三个脚本，按工作流顺序：

1. **预检查** (`scripts/bankflow_precheck.py`)：读取文件，输出列名、样本行、金额统计、科目分布。只探查不判断。
2. **流水合并** (`scripts/bankflow_merge.py`)：多银行多格式流水 → 统一12列标准化Excel
3. **流水核对** (`scripts/bankflow_reconcile.py`)：银行流水 vs 序时账，9层递进匹配，输出核对底稿

AI 的工作：运行脚本 → 看输出 → 填配置 → 运行脚本 → 问用户要不要 AI 复核。匹配逻辑全在代码里，AI 不需要理解引擎内部。

## 数据准备

核对需要两份数据：**序时账**（总账/明细账）和**银行流水**。

### 序时账必需字段

| 要素 | 说明 |
|------|------|
| 银行存款科目行 | 科目代码通常以 1002 开头。无科目代码列时可用科目名称"银行存款"代替 |
| 日期列 | 记账日期或凭证日期 |
| 借方/贷方金额列 | 两列分开，不能只有一列带正负号的金额 |
| 凭证号列 | 识别同一笔凭证的多行分录 |
| 摘要列 | L2 匹配层的关键信息源 |
| **客商信息** | ⭐ **决定性因素**。有客商→匹配率 90%+，无客商→30-50% |

### ⭐ 客商信息（两种来源，二选一）

| 来源 | 配置 | 场景 |
|------|------|------|
| **①客商辅助核算列** | `客商辅助项列名: "客户,供应商"` | 用友/金蝶标准账套，客商在对方科目行的辅助核算项中（**拆分模式**） |
| **②交易对手列** | `交易对手列名: "往来单位名称"` | 银行存款行上有独立的"往来单位"/"交易对手"列（**直接模式**，匹配率更高） |

直接模式实证 92.6%，拆分模式 78.5%。优先直接模式，银行存款行无客商值时才用拆分模式。

### 银行流水必需字段

| 要素 | 说明 |
|------|------|
| 交易日期 | 每笔交易日期 |
| 金额（借/贷 或 收/支） | 两列分开 |
| 对方户名 | 强烈建议，与序时账客商交叉匹配 |
| 摘要 | L2 匹配线索 |

文件格式 `.xlsx`/`.xls`/`.csv` 均可，表头不在第一行或尾部有汇总行都能处理。

---

## 工作流程

### 第1步：判断任务类型

- **仅合并**：多个银行流水 → 一个标准化Excel
- **仅核对**：已有标准化流水 → 与序时账核对
- **合并+核对**：先合并再核对

用户说"核对"但提供了多个银行的流水文件 → 通常需要先合并。

### 第2步：运行预检查

```bash
python SKILL_DIR/scripts/bankflow_precheck.py \
  --gl "序时账.xlsx" \
  --bank "银行流水.xls" \
  --bank-subject "1002"
```

输出：文件格式、列名、前3行样本、金额统计、**候选客商列诊断表**（列名+非空率+样本值）、银行科目分布、主体列分布。AI 看这些信息做第3步的判断。

> 常用参数：`--gl-subject-col`（科目代码列名）、`--bank-subject-name`（按名称过滤）、`--bank-header-row`（跳过前置行）。全表见 `references/配置参数详解.md`。

### 第3步：做判断

看预检查输出，做 4 个决策：

#### 决策1：列映射

根据列名和样本值确定配置中各字段对应哪列。看实际列名，不凭猜测——"科目编号"/"科目代码"/"科目编码"在不同软件中叫法不同。

**陷阱提醒**：
- **无科目代码列**：用科目名称列代替，配 `科目代码列名: "科目名称"`, `银行科目代码: "银行存款"`
- **科目代码混在编码列**（如"1002/8111001012600894851"）：直接用该列，配 `银行科目代码: "1002"`，引擎 startswith 天然处理
- **假客商陷阱**：`交易对手`列 100% 非空但样本值是银行账户名（如"中国农业银行墨江县支行007316"）→ 不是真客商。看样本值判断，不被非空率迷惑。真客商可能在对方科目行的复合字段中

#### 决策2：客商信息够不够？

看预检查的诊断表：候选客商列在银行存款行上有值 → 直接模式（`交易对手列名`）。只在对方科目行有值 → 拆分模式（`客商辅助项列名`）。

> **⓾ 客商缺失确认（STOP）**
>
> 如果所有候选列在两边都无值，或样本值是银行账户名等非客商信息——停下来用 `question` 工具问用户。
>
> **为什么停**：匹配率会从 90%+ 暴跌到 30-50%，落差太大。用户需要知情同意——他可能更愿意先整理客商数据，而不是接受一个大半匹配不上的底稿。
>
> - [A] 继续：仅用金额+日期匹配，接受低匹配率
> - [B] 补充字段：我指定正确的对手列
> - [C] 取消：先完善数据

#### 决策3：多账户覆盖了吗？

看预检查输出的账号分布。

单账户或两边账户一致 → 直接继续。

> **⓾ 多账户不完全覆盖确认（STOP）**
>
> 序时账有 5 个银行账户但流水只有 2 个——静默继续会让另外 3 个账户全部无法匹配，用户以为全核对过了实际只核了一部分。审计场景中这个认知差异是风险。
>
> - [A] 仅核对匹配的账户：过滤序时账只保留有流水的
> - [B] 全部核对：不设账户列名，整体核对（匹配率偏低）
> - [C] 补充流水：我补缺失的银行流水文件

**多账户标识不一致**：序时账用"招商银行"，流水用账号"3960xxx"→ 分组键不匹配 → 0%。此时不设账户列名（选[B]），整体核对。

**公司列必须对称**：序时账有公司列但流水没有 → 0%。不要配 `公司列名`，改用 `主体过滤`。

**性能**：>5000 行时强烈建议设账户列名分组（16s vs 129s）。

#### 决策4：范围对齐了吗？（低匹配率首要原因）

看预检查的银行科目分布和主体分布。序时账范围明显大于流水时，大量记录无法匹配。

| 类型 | 典型场景 | 解决方案 | 实证 |
|------|---------|---------|------|
| 科目代码范围 | 序时账含32个银行科目，流水只有1个 | 精确限定 `银行科目代码: "100201"` | 16% → 99% |
| 主体范围 | 序时账含11个主体，流水只有1个 | `主体过滤: "主体,西安德诺"` | 4% → 93% |
| 日期范围 | 序时账全年，流水半年 | `日期范围: "2025-01-01,2025-06-30"` | 偏低→正常 |

> **⓾ 范围限定确认（STOP）**
>
> 配 `主体过滤`/`日期范围` 或收窄 `银行科目代码` 前——被过滤的记录完全不参与核对，用户可能误以为全部核对过了。审计底稿遗漏记录而不披露是重大风险。
>
> - [A] 确认限定：接受范围对齐后的高匹配率
> - [B] 保留全部：不限定，整体核对（匹配率偏低但不遗漏）

选 [A] 后才配置过滤参数。汇报结果时披露实际使用的过滤条件。

### 第4步：写配置

根据判断结果写 `reconcile_config.json`。

> **完整参数表和 JSON 示例**见 `references/配置参数详解.md`（gl_config + bank_config 全字段、客商模式选择、从合并结果衔接核对的固定映射）。

### 第5步：运行核对

```bash
python SKILL_DIR/scripts/bankflow_reconcile.py \
  reconcile_config.json \
  --output "输入文件所在目录/核对底稿.xlsx"
```

不传 `--output` 默认保存到 CWD，文件名 `银行流水核对底稿_YYYYMMDD_HHMMSS.xlsx`。建议显式传 `--output`。

### 第6步：AI 复核（可选）

> **STOP — 运行完第5步后先停下来。不要自动加 `--ai-review` 重跑。**
>
> **为什么停下来问**：AI 复核逐条读未匹配记录（可能上百条），耗时 1-2 分钟和可观 token。但匹配率 90%+ 时，剩余十几条交给会计人工看反而更高效（他们有业务上下文）。自动复核 = 在用户不需要时浪费时间和钱。这是实际使用中最常被跳过的 gate——看到匹配率就想继续跑，但复核是可选的，选择权在用户。

读引擎输出的匹配率，用 `question` 工具问：

> 当前匹配率：金额 99.2% / 条数 98.4%，未匹配 112 条。
>
> - **[A] 进行 AI 复核**：逐条审查未匹配记录，可匹配的写入底稿（预计 1-2 分钟）
> - **[B] 不复核**：直接出底稿，剩余交人工（推荐：匹配率已高）
> - **[C] 先修范围/数据**：匹配率偏低时回到决策4

选 [A] 才进入 AI 复核（详见 `references/AI复核流程.md`）。未匹配 > 500 条时引擎自动跳过——说明范围没对齐，该修范围而不是硬复核。

---

## 匹配率预期

| 场景 | 预期金额匹配率 |
|------|-------------|
| 范围对齐 + 有客商 | 90%~99%（正常） |
| 范围对齐 + 无客商 + 有摘要 | 70%~90% |
| 无客商 + 无摘要 | 30%~50% |
| 范围不对齐 | <50%（先修范围） |

**金额匹配率 ≥ 90% 就算好结果，不需要分析原因。** 条数匹配率通常低于金额匹配率——序时账把多笔小额费用报销汇总成一笔凭证是常态（如 50 笔银行流水对应 1 笔 GL），这会拉低条数匹配率但不影响核对结论。只要总额平衡（流水收支 ≈ 序时账借贷），底稿可以直接交付，未匹配记录交会计人工核视即可。**不要主动长篇分析匹配率不高的原因——用户要的是底稿，不是分析报告。**

---

## 依赖安装

```bash
pip install pandas openpyxl xlrd rapidfuzz
```

`xlrd` 仅在读 .xls 时需要。`rapidfuzz` 可选（回退到 difflib）。

---

## 参考文档

| 文档 | 何时查阅 |
|------|---------|
| `references/配置参数详解.md` | 写配置时——三个模块全部参数表和 JSON 示例 |
| `references/AI复核流程.md` | 执行 AI 复核时——按月分批、subagent 提示词、三个判断层次 |

