Phạm Văn Thư
RAG và quản trị tri thức · AI-assisted content

MarkItDown: chuyển tài liệu văn phòng sang Markdown cho LLM và RAG

Đăng ngày 12/10/2026

Mục lục bài nghiên cứu
Hình đại diện MarkItDown — RAG mã nguồn mở

MarkItDown trong một trang: bước chuẩn hóa tài liệu trước khi tới tay mô hình ngôn ngữ

MarkItDown là tiện ích Python gọn nhẹ do Microsoft công bố mã nguồn, chuyển PDF, Word, Excel, PowerPoint, HTML, ảnh, âm thanh và nhiều định dạng khác thành Markdown để đưa vào mô hình ngôn ngữ lớn (LLM) hoặc chuỗi phân tích văn bản. README nhấn mạnh việc giữ tiêu đề, danh sách, bảng, liên kết, đồng thời thừa nhận đầu ra không nhằm tạo bản chuyển đổi trung thực cao cho người đọc. [1][2]

Công cụ đáng cân nhắc khi tổ chức đang dựng hệ thống hỏi đáp kiểu RAG (truy xuất tăng cường sinh: tìm đoạn tài liệu liên quan rồi đưa mô hình đọc trước khi trả lời) và cần một bước tiền xử lý chung cho kho tệp lẫn lộn định dạng. Ngoài CLI và API Python, dự án có gói máy chủ MCP để agent (tác nhân AI tự gọi công cụ) yêu cầu chuyển đổi. [1][4]

Không nên chọn nếu cần bản chuyển giữ nguyên bố cục để in, nếu kho chủ yếu là bản scan mà dữ liệu không được rời hạ tầng, hoặc nếu người dùng cuối cần ứng dụng có giao diện: máy chủ web, API REST và ứng dụng đồ họa được ghi rõ là nằm ngoài phạm vi kho. Khuyến nghị của bài là dùng MarkItDown như một mắt xích tiền xử lý có kiểm thử và luôn giữ tệp gốc làm nguồn đối chiếu. [1]

Khoảng cách giữa tệp văn phòng và đầu vào mà LLM đọc tốt

Tài liệu doanh nghiệp là tệp nhị phân với cấu trúc riêng: bảng tính nhiều sheet, slide có ghi chú, PDF xuất từ phần mềm kế toán, ảnh chụp biên bản. Hệ thống hỏi đáp nào cũng cần bước trích xuất văn bản; nếu bước này làm mất tiêu đề, trộn ô bảng thành chuỗi liền hoặc bỏ sót chữ trong hình, chất lượng truy xuất phía sau giảm dù mô hình mạnh tới đâu.

README của MarkItDown tự so sánh dự án với textract nhưng đặt trọng tâm vào việc giữ cấu trúc dưới dạng Markdown. Lý do được nêu: Markdown gần văn bản thuần mà vẫn thể hiện cấu trúc, các LLM phổ biến như GPT-4o dùng nó một cách tự nhiên, và quy ước này tiết kiệm token (đơn vị văn bản mô hình xử lý và tính phí). Đây là lập luận thiết kế, không kèm số liệu đo. [1]

Vấn đề thứ hai là phân mảnh: mỗi định dạng một thư viện, mỗi thư viện một kiểu dữ liệu trả về. Một lớp chuyển đổi chung giúp viết logic chia đoạn (chunking) và gắn metadata một lần cho mọi loại tệp, đổi lại tổ chức phụ thuộc vào cách lớp đó diễn giải từng định dạng.

Bộ chuyển đổi xếp theo mức ưu tiên, plugin và các gói trong cùng một kho

Kho microsoft/markitdown gồm gói lõi markitdown, gói markitdown-mcp chạy máy chủ MCP (Model Context Protocol, giao thức để ứng dụng AI gọi công cụ), plugin markitdown-ocr và một plugin mẫu. README xác định phạm vi đóng góp gồm cải thiện độ chính xác của bộ chuyển đổi, sửa lỗi, CLI, gói MCP, kiểm thử và tài liệu. [1][4][5][7]

