> ## Documentation Index
> Fetch the complete documentation index at: https://docs.profy.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 端到端：文档批处理

> 把几十份格式各异的文件变成一张能算的表，含抽样验收与脚本化的分界线

这篇处理的是一类很常见但很容易做砸的活：手上有一批文件（合同、发票、简历、周报、导出的 CSV），需要从里面把关键字段抽出来，汇总成一张能筛能算的表。

做砸的方式基本只有一种——**让模型逐个"读一下总结一下"**。那样做的结果是：前几份很准，中间开始漏字段，最后几份的数字是编的，而且你没有任何办法知道是从第几份开始坏的。这篇的核心就是绕开这个坑：**让模型写脚本去处理，而不是让模型自己去读**。

## 你会得到什么

| 产物                      | 说明                              |
| ----------------------- | ------------------------------- |
| `output/extracted.xlsx` | 一行一份文件，一列一个字段，**数值列带公式而非硬编码结果** |
| `output/extract.py`     | 抽取脚本本体，可复用、可审计、可修               |
| `output/failures.md`    | 没能处理的文件清单及原因，逐条列出               |

第三份产物和前两份一样重要。一个只输出成功项的批处理流程，等于把失败悄悄吞掉了。

## 关键认知：什么时候让模型读，什么时候让它写脚本

| 情况               | 做法            | 理由                  |
| ---------------- | ------------- | ------------------- |
| 文件数 ≤ 3，格式各异     | 直接让模型逐个读      | 脚本的开发成本高于收益         |
| 文件数 ≥ 5，格式一致     | **让模型写脚本批量跑** | 一致性由代码保证，不受注意力衰减影响  |
| 文件数多且格式各异        | 先分组，每组一个脚本    | 分组本身让模型做，处理交给脚本     |
| 需要理解语义（比如判断合同风险） | 脚本抽取 + 模型逐条判断 | 抽取要确定性，判断要理解力，两件事分开 |

分界线是 **5 份**。这不是硬规则，是一个经验阈值：超过 5 份，人工核对成本已经高到你不会真的去核，那就必须让流程本身可验证。

## 前置条件

<Steps>
  <Step title="上传文件">
    把文件传到工作区。单文件上限：文档类 512 MB、图片 20 MB、代码文件 50 MB。总量计入你的云盘配额（免费版 10 GB，付费档更高）。
  </Step>

  <Step title="确认文件是可解析的">
    扫描件 PDF（图片型）和文本型 PDF 是两回事。前者需要 OCR，抽取准确率和排版复杂度强相关。先随便挑一份让专家读一下，确认能读出文字再往下走。
  </Step>

  <Step title="自己先定字段">
    列出你要的字段名和类型（文本/数字/日期）。让模型「自己看看有什么字段」会导致每份文件抽出的字段集不一样，最后拼不成表。
  </Step>
</Steps>

## 步骤

### 第 1 步：抽样看清楚结构

不要一上来就处理全部。先看三份：

```text theme={null}
uploads/ 下有 47 份采购合同 PDF。先不要批量处理。

请随机挑 3 份读一下，然后告诉我：
1) 它们的结构是否一致（章节顺序、字段位置）
2) 我要的这些字段——合同编号、供应商名称、签署日期、含税总额、付款期限——
   分别出现在什么位置，有没有哪个字段在某些文件里根本不存在
3) 有没有扫描件（图片型 PDF）混在里面
4) 基于这 3 份，你打算用什么方式批量抽取
```

第 2 问的「有没有字段根本不存在」是关键。缺失字段和抽取失败是两回事，必须在写脚本之前就区分开。

### 第 2 步：让它写脚本，而不是直接干活

```text theme={null}
结构确认了。现在写一个脚本 output/extract.py 来处理，要求：

- 遍历 uploads/ 下所有 PDF
- 抽出这五个字段：合同编号、供应商名称、签署日期、含税总额、付款期限
- 字段抽不到时写入空值并记录到失败清单，不要跳过整份文件，也不要猜
- 输出两个文件：
  * output/extracted.csv —— 一行一份文件，第一列是源文件名
  * output/failures.md —— 每条记录：文件名、缺失的字段、原因

先只写脚本，写完给我看，我确认后再跑。
```

「先写完给我看」这一步别省。脚本是这个流程里唯一你能完整审阅的东西，看一眼正则和字段定位逻辑，比事后核对 47 行输出便宜得多。

### 第 3 步：先跑 5 份，再跑全量

```text theme={null}
脚本没问题。先只跑前 5 份，把 extracted.csv 和 failures.md 都打印给我看。
```

对照原文件核这 5 行。**全对**才继续跑全量；有一处不对就回去改脚本，不要手工改结果——手工改过的那一行会让你误以为脚本是对的。

```text theme={null}
5 份都核对无误。跑全量 47 份，跑完告诉我：
成功多少份、失败多少份、失败清单里出现频率最高的原因是什么。
```

