메인 콘텐츠로 바로가기
노트 목록

UrstoryRAG 개발 이력 요약

김성박1941
목차5

https://github.com/urstory/urstory-rag

에 다음과 같은 기능이 추가되거나 변경되었습니다. RAG에 관심있는 분의 참여 부탁드려요.

UrstoryRAG 개발 이력 요약

12개 이슈 처리 및 IBM Docling PDF 파싱 도입까지의 개발 과정을 정리한다.


처리된 이슈 (12건)

Phase 12: 보안 강화 — 이슈 #1, #2, #3, #4

이슈제목핵심 구현
#1JWT 인증/인가 시스템bcrypt + HS256 JWT (access 30분 / refresh 7일), RBAC (admin/user), Redis 토큰 블랙리스트, 초기 관리자 자동 생성
#2CORS 화이트리스트 및 보안 헤더환경변수 기반 오리진 관리, X-Content-Type-Options, X-Frame-Options, CSP 등 보안 미들웨어
#3Rate Limitingslowapi + Redis 연동, 로그인 5/min, 검색 30/min, 업로드 10/min
#4GitHub Actions CI 파이프라인pytest + ruff lint + Alembic 마이그레이션 + 프론트엔드 빌드 + Docker 이미지 검증

커밋: ce9e541, PR #22로 머지


Phase 13: 프로덕션 운영 기반 — 이슈 #5, #6, #8, #9

이슈제목핵심 구현
#5Docker 이미지 최적화멀티스테이지 빌드, non-root 사용자, standalone 모드 (Next.js), GHCR 자동 푸시
#6구조화된 로깅 (structlog)JSON/Console 포맷 전환, 민감 정보 마스킹 (API Key, JWT, 비밀번호), request_id 추적
#8에러 추적 (Sentry)Sentry SDK 통합, PII 전송 차단, Authorization/Cookie 헤더 제거, 사용자 에러 화면에 request_id 표시
#9Graceful Shutdown + Health ProbeLiveness/Readiness/Startup 프로브, SIGTERM 시 30초 정리, 셧다운 중 503 + Retry-After 응답

커밋: fcfd6a3, PR #23으로 머지


Langfuse v3 모니터링 — 이슈 #7

이슈제목핵심 구현
#7Langfuse v3 모니터링 검증 및 안정화Web + Worker + ClickHouse + Redis + MinIO 풀 스택 통합, 검색 파이프라인 트레이싱, no-op 모드 지원

커밋: 0253eca


Phase 14: Redis 응답 캐싱 레이어 — 이슈 #10

이슈제목핵심 구현
#10Redis 응답 캐싱SHA-256 키 해싱, 설정/문서 변경 시 자동 무효화, X-Cache 헤더, 3-tier 설정 캐시, maxmemory 256MB + allkeys-lru

커밋: 76993c4, PR #24로 머지


Circuit Breaker — 이슈 #12

이슈제목핵심 구현
#12Circuit Breaker 및 재시도 로직연속 5회 실패 시 30초 차단 (OPEN → HALF_OPEN → CLOSED), Exponential Backoff 재시도 (3회), Graceful Degradation

커밋: 0500185, PR #25로 머지


공개 테스트 데이터셋 — 이슈 #21

이슈제목핵심 구현
#21공개 테스트 데이터셋공공누리 제1유형 PDF 5개 + 직접 작성 MD 5개, 68개 Q&A, LLM-as-Judge + 키워드 재현율 자동 평가

커밋: c191907


Phase 15: IBM Docling PDF 레이아웃 인식 파싱

도입 배경

기존 pypdf는 PDF에서 텍스트만 추출하여 다음 문제가 있었다:

  • 테이블 구조 붕괴 (숫자가 뒤섞여 검색 불가)
  • 헤더 감지가 줄 길이 휴리스틱에 의존 (오탐/미탐)
  • 다단 컬럼이 하나의 텍스트 스트림으로 병합
  • 스캔 PDF 미지원

Open-Parse (GitHub 3.2K stars)를 검토했으나 16개월간 업데이트 없이 방치 상태. IBM Docling (55K stars, MIT, 주간 릴리즈)을 선택했다.

Docling이 해결하는 것

문제Before (pypdf)After (Docling)
테이블 정확도0% (구조 손실)90%+ (TableFormer)
헤더 감지줄 길이 휴리스틱레이아웃 모델 기반
다단 컬럼텍스트 뒤섞임읽기 순서 보존
스캔 PDF불가OCR 지원 (EasyOCR)
출력 형식평문 텍스트구조화된 마크다운

아키텍처

