你让 Agent 打开一个 Excel,把 B 列的数字乘 2 写进 C 列。Agent 回了一句"完成"。你打开文件——C 列数字是对的,但整张表的公式全没了。同事那份季报模板,跨表引用、条件格式、数据验证,全被这次"完成"给废掉了。

这不是 Agent 蠢。是它操作的三种格式——Excel、PDF、PPT——从诞生那天起,就没打算让别人"修改"。你以为在调 API,实际是在跟格式斗智斗勇。
xlsx 不是 Excel 文件,是一个 ZIP 压缩包
把任意一个 .xlsx 后缀改成 .zip,解压开:
$ unzip -q demo.xlsx -d demo_xlsx
$ ls demo_xlsx/xl/worksheets/
sheet1.xml sheet2.xml
底下是一堆 XML。Excel 保存的不是"表格",而是一个 ZIP 包里的 XML 文件集合。OOXML 规格定义了每个 XML 的职责。openpyxl 这类库存在的意义,就是替你解压、改 XML、再重新压缩。
但 openpyxl 对 OOXML 标准的覆盖是有限的。官方文档里写了 data_only 参数的行为。我第一次看到时没当回事,直到亲手踩进去:
from openpyxl import load_workbook
wb = load_workbook("demo.xlsx", data_only=True)
print(wb.active["C2"].value) # 结果:None
data_only=True 读出来的是公式的缓存值。Excel 每次打开文件,都会把公式结果缓存一份;但如果这个文件是刚用 openpyxl 生成的、从没被 Excel 打开过,缓存值根本不存在,读出来就是 None。
反过来也一样。Agent 往 C2 写入公式 =B2*2,保存后发给另一个 Agent 去读,那边用 data_only=True,还是 None——公式还没被计算过。公式和值,两套状态,这是 xlsx 的第一个坑。
第二个坑:openpyxl 不支持 .xls 老格式。你交给 Agent 一份老同事的 .xls 季度报表,openpyxl 直接报错。xlrd 能读 .xls,但不能写。转换?LibreOffice headless 能转,但转出来的排版大概率变形。
第三个坑更隐蔽:如果 Agent 用 openpyxl 打开一个复杂的 xlsx 再直接保存,Excel 可能提示"文件已损坏,是否修复"。原因是 xlsx 的 XML 组件太多——主题、图表、数据透视表各自独立存放,openpyxl 对其中不少组件的支持不完整。打开-保存一次,等于丢东西。
PDF 里根本没有段落,只有坐标
如果说 xlsx 的坑是"两套状态",PDF 的坑就是"根本没有状态"。
PDF 是 Adobe 1993 年发布的打印格式(ISO 32000)。它的内部结构里没有段落、没有标题、没有表格——只有一页一页的"坐标平面 + 绘制指令"。在坐标 (x,y) 用这个字体 12pt 画这几个字,画一条线从这里到这里。
这意味着,一切"读取"操作都是反编译。pdfplumber 用启发式猜测哪些文本构成一个段落、哪些坐标范围算一个表格。遇到合并单元格或者略微错位的线条,猜错是常态。文本顺序也一样:PDF 内容流里各文本块的存储顺序不一定等于阅读顺序。先画右边再画左边,提取出来的文字就是从右往左读的。
扫描版 PDF 更彻底:整个 PDF 就是一个图片容器,文本层是空的。所有文本提取库都返回空字符串。这种文件,Agent 只能走两条路:OCR 或视觉模型。
这也是 Agent 时代的思路转向:不解析 PDF,直接把每页转成图片,交给多模态模型"看"。文档理解类的 Agent(读合同、读财报、审阅报告)很多已经走这条路了——视觉模型对图像中文字排版的整体理解,确实比传统文本提取器反编译一个坐标流要靠谱。
生成 PDF 也有坑。reportlab 默认不嵌入中文字体,生成的文件里中文全是空白块。就算你注册了 .ttf,不同 PDF 查看器对同一字体的渲染也不完全一致。最稳的生成路径是 HTML 转 PDF(weasyprint),把字体和布局交给排版引擎,而不是在 Agent 代码里手动计算坐标。
PPT:占位符是朋友,文本框是杀手
python-pptx 是 Python 生态唯一主流的 .pptx 操作库。它的官方文档明确列出了不支持的:动画、切换效果、SmartArt、嵌入视频。Agent 说它"编辑"了一个 PPT,实际上它只能改形状的位置、大小和文本,其他都是碰运气。
品牌模板场景是重灾区。PPT 模板有两种放文字的结构:占位符(placeholder)和独立文本框。占位符是模板里"放内容"的标记,母版定义好它的位置和样式,python-pptx 支持良好。但商务模板里大量文字是直接画好的文本框——Agent 定位它靠坐标,改完文本变长了,没有自动排版逻辑,溢出文本框,排版就乱了。
我自己的项目里,凡是"原位修改" PPT 的,最后都会变成"读内容 → 套模板重新生成 → 导出 PDF 验证"。原位修改的不可控点太多了。
| 格式 | 内部本质 | 数据抽象级别 | Agent 踩坑程度 | 推荐处理路径 |
|---|---|---|---|---|
| xlsx | ZIP + XML | 有,但公式与缓存值双轨 | 中 | 读成 DataFrame,操作数据,重新生成文件 |
| 坐标绘制流 | 无 | 高 | 文本型转 Markdown;扫描型转图片走视觉模型 | |
| PPTX | ZIP + XML | 弱,文本与排版强耦合 | 高 | 读取内容,套模板重建,导出 PDF 验证 |
Agent 的正确工作方式:绕过格式
把上面的坑放在一起看,结论其实很清晰:Agent 不应该直接"操作格式",它应该在格式外面建一层数据抽象。这看起来是绕路,实际上是最短路径。
- Excel:加载为 DataFrame。让 Agent 在 DataFrame 上写逻辑(筛选、分组、计算),最后用 pandas + openpyxl 引擎导出新的 xlsx。要保留原格式时,用"复制原文件 + patch 指定 XML"而不是整本重写。
- PDF:能转 Markdown 就转(MinerU、Marker、PyMuPDF),不能转就走视觉模型。永远不要试图用正则或文本切片去"理解"PDF。
- PPT:读取为结构化内容(标题、要点、备注、图片),然后套模板重建。
MCP(Model Context Protocol)生态里已经出现很多文档处理服务器,它们把上述流程封装成语义化工具。这个方向是好的——它让 Agent 不再写 openpyxl 代码,而是调用 read_range、write_cell 这类语义清晰的操作。但底层仍然是 openpyxl。格式本身的坑不会消失,只是被封装后离 Agent 远了点。
几个大家最爱问的问题
为什么不让 Agent 直接用 Office 的 COM 接口?
Windows 上 pywin32 确实可以驱动本地 Excel。问题在于 Agent 通常跑在 Linux 服务器上,没有 Office;而且 COM 是同步 UI 驱动,每调一次都要启动 Office 进程,慢,容易因为弹窗卡死。它在"本机装有 Office 的 Windows 桌面"场景才有意义。
视觉模型读 PDF 会不会不准?
几页的 PDF 准确率很高;但 200 页的报告 token 消耗巨大,成本撑不住。长文档的正确路径是:转 Markdown → 分块检索(RAG)→ 引入页码和块号作为引用来源。视觉模型负责"看懂"局部,RAG 负责"找到"相关局部。
MCP 服务器能解决格式兼容性问题吗?
能缓解,不能根治。它把底层的坑封装得让 LLM 感知不到,但底层库的能力边界没变。openpyxl 做不到的事,MCP 服务器也做不到,只是不会把 Agent 暴露在错误细节里。
微软为什么不做官方 API?
做了,不够用。Office.js 能在浏览器里操作文档,但它是面向"加载项"的模型,不是面向 Agent 的数据通道;Graph API 能操作 Excel 单元格和公式,但复杂排版、图表、透视表等支持有限。微软的官方路线仍然是"人使用 Office"而不是"Agent 使用 Office"。
进阶阅读:这些格式为什么长成现在这个样子?
xlsx 和 pptx 的 DNA 是 2006 年 ECMA 标准化的 OOXML(ISO/IEC 29500),而 .xls 和 .ppt 是 90 年代的二进制格式(BIFF 和 OLE2)。PDF 则从 1993 年的 PostScript 演化而来。三个格式加起来快 90 年历史。它们的共同特点是:为人类视觉而设计,不为机器解析而设计。PDF 甚至允许字符顺序与阅读顺序不一致——这是打印性能优化带来的合法特性。理解了这一点,你就明白了为什么 Agent 操作文档永远需要翻译层:不是工具不够好,是格式本身拒绝被程序理解。
结论:格式的坑不会随模型变强而消失
回到开头的场景。
Agent 改 Excel、读 PDF、改 PPT,从来不是"调一个 API"那么简单。原因是这些格式从出生那天起,只对人眼承诺过——PDF 连"段落"都没定义过,PPT 把文本和排版焊死,Excel 把公式和值当成两个世界。Agent 的每一次绕路——转图片、转 Markdown、重新生成——本质都是在格式外面建立一层它真正能理解的抽象。
所以当你评估一个 Agent 能不能处理你的文档时,不要看它"支持不支持"那格式,要看它把格式背后的数据转到了什么层次。支持 .pdf 只是功能列表;把 PDF 变成数据是工程。
我目前的成熟度排序:Excel > PPT > PDF。Excel 有数据模型,PPT 有对象模型但能力受限,PDF 连模型都没有。这个顺序,恰好和 Agent 踩坑的数量成正比。
格式兼容性这个坑,不会因为模型变强而消失。模型可以变聪明,格式不会变。真正让 Agent 对文档"有用"的,还是那些老老实实的转换层和封装层。
原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/776.html