Đơn vị trung tâm là DocumentConverter. Theo plugin mẫu, mỗi bộ chuyển đổi có một mức ưu tiên và hai phương thức: accepts() quyết định có nhận luồng dữ liệu hay không dựa trên byte và StreamInfo, convert() trả về DocumentConverterResult chứa Markdown. Plugin xuất biến __plugin_interface_version__ (hiện chỉ hỗ trợ giá trị 1) và hàm register_converters được gọi mỗi khi khởi tạo MarkItDown, đăng ký qua entry point (điểm khai báo trong pyproject.toml) thuộc nhóm markitdown.plugin. [7]

Mức ưu tiên cho phép thay hành vi mặc định mà không sửa lõi: plugin OCR đăng ký bốn bộ chuyển đổi ở mức -1.0, đứng trước các bộ tích hợp ở mức 0.0; ba bộ DOCX, PPTX, XLSX kế thừa lớp lõi và ghi đè một phương thức bán nội bộ, và plugin yêu cầu lõi từ 0.1.8 đến dưới 0.2.0. Ngoài phần chạy cục bộ còn hai nhánh gọi Azure Document Intelligence và Content Understanding qua endpoint cấu hình bằng tham số hoặc biến môi trường. [1][5]

Hành trình của một tệp: từ luồng byte tới chuỗi Markdown

Đầu vào có thể là đường dẫn tệp, URI, luồng byte hoặc stdin của dòng lệnh. Hàm convert() được mô tả là cố ý dễ dãi, xử lý được tệp cục bộ, URI từ xa lẫn luồng byte; các hàm hẹp hơn gồm convert_local() cho tệp cục bộ, convert_response() cho phản hồi HTTP mà ứng dụng tự tải, và convert_stream() cho luồng do ứng dụng tự mở. [1]

Các bộ chuyển đổi được xét theo mức ưu tiên; bộ nào chấp nhận thì thực hiện chuyển đổi. Với mô tả ảnh bằng LLM, nếu client vẫn lỗi sau khi hết lượt thử lại, MarkItDown thử bộ chuyển đổi phù hợp khác và chỉ phát sinh FileConversionException khi không bộ nào thành công. Kết quả là một đối tượng có thuộc tính markdown. [1][7]

Ba nhánh có thể đưa dữ liệu ra khỏi máy. Plugin OCR gửi ảnh nhúng, hoặc từng trang PDF scan được kết xuất ở 300 DPI, tới LLM thị giác rồi chèn văn bản nhận về vào khối Image OCR; lời gọi nào lỗi thì bỏ qua ảnh đó. Content Understanding gửi tệp tới Azure và có thể trả thêm YAML front matter (khối siêu dữ liệu đầu tệp) với các trường như ngày hóa đơn. Nhánh MCP nhận URI từ agent và trả Markdown về. [1][4][5]

Những khả năng được README và tài liệu từng gói xác nhận

Định dạng đầu vào được liệt kê gồm PDF, PowerPoint, Word, Excel, ảnh (EXIF và OCR), âm thanh (EXIF và chuyển giọng nói), HTML, CSV, JSON, XML, ZIP (duyệt từng tệp bên trong), URL YouTube và EPub. Phụ thuộc chia thành các nhóm tùy chọn như pdf, docx, pptx, xlsx, xls, outlook, audio-transcription cho wav và mp3, youtube-transcription và hai nhóm Azure; nhóm all cài tất cả. [1]

CLI nhận đường dẫn tệp, tùy chọn -o hoặc dữ liệu qua pipe; API Python gọi convert() trên đối tượng MarkItDown; Dockerfile cho phép đẩy tệp vào qua stdin. Mô tả ảnh bằng LLM hiện chỉ áp dụng cho pptx và tệp ảnh khi truyền llm_client, llm_model. Plugin tắt mặc định, bật bằng --use-plugins hoặc enable_plugins=True, liệt kê bằng --list-plugins. [1]

Plugin markitdown-ocr thêm OCR qua LLM thị giác cho PDF, DOCX, PPTX, XLSX với mọi client tương thích API OpenAI; thiếu llm_client thì OCR bị bỏ qua mà không báo lỗi, còn tệp .xls kiểu cũ không có OCR ảnh. Gói markitdown-mcp chạy qua STDIO, Streamable HTTP hoặc SSE với đúng một công cụ convert_to_markdown(uri), nhận URI http, https, file hoặc data. [4][5]