[ Before ] PDF → PyPDFToDocument (텍스트) → SectionHeaderChunking (휴리스틱 헤더) [ After ] PDF → Docling (마크다운) → SectionHeaderChunking (정확한 # 헤더)

기존 청킹 파이프라인(SectionHeaderChunking, ContextualChunking)은 수정 없이 재사용한다. Docling의 마크다운 출력에 # 헤더가 포함되므로 오히려 더 정확한 breadcrumb 계층이 생성된다.

핵심 구현

DoclingPDFConverter (backend/app/services/document/docling_converter.py)

  • Docling DocumentConverter를 래핑
  • 지연 초기화: _get_converter() 호출 시에만 import (앱 시작 속도 보존)
  • 자동 폴백: Docling 실패 시 pypdf로 전환, 서비스 중단 없음
  • 메타데이터에 converter: "docling" | "pypdf_fallback" 기록

설정 제어 (RAGSettings)

pdf_parser: str = "docling" # docling | pypdf ocr_enabled: bool = False ocr_languages: list[str] = ["ko", "en"] table_extraction_enabled: bool = True

관리자 UI에서 실시간 변경 가능. GPU가 없는 서버에서는 pdf_parser=pypdf로 전환하면 된다.

GPU/CPU 호환성

Docling은 GPU 없이도 동작한다. PyTorch가 하드웨어를 자동 감지한다.

환경GPU 가속비고
Mac (Apple Silicon)MPSCelery --pool=solo 필요 (Metal은 fork 불가)
Linux + NVIDIACUDA가장 빠른 환경
Linux CPU only--느리지만 정상 동작

macOS 주의사항: Celery의 기본 fork 기반 워커는 Metal/MPS와 호환되지 않는다 (SIGABRT 발생). --pool=solo 옵션으로 실행해야 MPS GPU를 사용할 수 있다.

celery -A app.worker:celery_app worker --pool=solo --loglevel=info

Docling 모델 (첫 실행 시 자동 다운로드)

모델용도크기디바이스
Layout (Heron)레이아웃 분석~100MBCPU/MPS/CUDA
TableFormer테이블 구조 인식~100MBCPU
Picture Classifier이미지 분류~50MBCPU/MPS/CUDA
EasyOCR ko+en한국어/영어 OCR~200MBCPU/MPS/CUDA

총 ~450MB, ~/.cache/docling/models/에 캐시된다.

성능

항목pypdfDocling (OCR 없음)Docling (OCR 있음)
변환 속도~50 pages/sec~1.5 pages/sec~1 page/sec
테이블 정확도0%~90%+~85%+
헤더 감지휴리스틱레이아웃 기반레이아웃 기반

변환 속도가 느려지지만 Celery 비동기 처리이므로 사용자 대기에 영향 없다.

품질 측정 결과

공개 데이터셋 68개 Q&A, 12개 문서 기준:

지표이전 (pypdf)Docling 적용 후
LLM Judge 평균90.392.0
GOOD (70점 이상)95.2%96%
FAIL (40점 미만)4.8%3%
키워드 재현율60.8%67.7%
검색 적중률--100%

PDF 테이블이 포함된 문서에서 숫자/통계 검색 정확도가 크게 개선되었다.

TDD 구현 순서

Step 0: docling >= 2.78 의존성 추가 + 환경 검증 Step 1: RAGSettings에 pdf_parser, ocr_enabled 등 설정 추가 (RED → GREEN) Step 2: DoclingPDFConverter 구현 + pypdf 폴백 (RED → GREEN) Step 3: DocumentConverter에 Docling 통합 (RED → GREEN) Step 4: Processor/Task에서 RAGSettings → DocumentConverter 설정 전달 (RED → GREEN) Step 5: 실제 PDF 통합 테스트 + 품질 검증 Step 6: 전체 테스트 회귀 확인 (517 단위 + 8 통합 테스트 통과)

테스트

  • 단위 테스트: 11개 (DoclingPDFConverter) + 8개 (DocumentConverter 통합) + RAGSettings + Processor
  • 통합 테스트: 8개 (실제 PDF 변환, 폴백, 설정 토글, 청킹 파이프라인)
  • 품질 테스트: 68개 Q&A LLM-as-Judge 자동 평가

전체 시스템 계층

12개 이슈 처리 후의 시스템 아키텍처:

사용자 → 프론트엔드 (Next.js 15) ↓ 보안 헤더 미들웨어 (X-Content-Type-Options, X-Frame-Options, CSP) ↓ Rate Limiter (slowapi + Redis, 엔드포인트별 제한) ↓ JWT 인증 (access/refresh, RBAC) ↓ 구조화된 로깅 (structlog, request_id 추적) ↓ Redis 응답 캐시 (SHA-256 키, 자동 무효화) ↓ Circuit Breaker (연속 실패 감지, 자동 차단/복구) ↓ 문서 변환 (Docling PDF → 마크다운, pypdf 폴백) ↓ RAG 파이프라인 (Haystack, 하이브리드 검색, 리랭킹, HyDE) ↓ 데이터베이스 (PostgreSQL+PGVector, Elasticsearch+Nori, Redis) ↓ 모니터링 (Langfuse v3, Sentry)

남은 오픈 이슈

이슈제목우선순위
#11커넥션 풀링 최적화high
#13프로덕션 배포 가이드high
#14API 문서 강화medium
#15백엔드 테스트 커버리지 85%medium
#16E2E 테스트 시나리오 확대medium
#17React Error Boundary 개선medium
#18데이터 백업/복구 전략medium
#19의존성 보안 스캔 자동화medium
#20프론트엔드 접근성 개선medium

댓글

불러오는 중...

댓글을 작성하려면 이 필요합니다.