Giting.
낮의 Giting

홈 · 문서 변환 · 마크다운 · LLM 전처리 · RAG · Python · Microsoft

markitdown 대표 이미지 eb31b5c (2026-09-14, 전체 403커밋)
분석 리포트실측 정보적용점원문 README

무엇을 하는 도구인가

MarkItDown 은 마이크로소프트가 낸 파일 → 마크다운 변환기다. PDF, 워드, 파워포인트, 엑셀, HTML, 이미지, 오디오, ZIP, EPUB, 심지어 유튜브 자막까지 받아 하나의 마크다운 텍스트로 떨군다. 스타 184,705개, 포크 13,607개로 이번 검수 대상 중 최대 규모다.

핵심은 목적이다. 이건 사람이 예쁘게 읽을 문서를 만드는 도구가 아니다. README 가 밝히듯 대상 소비자는 LLM 이다. 구조(제목·목록·표·링크)를 마크다운으로 남기면 토큰 효율이 좋고, 모델이 텍스트로 읽기 좋다. 그래서 판단 기준도 "얼마나 예쁜가"가 아니라 "구조와 내용을 얼마나 잃지 않는가"다.

설치해서 여섯 포맷을 재봤다

말이 아니라 손으로 쟀다. 파이썬 3.11 격리 환경에 pip install "markitdown[all]" (0.1.7) 을 깔고, 서식·표·목록·특수값을 일부러 넣은 샘플을 포맷별로 만들어 변환했다.

