본문 바로가기
AI 개발 도구

MarkItDown 사용법: PDF·DOCX를 LLM용 마크다운으로 변환하는 실전 가이드 (2026)

by 정부우르사 2026. 5. 22.
반응형

사내 PDF 200건을 ChatGPT API에 그대로 던졌다가 토큰만 잔뜩 쓰고 답변 품질은 망가진 경험이 있다. 표는 줄이 어긋나고, 머리글·바닥글은 본문에 섞이고, 이미지 캡션은 통째로 사라졌다. 그날 이후 RAG 파이프라인의 첫 단계는 "PDF를 사람이 읽기 좋은 마크다운으로 먼저 깎기"가 됐다.

마이크로소프트가 공개한 MarkItDown은 그 깎는 작업을 한 줄로 끝낸다. PDF·DOCX·PPTX·XLSX·HTML·이미지·오디오까지 9종 이상의 포맷을 단일 API로 받아 LLM이 좋아하는 마크다운으로 토해낸다. 이번 글은 설치부터 OCR·LLM 캡션, LangChain/LlamaIndex 통합, 그리고 Unstructured·pdfplumber·pandoc 같은 경쟁 도구와의 실제 차이까지 한 번에 정리한다.


📌 핵심 3줄 요약

  • MarkItDown은 마이크로소프트가 공개한 오픈소스 파이썬 라이브러리로, PDF·DOCX·PPTX·XLSX·HTML·이미지 등 9종 포맷을 LLM 입력용 마크다운으로 변환한다.
  • pip install 'markitdown[all]' 한 줄이면 설치 끝이고, MarkItDown().convert(path) 한 줄이면 변환 끝이다.
  • OpenAI 호환 LLM 클라이언트를 주입해 이미지 캡션을 자동 생성하고, LangChain·LlamaIndex 인덱싱 워크플로에 그대로 끼워 넣을 수 있다.

1. 왜 LLM 입력에 마크다운이 유리한가

LLM은 토큰 단위로 텍스트를 본다. PDF에서 직접 추출한 raw 텍스트는 줄바꿈이 깨져 있고, HTML은 태그 잡음이 많고, DOCX 바이너리는 아예 못 읽는다. 마크다운은 그 사이의 최적 절충점이다.

  • 헤더 구조 보존#, ## 가 문서의 목차 위계를 그대로 담는다. 청크 분할기가 H1/H2 단위로 끊으면 의미 단위가 깔끔하다.
  • 표·리스트 보존 — 마크다운 표는 LLM이 학습 단계에서 수천만 건 본 포맷이라 인식률이 높다.
  • 토큰 효율 — HTML 대비 토큰 수가 30~50% 줄어든다. 같은 문서를 더 적은 비용으로 임베딩할 수 있다.
  • 사람도 검수 가능 — 변환 결과를 깃에 커밋해두면 diff로 품질 추적이 된다.

RAG 파이프라인을 운영해본 사람이면 마지막 항목의 가치를 안다. 자동 변환은 언젠가 망가지고, 그때 사람이 직접 열어보는 단계가 반드시 필요하다.


2. MarkItDown은 누가 만들었나

github.com/microsoft/markitdown에서 호스팅되는 마이크로소프트 공식 오픈소스다. AutoGen 팀이 내부 에이전트의 문서 인풋 전처리용으로 쓰던 코드를 분리해 공개한 것으로 알려져 있다. MIT 라이선스라 상업적 사용에도 제한이 없고, 의존성 대부분이 잘 알려진 파이썬 패키지(pdfminer, python-docx, openpyxl, mammoth 등)로 구성돼 있어 컨테이너 빌드도 가볍다.

핵심 설계 철학은 "포맷별 어댑터를 두되, 외부에는 MarkItDown().convert(path) 한 줄만 노출한다"는 단순함이다. PDF든 PPTX든 호출부 코드는 똑같이 한 줄이라 RAG 파이프라인의 전처리 함수를 통일하기 쉽다.


3. 설치: 5분 안에 끝낸다

요구사항은 단순하다. Python 3.10 이상, pip, 그리고 디스크 200MB 정도. 모든 포맷을 다 쓰겠다면 all extras를 잡아라.

# 전체 포맷 한 번에
pip install 'markitdown[all]'

# 가벼운 설치 (PDF만 필요한 경우)
pip install 'markitdown[pdf]'

# CLI 동작 확인
markitdown --version
markitdown sample.pdf > sample.md

가상환경 사용은 강력 추천한다. pdfminer.six, python-pptx, openpyxl, mammoth, azure-ai-document-intelligence, openai 등 의존성 그래프가 꽤 넓어 글로벌 환경에 깔면 다른 프로젝트와 충돌하기 쉽다. uv·poetry·venv 어느 쪽이든 무방하다.