Chọn đường chuyển đổi: cục bộ, plugin OCR hay dịch vụ Azure

Bảng so sánh trong README là cơ sở để định tuyến tài liệu. Bộ tích hợp trích xuất ngoại tuyến theo từng định dạng, không trả trường có cấu trúc, chỉ xử lý âm thanh cơ bản và không có video; Document Intelligence phân tích bố cục trên đám mây; Content Understanding thêm trích xuất trường, âm thanh và video. Cả hai nhánh Azure đều là lời gọi API tính phí. [1]

Quy tắc đề xuất: tệp sinh từ phần mềm như Word, Excel hay PDF có lớp chữ đi đường cục bộ; bản scan chỉ chuyển sang OCR hoặc Azure khi phép đo cho thấy đường cục bộ bỏ sót nội dung quan trọng. Tham số cu_file_types giới hạn định dạng được gửi tới Content Understanding, giúp khóa cả chi phí lẫn phạm vi dữ liệu rời máy. [1]

Với plugin OCR, ranh giới dữ liệu do client quyết định: API của OpenAI, Azure OpenAI hay một máy chủ nội bộ nói cùng giao thức. Việc một mô hình đặt trong nội bộ có đọc tốt chữ tiếng Việt có dấu hay không là câu hỏi phải thử nghiệm; bài này không có số liệu cho điểm đó. [5]

Ai nên dùng: đội dữ liệu, người dựng RAG và người tích hợp agent

Hưởng lợi rõ nhất là kỹ sư dữ liệu và nhà phát triển ứng dụng LLM cần nạp tài liệu hỗn hợp vào chỉ mục, qua pipeline batch, notebook hay dịch vụ nội bộ tự viết. Dự án định vị mình là thư viện để tích hợp vào hệ thống khác, không phải ứng dụng hoàn chỉnh cho người dùng cuối. [1]

Nhóm thứ hai là người dùng agent chạy cục bộ cần đọc một tệp PDF hay trang web theo yêu cầu. Gói MCP được thiết kế cho tình huống này, với giả định agent đáng tin cậy và máy chủ chỉ phục vụ trên chính chiếc máy đó. [4]

Lĩnh vực phù hợp là nơi nhiều tài liệu soạn bằng phần mềm và ít bản scan: tư vấn, đào tạo, nông nghiệp có quy trình thành văn, pháp chế, nghiên cứu thị trường. Người xây hệ thống tri thức cá nhân kiểu second brain, chủ đề gần với loạt bài trên phamvanthu.com, có thể dùng MarkItDown để gom ghi chú, sách EPub và biên bản họp về cùng một dạng văn bản trước khi lập chỉ mục.

Đề xuất cho một trang trại rau thủy canh: biến sổ tay kỹ thuật thành kho hỏi đáp

Tình huống giả định: một trang trại rau thủy canh ven đô có vài chục công nhân và ba kỹ thuật viên. Quy trình kỹ thuật soạn bằng Word, nhật ký pha dinh dưỡng và đo EC, pH ghi trên Excel, thông số giống và phân bón là PDF của nhà cung cấp, bài đào tạo là slide, phiếu kiểm nghiệm dư lượng do phòng thí nghiệm bên ngoài gửi về. Mục tiêu là công nhân ca đêm tự tra được ngưỡng EC cho xà lách giai đoạn cuối theo quy trình của trại. Đây là đề xuất, không phải dự án đã diễn ra.

Thiết kế: một máy tính văn phòng chạy script Python theo lịch, gọi MarkItDown cho thư mục tài liệu đã duyệt, ghi mỗi tệp thành Markdown kèm đường dẫn nguồn và ngày cập nhật, chia đoạn theo tiêu đề rồi nạp vào công cụ tìm kiếm hoặc kho vector; câu trả lời luôn dẫn về tệp gốc. MarkItDown chỉ lo khâu chuyển đổi; chỉ mục, mô hình trả lời và giao diện hỏi đáp phải chọn riêng. [1]