### 第 4 步：转成带公式的表格

CSV 只是中间产物。最终交付要能算：

```text theme={null}
把 output/extracted.csv 转成 output/extracted.xlsx，要求：

- 冻结首行，字段名加粗
- 「含税总额」列设为数值格式（两位小数）
- 末尾加一行合计，**用 SUM 公式**，不要把算好的数字写死
- 新增一列「不含税金额」，用公式从含税总额算（税率 13%），同样不要写死
- 抽取失败的行整行标黄
```

<Warning>
  「用公式，不要写死」这条必须明确说。默认行为容易变成把算好的数字直接填进单元格——表格看起来一模一样，但你改任何一个原始值，合计不会变。这类错误在交付给别人之后才暴露，代价最大。详见 [Excel 表格](/zh/documentation/capabilities/office-xlsx)。
</Warning>

### 第 5 步：处理失败清单

```text theme={null}
看一下 failures.md。把失败原因分个类，对每一类告诉我：
- 是脚本能修的（格式变体、正则没覆盖到）
- 还是文件本身的问题（扫描件、缺页、字段确实不存在）
- 脚本能修的，直接改脚本重跑这些文件
- 文件本身的问题，列出清单我人工处理
```

这一步走完，失败清单里剩下的应该全是「确实需要人处理」的。如果还剩着「脚本能修但没修」的条目，那这次批处理就没完成。

### 第 6 步：验收

1. 打开 xlsx，随机抽 5 行，对照原文件逐字段核
2. 改一个「含税总额」单元格的值，确认合计行和不含税列**跟着变**
3. 确认行数 = 成功数，且 成功数 + 失败数 = 文件总数
4. 打开 failures.md，确认每条都有具体原因，没有「解析失败」这种没信息量的描述

第 3 项是最容易发现问题的检查：数字对不上，说明中间有文件被静默丢掉了。

## 边界与失败态

| 现象           | 原因                     | 处理                              |
| ------------ | ---------------------- | ------------------------------- |
| 扫描件抽不出文字     | 图片型 PDF，需要 OCR         | 单独分组走 OCR 路径；准确率随排版复杂度下降，务必抽样核对 |
| 读取长文件只看到开头   | 读取工具默认按行截断（约 2000 行）   | 让脚本按块读，不要靠模型一次读完                |
| 脚本跑到一半超时     | 单条命令有默认执行时长上限（约 120 秒） | 分批跑，或让脚本自己记录进度支持续跑              |
| 表格里的合计不随数据变  | 结果被硬编码写死了              | 明确要求用公式重做该列                     |
| 同一字段在不同行格式不一 | 脚本没做归一化                | 在脚本里统一日期/金额格式，不要让模型逐行修          |
| 处理完文件数对不上    | 有文件被静默跳过               | 要求脚本对每个输入文件都产出一条记录（成功或失败）       |
| 上传时报文件过大     | 超过单文件上限                | 文档类 512 MB、图片 20 MB；超限需先拆分      |
| 上传时报配额不足     | 云盘总量用尽                 | 清理旧文件或升级套餐                      |

## 变体

<AccordionGroup>
  <Accordion title="需要语义判断，不只是抽字段">
    分两段：脚本先把原文段落抽成结构化的 CSV，再让模型逐行读那些段落做判断（比如「这条付款条款有没有风险」）。不要让模型一边解析 PDF 一边判断——两件事混在一起时，出错了你分不清是没读到还是判断错。
  </Accordion>

  <Accordion title="文件在飞书文档里，不在本地">
    连接飞书知识库后可以直接读，不用先下载。见 [飞书接入](/zh/documentation/guides/feishu-integration)。
  </Accordion>

  <Accordion title="要定期处理新到的文件">
    把定稿的脚本和提示词固化成定时任务。注意每次执行都会真实计费，见 [每日简报](/zh/documentation/guides/daily-briefing)。
  </Accordion>

  <Accordion title="结果要给团队看">
    xlsx 适合自己算，网页适合给人看。把汇总结论做成站点见 [发布一个站点](/zh/documentation/guides/publish-a-site)。
  </Accordion>
</AccordionGroup>

## 相关页面

<CardGroup cols={2}>
  <Card title="Excel 表格" icon="file-excel" href="/zh/documentation/capabilities/office-xlsx">
    公式优先原则与能力边界
  </Card>

  <Card title="文件与云盘" icon="folder" href="/zh/documentation/chat/files-and-cloud-drive">
    上传限制与配额
  </Card>

  <Card title="工具全表" icon="wrench" href="/zh/documentation/reference/tools-catalog">
    读写与命令执行工具的参数与默认值
  </Card>

  <Card title="沙盒环境" icon="box" href="/zh/documentation/concepts/sandbox">
    脚本运行在哪里
  </Card>
</CardGroup>
