ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

从OCR到结构化Markdown:文档解析如何重塑知识库与RAG流程

2026/9/12 3:23:37 拓冰建站 浏览量
从OCR到结构化Markdown:文档解析如何重塑知识库与RAG流程 最近 GitHub 上有个项目在技术圈热度涨得很快Firecrawl。原本它做的是把网页抓下来转成干净的 Markdown 喂给大模型后来新增的 anydoc 能力直接把 PDF、Word、PPT 这类办公文档整份丢进去出来就是结构清晰的 Markdown。这让我彻底扔掉了用了两年的截图→OCR→手动整理老流程。这篇就拆一拆Firecrawl anydoc 到底是怎么做到的以及我在实际项目中拿它替代截图 OCR 的完整记录和踩坑经验适合做知识库、文档分析、RAG 管线的朋友参考。1. 截图再 OCR 这套老流程痛点到底在哪1.1 一次合同扫描件让我彻底崩溃先说一个真实场景。去年底整理项目合同几十份 PDF 全是扫描件没有文字层。我当时的习惯动作很固定打开文件、找到关键页、截图、丢进 OCR 工具、复制文字到备忘录、手动排格式。一份合同四五页看着不多但每页都要截图、识别、清理遇到印章盖住了关键条款、表格斜着拍、页码混进正文的情况一次识别结果基本不能直接用。最崩溃的是表格。合同里的付款计划表、验收标准表截图 OCR 出来就成了一坨换行混乱的纯文本哪列是金额、哪行是时间节点全靠眼睛重新对齐。我算过一次一份 20 页的扫描版财报光整理表格就花了三个多小时。这个效率放在喂给 RAG 做问答的工作流里完全不可接受——文档问答的核心是保留结构纯文字流进去检索效果一定差。那次之后我开始认真找方案有没有一个工具能把整个 PDF 丢进去输出的不是乱糟糟的文本而是保留标题层级、表格、代码块的 Markdown结果就撞上了 Firecrawl 的 anydoc。1.2 截图 OCR 的四个硬伤回头看截图 OCR 在办公文档场景里有四个绕不开的硬伤分辨率瓶颈。屏幕截图受显示尺寸限制一张 A4 纸压缩到屏幕宽度后一行文字的像素高度可能只有十几像素。OCR 对这种低分辨率文字非常敏感识别率肉眼可见地往下掉小字号、细体字尤其严重。版式信息丢失。截图本身就是拍平的操作文档里的标题层级、列表嵌套、表格行列、页码全部变成了一张位图。OCR 只能输出文字流结构信息只能靠人后期脑补。表格基本靠人工。多列表格、合并单元格、跨页表格截图 OCR 基本无解。即便识别出了行列语义上的对齐关系也丢了输出结果需要大量手工修复。批量处理等于噩梦。一页页截图、一张张识别、一段段粘贴20 页的资料意味着至少 20 次重复劳动。中间只要搞错一页顺序整个整理工作就乱套。这还只是文字提取层面。如果目的是给 LLM 应用准备数据纯文本 OCR 输出几乎无法直接使用没有结构、没有分块边界、上下文碎片化。所以我需要的不是又一个 OCR 工具而是一个能输出结构化 Markdown 的文档解析器anydoc 恰好是这个定位。2. Firecrawl 和 anydoc从抓网页到啃文档的进化2.1 Firecrawl 本来是干嘛的Firecrawl 最早解决的是另一个问题网页抓取。传统爬虫抓下来的是 HTML带着大量导航、广告、脚本、样式标签直接喂给大模型既浪费 token 又干扰理解。Firecrawl 的思路是先把网页渲染成干净内容再转成结构化的 Markdown 或 JSON让 LLM 拿到的是一份清爽的正文。因为对 RAG 管线友好它在 GitHub 上一直保持很高的热度也成了不少本地知识库项目的数据管道组件。我自己用它的场景是抓取技术文档和博客文章。以前用 Requests BeautifulSoup 写解析规则换个网站结构就得改代码维护成本很高。Firecrawl 做了很多页面智能处理比如移除导航、识别正文主区域、把表格转成 Markdown能省下不少写规则的精力。不过这些都是网页层面的能力直到 anydoc 出现它才从网页抓取工具进化成全文档解析工具这也是它在技术讨论区重新被刷屏的原因。2.2 anydoc 在 Firecrawl 里承担什么角色anydoc 字面意思就是任何文档。它是 Firecrawl 在文档解析方向的延伸输入可以是 PDF、DOCX、PPTX、XLSX甚至是扫描件图片输出是统一结构的 Markdown。定位上它和网页抓取是互补的。Firecrawl 原来的抓取流程针对 HTML 文档优化但现实世界的知识库里大量资料是办公文档——产品手册、研究报告、合同协议、会议 PPT。这些文件不能像网页那样通过 DOM 解析必须先经过版面分析和 OCR 才能进入 Markdown 化流程。anydoc 干的就是这层脏活累活。使用方式上anydoc 没有搞一套独立体系而是延续了 Firecrawl 的 SDK 和 API 风格。本地部署一套服务后抓网页和解析文档用的是同一套调用入口只是参数不同。这对已经有 Firecrawl 使用习惯的人非常友好学习成本几乎为零。2.3 为什么偏偏是 Markdown 而非其他格式你可能会有疑问转换输出为什么选 Markdown而不是直接输出 HTML 或纯文本我在实际使用中体会很深Markdown 兼顾人读和机读。它保留标题层级、列表、表格、代码块、引用这些语义信息人可以直接打开编辑机器也能无损解析作为 RAG 管线的中间格式特别合适。Token 利用率高。同样的内容Markdown 比 HTML 少很多标签噪音喂给 LLM 时占用的 token 更少回答质量反而更高。生态成熟。Typora、VS Code、Obsidian 都原生支持 Markdown转换结果可以直接进笔记系统、知识库或后续的自动化流程不需要额外开发适配。一个格式打通多处。文档分析、自动摘要、问答检索、报告生成几乎所有的 LLM 应用都接受 Markdown 输入。输出一种格式就能服务下游所有任务。3. anydoc 内部是怎么把文档拆成 Markdown 的3.1 文档类型探测与预处理拿到一份文件后anydoc 首先做的是判断这是什么文档。这一步不是简单的看扩展名而是真的读文件头、解析内部结构。如果 PDF 本身带文字层数字生成的 PDF处理走的是解析路线直接从内容流里提取文本和排版信息准确率高且速度快。如果文件是扫描版 PDF 或图片没有文字层就走 OCR 路线先把每页渲染成图像再交给 OCR 引擎识别。预处理环节也很关键。很多扫描件存在页面倾斜、背景色偏、边缘阴影的问题直接丢给 OCR 会严重影响准确率。anydoc 会先做旋转矫正、去噪、增强对比度把图像调整到适合识别的状态。我在自托管环境跑过一次歪斜严重的扫描合同关闭预处理和开启预处理的输出差异非常明显前者出现了大量错字。3.2 版面分析与 OCR 引擎的配合这是把图片变成文字和文字摆回正确位置两步分开的关键。OCR 引擎解决的是像素到字符的转换它认识字但不理解版面。一份 PDF 扫描件里标题字号大、正文段落有缩进、表格有行列线、图片有边框这些都是版面信息。anydoc 通过版面分析把页面划分成不同区域标题区、正文区、表格区、图片区、页眉页脚区然后对每个区域分别处理。这样做的优势很明显。标题区域识别后可以映射为 Markdown 的#层级正文区域映射为普通段落表格区域映射为 Markdown 表格图片区域映射为![]()。OCR 引擎负责认出某个单元格里的数字是 1200 还是 120O版面分析负责这个数字属于表格第三行第二列。两者配合才能输出结构正确的 Markdown。自托管模式下 OCR 引擎的选择比较灵活常见的开源方案 Tesseract、PaddleOCR 都可以接。PaddleOCR 对中文识别效果好一些Tesseract 胜在部署简单稳定。我自己处理中文扫描件时会优先考虑中文优化过的引擎识别率有明显差距。3.3 表格、标题层级、代码块是怎么还原的文档里最难还原的三个元素表格、标题、代码块。表格处理上anydoc 会检测页面里的表格结构先找表格线或行列对齐特征再推断单元格边界最后按行列关系输出为 Markdown 表格语法。合并单元格会被尽量展开成占位单元格跨页表格会尝试拼接。实测下来带明显表格线的表格还原效果最好无边框表格仍然会有一定概率把列内容混在一起。标题层级的还原逻辑有点像给文字分类。通过字号大小、字体粗细、段落前后间距、是否处于页面顶端等特征判定一个文本块是第一级标题、第二级标题还是正文。然后对应输出#、##或普通段落。PPT 文件的标题识别会更简单一些因为每页都有明确的标题占位符。代码块的还原在技术文档里特别实用。等宽字体区域、特定背景色、行首缩进模式都会被识别为代码块输出为 Markdown 代码块语法并保留语言标注。我处理过一些技术手册 PDF代码部分被完整还原成可复制执行的代码块这在纯 OCR 流程里几乎不可能实现。4. 实操记录拿一份真实报告跑通全流程4.1 自托管部署时要注意的几个点Firecrawl 支持云端 API 和自托管两种方式。涉及企业内部文档、合同这类敏感内容时我建议优先自托管数据不出内网心里踏实。自托管基于 Docker 部署核心组件包括 API 服务、工作队列、Redis、数据库和 Worker。我的环境配置是 4 核 CPU、8GB 内存起步如果经常处理上百页的大文件16GB 会更稳。磁盘空间要留足文档解析过程会产生中间缓存和处理日志。部署命令不复杂git clone https://github.com/firecrawl/firecrawl.git cd firecrawl cp .env.example .env docker compose up -d启动完成后默认 API 地址一般在http://localhost:3002可以通过健康检查接口确认服务状态。整个启动过程大概几分钟第一次启动需要拉取基础镜像后面再启动就很快了。一个小提醒.env里的一些密钥配置生产环境务必替换成自己的随机值不要沿用示例配置。这块以前吃过亏虽然不影响功能但安全性不能偷懒。4.2 提交文档与拿结果核心调用逻辑我实际用的时候直接用 Python SDK 比较顺手调用逻辑非常直接from firecrawl import FirecrawlApp app FirecrawlApp( api_keyyour-api-key, api_urlhttp://localhost:3002 ) result app.scrape_url( file:///data/report.pdf, params{formats: [markdown]} ) markdown_content result[markdown] with open(report.md, w, encodingutf-8) as f: f.write(markdown_content)核心就一个scrape_url调用传文件路径和输出格式返回结果里取markdown字段。如果你用的是云端托管版本也可以直接传公网文件链接或直接上传文件流原理一样。这里注意一点不同版本的 SDK 字段名可能略有差异实际使用前先打印一下返回结果的结构确认markdown字段是否存在。我升级过一次 SDK 版本返回值结构就有细微变化盲取字段容易踩坑。4.3 同一份文档传统 OCR 和 anydoc 的对比结果为了验证效果我拿一份 15 页的混合型报告做过对比测试。这份报告包含数字生成的文字页、2 页扫描件、3 张复杂表格和一些代码片段。维度截图传统 OCRFirecrawl anydoc处理方式逐页截图、逐张识别整份 PDF 一次提交耗时约 40 分钟人工操作约 2 分钟自动完成表格还原基本不可用需手工重建表格语法完整还原标题层级丢失纯文字流按层级输出为 H1/H2/H3代码块无法识别输出代码块并保留缩进人工整理时间3 小时以上约 15 分钟校对扫描件准确率视截图质量波动大预处理后相对稳定当时最直观的感受是以前需要大半个下午做的事现在泡杯咖啡的功夫就完成了。当然这不是说 OCR 类工具就没用了轻量场景下截图 OCR 依然有它的便利性但一旦涉及整份文档、结构化输出、批量处理anydoc 的路线明显是更优解。5. 踩坑记录格式、扫描件和混合内容5.1 扫描件质量直接决定输出上限先泼一盆冷水anydoc 不是魔法扫描件的质量决定了输出质量的上限。我试过一份 150dpi 扫描且页面倾斜的 PDF转换结果里错字明显增多表格边界也识别得磕磕绊绊。提高扫描分辨率到 300dpi 以上倾斜校正做好输出质量立刻上了一个台阶。如果原始文件本身是手机随手拍的照片透视变形很严重建议在进入转换前先用图像处理工具做一次校正。还有一类问题是印章和背景干扰。合同上常见的红色印章、文件背景的水印有时候会被 OCR 误识别成正文内容。这种情况下输出里会出现一些奇怪的字符片段需要在后处理时过滤。anydoc 虽然做了一些预处理但复杂背景下的误识别仍是当前技术上限提前有心理预期会好很多至少比传统截图 OCR 的出错方式要集中、可控。5.2 最难的永远是表格和页眉页脚混合内容文档里我踩得最多的坑集中在表格和页眉页脚两处。表格方面带明显网格线的表格还原效果不错但无边框表格、用 Tab 对齐的伪表格、跨页断行的表格输出结果仍然可能出现列错位。特别是那种用空格和制表符硬排版的财务表格单元格边界全靠目测任何解析工具都会头疼。我的处理策略是这类关键表格不指望完全自动解析后用脚本快速校验列数再手动微调几十个单元格比从零开始快得多。页眉页脚则是另一个问题。文档页码、公司名称、日期这些页眉页脚信息有时会被混入正文段落导致内容衔接出问题。这个问题在传统 OCR 里更严重因为纯文本流里根本没有页的概念。anydoc 对页眉页脚做了区域识别大部分情况下能过滤掉但遇到页眉样式和正文接近的文档还是会有漏网之鱼。我在清理阶段会专门检查开头和结尾几行把混入的页码和重复标题删掉。5.3 输出前的清洗Markdown 不是终点转换完成只是第一步离能用还差一次清洗。常见的清洗任务包括删除多余空行、合并被错误断行的段落、清理 OCR 产生的特殊字符、校验表格列数是否一致、处理未正确转义的 Markdown 符号。我自己写了一个简单的后处理脚本用正则批量处理那些高频问题比如把连续三个以上的空行压缩成一个把行尾多余空格去掉把误识别的中文标点转回全角形式。import re with open(report.md, r, encodingutf-8) as f: content f.read() # 压缩连续空行 content re.sub(r\n{3,}, \n\n, content) # 去掉行尾多余空格 content re.sub(r[ \t]\n, \n, content) # 修复常见的全角/半角标点错乱 content content.replace(。, 。).replace(,,, ,) with open(report_clean.md, w, encodingutf-8) as f: f.write(content)清洗的目的不是追求完美还原而是让 Markdown 达到可以安全进入下游流程的程度。对 RAG 场景来说结构正确、内容干净比逐字逐句精确更重要。6. 这类工具对 RAG 和 LLM 工作流的实际意义6.1 喂给大模型之前文档结构就是上下文做 RAG 的朋友一定知道文档切块策略直接影响检索效果。以前用纯文本 OCR 输出的内容切块经常出现一个块里既包含标题又包含正文、甚至横跨两个表格片段的情况检索时上下文混乱回答质量自然上不去。Markdown 输出改变了这件事。标题层级可以作为切块的天然边界表格整体可以作为一个结构化块保存代码块可以被单独索引。检索时用户问到某一章内容系统能精确定位到对应标题下的块上下文完整度远高于无差别切块。我接的一个知识库问答项目切块策略从固定字符数改成按 Markdown 标题层级切块之后回答准确率提升非常明显。另外LLM 对 Markdown 的语义理解比对纯文本好得多。喂进去的如果是带结构的 Markdown模型在生成答案时能正确参考表格对应关系和层级逻辑而不是靠概率推断句子关系。这一点在所有文档类应用里都会体现出来。6.2 适合谁用、不适合谁用聊几个我在实践中总结的适用边界。适合用的场景搭建企业内部知识库、合同条款分析、论文文献整理、产品手册转问答机器人、财报数据提取。共同点是文档量大、需要保留结构、输出要进入自动化管道。不太适合的场景只想从手机拍的照片里提取一小段文字、快速复制聊天记录里的内容、偶尔一次性的轻量识别。这些场景截图 OCR 依然是更轻便的选择没必要为了一句话启动一整套文档解析服务。另外如果文档里全是复杂数学公式、手写批注、精细排版的艺术类 PDF目前的解析效果还不能让人满意。公式识别、手写识别本身是独立的难题不是文档转 Markdown 能顺手解决的。遇到这类内容我通常会把关键公式截出来单独处理。6.3 我现在的工作流变成了什么样经过这段时间的实际使用我处理办公文档的第一动作已经从截图变成了先丢给 anydoc。日常工作流大致是收到文档 → 提交转换 → 快速清洗 → 进入知识库或直接问 LLM。整个过程自动化之后最明显的变化不是我省了多少时间而是心态上的改变。以前看到扫描版合同会很烦躁因为知道接下来要花大量时间做机械劳动。现在完全不怕扔进 pipeline 里几分钟后拿到的就是能直接用的 Markdown。这种脏活有人承包的感觉可能是这类工具给我最大的价值。如果你也在搭知识库、做文档分析或者只是手上囤了一堆扫描版 PDF 不知道怎么处理可以试试把 Firecrawl 的 anydoc 加进你的工具链。先拿一份有代表性的真实文档跑一遍感受一下表格还原和标题层级保留的效果再决定要不要用它替换现在的 OCR 流程。