Image: AI generated
די בפקודה
pip install markitdownכדי להפוך קובצי PDF, מסמכי Word, גיליונות Excel ומצגות PowerPoint ל-markdown. אבל אם מזינים לו קובץ PDF שאינו אלא תמונות סרוקות — חוזה סרוק, למשל — מתקבל מסמך ריק. המאמר הזה נע בשני צירים: למה וכיצד להשתמש ב-MarkItDown, וכיצד מוסיפים OCR בדיוק בנקודה שבה האמון הזה קורס — קובצי PDF שמכילים רק תמונות.
למה כדאי להשתמש ב-MarkItDown — תנאי ה-agent-operable
MarkItDown היא ספריית CLI/Python בקוד פתוח של מיקרוסופט הממירה קבצי PDF, Word, Excel, PowerPoint, HTML, תמונה ואודיו ל-markdown.
נתחיל במושג agent-operable (מצב שסוכן יכול לעבוד איתו). כדי שסוכן יוכל לטפל במסמך באופן אוטונומי, המסמך הזה חייב להיות במצב שמכונה יכולה לנתח מבנית — לא רק במצב שאדם מוצא קריא. זה לא תנאי החל רק על קוד. כלל עסקי הקבור בתוך PDF או בגיליון Excel עשוי בעצם שלא להתקיים מבחינת סוכן, שכן אדם חייב לפתוח אותו כדי לדעת מה כתוב בו. זהו הראשון משלושה תנאים — קריא, ניתן לאימות, מתמיד — המפורטים ב-Building Agent-Operable Systems: “קריא ללא רעש”.
אז למה דווקא MarkItDown? אפשר לבנות בעצמך את אותה המרה על ידי הרכבת מנתחים (parsers) של צד שלישי (PyPDF2, python-docx). ההבדל הוא מי בנה את זה. docx, xlsx ו-pptx הן כולן OOXML — מפרט שמיקרוסופט עצמה הבעלים שלו. כאשר החברה שבבעלותה המפרט בונה את הממיר לפורמט שלה עצמה, מקרי קצה (תאים ממוזגים, טבלאות מקוננות, הערות שוליים) נוטים מבחינה מבנית לשרוד טוב יותר מאשר עם מנתח של צד שלישי. אם ההמרה עצמה אינה אמינה, כל מה שנבנה מעליה לכיוון מצב agent-operable מאבד משמעות. זו הסיבה להשתמש ב-MarkItDown — עבור הפורמטים של מיקרוסופט עצמה, האמון הזה מובנה כברירת מחדל.
הבעיה היא שהאמון הזה אינו עובר ל-קובצי PDF, ובמיוחד לאלה שמכילים רק תמונות. המחצית השנייה של המאמר מתמקדת בסגירת הפער הזה באמצעות OCR.
התקנה
התקנה בסיסית
pip install markitdown
ההתקנה הבסיסית לבדה מטפלת רק בפורמטים קלים כמו טקסט רגיל ו-HTML. כדי להמיר מסמכי PDF ו-Office, יש להתקין גם את התוספים (extras) הספציפיים לכל פורמט.
תוספים ספציפיים לכל פורמט
pip install 'markitdown[pdf]' # PDF (pdfminer.six + pdfplumber)
pip install 'markitdown[docx]' # Word
pip install 'markitdown[pptx]' # PowerPoint
pip install 'markitdown[xlsx]' # Excel
pip install 'markitdown[all]' # everything above, plus audio transcription, YouTube captions, Azure Document Intelligence, etc.
אם המאמר הזה זקוק רק ל-PDF, markitdown[pdf] מספיק.
שימוש בסיסי
CLI
markitdown example.pdf # print markdown to stdout
markitdown example.pdf -o example.md # save to a file
cat example.pdf | markitdown # read from stdin (pipe)
ממשק Python
from markitdown import MarkItDown
md = MarkItDown()
result = md.convert("example.pdf")
print(result.markdown)
שתי הדרכים בוחרות אוטומטית את הממיר לפי סיומת הקובץ או סוג ה-MIME. כאשר אין מידע על הסיומת — בקריאה מ-stdin, למשל — אפשר לתת רמז באמצעות -x (--extension) או -m (--mime-type).
מה שהמרת PDF עושה בפועל — היא קוראת רק את שכבת הטקסט
ממיר ה-PDF של MarkItDown (packages/markitdown/src/markitdown/converters/_pdf_converter.py) משתמש תחילה ב-pdfplumber כדי לזהות מבנה טבלה/טופס בכל עמוד, וחוזר ל-page.extract_text() כאשר עמוד אינו טבלה. אם pdfplumber נכשל, הוא חוזר ל-pdfminer.six.
שתי הספריות הן כלים הקוראים שכבת טקסט שכבר קיימת בתוך ה-PDF. אם עמוד מורכב רק מתמונה סרוקה ללא שכבת טקסט, extract_text() מחזירה מחרוזת ריקה, והפלט של MarkItDown מתברר כריק למעשה. אין כלל נתיב קוד בחבילה הבסיסית שמעבד תמונה או מזהה תווים בתוכה.
במילים אחרות, אלו שתי בעיות שונות:
- PDF עם שכבת טקסט (מיוצא מ-Word, רוב החוזים האלקטרוניים) → ההתקנה הבסיסית עובדת היטב. אותו אמון שנושא את הפורמטים של מיקרוסופט עצמה עובר גם לכאן.
- PDF ללא שכבת טקסט (מסמך שעבר דרך סורק, תמונה המוטבעת כתמונה) → ההתקנה הבסיסית מחזירה תוצאה ריקה. כאן נשבר תנאי ה"קריא" של agent-operable.
הגדרת OCR — היכן שמתקנים את האמון השבור
מכאן מתחיל הציר השני של המאמר. האמון ש-MarkItDown מבטיחה עבור הפורמטים של מיקרוסופט עצמה חייב להיבנות מחדש בנפרד עבור קובצי PDF שמכילים רק תמונות.
1. התקנת התוסף
תמיכת ה-OCR נמצאת בחבילה נפרדת, markitdown-ocr. היא נמצאת באותו מאגר (microsoft/markitdown), אך אינה כלולה ב-pip install markitdown.
pip install markitdown-ocr
pip install openai # an OpenAI-compatible client — this plugin has no OCR model of its own
לאחר ההתקנה, יש לוודא שהתוסף מזוהה.
markitdown --list-plugins
# * ocr (package: markitdown_ocr)
2. מה שאינו ניתן למשא ומתן — לקוח LLM Vision
markitdown-ocr אינה כוללת מנוע OCR מסורתי כמו Tesseract או PaddleOCR. כל מה שהיא בעצם עושה הוא לקודד את התמונה ל-base64 ולבקש מ-API של chat.completions תואם OpenAI (למשל gpt-4o) “לחלץ את הטקסט מהתמונה הזאת” (LLMVisionOCRService ב-_ocr_service.py). לכן, מפתח API המסוגל לקרוא למודל ראייה הוא דרישה שאינה ניתנת למשא ומתן כדי ש-OCR יעבוד בכלל.
from markitdown import MarkItDown
from openai import OpenAI
md = MarkItDown(
enable_plugins=True,
llm_client=OpenAI(), # reads OPENAI_API_KEY from the environment
llm_model="gpt-4o",
)
result = md.convert("scanned_contract.pdf")
print(result.markdown)
כל לקוח תואם OpenAI — כולל Azure OpenAI — אפשר להעביר באותה הדרך.
from openai import AzureOpenAI
md = MarkItDown(
enable_plugins=True,
llm_client=AzureOpenAI(
api_key="...",
azure_endpoint="https://<resource>.openai.azure.com/",
api_version="2024-02-01",
),
llm_model="gpt-4o",
)
3. זה לא עובד מה-CLI — מאומת מול הקוד בפועל
קובץ ה-README של markitdown-ocr מציג את הפקודה הבאה כדוגמת שימוש:
markitdown document.pdf --use-plugins --llm-client openai --llm-model gpt-4o
אך בבדיקה ישירה של הגדרות ארגומנטי ה-CLI של הליבה של MarkItDown (packages/markitdown/src/markitdown/__main__.py), מתברר כי דגלים כאלה אינם קיימים — אין --llm-client ואין --llm-model. ה-CLI תומך ב--o (קובץ פלט), -x (רמז סיומת), -m (רמז MIME), -c (קידוד תווים), -d/--use-docintel, --use-cu, -p/--use-plugins, --list-plugins ו---keep-data-uris, וזה הכול — הבנאי של MarkItDown מקבל רק enable_plugins=args.use_plugins. במילים אחרות, דוגמת ה-CLI ב-README היא שגיאת תיעוד; היא בפועל אינה פועלת.
OCR עובד רק דרך ממשק Python — יש להעביר llm_client/llm_model ישירות. אין דרך למסור מפתח API ל-CLI.
4. איך זה עובד בפועל — OCR לתמונות משובצות וגיבוי OCR לעמוד מלא
PdfConverterWithOCR (_pdf_converter_with_ocr.py) פועל בשני שלבים.
- תמונות משובצות בעדיפות ראשונה: כאשר עמוד מערבב טקסט עם תמונות (נניח, חתימה סרוקה שהוטבעה באמצע גוף הטקסט), רק התמונה נחתכת, נשלחת ל-LLM Vision, והתוצאה משולבת בחזרה עם הטקסט שמסביב לפי מיקומה המקורי על ציר Y, תוך שמירה על סדר הקריאה.
- גיבוי OCR לעמוד מלא: אם חילוץ הטקסט חוזר ריק לגמרי (PDF סרוק לחלוטין), העמוד כולו מעובד כתמונת PNG ברזולוציית 300dpi ונשלח ל-LLM Vision עמוד אחר עמוד (
_ocr_full_pages).
הטקסט המחולץ תמיד עטוף בפורמט הבא:
*[Image OCR]
<extracted text>
[End OCR]*
5. שיפור הדיוק באמצעות פרומפט מותאם אישית
הפרומפט המובנה כברירת מחדל הוא “חלץ את כל הטקסט מהתמונה הזאת, תוך שמירה על הפריסה והסדר המקוריים”. במסמכים עתירי טבלאות, טקסט אנכי, או חותמות וחתימות, החלפתו באמצעות llm_prompt יכולה לשפר את הדיוק.
md = MarkItDown(
enable_plugins=True,
llm_client=OpenAI(),
llm_model="gpt-4o",
llm_prompt="Extract all text from this image, but preserve table structure as markdown tables.",
)
6. עיבוד קבצים מרובים בבת אחת
בהרצת תיקייה שלמה של קובצי PDF סרוקים בבת אחת, כל קובץ מפעיל קריאת API משלו — יש לעטוף כל המרה בנפרד כדי שכשל בודד לא יפיל את כל האצווה.
from pathlib import Path
from markitdown import MarkItDown
from openai import OpenAI
md = MarkItDown(enable_plugins=True, llm_client=OpenAI(), llm_model="gpt-4o")
for pdf_path in Path("scans/").glob("*.pdf"):
try:
result = md.convert(str(pdf_path))
pdf_path.with_suffix(".md").write_text(result.markdown, encoding="utf-8")
except Exception as e:
print(f"failed: {pdf_path.name} — {e}")
7. מה קורה אם מתקינים את התוסף בלי llm_client?
התוסף נטען, אך ה-OCR כבה בשקט. register_converters() ב-_plugin.py בונה LLMVisionOCRService רק כאשר גם llm_client וגם llm_model קיימים; אחרת, הוא רושם את הממירים עם ocr_service=None. במצב הזה, המערכת חוזרת אוטומטית ובשקט לחילוץ שכבת הטקסט בלבד — בלי שגיאה, בלי אזהרה. רוב הבעיות מהסוג “התקנתי את התוסף אבל ה-OCR לא עובד” נובעות בדיוק מהנקודה הזאת.
8. הוא אפילו מנסה לשחזר קובצי PDF פגומים
כאשר pdfplumber ו-pdfminer אינם מצליחים לפתוח קובץ PDF כלל — EOF קטוע, למשל — markitdown-ocr חוזר לעבד את העמודים ישירות באמצעות PyMuPDF (fitz) ומנסה שוב. אם גם הנתיב הזה נכשל, הוא משאיר *[Error: Could not process scanned PDF]* בתוצאה.
9. עלות ומהירות
מכיוון שהוא שולח עמודים שלמים למודל ראייה, העלות והשהיה מצטברות ביחס למספר העמודים של המסמך הסרוק. עיבוד ברזולוציית 300dpi אינו זול מבחינת טוקנים לכל תמונה, ולכן בטוח יותר לדגום כמה עמודים תחילה כדי להעריך איכות ועלות לפני הרצת מסמך שלם בן מאות עמודים.
אימות תוצאת ה-OCR (Verifier) — יגיע בנפרד
כל מה שלמעלה עוסק באופן ה"הפעלה" של OCR. הפעלתו אינה זהה ליכולת לבטוח בתוצאה — במעצב הנוכחי, שבו הכול עובר בשקט בין אם llm_client הוגדר ובין אם לא, ובין אם העמוד ריק ובין אם לא, אין נוהל דטרמיניסטי לשפוט האם פלט ה-OCR אכן אמין.
הנוהל הזה אינו מכוסה כאן. כיצד ליישם את עקרון ה-Symbolic Feedback Loop — ה-LLM מייצר ← כלי דטרמיניסטי שופט ← משוב ← חזרה — על פלט ה-OCR הוא נושא למאמר/כלי נפרד.
רשימת בדיקה מעשית
- אם עוסקים רק בקובצי PDF רגילים בעלי שכבת טקסט, ההתקנה הבסיסית
markitdown[pdf]מספיקה. אין צורך בתוסף OCR. - אם יש לטפל בקובצי PDF סרוקים או מצולמים,
markitdown-ocrבתוספת מפתח API של OpenAI (או תואם) הם הכרחיים. אין אינטגרציה עם מנוע OCR מסורתי, מקומי וחינמי כמו Tesseract. - אם תוצאת ה-OCR חוזרת ריקה, הדבר הראשון שיש לבדוק הוא האם
llm_client/llm_modelהועברו בפועל. הכשל שקט, כך שכלום לא מופיע ביומנים. - אי אפשר להפעיל OCR רק מה-CLI. נדרש סקריפט Python הקורא ל-
MarkItDown(enable_plugins=True, llm_client=..., llm_model=...). - עדיין אין דרך מכנית לשפוט עד כמה התוצאה אמינה — כרגע, אדם חייב לבדוק דוגמית באופן ידני.
טבלת סיכום
| מצב | מה נדרש | הערות |
|---|---|---|
| PDF עם שכבת טקסט | pip install markitdown[pdf] | pdfplumber/pdfminer מחלצים את הטקסט |
| חלק מהתמונות המשובצות דורשות OCR | markitdown-ocr + לקוח LLM Vision | חותך רק את התמונות, משלב עם הטקסט |
| סרוק לחלוטין (העמוד כולו תמונה) | markitdown-ocr + לקוח LLM Vision | מעבד את העמוד כולו ב-300dpi, ואז מבצע OCR |
| PDF פגום | כמו לעיל (גיבוי אוטומטי) | מנסה שוב באמצעות עיבוד עם PyMuPDF |
llm_client לא הוגדר | — | OCR מדולג בשקט, ללא שגיאה |
מסירת --llm-client ב-CLI | בלתי אפשרי (הדגל הזה אינו קיים בפועל) | רק דרך ממשק Python |
| שיפוט אמינות תוצאת ה-OCR | (מתוכנן) | ייכלל בכלי אימות נפרד |
מאמרים קשורים
- Building Agent-Operable Systems — שלושת התנאים (קריא, ניתן לאימות, מתמיד), והיכן MarkItDown משתלב
- Agent Operable Codebase — אותו עיקרון מיושם על קוד
מקורות
- microsoft/markitdown — שורש המאגר
_pdf_converter.py— ממיר ה-PDF הבסיסי (חילוץ שכבת טקסט בלבד)__main__.py— הגדרות ארגומנטי CLI (מאשרות שאין--llm-client/--llm-model)markitdown-ocrREADME_pdf_converter_with_ocr.py_ocr_service.py_plugin.py- markitdown pyproject.toml — רשימת התוספים
יומן שינויים
- 2026-07-09: גרסה ראשונית — נוספה מסגרת ה-agent-operable, הגדרת ה-OCR הורחבה כמחצית השנייה, נוסף סעיף מציין מיקום עבור כלי האימות