marker에 로컬 LLM 붙이기
model_test 프로젝트 일환. marker(marker-pdf)의
--use_llm모드를 Ollama / llama.cpp로 구동하는 방법 정리.
파일 포맷 지원
pip install marker-pdf — PDF, image 기본 지원
pip install marker-pdf[full] — PPTX, DOCX, XLSX, HTML, EPUB 추가 지원
내부 구조상 같은 PdfConverter 파이프라인을 쓰되, Provider 레이어가 파일 타입에 따라 다르게 처리. 사용자는 파일 경로만 바꿔 넣으면 된다.
LLM의 역할
--use_llm 플래그를 켜면 LLM은 후처리 단계에 투입된다:
- 페이지 경계를 넘는 테이블 병합
- inline math LaTeX 교정
- form 값 추출
- 전반적인 마크다운 품질 향상
marker가 먼저 OCR + 레이아웃 파싱을 수행하고, 그 결과를 LLM이 교정하는 파이프라인. 따라서 텍스트 전용 LLM으로도 동작 가능하다 (단, 이미지/수식 heavy 문서는 multimodal 모델이 유리).
LLM 서비스 추상화
marker는 marker/services/ 아래에 서비스를 추상화해뒀다:
| 서비스 | 클래스 |
|--------|--------|
| Gemini | marker.services.gemini.GoogleGeminiService (기본값) |
| Ollama | marker.services.ollama.OllamaService |
| llama.cpp (OpenAI compat) | marker.services.openai.OpenAIService |
| Anthropic | marker.services.claude.ClaudeService |
Ollama 연결
from marker.converters.pdf import PdfConverter
from marker.models import create_model_dict
from marker.config.parser import ConfigParser
config_parser = ConfigParser({
"use_llm": True,
"llm_service": "marker.services.ollama.OllamaService",
"ollama_model": "llama3.2-vision",
"ollama_base_url": "http://localhost:11434",
})
converter = PdfConverter(
config=config_parser.generate_config_dict(),
artifact_dict=create_model_dict(),
processor_list=config_parser.get_processors(),
renderer=config_parser.get_renderer(),
llm_service=config_parser.get_llm_service(),
)
rendered = converter("file.pdf")
llama.cpp 연결
llama.cpp를 --server 모드로 실행하면 OpenAI 호환 엔드포인트를 노출한다. OpenAIService에 base_url만 교체하면 된다.
# llama.cpp 서버 실행
./llama-server -m model.gguf --port 8080 --host 0.0.0.0
config_parser = ConfigParser({
"use_llm": True,
"llm_service": "marker.services.openai.OpenAIService",
"openai_base_url": "http://localhost:8080/v1",
"openai_api_key": "dummy", # llama.cpp는 key 검사 안 함
"openai_model": "your-model-name",
})
FastAPI 서버로 감싸기
marker 자체 API 서버 (marker_server.py)가 있지만, LLM 서비스를 직접 제어하려면 FastAPI로 감싸는 게 낫다:
from fastapi import FastAPI
from marker.converters.pdf import PdfConverter
from marker.models import create_model_dict
from marker.config.parser import ConfigParser
from marker.output import text_from_rendered
app = FastAPI()
models = create_model_dict() # 서버 시작 시 1회 로드
@app.post("/convert")
async def convert(filepath: str, use_llm: bool = False):
config = {"use_llm": use_llm}
if use_llm:
config.update({
"llm_service": "marker.services.ollama.OllamaService",
"ollama_model": "llama3.2-vision",
})
cp = ConfigParser(config)
converter = PdfConverter(
config=cp.generate_config_dict(),
artifact_dict=models,
processor_list=cp.get_processors(),
renderer=cp.get_renderer(),
llm_service=cp.get_llm_service(),
)
rendered = converter(filepath)
text, _, _ = text_from_rendered(rendered)
return {"markdown": text}
create_model_dict()는 surya OCR 모델 등을 로드하므로 한 번만 호출해야 한다.
model_test 관점에서
- 정량 비교 기준: README의 FinTabNet table benchmark (heuristic + LLM judge 점수)
- 비교 후보:
llama3.2-vision(ollama) vs llama.cpp + llava - LLM 없는 baseline marker vs
--use_llm모드 비교도 의미 있음 - table 변환에서 LLM 효과가 가장 두드러짐:
0.816 → 0.907(marker w/use_llm)