Cohere 发布了 Parse 5,面向复杂文档的多模态解析。所谓多模态,指的不只是文字:版式、表格、图表、文字混排,Parse 5 都能从复杂文档里高效提取。对长期被 PDF 表格、扫描件、PPT 版式折磨的接入方来说,这算得上一次关键升级。
为什么把这一期放进"接入降本"系列?因为文档解析是 RAG 与智能体知识库的第一道工序,也是被低估最严重的成本黑洞。解析质量差,后面所有环节都在为错误买单。
Parse 5 更新的重点在多模态信息的保真:图表不再是一张孤立的截图,而是连同位置、标题与可检索的描述一起输出;表格还原成真实的行列结构,而不是被拍平成字符串。对知识库接入来说,这两点直接决定检索能不能命中。
2. 痛点:解析翻车,答案连带翻车
先讲一个我经手过的真实场景。某团队把一批产品手册接入知识库,PDF 里是双栏排版、带页眉页脚、夹杂大量表格和截图。他们图省事,用最简单的文本抽取工具直接切块,结果:表格被抽成一行行散落的字符串,双栏文字交叉拼接,页眉页脚混进正文。入库之后,Embedding 算出来的向量一团糟,检索召回率惨不忍睹。用户问"第三季度退货率是多少",系统召回的是"联系电话:400-xxx"。
关键认知是:解析质量直接决定 RAG / 智能体知识库的命中率。切块是 API 之前的第一道工序,切块之前还有解析。这道工序做不好,后面模型再强也答不对——不是模型不行,是喂进去的东西本身就是碎的。答案翻车,十有八九是解析先翻车。
再算一遍成本账,就知道解析省下的钱迟早加倍还回去。解析碎了,切块跟着碎,Embedding 向量混在一起,召回差,用户问不到答案就开始反复重试;重试还不行,就得人工返工——重新解析、重新切块、重新入库、重新验证,每一轮都是工程师工时和 API 调用费。我见过一个团队在脏数据上返工了三轮,花费早超过当初买托管解析的钱。解析这道工序,省不得。
智能体场景更敏感。智能体要自主调用工具、拆解任务,靠的就是知识库给的上下文;上下文里是一堆错位文字,智能体就会一本正经地胡说。解析质量差,最先暴露的就是这类问题,因为重试多少次都一样,错的底料做不出对的菜。
3. 原理速览:一条完整的解析链路
要把"解析翻车"讲清楚,先看这条链路:
原始文档(PDF / DOCX / PPTX / XLSX / 扫描件)
│
▼
版面分析(Layout Analysis)
识别标题、段落、表格、图表、页眉页脚、阅读顺序
│
▼
元素抽取(Element Extraction)
文字 OCR、表格结构还原、图表区域定位与描述
│
▼
结构化输出(Structured Markdown / JSON)
保留标题层级、表格行列、图片与图表占位符
│
▼
切块入向量库(Chunking → Vector DB)
按标题层级切块、控制重叠,再喂给 Embedding API
│
▼
RAG 检索 → 大模型生成最终答案
Parse 5 这类托管解析能力做的是前三段:把复杂版式还原成结构化的 Markdown / JSON。后两段——切块与检索——由我自己的管线负责。这条链路里任何一段偷懒,最终答案都会连带翻车。反过来,前三段做得越扎实,切块越有语义边界,检索命中越准,模型答对的概率越高。
结构化输出的价值正在于切块。按标题层级切块,块与块之间才有清晰的语义边界;表格保持行列结构,切块才不会把一行数据腰斩;图表带着描述文字,检索时才能被关键词命中。这些都是 markdown 结构直接带来的好处,也是为什么托管解析和开源转换都把 markdown 当作标准中间格式。
4. 托管解析 API vs 开源自建
接入方真正纠结的选型问题是:Parse 5 这类托管解析 API,和 microsoft/markitdown 这类开源自建,到底选哪个。我把两边的账摊开:
| 维度 | 托管解析 API(Parse 5 一类) | 开源自建(markitdown 一类) |
|---|---|---|
| 上手成本 | 调 API 即用,几行代码接入 | 本地安装依赖,脚本自维护 |
| 复杂版式质量 | 版面分析 + OCR + 表格还原开箱即用 | 简单版式够用,复杂版式需自己调 |
| 成本结构 | 按页计费,量大可谈阶梯 | 基本只花算力与维护时间 |
| 数据隐私 | 文档会经过第三方服务 | 全程本地,适合敏感文档 |
| 更新维护 | 厂商持续迭代,比如 Parse 5 | 依赖开源社区,升级自己跟进 |
| 适合场景 | 公开资料、海量文档、要速度 | 敏感文档、固定版式、要省钱 |
我的结论是:这不是二选一,而是按文档类型分流。公开手册走托管 API 省事,含客户数据、合同、内部制度的文档走本地路线。两条腿走路,成本和风险才都能压住。
5. 开源侧的风向:markitdown 为什么这么火
开源侧的信号同样强烈。microsoft/markitdown 在 GitHub 趋势榜上热度极高,星标数约 18 万,做的事情朴素到极致:把 Office 文件批量转成 markdown。为什么一个"格式转换工具"能火成这样?因为越来越多的接入方终于意识到,解析选型如今是自提管线的第一步——后面接的 RAG、智能体、知识库,全都要吃这份 markdown。
markitdown 的意义在于把"解析"从黑盒变成了可控管线:转出来的 markdown 我能直接看、直接改、直接抽检。托管 API 返回的是结果,开源自建返回的是过程,过程在手,质量才有抓手。这正是下一节教程的思路:先批量转换,再逐项抽检,把质量问题堵在入库之前。
从成本账看也说得通:解析引擎的研发投入极高——版面分析、OCR、表格识别、阅读顺序还原,每一块都是独立的技术栈,自建到生产级要养一个团队。markitdown 把门槛降到了 pip install 一条命令,而 Parse 5 这类托管 API 把质量做到了开箱即用。开源负责把下限抬高,托管负责把上限顶高,中间的空间留给接入方自己权衡。
6. Python 教程:markitdown 批量转换
先说清楚定位:下面的脚本走的是本地自建路线,适合文档不打算外传的场景;如果手头是海量公开文档、想省维护时间,托管解析 API 按页计费也不贵,混合策略在第 4 节和第 9 节有展开。转换脚本如下:
from pathlib import Path
from markitdown import MarkItDown
md = MarkItDown()
input_dir = Path("./docs_in")
output_dir = Path("./docs_out")
output_dir.mkdir(exist_ok=True)
# 支持的 Office 与 PDF 格式
SUFFIXES = {".docx", ".pptx", ".xlsx", ".pdf"}
for f in sorted(input_dir.rglob("*")):
if f.suffix.lower() not in SUFFIXES:
continue
try:
result = md.convert(str(f))
out = output_dir / f"{f.stem}.md"
out.write_text(result.text_content, encoding="utf-8")
print(f"[OK] {f.name} -> {out.name} ({len(result.text_content)} 字符)")
except Exception as e:
print(f"[FAIL] {f.name}: {e}")
运行前先安装依赖:pip install "markitdown[all]"。批量转换产出的是原始 markdown,质量如何,还要抽检。这套管线跑通之后,Embedding 与推理环节我走 4sapi(https://4sapi.com)的合规中转接入,把整条链路的 API 成本统一管起来。
7. 质量抽检脚本:三件事必须查
批量转换之后,我永远先跑一遍抽检再入库。抽检只查三件事:标题层级、表格行列数、图表占位符。
import re
from pathlib import Path
def check_md(path: Path) -> list[str]:
text = path.read_text(encoding="utf-8")
issues = []
# 1. 标题层级:出现跳跃说明版面分析丢了中间层级
levels = [len(m.group(0)) for m in re.finditer(r"^(#+)\s", text, re.M)]
for prev, cur in zip(levels, levels[1:]):
if cur > prev + 1:
issues.append(f"标题层级跳跃: H{prev} -> H{cur}")
# 2. 表格行列数:行首行尾管道符数量不一致说明表格还原失败
table_lines = [ln for ln in text.splitlines() if ln.strip().startswith("|")]
if table_lines:
expected = len(table_lines[0].strip("|").split("|"))
bad = [ln for ln in table_lines[1:]
if len(ln.strip("|").split("|")) != expected]
if bad:
issues.append(f"表格列数不一致: 期望 {expected} 列")
# 3. 图表占位符:图片引用指向不存在的文件,说明图表被丢弃
imgs = re.findall(r"!\[[^\]]*\]\(([^)]*)\)", text)
missing = [src for src in imgs if not (path.parent / src).exists()]
if missing:
issues.append(f"图表占位符缺失 {len(missing)} 处: {missing[:3]}")
return issues
for md_file in sorted(Path("./docs_out").glob("*.md")):
issues = check_md(md_file)
print(f"{md_file.name}: {'OK' if not issues else issues}")
三条检查对应三种最常见的解析事故。标题层级跳跃意味着标题树断了,切块会失去语义边界,检索时上下文被拦腰截断;表格列数不一致意味着结构化信息退化成字符串,数值型问题从此无解;图表占位符缺失意味着图表内容根本没进知识库——而图表恰恰是复杂文档信息密度最高的部分,丢了图表,等于丢了半份文档。
8. 解析质量评分表
抽检脚本只能抓硬伤,完整的质量评估我用下面这张评分表,每项满分 10 分:
| 质量维度 | 检查方法 | 权重 | 达标线 |
|---|---|---|---|
| 标题层级完整 | 抽检脚本 + 人工抽查目录 | 25% | ≥ 8 |
| 正文连贯性 | 抽查段落是否错乱、重复 | 20% | ≥ 8 |
| 表格结构还原 | 行列数校验 + 抽样核对数值 | 20% | ≥ 9 |
| 图表与图片 | 占位符完整性 + 描述文字 | 15% | ≥ 7 |
| OCR 准确率 | 扫描件抽样人工比对 | 15% | ≥ 8 |
| 特殊符号 | 公式、单位、代码块抽查 | 5% | ≥ 7 |
加权总分低于 8 分的文档,我会打回重新解析或换解析路线。规则很简单:质量分不达标,宁可不上库,也不把脏数据喂给 Embedding API——脏数据进库容易,清洗返工的成本高得多。
评分表还有一个隐藏作用:给托管 API 和自建管线设定同一把尺子。同一批文档,两条路线各解析一遍,对照评分,谁的分高就用谁,分数接近就看成本。选型不再靠感觉,而是靠数据说话。
9. 成本与风险提示
托管解析 API 与自建路线各有各的账,三个风险点必须提前想清楚:
- 解析 API 按页计费。Parse 5 这类托管解析通常按页计价,接入前先统计文档总页数,算清单批成本。几十页的小文档无所谓,几千页的合同库就要认真算账,页数 × 单价 × 重复解析次数,都是真金白银。
- 长文档分页策略。托管 API 对单文档页数常有限制,超限要拆分。拆分边界优先选章节,绝不要把表格从中间切开——一个被切两半的表格,两个半块都是废数据,检索永远拼不回来。
- 隐私合规。含客户信息、合同、内部制度的文档不要外传,走本地路线:markitdown + 本地 OCR 就能闭环。公开资料再走托管 API 提质量。合法接入的底线是:数据流向与数据权限必须由我自己可控,不能因为省事把合规风险外包出去。
混合路线的具体做法,我一般这样切:公开产品手册、行业报告这类非敏感文档,量大时交给托管解析 API,质量高、维护省;合同、员工档案、客户数据一律本地解析,解析结果同样进同一套抽检与评分流程。两条管线的产出格式统一成 markdown,后续切块与入库完全共用一套代码,切换成本接近于零。
10. 验收清单
上生产前,我按这张清单逐项打勾:
- 批量转换脚本跑通,产出 markdown 文件齐全
- 抽检脚本零硬伤:无标题层级跳跃、表格列数一致、图表占位符完整
- 加权质量分全部 ≥ 8,抽样人工核对通过
- 长文档分页策略确认:按章节切分,表格不被拆开
- 托管解析的按页账单有预估,成本在预算内
- 敏感文档确认全程本地处理,未上传第三方
- 切块参数(块大小、重叠)按标题层级配置,做过一轮检索验证
- 用 3–5 个典型问题实测召回,答案质量达标
清单里最后两项最容易偷懒,恰恰最关键:切块参数不验证,向量库就是盲盒;典型问题不实测,上线即翻车。这两项做完了,这一期的接入成本账才算真正闭环。
11. 总结
这一期讲清楚了文档解析这条第一道工序:解析质量决定 RAG 命中率,Parse 5 把托管解析的复杂版式质量拉到了新的水位,而 markitdown 的 18 万星证明开源自建管线同样可行,真正聪明的做法是按文档敏感度和版式复杂度分流,把解析成本花在该花的地方。4sapi 在 https://4sapi.com 提供合规的大模型 API 中转,把 Embedding、推理这一串 API 的接入成本压下来,解析这一步做扎实,整条链路的钱才算花得值。我踩过的解析坑,多半都是同一条管线上的常见坑——评论区聊聊,交换各自的翻车经历。