【python】一文掌握 markitdown 库的操作:把 PDF/Word/PPT 转成 Markdown 的完整配置与验证
1. 为什么文档知识库整理总卡在格式转换这一步做文档知识库整理的人大概率都遇到过同一个场景手头攒了几十上百份 PDF 报告、Word 方案、PPT 汇报和 Excel 台账想把它们喂给大模型做检索问答或者内容迁移结果第一步就卡住了。PDF 复制出来是乱序的Word 里的表格粘到编辑器里全散架PPT 一页页导出图片又没法检索。这时候你需要的是一个能把办公文档结构尽量保留地转成 Markdown 的 Python 工具markitdown 就是干这个的。markitdown 是微软开源的一个轻量级 Python 库核心能力是把 PDF、Word、PPT、Excel、图片、音频、HTML、CSV、JSON、XML、ZIP、EPub 等格式统一转成 Markdown。它和 textract 定位相似但更侧重保留文档结构——标题层级、列表、表格、链接这些在转换后尽量不丢。输出结果对人类可读但它的设计目标其实是给文本分析管道和 LLM 用的所以 token 效率高主流大模型对 Markdown 的“母语感”也强拿它做知识库切分和向量化会顺很多。适合谁用做 RAG 知识库的工程师、需要批量迁移历史文档的内容运营、想把会议材料整理成可检索笔记的技术同学。这篇文章我会从安装、单文件转换、批量目录处理、Python API 调用一路写到常见乱码和表格错位的排查最后给一套可复制的配置让你一次跑通全流程。中间涉及模型调用验证的部分我会用 TaoToken 的接口来演示因为它兼容 OpenAI SDK改个 base_url 就能接上省去自己折腾环境的时间。先说清楚一个预期markitdown 不是高保真排版还原工具。它不会帮你把 PDF 里的双栏排版完美重排也不会把复杂合并单元格的 Excel 还原成 Markdown 表格的每个格子。它的强项是“结构保留 文本可读”够用且高效。如果你要的是像素级还原那得走别的路子。但对知识库整理来说markitdown 的性价比很高。2. 安装 markitdown 与 TaoToken 接入前置准备2.1 markitdown 的三种安装方式最省事的是 pip 一把梭把全部可选依赖都装上pip install markitdown[all]如果你只处理特定格式可以按需装减少依赖体积pip install markitdown[pdf,docx,pptx,xlsx]可选依赖项对照如下方便你按场景裁剪依赖项作用all安装所有可选依赖pdfPDF 文件转换docxWord 文件转换pptxPowerPoint 文件转换xlsxExcel 文件转换xls旧版 Excel 文件转换outlookOutlook 邮件转换audio-transcriptionwav/mp3 音频转录youtube-transcriptionYouTube 视频转录az-doc-intelAzure 文档智能源码安装适合想改代码或跟最新特性的同学git clone gitgithub.com:microsoft/markitdown.git cd markitdown pip install -e packages/markitdown[all]Docker 方式适合放进流水线做隔离运行docker build -t markitdown:latest . docker run --rm -i markitdown:latest ~/your-file.pdf output.md2.2 为什么这里要提 TaoTokenmarkitdown 本身做纯文本转换不需要联网但有两个场景会用到模型能力一是图片 OCR 和图像描述二是音频转录后的文本润色。markitdown 支持传入llm_client和llm_model用大模型给图片生成描述。这时候你需要一个兼容 OpenAI SDK 的接口。TaoToken 的 API 地址是https://taotoken.net/api兼容 OpenAI 的调用方式你只需要把base_url指过去、填上自己的 Key 就能用。它的模型对话入口在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API Key 在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 管理。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。如果你只是做 PDF/Word/PPT 转 Markdown不碰图片和音频那这一步可以跳过markitdown 离线就能跑。但既然要做完整知识库图片里的文字和图表说明往往也是信息建议把这条链路一起配好。2.3 环境检查装完后先确认版本和命令可用markitdown --version python -c from markitdown import MarkItDown; print(ok)如果markitdown命令找不到多半是 pip 的 scripts 目录没进 PATH用python -m markitdown也能跑。这一步别跳过后面批量脚本报错时能快速定位是环境问题还是代码问题。3. 可复制的转换配置与批量目录处理脚本3.1 命令行单文件转换最基础的用法把 PDF 转成 Markdown 输出到终端markitdown path-to-file.pdf document.md用-o指定输出文件更规范markitdown path-to-file.pdf -o document.md也支持管道输入cat path-to-file.pdf | markitdown3.2 Python API 基本用法单文件转换的 Python 写法from markitdown import MarkItDown md MarkItDown(enable_pluginsFalse) result md.convert(test.xlsx) print(result.text_content)enable_pluginsFalse是默认值插件默认禁用。要启用第三方插件改成True或者命令行加--use-pluginsmarkitdown --list-plugins markitdown --use-plugins path-to-file.pdf3.3 批量目录处理脚本知识库整理的核心诉求是批量。下面这个脚本递归遍历目录把所有支持的办公文档转成同名.md并保留相对目录结构import os from pathlib import Path from markitdown import MarkItDown SUPPORTED {.pdf, .docx, .pptx, .xlsx, .xls, .html, .csv, .json, .xml, .epub} def batch_convert(src_dir: str, dst_dir: str): md MarkItDown(enable_pluginsFalse) src_root Path(src_dir) dst_root Path(dst_dir) ok, fail 0, [] for path in src_root.rglob(*): if not path.is_file() or path.suffix.lower() not in SUPPORTED: continue rel path.relative_to(src_root) out_path dst_root / rel.with_suffix(.md) out_path.parent.mkdir(parentsTrue, exist_okTrue) try: result md.convert(str(path)) out_path.write_text(result.text_content, encodingutf-8) ok 1 print(f[OK] {rel} - {out_path}) except Exception as e: fail.append((str(rel), str(e))) print(f[FAIL] {rel}: {e}) print(f\n完成成功 {ok} 个失败 {len(fail)} 个) for name, err in fail: print(f - {name}: {err}) if __name__ __main__: batch_convert(./docs, ./markdown_out)这个脚本的关键点用rglob(*)递归、用relative_to保留目录层级、用with_suffix(.md)换扩展名、用encodingutf-8写文件避免中文乱码。失败的文件单独收集方便二次处理。3.4 带模型能力的配置片段如果你要用大模型给图片生成描述配置如下。这里用 TaoToken 的兼容接口把base_url指向https://taotoken.net/apifrom markitdown import MarkItDown from openai import OpenAI client OpenAI( api_key你的_TaoToken_Key, base_urlhttps://taotoken.net/api ) md MarkItDown( llm_clientclient, llm_modelgpt-4o ) result md.convert(example.jpg) print(result.text_content)如果你用 Claude Code 或 Cline 这类工具做长期编码和 Agent 任务可以考虑 Coding Plan入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。它的定位是给持续编码场景用的和单次转换的按量调用是两回事按自己的使用频率选。3.5 文档智能转换配置markitdown 还支持 Azure 文档智能做更强的 PDF 解析from markitdown import MarkItDown md MarkItDown(docintel_endpointdocument_intelligence_endpoint) result md.convert(test.pdf) print(result.text_content)这个需要你有对应的 endpoint普通知识库整理用默认解析器就够了遇到复杂表格再考虑上文档智能。4. 验证请求与转换结果对照4.1 转换前后对照拿一个带标题、列表和表格的 Word 文档测试转换前是常规排版转换后 Markdown 大致长这样# 季度运营报告 ## 一、核心指标 - 新增用户12,340 - 活跃率38.2% - 留存率61.5% ## 二、渠道明细 | 渠道 | 曝光 | 转化 | | --- | --- | --- | | 搜索 | 45000 | 3.2% | | 社交 | 32000 | 1.8% |标题层级、列表符号、表格管道符都保留了这就是 markitdown 的价值——结构没丢后续切分和向量化都好处理。4.2 验证模型接口是否通如果你配了 TaoToken 做图片描述先单独验证接口连通性别等批量跑一半才发现 Key 错了from openai import OpenAI client OpenAI( api_key你的_TaoToken_Key, base_urlhttps://taotoken.net/api ) resp client.chat.completions.create( modelgpt-4o, messages[{role: user, content: 回复两个字通了}] ) print(resp.choices[0].message.content)返回正常内容说明 Base URL、Key、Model ID 三件套都对。这一步过了再跑 markitdown 的图片转换就不会因为接口问题失败。4.3 批量结果抽查批量脚本跑完后别只看“成功 N 个”就完事。抽查几个文件ls -lh markdown_out/ head -50 markdown_out/某报告.md重点看三处中文有没有乱码、表格有没有错位、标题层级对不对。抽查通过再进下一步的切分和入库。4.4 转换质量快速评估可以写个小脚本统计每个输出文件的字符数和行数异常小的文件往往是转换失败的信号from pathlib import Path for p in Path(./markdown_out).rglob(*.md): text p.read_text(encodingutf-8) if len(text) 100: print(f[可疑] {p} 仅 {len(text)} 字符)这个动作能帮你快速捞出那些“转换成功但内容为空”的坑。5. 常见报错与乱码表格错位排查5.1 401 报错现象调用模型接口时返回401 Unauthorized或invalid api key。原因基本是 Key 填错、Key 过期、或者base_url写成了带路径的完整地址。检查两点api_key是不是从 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 复制的完整串base_url是不是https://taotoken.net/api不要多加/v1之类的后缀。改完重跑 4.2 的验证脚本。5.2 local proxy failed现象请求报local proxy failed或连接超时。这类报错通常是本地网络环境或代理配置干扰了请求。检查你的环境变量里有没有残留的HTTP_PROXY、HTTPS_PROXY有的话临时清掉再试unset HTTP_PROXY HTTPS_PROXY另外确认base_url拼写正确别把taotoken.net敲错。5.3 reading choices 报错现象KeyError: choices或reading choices of undefined。这说明返回体里没有choices字段通常是接口返回了错误信息但代码直接去取choices了。加一层判断resp client.chat.completions.create(...) if not resp.choices: print(返回异常, resp) else: print(resp.choices[0].message.content)根因多半还是 Key 或模型名不对先按 5.1 排查。5.4 OAuth 相关报错现象出现OAuth、token expired之类提示。如果你用的是需要 OAuth 的客户端工具检查登录态是否过期重新授权即可。用 API Key 直连的方式不涉及 OAuth遇到这类报错说明你走的是另一条链路确认自己用的是哪种鉴权方式。5.5 中文乱码现象转换后的 Markdown 里中文变成????或方块。根因是写文件时没指定编码。Python 里open()默认编码跟系统有关Windows 上常是 GBK。解决写文件统一用encodingutf-8读文件也一样。批量脚本里我已经加了如果你自己写别漏。5.6 表格错位现象Excel 或 PDF 里的表格转出来列对不齐管道符数量不一致。markitdown 对简单表格处理得好复杂合并单元格、跨页表格容易错位。排查动作先看原始文件是不是有合并单元格如果有转换前先在 Excel 里拆开PDF 里的表格如果是图片形式纯文本解析拿不到需要走 OCR 或文档智能。对错位的表格可以转换后手动修或者用脚本检测每行管道符数量是否一致for line in text.splitlines(): if line.strip().startswith(|): cols line.count(|) if cols ! expected_cols: print(列数异常, line)5.7 图片没有文字现象PDF 或 PPT 里的图片转出来是空的。markitdown 默认不做 OCR图片里的文字需要配llm_client走模型描述或者装 OCR 相关依赖。按 3.4 的配置接上模型接口图片就能生成描述文本。5.8 插件没生效现象加了--use-plugins但插件没起作用。先markitdown --list-plugins确认插件装上了。插件默认禁用是安全设计必须显式开启。如果列表为空说明插件没装成功检查 pip 安装日志。6. 把转换链路接进你的知识库工作流跑通单文件和批量转换只是第一步真正省时间的是把这条链路固化下来。我的做法是源文档放./docs转换输出到./markdown_out然后用一个定时任务或手动触发跑批量脚本输出目录直接对接后续的切分和向量化流程。这样每次新增文档重跑一次脚本就行不用手动一个个转。如果你后续要做检索问答Markdown 的标题层级天然适合做分块依据——按##切分每块带上下文标题检索命中率比纯文本高不少。表格转成 Markdown 后也能被模型直接理解比截图强。模型接口这块按量调用走 API Keys 就行入口在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 接入细节看文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。如果你要长期跑 Agent 做自动化整理Coding Plan 更合适入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。想先试试模型对话效果可以直接去 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 体验。最后提醒一个容易忽略的点批量转换前先备份源文件转换脚本只读源文件、只写输出目录别让脚本误删或覆盖原文档。输出目录和源目录分开这是最基本的隔离。跑完抽查几个文件确认中文、表格、标题都正常再进下一步。这套流程我用了挺久稳定且省心你可以直接拿去改。