반응형
RAG 파이프라인을 만들다 보면 항상 이 벽에 부딪혀요.
"이 PDF 분석해줘"
→ LLM: ????
이유:
PDF는 렌더링용 포맷
텍스트, 이미지, 표가 뒤섞인 이진 파일
LLM이 직접 이해하기 어려움
그래서 보통 이렇게 함:
PDF → PyPDF2로 텍스트 추출 → 근데 표/이미지 날아감
Word → python-docx → 복잡한 파싱 코드 작성
PPT → 슬라이드 하나씩 수동 처리
Excel → pandas로 읽고 또 변환
→ 포맷마다 다른 라이브러리
→ 포맷마다 다른 코드
→ 복잡하고 유지보수 힘듦
Microsoft가 이 문제를 해결하는 도구를 오픈소스로 냈어요. markitdown이에요.
pip install 'markitdown[all]'
markitdown 문서.pdf
끝.
GitHub 별 5만개+. MIT 라이선스.
뭘 지원하나
문서:
PDF, DOCX, PPTX, XLSX, CSV
웹:
HTML, XML, JSON, RSS
미디어:
이미지 (JPG, PNG) → LLM으로 설명 추출
음성 파일 (MP3, WAV) → Whisper로 자동 전사
YouTube URL → 자막 자동 추출
압축:
ZIP → 내부 파일 일괄 변환
설치
# 전체 기능 포함 설치 (권장)
pip install 'markitdown[all]'
# 최소 설치 (기본 문서만)
pip install markitdown
# 이미지 설명 추출 추가 (LLM 필요)
pip install 'markitdown[all]' openai
기본 사용 — CLI
# PDF 변환
markitdown 문서.pdf
# Word 변환
markitdown 보고서.docx
# PPT 변환
markitdown 발표자료.pptx
# Excel 변환
markitdown 데이터.xlsx
# 파일로 저장
markitdown 문서.pdf > output.md
# 여러 파일
markitdown *.pdf > all_docs.md
# YouTube 자막 추출
markitdown "https://www.youtube.com/watch?v=xxxxx"
# URL 웹페이지 변환
markitdown "https://docs.python.org/3/tutorial/"
기본 사용 — Python
from markitdown import MarkItDown
md = MarkItDown()
# PDF
result = md.convert("report.pdf")
print(result.text_content)
# Word
result = md.convert("document.docx")
print(result.text_content)
# Excel
result = md.convert("data.xlsx")
print(result.text_content)
# URL
result = md.convert("https://example.com")
print(result.text_content)
# 결과는 항상 result.text_content로 접근
# 포맷마다 다른 API 없음 — 통일된 인터페이스
실전 활용 1 — RAG 전처리 파이프라인
회사 문서를 LLM 지식베이스로 만드는 가장 흔한 사례예요.
from markitdown import MarkItDown
from pathlib import Path
import anthropic
import json
md = MarkItDown()
client = anthropic.Anthropic()
def process_documents(doc_dir: str) -> list[dict]:
"""폴더 안 문서들을 전부 Markdown으로 변환"""
docs = []
supported = ['.pdf', '.docx', '.pptx', '.xlsx', '.html', '.csv']
for path in Path(doc_dir).rglob('*'):
if path.suffix.lower() not in supported:
continue
try:
result = md.convert(str(path))
docs.append({
"filename": path.name,
"path": str(path),
"content": result.text_content,
"format": path.suffix
})
print(f"✅ {path.name}")
except Exception as e:
print(f"❌ {path.name}: {e}")
return docs
def ask_about_docs(docs: list[dict], question: str) -> str:
"""변환된 문서들로 질문 답변"""
# 문서 내용 합치기
context = "\n\n---\n\n".join([
f"[{doc['filename']}]\n{doc['content']}"
for doc in docs
])
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=2048,
system="주어진 문서를 바탕으로 질문에 답해줘. 문서에 없는 내용은 모른다고 해.",
messages=[{
"role": "user",
"content": f"문서 내용:\n{context}\n\n질문: {question}"
}]
)
return response.content[0].text
# 실행
docs = process_documents("./company_docs")
print(f"\n{len(docs)}개 문서 처리 완료\n")
answer = ask_about_docs(docs, "우리 회사 환불 정책이 어떻게 되나요?")
print(answer)
실전 활용 2 — 이미지 설명 자동 추출
이미지가 포함된 PDF의 경우 LLM으로 이미지 내용까지 추출해요.
from markitdown import MarkItDown
from openai import OpenAI
# LLM 클라이언트 연결
openai_client = OpenAI()
md = MarkItDown(
llm_client=openai_client,
llm_model="gpt-4o" # 이미지 이해 가능한 멀티모달 모델
)
# 이미지가 포함된 PDF 변환
# → 이미지 부분은 GPT-4o가 설명 텍스트로 변환
result = md.convert("technical_manual_with_diagrams.pdf")
print(result.text_content)
# 출력 예시:
# # 기술 매뉴얼
#
# ## 1장. 시스템 구성
#
# [이미지 설명: 3개의 서버가 로드밸런서에 연결된 클러스터 아키텍처 다이어그램.
# 왼쪽에 클라이언트, 중앙에 로드밸런서(Nginx), 오른쪽에 App Server 3대]
#
# 시스템은 다음과 같이 구성됩니다...
실전 활용 3 — Excel 데이터 분석 자동화
from markitdown import MarkItDown
import anthropic
md = MarkItDown()
client = anthropic.Anthropic()
def analyze_excel(filepath: str, question: str) -> str:
"""Excel 파일을 분석해서 질문에 답변"""
# Excel → Markdown 표 변환
result = md.convert(filepath)
# 변환 결과 확인
# | 월 | 매출 | 비용 | 순이익 |
# |---|---|---|---|
# | 1월 | 1,200만 | 800만 | 400만 |
# | 2월 | 1,500만 | 850만 | 650만 |
# ...
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{
"role": "user",
"content": f"""
다음 Excel 데이터를 분석해줘:
{result.text_content}
질문: {question}
"""
}]
)
return response.content[0].text
# 사용
analysis = analyze_excel(
"2026_Q1_sales.xlsx",
"1분기에서 가장 성과가 좋은 제품 카테고리는?"
)
print(analysis)
실전 활용 4 — 회의록/음성 자동 처리
from markitdown import MarkItDown
md = MarkItDown()
# 회의 녹음 파일 → 텍스트 전사
result = md.convert("meeting_recording.mp3")
print(result.text_content)
# 출력:
# [00:00] 안녕하세요, 오늘 Q1 리뷰 회의를 시작하겠습니다.
# [00:15] 먼저 매출 현황부터 보면...
# ...
# YouTube 영상 → 자막 추출
result = md.convert("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
print(result.text_content)
실전 활용 5 — 일괄 변환 스크립트
from markitdown import MarkItDown
from pathlib import Path
import concurrent.futures
import time
md = MarkItDown()
def convert_file(path: Path) -> dict:
"""단일 파일 변환"""
start = time.time()
try:
result = md.convert(str(path))
duration = time.time() - start
return {
"status": "success",
"file": path.name,
"chars": len(result.text_content),
"duration": f"{duration:.1f}초",
"content": result.text_content
}
except Exception as e:
return {
"status": "error",
"file": path.name,
"error": str(e)
}
def batch_convert(input_dir: str, output_dir: str):
"""폴더 전체 병렬 변환"""
input_path = Path(input_dir)
output_path = Path(output_dir)
output_path.mkdir(exist_ok=True)
supported = {'.pdf', '.docx', '.pptx', '.xlsx', '.html', '.csv'}
files = [f for f in input_path.rglob('*') if f.suffix.lower() in supported]
print(f"총 {len(files)}개 파일 변환 시작...")
# 병렬 처리 (최대 4개 동시)
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
results = list(executor.map(convert_file, files))
# 결과 저장 + 통계
success = 0
fail = 0
for result in results:
if result["status"] == "success":
# 변환된 내용을 .md 파일로 저장
out_file = output_path / (Path(result["file"]).stem + ".md")
out_file.write_text(result["content"], encoding="utf-8")
print(f"✅ {result['file']} → {result['chars']:,}자 ({result['duration']})")
success += 1
else:
print(f"❌ {result['file']}: {result['error']}")
fail += 1
print(f"\n완료: 성공 {success}개 / 실패 {fail}개")
# 실행
batch_convert("./documents", "./markdown_output")
MCP 서버로 Claude Desktop에서 직접 사용
# markitdown MCP 서버 설치
pip install markitdown-mcp
Claude Desktop 설정 (claude_desktop_config.json):
{
"mcpServers": {
"markitdown": {
"command": "python",
"args": ["-m", "markitdown_mcp"]
}
}
}
설정 후 Claude Desktop에서:
"이 PDF 분석해줘" → 파일 드래그 앤 드롭
→ markitdown이 자동으로 변환
→ Claude가 내용 분석
한계 알고 쓰기
잘 되는 것:
✅ 텍스트 중심 PDF
✅ Word/PPT/Excel 표
✅ HTML, CSV
✅ 음성 파일 전사
✅ YouTube 자막
잘 안 되는 것:
❌ 스캔된 PDF (OCR 별도 필요 → markitdown-ocr 플러그인)
❌ 복잡한 레이아웃 PDF (표 구조 깨질 수 있음)
❌ 이미지 내 텍스트 (LLM 연결 없으면 플레이스홀더)
❌ 암호화된 파일
복잡한 PDF가 필요하면:
→ Marker, MinerU 같은 전문 도구 고려
→ markitdown-ocr 플러그인 추가
요약 — 이런 상황에서 바로 써라
RAG 파이프라인 전처리:
→ 다양한 포맷 문서를 벡터 DB에 넣기 전
→ markitdown으로 일괄 변환 후 chunking
LLM에 문서 분석 요청:
→ PDF/Excel을 Claude/GPT에게 바로 줄 때
→ markitdown 변환 후 API 호출
사내 지식베이스:
→ 기존 문서들을 검색 가능한 형태로
→ 포맷 관계없이 한 번에 처리
회의록 자동 정리:
→ 녹음 파일 → 텍스트 → LLM 요약
반응형
'AI Development' 카테고리의 다른 글
| GitHub Copilot Agent Mode 실전 가이드 — VS Code에서 자율 코딩 에이전트 쓰는 법 (0) | 2026.04.21 |
|---|---|
| markitdown-ocr 플러그인 — 스캔 PDF, 이미지 속 텍스트까지 뽑아내는 법 (0) | 2026.04.21 |
| Gemini CLI 가이드 — Claude Code 대신 $0에 쓰는 법 (1) | 2026.04.21 |
| AI 에이전트 트래픽 7,851% 폭증 — 바뀌어야 하는 서버 설계, 방어 전략 (0) | 2026.04.20 |
| Spec-Driven Development — Vibe Coding 다음 단계, AI 에이전트 개발 방법론 (1) | 2026.04.17 |