Nhật ký EC, pH nên ở lại bảng tính hoặc cơ sở dữ liệu để vẽ biểu đồ và đặt cảnh báo; bản Markdown chỉ phục vụ hỏi đáp. Phiếu kiểm nghiệm dạng scan cần OCR, và dùng plugin với API đám mây nghĩa là nội dung phiếu rời máy của trại, nên cần chủ trại đồng ý và đối chiếu thỏa thuận bảo mật với đối tác thu mua. Mỗi quy trình nên ghi người phụ trách và số phiên bản ở đầu tệp để hệ thống biết bản nào còn hiệu lực. [5]

Cài đặt có chọn lọc, chạy theo lô và khóa phiên bản

MarkItDown cần Python từ 3.10 đến 3.14; README khuyên dùng môi trường ảo qua venv, uv hoặc conda. Môi trường vận hành nên chỉ cài nhóm phụ thuộc thật sự cần, ví dụ pdf, docx, xlsx, thay vì nhóm all, để thu hẹp bề mặt tấn công. [1]

Kho có Dockerfile cho CLI và cho máy chủ MCP; image MCP chỉ đọc được tệp cục bộ khi thư mục được gắn vào /workdir. Bài đề xuất chạy pipeline theo lô trong container không có mạng ra ngoài khi chỉ dùng đường cục bộ, với thư mục đầu vào gắn ở chế độ chỉ đọc; đây là khuyến nghị của bài, không phải cấu hình dựng sẵn. [1][4]

Phiên bản phải được ghim: plugin OCR ràng buộc lõi dưới 0.2.0 và dựa vào phương thức bán nội bộ, dấu hiệu cho thấy giao diện bên trong còn thay đổi. Nên lưu một bộ tài liệu mẫu cùng Markdown kỳ vọng để so sánh trước mỗi lần nâng cấp, bắt FileConversionException và thu thập cảnh báo của plugin OCR, vì lỗi API của plugin chỉ hiện dưới dạng cảnh báo. [1][5]

Đặc quyền tiến trình, URI không tin cậy và máy chủ MCP không xác thực

README đặt cảnh báo ngay đầu trang: MarkItDown thực hiện I/O bằng đặc quyền của tiến trình, giống open() hay requests.get(). Khi đầu vào có thể do bên không tin cậy kiểm soát, như ở ứng dụng phía máy chủ, phải xác thực trước khi gọi: hạn chế đường dẫn tệp, giới hạn lược đồ URI và đích mạng, chặn địa chỉ riêng, loopback, link-local và địa chỉ dịch vụ metadata. [1]

Rủi ro điển hình là SSRF (khiến máy chủ tự gọi vào địa chỉ nội bộ) và đọc tệp trái phép qua URI file. Dự án khuyên gọi hàm hẹp nhất: convert_local() khi chỉ cần tệp cục bộ, tự tải bằng requests.get() rồi chuyển cho convert_response(), hoặc tự mở luồng và gọi convert_stream(). [1]

Máy chủ MCP không hỗ trợ xác thực và chạy với quyền của người khởi động; ở chế độ HTTP hay SSE nó mặc định chỉ gắn vào localhost, nhưng mọi tiến trình trên cùng máy vẫn gọi được, và công cụ có thể đọc bất kỳ tệp nào người dùng đó đọc được. Dự án khuyên chạy trong máy ảo hoặc container hạn chế quyền. Lỗ hổng được báo riêng cho Microsoft Security Response Center, không qua issue công khai. [3][4]

MIT cho mã của Microsoft, Apache 2.0 cho phần mượn từ dwml

Tệp LICENSE gốc của microsoft/markitdown tại commit được ghim là giấy phép MIT, bản quyền Microsoft Corporation. Giấy phép cho phép sử dụng, sửa đổi, hợp nhất, phân phối, cấp phép lại và bán bản sao, miễn là mọi bản sao kèm theo dòng bản quyền cùng nội dung giấy phép; không có bảo hành. Gói markitdown-ocr có tệp LICENSE riêng, cũng là MIT. [2][6]