입력결과충실도
HTML제목(#)·굵게·링크·표·불릿 전부 보존깔끔
CSV표로 변환, 따옴표 안 쉼표("쉼표,포함")도 한 칸에 유지깔끔
엑셀(xlsx)시트마다 ## 시트명 + 마크다운 표. 코드 칸이 전부 숫자처럼 생기면 앞자리 0이 빠진다('00123' → 123, 정정 참고)양호 (빈 칸은 NaN, 금액은 13500.0 처럼 소수점)
파워포인트(pptx)<!-- Slide number: N --> 주석 + 제목(#) + 본문양호 (불릿은 평면 줄로)
워드(docx)굵게·기울임·목록·헤딩은 살았으나 표의 헤더 행을 빈 칸으로 만들고 진짜 헤더를 본문으로 밀었다. Title 스타일은 # 이 아닌 평문으로부분적
PDF텍스트는 깔끔히 추출하되 헤딩·표 없이 평면, 페이지 구분도 없음평면 (PDF 한계)
JSON변환 없이 원문 통과대상 아님

두 결과가 특히 말해 준다. 엑셀의 앞자리 0은 스프레드시트 변환에서 흔히 깨지는 지점인데, 코드 칸이 전부 숫자처럼 생기면 여기서도 깨진다(아래 정정). 워드 표의 헤더 행 소실도 실제 결함이다. 표를 그대로 살려야 하는 파이프라인이라면 후처리가 필요하다.

정정 (2026-10-11)

처음 판(2026-09-16)에는 엑셀 줄을 「앞자리 0('00123') 텍스트 보존」으로 적었다. 인스타그램 실험을 준비하며 다시 재 보니 조건이 붙는 말이었다.

엑셀의 코드 칸MarkItDown 결과
00123 · 00045 · 01200 처럼 전부 숫자처럼 생김 (셀은 문자 형식)123 · 45 · 1200: 앞자리 0이 빠진다
00123 · 00045 · B001 처럼 글자가 섞임00123 · 00045 · B001: 그대로

MarkItDown 0.1.7·0.1.8, pandas 2.3.3·3.0.6 모두 같았다(파이썬 3.11, markitdown[xlsx]). 엑셀을 표로 읽는 단계에서 숫자처럼 보이는 칸을 숫자로 바꾸기 때문으로 보인다. 처음 실측 때의 샘플 파일은 남아 있지 않아 그때 왜 「보존」으로 나왔는지는 확인하지 못했다. 코드·우편번호·전화번호처럼 0으로 시작하는 값이 있는 엑셀을 넘길 때는 바꾼 뒤 그 칸을 꼭 확인할 것.

그래서 이건 무슨 부류의 도구인가

여섯 번의 변환이 한 문장으로 수렴한다. MarkItDown 은 문서 변환기가 아니라 LLM 입력용 텍스트 추출기다. HTML 처럼 구조가 명시된 입력은 거의 완벽하게 오고, PDF 처럼 구조가 시각적으로만 있는 입력은 텍스트만 남는다. 목적이 "모델에게 읽히기"라 이 트레이드오프는 설계 의도에 가깝다. 표를 잃더라도 텍스트를 얻는다.

실측: 규모와 관리

repo 도 그 목적에 걸맞게 관리된다. 전체 커밋 403, 최근 90일 94커밋, 기여자 129명, 테스트 파일 87개. 열린 이슈는 676개로 규모 대비 많지만, 25건을 표본으로 재보니 중앙 응답 시간이 2.3시간으로 이번 시리즈에서 가장 빨랐다(비교: archify 20.8시간). MS AutoGen 계열 저자들이 유지하고, MIT 라이선스에 파일 종류 감지는 자사 딥러닝 탐지기 magika 를 코어 의존으로 쓴다.

가져올 것과 주의

  • 임의 문서를 LLM·RAG 에 먹이기 전 마크다운화가 필요하면 지금 쓸 값이 있다. 한 줄 CLI(markitdown file.pdf) 또는 파이썬 한 줄이면 된다
  • ⚠️ Python 3.10+ 필수. 3.9 환경에서는 조용히 옛 알파(0.0.1a1)로 설치되고 CLI 도 안 생긴다. 실측 중 실제로 밟은 함정이다. 설치 후 markitdown --help 와 버전을 반드시 확인할 것
  • ⚠️ 표 구조를 그대로 살려야 하면 워드 표 헤더 소실을 후처리로 메워야 한다. PDF 는 구조가 필요하면 다른 도구를 봐야 한다
  • ⚠️ [all] 설치는 가볍지 않고(약 390MB), 오디오 전사는 ffmpeg 를 따로 깔아야 동작한다

실측 정보

HEAD 커밋
eb31b5c (2026-09-14, 전체 403커밋)
소유
microsoft/markitdown · 저자 129명(afourney·gagb 등 MS AutoGen 계열) · 생성 2024-11
규모
텍스트 24,664줄 · 파이썬 96파일 · 테스트 파일 87 · 태그 24 · 최근 90일 94커밋
형태
파이썬 패키지(pip) + CLI(markitdown) + 플러그인 아키텍처. 파일 종류 감지에 MS의 딥러닝 탐지기 magika 를 코어 의존으로 씀
설치
Python 3.10+ 필수(3.9는 옛 알파로 떨어짐). pip install "markitdown[all]" venv 약 390MB. 오디오 전사는 ffmpeg 별도
지원 입력
PDF · Word · PowerPoint · Excel · HTML · CSV · JSON/XML · 이미지(EXIF·OCR·캡션) · 오디오(전사) · ZIP · EPUB · YouTube 자막 등
이슈 관리
열린 이슈 676(규모 대비) · 25건 표본 중 8건 응답 · 중앙 응답 2.3시간(빠름)
실측 환경
0.1.7 · Python 3.11.15 · macOS · 자체 생성 샘플 6종 격리 변환(docx·xlsx·pptx·html·csv·json·pdf)
라이선스
MIT © Microsoft

적용점

  • 이럴 때 유용임의의 문서 더미를 LLM 컨텍스트나 RAG 파이프라인에 넣기 전, 마크다운 텍스트로 일괄 변환할 때. 한 줄 CLI 또는 파이썬 한 줄로 PDF·오피스·HTML을 텍스트로 떨군다. MS가 유지보수하고 이슈 응답이 빠르다.
  • 이럴 땐 부적합표 구조나 서식을 픽셀 단위로 재현해야 할 때. 실측에서 워드 표는 헤더 행을 비우고 실제 헤더를 본문으로 밀었고, PDF는 헤딩·표 없이 평면 텍스트로 떨어졌다. 이건 '보기 좋은 문서 변환기'가 아니라 'LLM에 먹일 텍스트 추출기'다.
  • 먼저 볼 것Python 3.10+ 가 아니면 조용히 옛 알파(0.0.1a1)로 설치돼 CLI도 안 생긴다. 버전을 반드시 확인할 것. 코어 의존 magika(딥러닝 파일 탐지)와 [all] 익스트라로 설치가 가볍지 않다. 오디오 전사는 ffmpeg 를 따로 깔아야 동작한다.
◆ 도입 후보

검수 질문은 하나다. 설치해서 실제로 돌리면 쓸 만한가. 파이썬 3.11 venv 에 markitdown[all] 0.1.7 을 깔고, 자체 생성한 워드·엑셀·PPT·HTML·CSV·JSON·PDF 일곱 개를 격리 변환했다. 결과는 갈렸다. HTML·CSV·PPT 는 깔끔했다. 굵게·링크·표·다중 시트가 그대로 왔다. 엑셀도 시트와 표는 그대로 왔지만, 코드 칸이 전부 숫자처럼 생기면 앞자리 0('00123')을 지운다(2026-10-11 재측정으로 정정. 처음 판에는 「보존」으로 잘못 적었다). 반면 워드 표는 헤더 행을 빈 칸으로 만들고 진짜 헤더를 첫 데이터 행으로 밀었고, PDF 는 헤딩도 표도 없이 평면 텍스트로 떨어졌다(PDF 특성상 예상된 한계다). JSON 은 변환 없이 원문을 통과시켰다. 결론은 명확하다. 이건 사람 눈을 위한 문서 변환기가 아니라 LLM 입력을 위한 텍스트 추출기다. 그 용도(문서 더미를 모델에 먹이기 전 마크다운화)로는 184k 스타·MS 유지보수·중앙 2.3시간 응답이 받쳐 주는 도입 후보다. 다만 표를 그대로 살려야 하거나 Python 3.10 미만 환경이라면 먼저 확인할 것들이 있다.

원문 README

아래는 microsoft/markitdown 저장소의 README 원문입니다(GitHub 렌더, 수집 시점 기준). 저작권은 원 프로젝트에 있으며 원 저장소의 라이선스를 따릅니다. GitHub에서 보기

README 전문 펼치기

MarkItDown

PyPI PyPI - Downloads

Important

MarkItDown performs I/O with the privileges of the current process. Like open() or requests.get(), it will access resources that the process itself can access. Sanitize your inputs in untrusted environments, and call the narrowest convert_* function needed for your use case (e.g., convert_stream(), or convert_local()). See the Security Considerations section of the documentation for more information.

MarkItDown is a lightweight Python utility for converting various files to Markdown for use with LLMs and related text analysis pipelines. To this end, it is most comparable to textract, but with a focus on preserving important document structure and content as Markdown (including: headings, lists, tables, links, etc.) While the output is often reasonably presentable and human-friendly, it is meant to be consumed by text analysis tools -- and may not be the best option for high-fidelity document conversions for human consumption.

MarkItDown currently supports the conversion from:

  • PDF
  • PowerPoint
  • Word
  • Excel
  • Images (EXIF metadata and OCR)
  • Audio (EXIF metadata and speech transcription)
  • HTML
  • Text-based formats (CSV, JSON, XML)
  • ZIP files (iterates over contents)
  • YouTube URLs
  • EPubs
  • ... and more!

Why Markdown?

Markdown is extremely close to plain text, with minimal markup or formatting, but still provides a way to represent important document structure. Mainstream LLMs, such as OpenAI's GPT-4o, natively "speak" Markdown, and often incorporate Markdown into their responses unprompted. This suggests that they have been trained on vast amounts of Markdown-formatted text, and understand it well. As a side benefit, Markdown conventions are also highly token-efficient.

Prerequisites

MarkItDown requires Python 3.10 or higher. It is recommended to use a virtual environment to avoid dependency conflicts.

With the standard Python installation, you can create and activate a virtual environment using the following commands:

python -m venv .venv
source .venv/bin/activate

If using uv, you can create a virtual environment with:

uv venv --python=3.12 .venv
source .venv/bin/activate
# NOTE: Be sure to use 'uv pip install' rather than just 'pip install' to install packages in this virtual environment

If you are using Anaconda, you can create a virtual environment with:

conda create -n markitdown python=3.12
conda activate markitdown

Installation

To install MarkItDown, use pip: pip install 'markitdown[all]'. Alternatively, you can install it from the source:

git clone git@github.com:microsoft/markitdown.git
cd markitdown
pip install -e 'packages/markitdown[all]'

Usage

Command-Line

markitdown path-to-file.pdf > document.md

Or use -o to specify the output file:

markitdown path-to-file.pdf -o document.md

You can also pipe content:

cat path-to-file.pdf | markitdown

Optional Dependencies

MarkItDown has optional dependencies for activating various file formats. Earlier in this document, we installed all optional dependencies with the [all] option. However, you can also install them individually for more control. For example:

pip install 'markitdown[pdf, docx, pptx]'

will install only the dependencies for PDF, DOCX, and PPTX files.

At the moment, the following optional dependencies are available:

  • [all] Installs all optional dependencies
  • [pptx] Installs dependencies for PowerPoint files
  • [docx] Installs dependencies for Word files
  • [xlsx] Installs dependencies for Excel files
  • [xls] Installs dependencies for older Excel files
  • [pdf] Installs dependencies for PDF files
  • [outlook] Installs dependencies for Outlook messages
  • [az-doc-intel] Installs dependencies for Azure Document Intelligence
  • [az-content-understanding] Installs dependencies for Azure Content Understanding
  • [audio-transcription] Installs dependencies for audio transcription of wav and mp3 files
  • [youtube-transcription] Installs dependencies for fetching YouTube video transcription

Plugins

MarkItDown also supports 3rd-party plugins. Plugins are disabled by default. To list installed plugins:

markitdown --list-plugins

To enable plugins use:

markitdown --use-plugins path-to-file.pdf

To find available plugins, search GitHub for the hashtag #markitdown-plugin. To develop a plugin, see packages/markitdown-sample-plugin.

markitdown-ocr Plugin

The markitdown-ocr plugin adds OCR support to PDF, DOCX, PPTX, and XLSX converters, extracting text from embedded images using LLM Vision — the same llm_client / llm_model pattern that MarkItDown already uses for image descriptions. No new ML libraries or binary dependencies required.

Installation:

pip install markitdown-ocr
pip install openai  # or any OpenAI-compatible client

Usage:

Pass the same llm_client and llm_model you would use for image descriptions:

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)

If no llm_client is provided the plugin still loads, but OCR is silently skipped and the standard built-in converter is used instead.

See packages/markitdown-ocr/README.md for detailed documentation.

Azure Content Understanding

Azure Content Understanding provides higher-quality conversion with structured field extraction (YAML front matter), multi-modal support (documents, images, audio, video), and configurable analyzers.

Install: pip install 'markitdown[az-content-understanding]'

When to use Content Understanding

Content Understanding is ideal when you need capabilities beyond what built-in or Document Intelligence converters provide:

  • Audio and video files — CU is the only option for video, and the higher-quality cloud option for audio. Built-in converters have no video support and only basic audio transcription.
  • Structured field extraction — Prebuilt or custom-built analyzers extract domain-specific fields (invoice amounts, receipt dates, contract clauses) serialized as YAML front matter. Neither built-in nor Doc Intel integration exposes fields.
  • Higher-quality document extraction — Cloud-based layout analysis and OCR for scanned PDFs, complex tables, and multi-page documents.
  • Single API for all modalities — One cu_endpoint handles documents, images, audio, and video with automatic analyzer routing.
Capability Built-in converters Azure Document Intelligence Azure Content Understanding
Document conversion Offline, format-specific extraction Cloud layout extraction Cloud multimodal extraction
Structured fields Not available Not exposed by this integration YAML front matter from analyzer fields
Custom analyzers Not available Not configurable in this integration Supported with cu_analyzer_id
Audio and video Basic audio, no video Not supported Audio and video analyzers
Cost Local compute only Billable Azure API calls Billable Azure API calls

CLI:

markitdown path-to-file.pdf --use-cu --cu-endpoint "<content_understanding_endpoint>"

The endpoint can also be set once in the environment, so callers only need --use-cu:

export MARKITDOWN_CU_ENDPOINT="<content_understanding_endpoint>"
markitdown path-to-file.pdf --use-cu

Python API:

from markitdown import MarkItDown

# Zero-config — auto-selects analyzer per file type
md = MarkItDown(cu_endpoint="<content_understanding_endpoint>")
result = md.convert("report.pdf")   # documents → prebuilt-documentSearch
result = md.convert("meeting.mp4")  # video → prebuilt-videoSearch
result = md.convert("call.wav")     # audio → prebuilt-audioSearch
print(result.markdown)

With a custom analyzer (for domain-specific field extraction):

md = MarkItDown(
    cu_endpoint="<content_understanding_endpoint>",
    cu_analyzer_id="my-invoice-analyzer",
)
result = md.convert("invoice.pdf")
print(result.markdown)
# Output includes YAML front matter with extracted fields:
# ---
# contentType: document
# fields:
#   VendorName: CONTOSO LTD.
#   InvoiceDate: '2019-11-15'
# ---
# <!-- page 1 -->
# ...

When cu_analyzer_id is set, the converter automatically scopes it to compatible file types based on the analyzer's modality. Incompatible types (e.g., audio files with a document analyzer) auto-route to default prebuilt analyzers.

Cost note: Each convert() call for a CU-routed format is a billable Azure API call. Use cu_file_types to restrict which formats route to CU:

from markitdown.converters import ContentUnderstandingFileType

md = MarkItDown(
    cu_endpoint="<content_understanding_endpoint>",
    cu_file_types=[ContentUnderstandingFileType.PDF],  # only PDFs use CU
)

More information about Azure Content Understanding can be found here.

Azure Document Intelligence

To use Microsoft Document Intelligence for conversion:

markitdown path-to-file.pdf -o document.md -d -e "<document_intelligence_endpoint>"

The endpoint can also be set once in the environment, so callers only need -d:

export MARKITDOWN_DOCINTEL_ENDPOINT="<document_intelligence_endpoint>"
markitdown path-to-file.pdf -o document.md -d

More information about how to set up an Azure Document Intelligence Resource can be found here

Python API

Basic usage in Python:

from markitdown import MarkItDown

md = MarkItDown(enable_plugins=False) # Set to True to enable plugins
result = md.convert("test.xlsx")
print(result.markdown)

Document Intelligence conversion in Python:

from markitdown import MarkItDown

md = MarkItDown(docintel_endpoint="<document_intelligence_endpoint>")
result = md.convert("test.pdf")
print(result.markdown)

To use Large Language Models for image descriptions (currently only for pptx and image files), provide llm_client and llm_model:

from markitdown import MarkItDown
from openai import OpenAI

client = OpenAI(max_retries=5)
md = MarkItDown(llm_client=client, llm_model="gpt-4o", llm_prompt="optional custom prompt")
result = md.convert("example.jpg")
print(result.markdown)

max_retries controls the OpenAI client's automatic retries for retryable errors (the default is 2); 5 allows up to six attempts with backoff. See the OpenAI SDK retry documentation.

If any attempt succeeds, image conversion continues normally. If the client raises an error after exhausting its retries, or encounters a non-retryable error, MarkItDown tries other applicable converters and raises FileConversionException only if none succeeds.

Docker

docker build -t markitdown:latest .
docker run --rm -i markitdown:latest < ~/your-file.pdf > output.md

Contributing

Before starting significant work, please read What to Contribute, which describes what is in and out of scope for this repository.

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.

What to Contribute

MarkItDown is a Python utility for converting files to Markdown for use with LLMs and related text analysis pipelines. This repository is intended to provide Python libraries that can be incorporated into other systems — not the end-user applications built on top of them.

In scope

  • Improvements to the fidelity of existing converters (New formats are added sparingly -- especially if they incur new dependencies. In most cases, new formats can be better supported via 3rd-party plugins.)
  • Bug fixes, performance improvements, and security fixes
  • The markitdown command-line interface
  • The markitdown-mcp package
  • Tests, documentation, and developer tooling

Out of scope

We cannot accept additional applications, services, or servers. This includes:

  • Web servers, REST or HTTP APIs, and hosted conversion services
  • Web frontends and browser-based user interfaces
  • Desktop and mobile applications (PyQt, PySide, Tkinter, Electron, Flutter, and similar)

Projects like these are genuinely useful, and we would rather see them thrive than be turned away. If you are interested in providing a web service, API, or graphical application for MarkItDown, please maintain it as a separate package or project that depends on markitdown from PyPI.

Extending MarkItDown Without Changing This Repository

MarkItDown supports 3rd-party plugins, so support for a new format can be published and installed independently of this repository:

markitdown --list-plugins
markitdown --use-plugins path-to-file.pdf

See packages/markitdown-sample-plugin to get started, and tag your repository #markitdown-plugin so that others can find it.

How to Contribute

You can help by looking at issues or helping review PRs. We have also marked some issues as 'open for contribution' and PRs as 'open for reviewing' to help facilitate community contributions. These labels are suggestions; contributions within the scope described above are welcome.

All Especially Needs Help from Community
Issues All Issues Issues open for contribution
PRs All PRs PRs open for reviewing

Running Tests and Checks

  • Navigate to the MarkItDown package:

    cd packages/markitdown
  • Install hatch in your environment and run tests:

    pip install hatch  # Other ways of installing hatch: https://hatch.pypa.io/dev/install/
    hatch shell
    hatch test

    (Alternative) Use the Devcontainer which has all the dependencies installed:

    # Reopen the project in Devcontainer and run:
    hatch test
  • Run pre-commit checks before submitting a PR: pre-commit run --all-files

Security Considerations

MarkItDown performs I/O with the privileges of the current process. Like open() or requests.get(), it will access resources that the process itself can access.

Sanitize your inputs: Do not pass untrusted input directly to MarkItDown. If any part of the input may be controlled by an untrusted user or system, such as in hosted or server-side applications, it must be validated and restricted before calling MarkItDown. Depending on your environment, this may include restricting file paths, limiting URI schemes and network destinations, and blocking access to private, loopback, link-local, or metadata-service addresses.

Call only the conversion method you need: Prefer the narrowest conversion API that fits your use case. MarkItDown's convert() method is intentionally permissive and can handle local files, remote URIs, and byte streams. If your application only needs to read local files, call convert_local() instead. If you need more control over URI fetching, call requests.get() yourself and pass the response object to convert_response(). For maximum control, open a stream to the input you want converted and call convert_stream().

Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.

의견

판정에 대한 반론, 도입 경험, 정정 제보를 환영합니다. GitHub 계정으로 참여합니다.

이것도 재봤습니다

전체 리포트 →