$npx -y skills add nigo81/nigo-skills --skill audit-report-checker检查审计报告(财务报表 + 附注),发现勾稽错误、加总错误、文本格式问题。用于"检查审计报告/勾稽验证/报表核对/报告核查/数字核对/加总核对/报表平衡/审计报告复核/报告校对"。即使用户只说"帮我检查这份审计报告""看看这个报告有没有错""核对下报表数字"也应触发。支持分体式(报告+附注分文件)与合体式(单文件)报告,支持 Word/PDF/扫描件/图片报表,覆盖 50-150 页合体大报告,输出 7 sheet Excel + Markdown 复核报告。算术 100% 走代码计算,AI 负责语义定位与结构判断。
| 1 | # 审计报告核查 |
| 2 | |
| 3 | > 作者:nigo(公众号:逆行的狗) |
| 4 | > 版本:1.0.0 |
| 5 | |
| 6 | 检查审计报告(财务报表 + 附注),发现勾稽错误、加总错误、文本格式问题。Claude 是主控——负责语义理解(定位报表、理解附注章节、判断列含义、标注表格结构),代码负责确定性算术(求和、核对、reconcile)。两者分工,消除旧工具"硬拆分 + 关键词匹配"导致的系统性误报。 |
| 7 | |
| 8 | ## 最重要的一条原则:算术绝不手算 |
| 9 | |
| 10 | LLM 直接做数值加减会算错,且无法复现——审计核查中算错等于致命。所有数值计算,哪怕只是三个数相加,都调用 `scripts/calculator.py`。AI 只决定"传哪些数""哪个等于哪个",代码算出结果。 |
| 11 | |
| 12 | 正确做法: |
| 13 | ``` |
| 14 | # 从报表/附注提取出数字后,调 calculator 验算 |
| 15 | python3 scripts/calculator.py check "113,157,711.68" "113,157,711.68" # 核对相等 |
| 16 | python3 scripts/calculator.py sum "1,234.56 5,678.90 100.00" # 求和 |
| 17 | python3 scripts/calculator.py reconcile "100" "50" "30" "120" # 期初+增-减=期末 |
| 18 | ``` |
| 19 | |
| 20 | 错误做法: |
| 21 | ``` |
| 22 | # 心算"流动资产合计 = 货币资金 + 应收账款 + ..." ← 会算错,且别人无法核验 |
| 23 | ``` |
| 24 | |
| 25 | calculator 支持千分位逗号、括号负数、横线(=0)、全角字符、万元单位,容差默认 0.01,用 `round(diff, 6)` 避免浮点边界误判。这是上一版已验证有效的原则,保留。 |
| 26 | |
| 27 | --- |
| 28 | |
| 29 | ## 工作流 |
| 30 | |
| 31 | ### Step 0 — 选检查深度(scope) |
| 32 | |
| 33 | 开始前用 `question` 工具问用户两件事:检查深度(单选)+ 检查类型(多选,可空则按深度档执行)。 |
| 34 | |
| 35 | **三档深度**: |
| 36 | |
| 37 | | 档位 | 覆盖范围 | 耗时 | 适用 | |
| 38 | |---|---|---|---| |
| 39 | | 快速检查 | 四表间勾稽 + 格式(公司名/页码/页眉) | 几分钟 | 初筛、只关心报表平衡 | |
| 40 | | 标准检查(默认) | 快速 + 表内横加竖加 + 高频表注勾稽 + 文本(错别字/病句) | 十几分钟 | 日常复核,覆盖常见错误 | |
| 41 | | 深度检查 | 标准 + 附注所有变动表 reconcile + 跨科目勾稽 + AI 结构标注全表 | 半小时以上,token 消耗大 | 重大报告、终稿复核 | |
| 42 | |
| 43 | 用户不选就默认标准。选深度检查时先提示 token 消耗较大让用户确认(128 页报告深度检查可能消耗很多)。 |
| 44 | |
| 45 | **检查类型多选**:勾稽 / 横加竖加 / 表注 / 文本 / 格式。用户可自由组合覆盖深度档(多选全部 ≈ 深度检查)。 |
| 46 | |
| 47 | 为什么要分档:审计师多数时候只需快速验证勾稽,无差别深度检查既慢又费 token。scope 让用户知情选择,按需触发。 |
| 48 | |
| 49 | **附注-only 自动调整**:若识别到文档只有附注、无四表(如盛屯/博达新材的纯附注 Word),自动跳过报表间/表注勾稽,聚焦附注内勾稽 + 横加竖加 + 文本格式,并告知用户调整了范围。详见后文"附注-only"。 |
| 50 | |
| 51 | **DeepSeek 模型选择(启用 AI 时执行)**:标准/深度检查默认启用 DeepSeek 加速(文本错别字、附注表结构标注、warning 二次复核)。涉及 AI 时,问完深度+类型后先选模型,避免 reasoning 模型拖垮批处理: |
| 52 | |
| 53 | 1. 检查 key 有效性:`python3 scripts/ai_worker.py --test-check-key`(读 ~/.deepseek/config.json;无 key 则全程走 `--no-ai` 纯代码) |
| 54 | 2. 查可用模型:`python3 scripts/ai_worker.py --test-list-models`(DeepSeek 503 服务繁忙时可能查不到,可跳过用默认) |
| 55 | 3. 用 `question` 让用户选模型,**默认推荐 flash 类模型**(非 reasoning,单请求延迟低,适合大批量并发;reasoning 类如 v4-flash 单请求 25s+ 会拖垮批处理)。用户无偏好直接用 flash。 |
| 56 | 4. 选定后 run_check 加 `--model <选定>` 传入,或写入 ~/.deepseek/config.json 的 model 字段持久化。 |
| 57 | |
| 58 | **降级原则**:DeepSeek API 服务繁忙(503)/限流属外部问题。多次失败时降级 `--no-ai`(纯代码 L1+scan+词库),文本/标注/warning 复核由 Claude 终审兜底(Step 5 本就要求 Claude 复核,不完全依赖 API)。 |
| 59 | |
| 60 | ### Step 1 — 解析文档 |
| 61 | |
| 62 | ```bash |
| 63 | python3 scripts/parse_report.py "<文件或目录>" -o <输出目录> |
| 64 | ``` |
| 65 | |
| 66 | 脚本四路自动分流,按文档类型和内容特征选最佳提取路径: |
| 67 | - PDF 文本型(首页文本 > 50 字)→ pdfplumber,数字 100% 精确 |
| 68 | - PDF 扫描型 → mineru 云端 API(`extract --model vlm`),数字需人工复核 |
| 69 | - Word 文本表格为主 → python-docx,精确 |
| 70 | - Word 图片报表(inline_shapes 偏多)→ mineru 云端 API |
| 71 | |
| 72 | **Word/PDF 双路(重要)**:实际场景大部分是 Word 报告。parse 对同 basename 的 .docx/.pdf **优先 .docx**(去重,Word 表格精确无断字);无 Word 才用 PDF。两路分开处理: |
| 73 | - **Word 路(.docx)**:python-docx 提取 table 对象→markdown(实测金星90/博达87表全成功)+ 段落文本;**章节定位**(附注五-N 科目,Word 无固定页码);table 自动归属 chapter(Heading1 大章节 + Heading2/短文本明细)。伪表格(非 table 对象的制表位排版,少数)AI 兜底。 |
| 74 | - **PDF 路(.pdf)**:pdfplumber + **页码定位**(page=N,超链接可点击)。 |
| 75 | |
| 76 | 定位差异:Word 用章节("附注五-3 应收账款"),PDF 用页码("第N页")。result 的 chapter(Word)/ page(PDF)字段区分,export 自动适配。 |
| 77 | |
| 78 | 输出两个文件: |
| 79 | - `report.md`:全文 markdown,每段用 `<!-- SOURCE file="..." page=N method=... -->` 标注来源页码和提取路径 |
| 80 | - `extracted_tables.json`:原始二维表格(headers + rows),不做列映射、不做报表分类、不做续表合并 |
| 81 | |
| 82 | 解析层只输出原始数据,报表定位、附注识别、列含义判断全部由 Claude 在后续步骤用语义完成。这是消除旧工具"拆分匹配错误"的核心——parse 层不越界做本该人做的事。提取策略原理见 `references/extraction.md`。 |
| 83 | |
| 84 | mineru 是云端 API,数据会上传 mineru.net。审计报告含敏感财务数据,首次走 mineru 路径前要告知用户并获得知情同意。详见 `references/mineru_usage.md`。 |
| 85 | |
| 86 | ### Step 2 — 理解文档结构(语义,不靠关键词) |
| 87 | |
| 88 | 读 `report.md`,理解整体结构: |
| 89 | - 编制单位、会计期间 |
| 90 | - 报告类型:合并报告(含合并 + 母公司共 8 张表)还是单体(4 张)?通过看是否有"母公司"字样和报表数量判断,不靠硬编码关键词字典 |
| 91 | - 四张报表的位置(合并资产负债表/利润表/现金流量表/所有者权益变动表,及母公司版本)及其页码范围 |
| 92 | - **合并报告同名报表会重复**:合并报告里"资产负债表""所有者权益变动表"等标题通常**出现两次**——第一次是合并口径、第二次是母公司口径,表头往往**都不带"合并"/"母公司"前缀**,靠出现顺序(先合并后母公司)和编制单位行区分。**两套都要提取**,漏掉母公司 4 张表会让母公司层面的勾稽完全缺失。判断方法:同名报表在 report.md 中出现 ≥2 次 → 合并报告,按顺序分别归为合并/母公司。 |
| 93 | - 附注章节结构——每章讲哪个科目(如"附注三、货币资金"讲货币资金) |
| 94 | - 是否附注-only(无四表)→ 走附注-only 分支 |
| 95 | - **图片报表页检测(重要)**:读 report.md 时留意是否有**连续多页文本为空白**。审计报告中四表(资产负债表等)常被做成图片嵌入 PDF,pdfplumber 对这些页提取为空白(实测盛屯 page 7-16 共10页空白=四表全是图片)。若 parse_report 的 report.md 已标注 `<!-- WARNING: ... 为图片/扫描页 -->`,直接据此处理;否则自己扫描各页文本量。发现四表区域空白时: |
| 96 | 1. 对该页范围用 mineru 云端 OCR 重新提取:`mineru-open-api extract "<报告.pdf>" --pages 7-16 -o <目录> --model vlm --language ch`(需先 `mineru-open-api auth` 配 token,见 references/mineru_usage.md,含数据上传云端隐私提示) |
| 97 | 2. OCR 结果(md)合并回 statements 提取 |
| 98 | 3. mineru 不可用时,在报告中明确标注"四表为图片,pdfplumber 未能提取,本次未执行报表间勾稽,建议人工复核或配 mineru token 重跑"——**不要假装做了** |
| 99 | |
| 100 | 识别同义科目变体靠语义理解,不做映射表:股东权益 = 所有者权益、股本 = 实收资本、股东权益变动表 = 所有者权益变动表。为什么用语义而不是关键词字典:每遇到一个新报告格式就要加规则,关键词爆炸不可持续;Claude 一次调用就能理解,且能处理变体。 |
| 101 | |
| 102 | **生成 note_map.json(表注勾稽的定位基石,Step 2 必做)**:理解附注结构时,一次性生成「科目→附注明细表」精确映射 `note_map.json`(写入 parse 输出目录)。这是三层分工架构的**定位层**——Claude 语义定位(准、只做一次、低 token),取数/算术交给代码(DeepSeek locate + calculator)。 |
| 103 | |
| 104 | 为什么定位必须 Claude 做:旧工具靠正则匹配标题 + 页码邻近定位,在①标题格式多样 ②同页多科目 ③续表跨页 上系统性失败(详见 `旧报告检查工具_定位研究.md` 的 4 |