4. Python API 기본 사용법

CLI도 좋지만 RAG 파이프라인에 끼워넣을 거라면 Python API가 정답이다. 인터페이스는 한 줄짜리다.

from markitdown import MarkItDown

md = MarkItDown()
result = md.convert("contracts/2026_supply_agreement.pdf")

print(result.text_content)   # 마크다운 본문
print(result.title)          # 추출된 제목 (가능한 경우)

convert() 함수는 확장자를 보고 적절한 변환기를 자동 선택한다. PDF면 pdfminer, DOCX면 mammoth, PPTX면 python-pptx 식이다. 사용자 입장에서는 파일 종류를 신경 쓸 필요가 없다.

URL을 직접 넘기는 것도 된다. HTML 페이지를 받아서 광고·내비게이션을 제거한 본문 마크다운으로 변환한다.

result = md.convert("https://github.com/microsoft/markitdown")
with open("readme.md", "w", encoding="utf-8") as f:
    f.write(result.text_content)

5. 9종 포맷별 변환 품질 한눈에 보기

지난주 사내 문서 50건(PDF 30, DOCX 10, PPTX 5, XLSX 5)을 돌려본 체감 품질을 정리했다.

포맷 변환 품질 주의할 점
PDF (텍스트) 2단 레이아웃은 가끔 줄 순서가 섞임
PDF (스캔본) OCR 옵션 필요, 표 깨질 가능
DOCX 최상 머리글·각주까지 깔끔, 표 100% 보존
PPTX 슬라이드 노트도 함께 추출됨
XLSX 시트별 표 생성, 수식은 평가값
HTML 본문 추출 휴리스틱, 광고 제거
이미지 (PNG/JPG) 중~상 OCR + LLM 캡션 옵션 의존
CSV / JSON 최상 그대로 표·코드블록으로 변환
오디오 (mp3/wav) 전사 모델 의존, 길면 느림

DOCX·XLSX 변환 품질이 인상적으로 좋다. 마이크로소프트가 만든 라이브러리답게 자기 포맷에 강하다.


6. OCR과 LLM 이미지 캡션 옵션

이미지가 박힌 PDF나 PNG 자체를 마크다운으로 만들고 싶다면 이미지 캡션 기능을 켜라. OpenAI 호환 LLM 클라이언트를 주입하면, MarkItDown이 이미지를 base64로 인코딩해서 비전 모델에 캡션을 요청하고 그 결과를 마크다운에 끼워넣는다.

from markitdown import MarkItDown
from openai import OpenAI

client = OpenAI()  # OPENAI_API_KEY 환경변수 사용
md = MarkItDown(
    llm_client=client,
    llm_model="gpt-4o-mini",
)

result = md.convert("annual_report_2025.pdf")
print(result.text_content)

LLM 클라이언트는 OpenAI SDK 인터페이스만 따르면 무엇이든 된다. Azure OpenAI, Together AI, vLLM 로컬 서버, Ollama의 OpenAI 호환 엔드포인트도 모두 동작한다. 비용이 부담된다면 캡션이 꼭 필요한 문서만 별도 큐로 돌리는 게 합리적이다.

스캔본 PDF 위주라면 OCR 옵션도 함께 살펴보자. MarkItDown은 Azure Document Intelligence를 옵션으로 지원하는데, 표가 많은 보고서·계약서에서 정확도가 눈에 띄게 좋다. 무료 대안으로는 tesseract를 미리 텍스트로 뽑아 두는 전처리 방식이 무난하다.


7. LangChain·LlamaIndex 인덱싱 통합

RAG 파이프라인 입장에서 MarkItDown은 그저 "문서 → 텍스트" 한 단계다. LangChain·LlamaIndex 인덱싱 워크플로에 직접 꽂아 쓸 수 있다.

LangChain Document Loader 패턴

from pathlib import Path
from langchain_core.documents import Document
from langchain_text_splitters import MarkdownHeaderTextSplitter
from markitdown import MarkItDown

md = MarkItDown()

def load_as_documents(file_path: str) -> list[Document]:
    result = md.convert(file_path)
    splitter = MarkdownHeaderTextSplitter(
        headers_to_split_on=[("#", "h1"), ("##", "h2"), ("###", "h3")]
    )
    chunks = splitter.split_text(result.text_content)
    return [
        Document(
            page_content=c.page_content,
            metadata={**c.metadata, "source": Path(file_path).name},
        )
        for c in chunks
    ]

docs = load_as_documents("policy.pdf")
print(len(docs), "chunks")

MarkdownHeaderTextSplitter가 H1/H2/H3 단위로 깔끔하게 청크를 끊어준다. 헤더 정보가 메타데이터로 따라붙어서 검색 결과를 사용자에게 보여줄 때 "어느 섹션에서 나왔는지"가 자연스럽게 표시된다.