ThirdPartyNotices cho biết gói lõi tích hợp hai tệp latex_dict.py và omml.py của dự án dwml cho phần công thức toán trong DOCX, theo giấy phép Apache 2.0, chỉ được định dạng lại bằng black. Bản phân phối lại phải giữ nguyên thông báo này. [8]

Phạm vi của MIT dừng ở mã nguồn trong kho tại commit đã ghim; thư viện phụ thuộc, plugin bên thứ ba, mô hình LLM, dịch vụ Azure và điều khoản của nội dung YouTube hay trang web được chuyển đổi đều nằm ngoài. README lưu ý bản sửa đổi không được dùng nhãn hiệu Microsoft gây nhầm lẫn, và người đóng góp mã phải ký Contributor License Agreement. Không tệp nào trong phạm vi đọc nhắc tới một phiên bản thương mại của MarkItDown; thứ có tính phí duy nhất được nêu là các dịch vụ Azure tùy chọn. [1]

Nguồn lực: tính toán cục bộ là mặc định, lời gọi API là chi phí biến đổi

README xếp chi phí của bộ tích hợp là chỉ dùng tài nguyên tính toán cục bộ, còn hai nhánh Azure là lời gọi API có tính phí. Bài không nêu đơn giá vì giá dịch vụ thay đổi theo vùng và thời điểm. [1]

Giả định cho thí điểm: một kỹ sư Python bán thời gian trong vài tuần, một máy trạm phổ thông, một người nghiệp vụ dành vài giờ mỗi tuần chấm đầu ra. Bật OCR qua LLM thì chi phí tăng theo số ảnh và số trang scan; plugin chỉ tránh gọi lại cho ảnh trùng lặp trong cùng một lần chuyển đổi. [5]

Chi phí ẩn là bảo trì phiên bản và chạy lại toàn bộ kho khi đổi chiến lược chia đoạn. Nên tính trên mỗi nghìn trang chuyển đổi đạt yêu cầu thay vì trên số tệp, vì khối lượng của một bảng tính nhiều sheet và một PDF một trang rất khác nhau.

Đặt MarkItDown cạnh các cách tiếp cận khác

Tự ghép thư viện riêng cho từng định dạng cho quyền kiểm soát cao nhưng phải tự thống nhất đầu ra. MarkItDown đóng vai lớp thống nhất, tự nhận gần với textract nhưng ưu tiên giữ cấu trúc dưới dạng Markdown. [1]

Các dự án mã nguồn mở khác cũng nhắm tới việc chuẩn bị tài liệu cho AI, như Docling hay Unstructured; bài không đánh giá chúng. Khác biệt ở mức phương pháp là MarkItDown chọn hướng nhẹ, phủ nhiều định dạng và đẩy phần khó sang plugin hoặc dịch vụ ngoài, nên việc chọn công cụ cần phép thử trên cùng một bộ tài liệu.

Dịch vụ trích xuất trên đám mây, gồm chính Azure Document Intelligence, lo OCR và bố cục nhưng dữ liệu rời hạ tầng và chi phí tính theo lượt. Đưa thẳng PDF cho mô hình đa phương thức thì đơn giản với tài liệu lẻ nhưng khó kiểm soát chi phí khi xử lý hàng nghìn tệp. Giữ đầu ra trung gian là Markdown kèm metadata nguồn giúp đổi công cụ mà không phải dựng lại chỉ mục. [1]

Khi Markdown không phải đích đến phù hợp

README thừa nhận đầu ra có thể không phải lựa chọn tốt cho chuyển đổi trung thực cao; bố cục nhiều cột, ô gộp, biểu đồ sẽ bị đơn giản hóa, nên không dùng bản Markdown thay tệp gốc trong hồ sơ có giá trị pháp lý. [1]

OCR cho ảnh nhúng và bản scan cần plugin LLM hoặc Azure, còn bộ tích hợp không có video. Nếu dữ liệu không được rời hạ tầng và tổ chức không có mô hình thị giác nội bộ đủ tốt, tài liệu scan sẽ thành điểm nghẽn. [1][5]

