markitdown-ocr について
markitdown-ocr プラグインの利用ガイドで、MarkItDown による PDF、DOCX、PPTX、XLSX 変換へ LLM ビジョン OCR を追加します。スキャンページや埋め込み画像向けに、互換クライアントやプロンプトの設定、問題の切り分けを案内します。
主な機能
- 01PDF、DOCX、PPTX、XLSX の OCR
- 02OpenAI 互換のビジョンクライアント利用
- 03OCR プロンプトのカスタマイズ
- 04Markdown 出力で OCR ブロックを保持
- 05プラグイン設定とトラブルシューティング
活用シーン
- 01スキャン PDF からテキストを抽出
- 02文書内画像の文字を認識
- 03ローカルまたは Azure の OCR バックエンド設定
- 04OCR 出力がない場合の原因調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ full-stack-skills/ document-skills --skill markitdown-ocrインストール後、Claude Code で/markitdown-ocrを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlexamples/advanced/cost-and-concurrency.mdscenarios.mdexamples/backends/azure-and-local.mdexamples/basic/first-ocr.mdreferences/backends/compatible-clients.mdreferences/plugin/internals.md詳細
MarkItDown OCR(LLM Vision)完全ガイド
用途:LLM がこのスキルを使って
markitdown-ocrプラグインを正しく設定して呼び出し、PDF/DOCX/PPTX/XLSX 内の埋め込み画像やスキャンページから OCR 抽出を行えるようにします。オフラインの基準:
packages/markitdown-ocr/の main ブランチ(2026-08 時点)に基づきます。 「プラグインが現在 X に対応しているか/パラメーター名が変更されたか」に関する質問は、公式 README とソースコードを基準にしてください:
- ソースコード:
packages/markitdown-ocr/src/markitdown_ocr/- エントリーポイント:
_plugin.py- OCR サービスの抽象化:
_ocr_service.py
このスキルを使う場面
✅ このスキルを使う場面(LLM Vision OCR/スキャン文書/埋め込み画像):
- ユーザーが「スキャンした PDF をどうやって Markdown に変換するのか」と尋ねた場合(元の PDF に選択可能なテキストがない)
- ユーザーが「PPT/Word/Excel に埋め込まれた画像から、どうやって文字を抽出するのか」と尋ねた場合
- ユーザーが GPT-4o/GPT-4o-mini/Claude/Gemini を使って OCR を行いたい場合
- ユーザーが「Azure OpenAI で markitdown-ocr をどう設定するのか」と尋ねた場合
- ユーザーが「markitdown-ocr プラグインをどうインストールして使うのか」と尋ねた場合
- ユーザーがローカルで OCR を行いたい場合(vLLM/Ollama を使用)
❌ このスキルを使わない場面:
- 通常の CLI の使い方だけを知りたい場合(画像内の文字は不要で、PDF/DOCX を変換するだけ)→
markitdown-cli - ユーザーが「MarkItDown とは何か/どの形式に対応しているか/どれを選べばよいか」と尋ねた場合 →
markitdown-awesome - ユーザーが「Azure Document Intelligence をどう設定するのか」と尋ねた場合 →
markitdown-cli(MarkItDown に組み込まれたバックエンドであり、この OCR プラグインではありません) - ユーザーが「PDF をプレーンテキストに変換するにはどうすればよいか」と尋ねた場合(textract のほうが適しています)→
markitdown-awesomeに案内します(references/ecosystem/alternatives.mdに markitdown/textract/unstructured/pandoc/docling の比較があります)
⚠️ 判断が曖昧な場合:
- ユーザーが「PDF を Markdown に変換したが、画像内の文字がない」と言った場合 → デフォルトで OCR プラグインの手順を案内します(このスキル)
- ユーザーが「LLM で表を抽出したい」と言った場合 → OCR で対応できますが、表の精度が重要な場合は Azure Document Intelligence を優先します
- ユーザーがすでに別の OCR(Tesseract/PaddleOCR)を使っている場合 → このスキルの対象外です。ツールの比較を案内してください
ワークフロー
OCR に関する質問に回答する際は、毎回次の手順に沿って進めます。
Step 1 — 文書の種類とユーザーの目的を確認する
- 入力形式:PDF/DOCX/PPTX/XLSX(このスキルはこの 4 種類のみを対象とします)
- 文字の位置:埋め込み画像/ページ全体のスキャン/両方
- LLM の選択肢:OpenAI/Azure/Gemini/ローカル
- コストの予算:高コストか低コストか(
gpt-4oとgpt-4o-mini)
Step 2 — 環境を確認する
pip show markitdown-ocr openai | grep -E '^(Name|Version)'
markitdown --list-plugins | grep ocr
どちらも出力があるはずです。
Step 3 — Python API の形式を選択する
- OpenAI:
MarkItDown(enable_plugins=True, llm_client=OpenAI(), llm_model="gpt-4o") - Azure OpenAI:
AzureOpenAI(...)に置き換え、azure_endpoint/api_versionを渡します - ローカル vLLM/Ollama:
OpenAI(base_url=..., api_key=<your-token>)(ローカルサービスでは通常、キーは検証されません) - Gemini:
OpenAI(base_url=..., api_key=<your-key>)
Step 4 — プロンプトを決める
- デフォルトのプロンプト(プラグインに組み込み済み):「すべてのテキストを抽出 … レイアウトを維持 … 解説は不要」
- 表を重視する場合:「表のレイアウトを Markdown のパイプで維持」を追加します
- テキストのみの出力を重視する場合:「説明、要約、コメントはしないでください」を追加します
Step 5 — 自己チェックして実行する
Validation 自己チェックリストと照らし合わせます。
Step 6 — 結果を処理する
- 出力に
*[Image OCR]…[End OCR]*ブロックが含まれている → 成功です - 表示されない → プラグイン一覧、クライアント、モデル名を確認します(詳しくは §8 のトラブルシューティングを参照)
Validation(自己チェックリスト)
OCR に関する質問に回答する前後に、毎回確認します。
- ユーザーは
markitdown-ocrをインストールしていますか?(pip show markitdown-ocr) - ユーザーは OpenAI 互換 SDK をインストールしていますか?(
openai/azure-openai/カスタム) - ユーザーは
OPENAI_API_KEY(または同等の認証情報)を設定していますか? - Python コードで
enable_plugins=True、llm_client、llm_modelのすべてを指定していますか?(3 つのうち 1 つでも欠けると OCR はスキップされます) - モデルは vision に対応していますか?(
gpt-3.5-turboのようなテキスト専用モデルは使用できません) - Azure OpenAI を使用する場合、
azure_endpointの末尾に/がなく、api_versionは有効ですか? - 機密文書を処理する場合、クラウド API ではなくプライベートなバックエンド(vLLM/Ollama)を推奨していますか?
- CLI に
--llm-client/--llm-modelを設定できると誤って約束していませんか?(これら 2 つの CLI オプションは存在せず、Python でラップする必要があります)
Gotchas
按命中频率从高到低:
- CLI 没有
--llm-client/--llm-model— 任何"命令行直接启用 OCR"的说法都是错的。要么写 Python 包装,要么告诉用户走 Python API。__main__.py的 argparse 注册表确认。 enable_plugins=True漏写 — MarkItDown 默认enable_plugins=False,插件根本不会注册。必带。- 漏
llm_client或llm_model— 插件"仍会注册"(无 OCR service),但实际转换静默跳过 OCR。检查清单:三个参数必须都给。 - LLM 失败被静默吞掉 —
_ocr_service.py::extract_text把异常转成OCRResult(text="", error=str(e));插件的convert()继续,不抛。表现:某张图的 OCR 块缺失,但文档其它部分 OK。没有任何 stderr 警告。 - PPTX 描述优先于 OCR — 若 LLM 返回了"图像描述",OCR 仅作 fallback。这意味着:同一张图,不同调用可能得到不同文本(描述 vs OCR)。
- XLSX 位置上下文丢失 — 图片被统一追加在数据表后(
### Images in this sheet:),不与行交错。表格密集场景慎用。 - 扫描 PDF 整页 300 DPI 渲染 — 比"嵌入小图"贵很多;50 页扫描件 ≈ 50 次 vision 调用,token 成本高。
- OCR 块靠正则识别 — 输出格式
*[Image OCR]\n…\n[End OCR]*是公开契约;后处理依赖它时,改了插件源码会让正则失效。 - 本地视觉模型可能不支持
data:URI — vLLM / Ollama 部分模型对 Base64 内嵌图片支持不稳;若失败,确认模型本身支持。 - Azure OpenAI
api_version不匹配 — deployment 与 SDK 版本必须兼容;用太新的版本号可能 404。 - 每张图一次 LLM 调用 = 高并发风险 — 100 张图直接用线程池可能撞 OpenAI RPM/TPM 限制。429 被静默吞掉表现为"图片没 OCR",不易察觉。
- OCR 块污染正文摘要 — 想"只看正文"必须先正则剥离
*[Image OCR]…[End OCR]*,否则 LLM 会把 OCR 文本当正文引用。 gpt-3.5-turbo不支持 vision — 用户填错模型名时,API 会 400,但被插件静默吞;表现是 OCR 块全没。- 缺
Pillow或PyMuPDF—markitdown-ocr依赖列表里已有;若手贱pip install markitdown-ocr --no-deps会缺这些,导致import直接报错。 - 大文件单次 memory spike — 整 PDF 走
convert_local时,PyMuPDF 渲染 + base64 编码同时在内存中;几十 MB 图片会爆内存。
1. 是什么 / 解决什么问题
MarkItDown 内置的 PDF/DOCX/PPTX/XLSX 转换器不会对内嵌图片或扫描页做 OCR——它们只取"已可解析的文本"。如果文档里有图片、扫描页、被转成图像的文字,默认输出里那块就是空的。
markitdown-ocr 插件接管上述四个内置转换器(优先级 -1.0,比内置 0.0 更高),通过 LLM Vision(任何支持图像输入的 OpenAI 兼容模型)抽取内嵌图片中的文字并按格式插回 Markdown 流。
核心特性:
- ✅ PDF / DOCX / PPTX / XLSX 全部支持
- ✅ 扫描 PDF 自动整页 OCR 回退(每页 300 DPI 渲染后整页送 LLM)
- ✅ DOCX 图片关系图完整保留(段落/标题/表格流不被破坏)
- ✅ PPTX 按"上→左"阅读顺序处理图片/占位符/组内图片
- ✅ XLSX 按图像 anchor 还原列/行字母坐标,图片统一追加在表格后
- ✅ 输出用
*[Image OCR]…[End OCR]*包裹每个 OCR 块,便于后处理 - ❌ 不引入新的 ML 库或二进制依赖(依赖已经在内置转换器里)
- ⚠️ LLM 调用失败时静默跳过,转换继续
2. 安装
pip install markitdown-ocr
# 同时确保有可用的 OpenAI 兼容客户端
pip install openai # 官方 OpenAI
# 或
pip install azure-openai # Azure OpenAI(若走 Azure)
源码安装(开发/调试):
git clone https://github.com/microsoft/markitdown.git
cd markitdown/packages/markitdown-ocr
pip install -e .
依赖项(自动拉取):markitdown>=0.1.0、pdfminer.six、pdfplumber、PyMuPDF、mammoth、python-docx、python-pptx、pandas、openpyxl、Pillow。
3. 配置 — LLM 客户端与模型
关键约束:插件本身不读任何 API key——它从 MarkItDown(llm_client=…, llm_model=…, llm_prompt=…) 拿客户端与模型,认证完全由客户端负责(走其自身的环境变量/凭据链)。
3.1 OpenAI(默认)
export OPENAI_API_KEY=sk-...
from openai import OpenAI
client = OpenAI() # 自动读 OPENAI_API_KEY
3.2 Azure OpenAI
from openai import AzureOpenAI
client = AzureOpenAI(
api_key=os.environ["AZURE_OPENAI_API_KEY"], # 或读其它环境变量
azure_endpoint="https://<res>.openai.azure.com/",
api_version="2024-02-01",
)
3.3 其它 OpenAI 兼容服务(Gemini / Ollama / vLLM / LM Studio / DeepSeek-VL 等)
任何实现了 client.chat.completions.create(model=…, messages=[…]) 接口的对象都能传进去,前提是它支持 vision 输入。示例:
import openai
client = openai.OpenAI(
base_url="https://generativelanguage.googleapis.com/v1beta/openai/",
api_key=os.environ["GOOGLE_API_KEY"],
)
# 之后正常使用,llm_model="gemini-2.0-flash" 等
更完整的兼容客户端矩阵见 backends/compatible-clients.md;实战脚本见 examples/backends/azure-and-local.md。
3.4 缺少 llm_client 时的行为
_plugin.py::register_converters 中:
if llm_client and llm_model:
ocr_service = LLMVisionOCRService(client=…, model=…, default_prompt=…)
如果 llm_client 或 llm_model 缺失,插件仍然注册(注册的是无 OCR service 的版本),但实际转换时静默跳过 OCR,回退到内置转换器的行为。验证插件存在:
markitdown --list-plugins
# 应当看到: ocr (package: markitdown_ocr)
4. Python API — 三种典型用法
4.1 最简(OpenAI + gpt-4o)
from markitdown import MarkItDown
from openai import OpenAI
md = MarkItDown(
enable_plugins=True, # ← 必须
llm_client=OpenAI(), # ← 必须
llm_model="gpt-4o", # ← 必须
)
result = md.convert("document_with_images.pdf")
print(result.markdown)
4.2 Azure OpenAI
from markitdown import MarkItDown
from openai import AzureOpenAI
md = MarkItDown(
enable_plugins=True,
llm_client=AzureOpenAI(
api_key=os.environ["AZURE_OPENAI_API_KEY"],
azure_endpoint="https://<res>.openai.azure.com/",
api_version="2024-02-01",
),
llm_model="gpt-4o",
)
print(md.convert("report.docx").markdown)
4.3 自定义 Prompt
md = MarkItDown(
enable_plugins=True,
llm_client=OpenAI(),
llm_model="gpt-4o",
llm_prompt="Extract all text from this image, preserving table structure.",
)
5. CLI — 当前没有原生 --llm-client / --llm-model
⚠️ 重要:
markitdown当前 CLI(__main__.py)未注册--llm-client/--llm-model。要通过命令行启用 OCR,用 Python 写一个 3 行包装即可。
5.1 推荐做法:shell 包装
写一个小文件 mdocr:
#!/usr/bin/env python3
# mdocr — 命令行包装 markitdown-ocr
import os, sys, argparse
from markitdown import MarkItDown
ap = argparse.ArgumentParser()
ap.add_argument("filename")
ap.add_argument("-o", "--output")
ap.add_argument("--model", default=os.environ.get("MD_OCR_MODEL", "gpt-4o"))
ap.add_argument("--prompt", default=None)
args = ap.parse_args()
client = OpenAI() # ← 替换为你要用的客户端构造
md = MarkItDown(
enable_plugins=True,
llm_client=client,
llm_model=args.model,
llm_prompt=args.prompt,
)
# 注意:请在环境变量 OPENAI_API_KEY / AZURE_OPENAI_API_KEY / OLLAMA_HOST 等中配置凭据
# 切勿把真实 key 写进源代码或 commit。
result = md.convert(args.filename)
sys.stdout.write(result.markdown)
if args.output:
with open(args.output, "w", encoding="utf-8") as f:
f.write(result.markdown)
chmod +x mdocr
./mdocr scan.pdf -o scan.md --model gpt-4o
5.2 一行 python -c(临时用)
python -c "
from markitdown import MarkItDown
from openai import OpenAI
import sys
md = MarkItDown(enable_plugins=True, llm_client=OpenAI(), llm_model='gpt-4o')
sys.stdout.write(md.convert(sys.argv[1]).markdown)
" scan.pdf > scan.md
6. フォーマットごとの動作の違い(OCR 結果の挿入方法)
| フォーマット | OCR ブロックの挿入位置 | 説明 |
|---|---|---|
| インライン(周囲のテキストに挿入)、上から下への垂直方向の読み順で挿入。スキャンページはページ全体を LLM に送信 | 埋め込み画像は page.images / ページ XObject から抽出。malformed PDF は自動的に PyMuPDF によるページ全体のレンダリングに切り替え | |
| DOCX | OCR は「DOCX→HTML→Markdown」パイプラインの前に実行。ドキュメントの構造(見出し/段落/表)は 100% 保持 | doc.part.rels を使って画像の関連付けを抽出 |
| PPTX | スライド内の「上から左」の読み順で挿入。LLM が「画像の説明」を返した場合は説明を優先し、OCR はフォールバックとしてのみ使用 | Picture shape、placeholder shape、グループ内の画像に対応 |
| XLSX | 各ワークシートの画像をデータ表の後にまとめて追加し、### Images in this sheet: とラベル付け | 画像のアンカーから列のアルファベット/行番号を算出。位置情報は失われます(ほかの 3 形式とは異なります) |
OCR 出力形式:後処理で識別しやすいよう、各ブロックを Markdown の強調記法で囲みます。
*[Image OCR]
<抽取到的文字>
[End OCR]*
OCR ブロックをまとめて削除し、「本文のみ」の要約を作成するには、次の 1 行の sed コマンドを使えます。
sed -e '/^\*\[Image OCR\]$/,/^\[End OCR\]\*$/d' input.md > cleaned.md
7. 制限事項とコスト(デプロイ前に必ずお読みください)
| 項目 | 説明 |
|---|---|
| 画像ごとに LLM を 1 回呼び出し | 画像 100 枚の場合、vision 呼び出しは 100 回となり、コストは画像数に比例して増加します |
| スキャン PDF はより高コスト | スキャンページは 300 DPI でページ全体を LLM に送信するため、「埋め込み小画像」よりも多くのトークンを消費します |
| LLM のエラーは通知されません | 「LLM 呼び出しが失敗しても、その画像のテキストなしで変換を続行します」——失敗は握りつぶされるため、監視が必要です |
| PPTX では説明を優先 | LLM が「画像の説明」を返した場合、OCR はフォールバックとしてのみ使われ、最終テキストには元の文字ではなく説明が含まれます |
| XLSX では位置情報が失われます | 画像は表の後に追加されるため、元のセルの近くには表示されません |
| 画像 MIME | OCR サービスは stream_info.mimetype または PIL で検出します。どちらでも判別できない場合は image/png として扱います |
8. トラブルシューティング早見表
| 現象 | 確認方法 |
|---|---|
| OCR ブロックがまったく表示されない | markitdown --list-plugins で ocr が含まれているか確認します。enable_plugins=True と llm_client + llm_model を渡したことも確認してください |
ModuleNotFoundError: markitdown_ocr が発生する | pip install markitdown-ocr または pip install -e packages/markitdown-ocr を実行します |
ModuleNotFoundError: openai が発生する | pip install openai を実行するか、別の OpenAI 互換 SDK に切り替えます |
| 一部の画像で OCR が欠落する | その LLM 呼び出しの失敗が握りつぶされています。ログ/再試行を追加するか、より安定したモデルに切り替えます |
BadRequestError: image_url invalid が発生する | クライアント/MIME が認識されていません。_ocr_service.py で content_type が正しく推定されているか確認するか、クライアントを変更します |
| Azure OpenAI の認証に失敗する | api_version が該当 deployment でサポートされているバージョン(例:2024-02-01)であること、および azure_endpoint の末尾に / がないことを確認します |
| 出力から data:image がすべて消える | これは MarkItDown 本体の動作であり、OCR とは無関係です。--keep-data-uris(CLI)を追加するか、Python API で keep_data_uris=True を渡します |
9. テスト/二次開発
# 跑插件自带的测试套件
cd packages/markitdown-ocr
pytest tests/ -v
# 本地装好后做最小冒烟
python -c "
from markitdown import MarkItDown
from openai import OpenAI
print(MarkItDown(enable_plugins=True, llm_client=OpenAI(), llm_model='gpt-4o').convert('sample.pdf').markdown[:500])
"
プラグインの内部メカニズム(登録フロー、OCRService の実装詳細、各コンバーターの違い)については、plugin/internals.md を参照してください。
10. 関連 Skill に切り替えるタイミング
| ユーザーの質問 | 切り替え先 |
|---|---|
| 「MarkItDown とは何ですか?どのフォーマットに対応していますか?」 | markitdown-awesome |
| 「markitdown コマンドの使い方や、引数の渡し方を教えてください」 | markitdown-cli |
| 「Azure Document Intelligence / Content Understanding を使っています。OCR プラグインは不要です」 | markitdown-cli の「Azure バックエンド」セクション |
11. プライバシーポリシー
この Skill はローカルのドキュメントとサンプルコードを提供し、ユーザーデータを収集、保存、送信することはありません。実際の OCR 呼び出しでは、渡した画像の内容(機密情報を含む可能性があります)が選択した LLM プロバイダーに送信されます。該当プロバイダーのプライバシー条項と、ユーザーの居住地域の法令を遵守してください。本番環境へのデプロイでは、次の対応を推奨します。
- 高機密文書にはプライベート環境の LLM(ローカルの vLLM / Ollama + OpenAI 互換プロトコルなど)を使用する
- リクエストログ/一時監査を無効にする
12. 参考リンク
- プラグイン README: https://github.com/microsoft/markitdown/blob/main/packages/markitdown-ocr/README.md
- プラグインのソースコードのエントリーポイント: https://github.com/microsoft/markitdown/blob/main/packages/markitdown-ocr/src/markitdown_ocr/_plugin.py
- OCR サービスの抽象化: https://github.com/microsoft/markitdown/blob/main/packages/markitdown-ocr/src/markitdown_ocr/_ocr_service.py
- MarkItDown メインリポジトリ: https://github.com/microsoft/markitdown
- 関連 Skill:
markitdown-awesome—npx skills add full-stack-skills/document-skills --skill markitdown-awesomeでインストールした後、skill 名で参照 - 関連 Skill:
markitdown-cli—npx skills add full-stack-skills/document-skills --skill markitdown-cliでインストールした後、skill 名で参照 - 一括インストール:
npx skills add full-stack-skills/document-skills(11 個すべての skill を一度にインストール)