LlamaIndex Reader 패턴

from llama_index.core import Document, VectorStoreIndex
from markitdown import MarkItDown

md = MarkItDown()

def to_llama_doc(path: str) -> Document:
    result = md.convert(path)
    return Document(text=result.text_content, metadata={"source": path})

docs = [to_llama_doc(p) for p in ["a.pdf", "b.docx", "c.pptx"]]
index = VectorStoreIndex.from_documents(docs)
query_engine = index.as_query_engine()
print(query_engine.query("환불 정책 요약해줘"))

핵심은 MarkItDown이 모든 입력 포맷을 str 마크다운으로 평탄화해준다는 점이다. LlamaIndex나 LangChain은 더 이상 PDF·DOCX 각각의 로더를 신경 쓸 필요가 없다.


8. Unstructured·pdfplumber·pandoc과 어떻게 다른가

비슷한 도구가 이미 많다. 솔직히 정리하면 이렇다.

도구 강점 약점
MarkItDown 단일 API로 9종 포맷, LLM 캡션 옵션, MS 공식 표 추출 정밀도는 Unstructured 한 단계 아래
Unstructured 청킹·요소 분류 정교, 엔터프라이즈 기능 의존성 무겁고 라이선스 일부 상업 제한
pdfplumber PDF 표 추출 정밀도 최상 PDF 외 미지원, 마크다운 변환 직접 작성
pandoc 포맷 변환의 정석, CLI 안정성 최상 LLM 옵션 없음, Python 통합이 외부 호출

RAG 파이프라인의 1차 후보는 MarkItDown, 표가 핵심인 재무·법무 PDF는 pdfplumber로 따로 전처리, 그래도 안 되면 Unstructured 엔터프라이즈 — 이게 현실적인 선택지다. 한 가지 도구로 끝내려 하지 말고, 어떤 도구든 결국 후처리 정규화가 필요하다고 가정하는 게 마음 편하다.


9. 실무 팁과 자주 묻는 질문

  • "한국어 PDF가 깨지는데요" — 폰트 임베딩이 안 된 오래된 PDF에서 종종 발생한다. 그런 PDF는 OCR 옵션 켜는 게 차라리 빠르다.
  • "표가 줄이 어긋나요" — 셀 병합이 많은 표는 어떤 도구도 완벽하지 않다. 변환 후 마크다운 표를 정규식으로 한 번 청소하는 단계를 넣자.
  • "대용량 PDF는 메모리가 터집니다" — 페이지 범위를 잘라 여러 번 호출하거나, 사전에 PyPDF2로 페이지 분할 후 배치 처리하면 안정적이다.
  • "비용이 걱정됩니다" — LLM 캡션은 옵션이다. 안 켜면 100% 로컬에서 동작하니 API 비용 0원이다.
  • "라이선스 안전한가요" — MIT 라이선스라 사내·상업 프로젝트 모두 자유롭게 쓸 수 있다.

⚠️ 단점과 주의할 점

  • 스캔본 PDF의 표 인식은 여전히 약점이다. 재무·법무 문서가 메인이면 pdfplumber나 Azure Document Intelligence 같은 보조 도구가 필요하다.
  • LLM 캡션 옵션을 켜면 비용이 빠르게 누적된다. 문서 수천 건 단위로 돌릴 거면 캡션 대상 문서를 사전에 필터링해라.
  • 한글 폰트 임베딩이 빠진 오래된 PDF는 변환이 거의 안 된다. OCR 전처리를 우회하지 말고 받아들이는 게 빠르다.
  • 릴리스가 잦아 API가 마이너 버전에서 미세하게 바뀐다. 운영 환경에서는 버전을 핀으로 고정해두자.

🚀 지금 바로 할 일

  1. pip install 'markitdown[all]'로 설치하고 가장 까다로운 사내 문서 5개를 변환해 출력 마크다운을 사람 눈으로 검수한다.
  2. 변환 품질이 만족스러우면 LangChain 또는 LlamaIndex 로더 자리에 MarkItDown().convert()를 정식으로 끼워 넣는다.
  3. 이미지가 핵심인 문서는 OpenAI 호환 클라이언트를 주입해 캡션 옵션을 켜고, 표가 핵심인 문서는 pdfplumber와 병행하는 하이브리드 전처리 파이프라인을 구성한다.

💬 의견

RAG 전처리에 어떤 도구를 쓰고 있는지, MarkItDown으로 옮길 만한 부분이 있었는지 댓글로 공유 부탁드립니다. 다음 글은 LangChain의 MarkdownHeaderTextSplitter 청크 전략 튜닝을 다룰 예정입니다.


참고 자료

반응형