MarkItDown: Cái Máy Xay Thịt Mà RAG Pipeline Nào Cũng Cần
TL;DR
- pdfminer trả về garbage text; textract bắt cài
ghostscript antiword poppler-utilstrên production pip install 'markitdown[all]'và mọi file Word, Excel, PPTX, YouTube thành Markdown giữ heading và bảng- Dành cho dev xây RAG, agent AutoGen/LangChain, hoặc pipeline chuẩn hóa tài liệu từ nhiều phòng ban
- Thuần Python, zero Tesseract, zero LibreOffice, tích hợp sẵn MCP server cho Claude Desktop
- README tự nhận “đủ tốt cho LLM đọc, không phải cho người đọc”: điểm mạnh, không phải lỗi
Văn phòng hỗn loạn và cái pipeline chưa chạy được
Tôi nhận task vào thứ Hai: xây RAG cho hệ thống tra cứu tài liệu nội bộ. Tài liệu gồm 200 file từ ba phòng ban, ba format khác nhau. Kế toán gửi Excel, pháp chế gửi DOCX bị password-protect trước khi forward, còn sếp cũ để lại đống PDF không biết scan từ đời nào.
pdfminer trả về một chuỗi ký tự không dấu, không xuống dòng, bảng vỡ tan thành ba dòng chữ vô nghĩa cạnh nhau. textract thì yêu cầu apt-get install ghostscript antiword poppler-utils trên production server, cái thứ tôi không có quyền chạm vào. LLM của tôi nhận được cái chuỗi đó và trả lời như thể vừa đọc xong bộ nhớ cache bị dump ra sàn.
Gai chưa gỡ: mỗi format một thư viện khác nhau, mà không cái nào trong số đó nhớ rằng “LLM sẽ đọc cái này thay vì browser.”
MarkItDown làm một việc duy nhất
Repo này nhận file vào, trả Markdown ra. Không cố in đẹp cho mắt người, chỉ cố giữ cấu trúc để LLM hiểu heading là heading, bảng là bảng, danh sách là danh sách.
Nói cho intern mới vào: MarkItDown nhận PDF/DOCX/XLSX/PPTX/YouTube URL, xuất Markdown string. Một hàm Python, không phụ thuộc binary ngoài.
DNA của nó đến từ team AutoGen của Microsoft, nhóm xây framework multi-agent, nên mặc định của nó là “tài liệu cho agent đọc, không phải cho browser hiển thị.” Đó là lý do 103k sao tích lũy trong vòng sáu tháng sau khi ra mắt. Và đó cũng là lý do con số đó không bình thường tí nào.
Bốn cảnh thực chiến
RAG pipeline với định dạng hỗn hợp: bạn có thư mục 200 file DOCX, XLSX, PDF, PPTX từ các phòng ban. Thay vì viết converter riêng cho từng format, gọi md.convert(path) trong một vòng lặp. Mỗi file ra một Markdown chuẩn, bước chunk tiếp theo không còn phải xử lý “tại sao bảng Excel bị vỡ thành chuỗi.”
AI agent đọc tài liệu không biết trước format: agent cần tóm tắt một report nhưng không biết file là gì trước khi chạm vào. MarkItDown dùng magika để auto-detect format, nên agent chỉ cần gọi convert() và nhận text có cấu trúc thay vì binary soup. AutoGen và LangChain tích hợp thẳng vào.
MCP server cho Claude Desktop: cài pip install markitdown-mcp, cấu hình trong Claude Desktop, và Claude tự biết đọc file local PDF/DOCX của bạn. Cái ổ điện đa năng nằm ngay sau desktop AI, không cần bạn copy-paste gì thêm.
YouTube transcript không cần API key: link video training nội bộ hay tech talk muốn đẩy vào knowledge base? markitdown https://youtube.com/watch?v=... kéo transcript về Markdown thẳng, không tải video, không cần credential YouTube.
Bốn tình huống đó đều xoay quanh một điểm chung: dữ liệu thật không bao giờ sạch, không bao giờ đúng format, và bạn cần một lớp chuẩn hóa trước khi LLM nhìn thấy nó.
Cài và chạy
# Cài đầy đủ -- khuyên dùng khi bắt đầu
pip install 'markitdown[all]'
# Chỉ một vài format cần thiết
pip install 'markitdown[pdf,docx,pptx]'
Yêu cầu Python >= 3.10.
CLI
# PDF thành file Markdown
markitdown report.pdf -o report.md
# YouTube transcript
markitdown https://www.youtube.com/watch?v=VIDEO_ID -o notes.md
# Pipe thẳng vào LLM
markitdown quarterly.docx | ollama run mistral
Python API
from markitdown import MarkItDown
md = MarkItDown()
result = md.convert("quarterly_report.xlsx")
print(result.text_content)
Kết quả thực tế với file Excel, trước và sau:
# Trước (pdfminer-style raw text)
Q1 Revenue 1200000 Q2 Revenue 1450000Q3 Revenue missing Q4 Revenue 1800000
# Sau (MarkItDown)
## Sheet: Q1-Q4 Summary
| Quarter | Revenue | Note |
|---------|-----------|---------|
| Q1 | 1,200,000 | |
| Q2 | 1,450,000 | +20.8% |
| Q3 | - | missing |
| Q4 | 1,800,000 | |
LLM nhận bảng như vậy mới có thể trả lời “Q3 bị thiếu dữ liệu” thay vì bịa ra số. Khoảng cách giữa “tôi hiểu” và “tôi đoán” nằm ở cái bảng đó.
LLM Vision cho PPTX có nhiều ảnh
from markitdown import MarkItDown
from openai import OpenAI
md = MarkItDown(
llm_client=OpenAI(),
llm_model="gpt-4o",
)
result = md.convert("product_demo.pptx")
# Slide chứa screenshot được mô tả bằng ngôn ngữ tự nhiên
print(result.text_content)
💡 Tip: Không cần truyền
llm_clientvới PDF text-based thuần túy và DOCX thông thường.llm_clientchỉ phát huy tác dụng với file ảnh và PPTX có slide hình. Truyền vào mà không cần sẽ tốn API cost nhưng output không khác.
Plugin OCR cho PDF scan
pip install markitdown-ocr openai
md = MarkItDown(
enable_plugins=True, # phải bật tường minh
llm_client=OpenAI(),
llm_model="gpt-4o",
)
result = md.convert("scan_report.pdf")
Formats được hỗ trợ
Danh sách đầy đủ với optional extras:
- PDF (
[pdf]): text-based; scan cần OCR plugin - Word, PowerPoint, Excel cũ và mới (
[docx],[pptx],[xlsx],[xls]) - Outlook email (
[outlook]) - Audio WAV/MP3: EXIF metadata và speech transcription (
[audio-transcription]) - YouTube URL: transcript tự động (
[youtube-transcription]) - HTML, CSV, JSON, XML, ZIP, EPub: trong core, không cần extra
- Azure Document Intelligence cho PDF phức tạp (
[az-doc-intel])
Stack nào khớp
MarkItDown không thay thế toàn bộ document processing stack. Nó là lớp chuẩn hóa đầu vào trước khi đi vào embed, chunk, rồi vector store.
| Stack | Vai trò của MarkItDown |
|---|---|
| LangChain / LlamaIndex | Document loader đa format, thay PyPDFLoader |
| AutoGen agent | Tool cho agent tự đọc file, không cần user convert trước |
| Claude Desktop (MCP) | Extension đọc file local qua giao thức MCP |
| Data pipeline nội bộ | ETL từ “văn phòng hỗn loạn” về schema Markdown nhất quán |
Markdown đang trở thành lingua franca của AI pipeline. LLM được train trên lượng lớn Markdown nên token hiệu quả hơn HTML hay PDF raw rất nhiều. Nếu bạn đang xây documentation workflow xung quanh Markdown, bài về Markdy đi theo hướng ngược lại thú vị: lấy Markdown làm đầu vào để tạo animated docs, đúng cái chiều MarkItDown không làm.
Chỗ cùi bắp và cần coi chừng
PDF scan là điểm yếu lớn nhất. pdfminer và pdfplumber chỉ extract text từ PDF có layer text. PDF scan, ảnh chụp tài liệu, hóa đơn photo: output rỗng hoặc garbage. Plugin markitdown-ocr giải quyết bằng LLM Vision nhưng tốn API cost và không chạy offline. Nếu phần lớn dữ liệu là scan, cân nhắc Azure Document Intelligence hoặc công cụ OCR chuyên biệt trước khi cài MarkItDown vào pipeline.
⚠️ Cảnh báo:
convert_stream()từ version 0.1.0 chỉ nhận binary file-like object. Code cũ dùngio.StringIOsẽ lỗi thầm lặng không báo gì.# Đúng with open("doc.pdf", "rb") as f: result = md.convert_stream(f) # Sai -- StringIO không còn được chấp nhận từ v0.1.0 # result = md.convert_stream(io.StringIO(text))
Vài điểm khác cần nhớ trước khi đưa production:
llm_clientchỉ áp dụng cho PPTX và file ảnh: không phải mọi format đều tận dụng được LLM Vision- Plugins tắt theo mặc định: phải pass
enable_plugins=Truehoặc--use-pluginstrên CLI - Output không dành cho human consumption: README nói thẳng, đừng dùng để publish docs trực tiếp
103k sao, không có chuyện ngẫu nhiên
Cái đống 200 file từ đầu bài, tôi chạy:
find ./docs -type f \( -name "*.pdf" -o -name "*.docx" -o -name "*.xlsx" \) | \
xargs -I {} markitdown {} -o {}.md
Hai mươi phút sau, docs/ có *.md đi kèm từng file. Vector store có thứ để chunk. LLM ngừng bịa.
103k sao không phải vì tính năng lạ. Nó là vì thế hệ dev xây RAG đầu tiên đều chạm vào đúng cái nỗi đau này: tài liệu thật không bao giờ sạch, không bao giờ đúng format, và không có công cụ nào nghĩ đến “LLM sẽ đọc cái này.” MarkItDown xuất hiện đúng lúc, đúng chỗ, với câu trả lời vừa đủ thực dụng: thuần Python, không binary, hiểu Markdown là ngôn ngữ LLM. Không ảo, không khoa trương. Chỉ là đúng chỗ.
microsoft/markitdown · MIT · 103.5k★
Hoang Yell
Một nhà phát triển phần mềm và là người kể chuyện kỹ thuật. Tôi dành thời gian để khám phá những repository mã nguồn mở thú vị nhất trên GitHub và trình bày chúng dưới dạng những câu chuyện dễ hiểu cho mọi người.