Không nên mở MarkItDown cho người dùng Internet tải tệp lên khi chưa có sandbox và kiểm soát đầu vào, cũng không nên chờ API REST chính thức vì nó nằm ngoài phạm vi kho. Dải phiên bản 0.1.x đòi hỏi năng lực ghim phiên bản và kiểm thử hồi quy. [1][5]

Thử nghiệm bốn tuần với bộ tài liệu có đáp án

Tuần 1: chọn 150 đến 300 tệp đại diện theo định dạng và nguồn gốc, có tài liệu tiếng Việt nhiều bảng; người nghiệp vụ soạn 30 đến 50 câu hỏi kèm vị trí đáp án trong tệp gốc. Toàn bộ kế hoạch này chỉ là đề xuất; bài không có số đo thực tế nào.

Tuần 2 và 3: chạy đường cục bộ, ghi tỷ lệ tệp không lỗi, tỷ lệ bảng giữ đúng số hàng và cột, tỷ lệ lỗi ký tự có dấu so với văn bản tham chiếu, tỷ lệ câu hỏi có đoạn đáp án nằm trong năm kết quả truy xuất đầu. Chạy riêng nhóm scan qua OCR hoặc Azure, ghi thêm số lời gọi API và thời gian xử lý.

Tuần 4: thử URI trỏ vào địa chỉ nội bộ, ZIP lồng nhau, tệp hỏng, tệp rất lớn. Dừng nếu tỷ lệ truy xuất không đạt mốc đặt trước hoặc giá trị chính nằm ở tài liệu scan không được gửi ra ngoài; mở rộng khi đã có người sở hữu pipeline, bộ kiểm thử hồi quy và ngân sách API có trần. [1]

Kết luận: một mắt xích nhỏ, cần đặt đúng chỗ

MarkItDown giải một bài toán hẹp mà hầu hết dự án RAG đều gặp: đưa tài liệu văn phòng về văn bản có cấu trúc. Điểm mạnh là độ phủ định dạng và cơ chế plugin; điểm yếu là bản scan và bố cục phức tạp phụ thuộc thành phần bên ngoài. [1][5]

Với doanh nghiệp Việt Nam, giá trị chỉ lộ rõ khi đo trên tài liệu tiếng Việt thật và khi ranh giới dữ liệu của từng nhánh xử lý được ghi lại.

Hãy coi MarkItDown là tầng tiền xử lý có kiểm thử, không phải một hệ thống quản trị tri thức hoàn chỉnh.

Nguồn, commit và giới hạn của bài nghiên cứu MarkItDown

Bài thuộc nhóm RAG và quản trị tri thức. MarkItDown lọt vào danh sách nghiên cứu nhờ một kho lưu trữ độc lập ghi lại trang GitHub Trending của từng ngôn ngữ: bản ghi ngày 24/01/2026 có microsoft/markitdown trong mục Python. Kho này chỉ theo dõi Python, Go, JavaScript và Swift, không có dữ liệu cho hai ngày 03/09/2026 và 12/10/2026, nên loạt bài là tuyển chọn biên tập chứ không phải bảng xếp hạng chính thức nào của GitHub. [9]

Nguồn kỹ thuật gồm README, LICENSE, SECURITY.md, README của markitdown-mcp, markitdown-ocr và plugin mẫu, LICENSE của markitdown-ocr và ThirdPartyNotices, tất cả lấy tại commit 4cc9fa17653d695d64fb9eee5b33d4de55ff84e8 (ngày 04/10/2026) và đối chiếu lần cuối ngày 12/10/2026. Mã của từng bộ chuyển đổi không nằm trong phạm vi đọc. [1][2][3][4][5][6][7][8]

Đây là nghiên cứu tài liệu có hỗ trợ AI: không cài đặt, không chạy chuyển đổi thử, không đo hiệu năng MarkItDown; theo siêu dữ liệu GitHub API lấy ngày 12/10/2026, kho chưa bị chuyển sang chế độ archived. Tình huống trang trại, ước lượng nguồn lực và kế hoạch thử là đề xuất phân tích; bài không phải công trình khoa học đã qua bình duyệt.

Xem mã nguồn MarkItDown trên GitHub

Khám phá nghiên cứu của BDSG Foundation

Trao đổi về ứng dụng công nghệ cho doanh nghiệp