PDF-Assistant-RAG: 에이전트 기반 RAG 파이프라인을 갖춘 AI 문서 어시스턴트
요약
에이전트 기반 RAG 파이프라인을 활용하여 PDF, 재무 보고서 등을 분석하는 프로덕션급 AI 문서 어시스턴트 프로젝트입니다. 의미 검색과 크로스-인코더 재랭킹을 결합하여 답변의 정확도를 높였으며, 스트리밍 응답과 데이터 격리 기능을 제공합니다.
핵심 포인트
- 의미 검색 및 크로스-인코더 재랭킹을 통한 고품질 RAG 구현
- FastAPI와 Next.js를 활용한 엔드투엔드 아키텍처 구축
- SSE를 이용한 토큰 단위 스트리밍 응답 지원
- ChromaDB 기반의 벡터 임베딩 및 세션별 데이터 격리 적용
| title | Document AI Analyst |
|---|---|
| emoji | 🧠 |
| ... |
██████╗ ██████╗ ███████╗ █████╗ ███████╗███████╗██╗███████╗████████╗ █████╗ ███╗ ██╗████████╗
██╔══██╗██╔══██╗██╔════╝ ██╔══██╗██╔════╝██╔════╝██║██╔════╝╚══██╔══╝██╔══██╗████╗ ██║╚══██╔══╝
██████╔╝██║ ██║█████╗ ███████║███████╗███████╗██║███████╗ ██║ ███████║██╔██╗ ██║ ██║
...
Upload · Embed · Retrieve · Chat— 에이전트 기반 RAG 파이프라인, 스트리밍 응답, 사용자별 데이터 격리를 통해 엔드투엔드로 구축된 프로덕션급 AI 문서 어시스턴트.
Features · Tech Stack · Getting Started · Architecture · RAG Pipeline · API Reference · Deployment · Contributing
PDF-Assistant-RAG에 기여한 모든 훌륭한 분들께 감사드립니다! 🎉
🌟
참여하고 싶으신가요? CONTRIBUTING.md에서 기여 가이드라인을 확인하고 시작할 좋은 첫 이슈를 찾아보세요!
PDF-Assistant-RAG는 사용자가 복잡한 PDF, 재무 보고서, 법률 계약서 및 연구 논문을 업로드하면 — 다단계 Retrieval-Augmented Generation (RAG) 파이프라인으로 구동되는 정확하고 인용된 답변을 제공하는 AI와 채팅할 수 있게 해주는 완전하고 프로덕션 준비가 된 AI 문서 어시스턴트입니다.
이 시스템은 가장 관련성 높은 문서 청크를 찾기 위해 **의미 검색(semantic search) + 크로스-인코더 재랭킹(cross-encoder reranking)**을 사용하고, AI 생성 답변을 토큰 단위로 스트리밍하며, 세션 기반 사용자별 데이터 격리가 적용된 깔끔한 Flask 서버 UI 내에서 페이지 번호와 함께 정확한 출처 인용을 하이라이트합니다.
기여자 참고: 라우트별 시스템 맵, 요청 흐름 다이어그램, 소유 경계 및 Swagger/OpenAPI 문서화 가이드라인은 docs/ARCHITECTURE.md를 참조하세요.
graph TD
subgraph Frontend["Frontend (Next.js 16)"]
UI["Dashboard UI (React)"]
...
- 사용자는 Next.js 프론트엔드와 상호작용하여 문서를 업로드하고 질문을 합니다.
- FastAPI는 인증 (Authentication), 문서 인제스션 (Ingestion), 그리고 채팅 API를 처리합니다.
- 업로드된 문서는 파싱 (Parsing)되고, 청킹 (Chunking)되어 벡터 임베딩 (Vector Embeddings)으로 변환됩니다.
- 임베딩은 의미론적 검색 (Semantic Retrieval)을 위해 ChromaDB에 저장됩니다.
- 쿼리 (Querying) 시, 리트리버 (Retriever)가 ChromaDB에서 관련 청크를 가져옵니다.
- 리랭커 (Reranker)가 LLM에 컨텍스트를 보내기 전에 검색 품질을 개선합니다.
- Hugging Face Inference API가 최종 응답을 생성합니다.
- 응답은 SSE를 사용하여 프론트엔드로 스트리밍 (Streaming)됩니다.
| 기술 (Technology) | 용도 (Purpose) |
|---|---|
| Jinja2 (via Flask) | 서버 사이드 HTML 템플릿 (Server-side HTML templating) |
| HTML + CSS + JavaScript | 프론트엔드 UI (/static 및 /templates에서 제공) |
| 기술 (Technology) | 용도 (Purpose) |
|---|---|
| Docker Multi-Stage | 컨테이너화된 배포 (Containerized deployment) |
| GitHub Actions | CI 파이프라인 (dev 브랜치) |
| Git LFS | 바이너리 자산 관리 (Binary asset management) |
| HuggingFace Spaces | 프로덕션 배포 (Production deployment) |
||
||
||
PDF-Assistant-RAG/
│
├── app.py # Flask 앱 — 모든 라우트 (업로드, 질문, 다운로드, 인증)
...
Python 3.11+
MongoDB (Atlas 무료 티어 또는 로컬)
Pinecone 계정 — pinecone.io
Google Gemini API key — aistudio.google.com
Groq API key — console.groq.com
git clone https://github.com/param20h/PDF-Assistant-RAG.git
cd PDF-Assistant-RAG
cp .env.example .env
`.env` 편집:
SECRET_KEY=your-strong-random-secret
...
huggingface.co/settings/tokens 에서 무료 HuggingFace 토큰을 받으세요.
비밀번호 등록은 사용자가 로그인하기 전에 이메일 인증이 필요합니다. 실제 인증 이메일을 보내려면 backend/.env에 SMTP 설정을 추가하세요.
:
FRONTEND_URL=http://localhost:3000
EMAIL_VERIFICATION_TOKEN_EXPIRE_HOURS=24
MAIL_USERNAME=your_smtp_username
...
Gmail의 경우, 발신자 Google 계정에서 2단계 인증을 활성화하고, Google 계정 > 보안 > 앱 비밀번호에서 16자리의 앱 비밀번호를 생성한 다음 다음을 사용하세요:
MAIL_USERNAME=yourgmail@gmail.com
MAIL_PASSWORD=your_16_character_app_password
MAIL_FROM=yourgmail@gmail.com
...
비운영 환경 (non-production environment)에서 SMTP 설정이 없으면, 기여자(contributors)들이 개인 이메일 자격 증명 없이도 흐름을 테스트할 수 있도록 로컬 인증 링크가 반환됩니다. SMTP가 구성되면 동일한 링크가 이메일로 전송됩니다.
URL 업로드 기능 (POST /api/v1/documents/urlupload)
은 Playwright 브라우저와 함께 crawl4ai를 사용하여 웹 페이지를 크롤링합니다. crawl4ai-setup은 Playwright 브라우저 설치를 자동으로 처리합니다. pip install 이후에 한 번 실행하세요:
crawl4ai-setup
# 단일 터미널 — Flask 앱
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
...
docker compose up --build
# → http://localhost:7860 에서 앱 실행 중
┌─────────────────────────────────────────────┐
│ PDF / DOCX 업로드 │
└───────────────────┬─────────────────────────┘
...
| 메서드 (Method) | 엔드포인트 (Endpoint) | 인증 (Auth) | 설명 (Description) |
|---|---|---|---|
POST | /api/v1/auth/register | ❌ | 새 사용자 계정 생성 |
POST | /api/v1/auth/login | ❌ | 로그인 및 JWT 토큰 수신 |
GET | /api/v1/auth/me | ✅ | 현재 사용자 프로필 가져오기 |
POST | /api/v1/documents/upload | ✅ | PDF/DOCX 업로드 및 백그라운드 인덱싱 대기열 추가 (202 Accepted) |
GET | /api/v1/documents | ✅ | 현재 사용자의 모든 문서 목록 조회 |
GET | /api/v1/documents/{id}/status | ✅ | 백그라운드 문서 처리 상태 폴링 (Poll) |
DELETE | /api/v1/documents/{id} | ✅ | 문서 및 해당 벡터 데이터 삭제 |
POST | /api/v1/chat/ask/stream | ✅ | 질문하기 (SSE 스트리밍 응답) |
GET | /api/v1/chat/history/{doc_id} | ✅ | 문서에 대한 채팅 기록 가져오기 |
DELETE | /api/v1/chat/history/{doc_id} | ✅ | 문서에 대한 채팅 기록 삭제 |
GET | /health | ❌ | 상태 확인 (db + chroma 상태) |
로컬에서 실행 중일 때 /docs (Swagger UI)에서 전체 대화형 문서를 확인할 수 있습니다.
| 변수 (Variable) | 필수 (Required) | 기본값 (Default) | 설명 (Description) | 획득 방법 (Where to Get It) |
|---|---|---|---|---|
SECRET_KEY | ✅ | — | JWT 서명 및 세션 비밀키 (session secret). 강력한 무작위 문자열을 사용하세요. | 생성: python -c "import secrets; print(secrets.token_urlsafe(32))" |
HF_TOKEN | ✅ | — | Inference API를 통한 LLM 추론을 위한 HuggingFace API 토큰. | huggingface.co/settings/tokens (무료) |
HF_CLIENT_ID | ❌ | — | HuggingFace OAuth 클라이언트 ID (Client ID). Hugging Face 로그인 시에만 필요합니다. | HuggingFace Developer Settings |
HF_CLIENT_SECRET | ❌ | — | HuggingFace OAuth 클라이언트 비밀키 (Client Secret). Hugging Face 로그인 시에만 필요합니다. | HuggingFace Developer Settings |
HF_REDIRECT_URI | ❌ | http://localhost:8000/api/v1/auth/callback/huggingface | HuggingFace OAuth 콜백 리다이렉트 URI (redirect URI). | — |
FRONTEND_URL | ❌ | http://localhost:3000 | OAuth 리다이렉트 및 이메일 인증 링크에 사용되는 공개 프론트엔드 URL. | 배포된 프론트엔드 URL |
ENVIRONMENT | ❌ | development | 런타임 모드 (Runtime mode). 배포 시 CORS를 잠그려면 production으로 설정하세요. | — |
DEBUG | ❌ | False | 상세한 에러 페이지를 포함하는 디버그 모드 (debug mode) 활성화. 프로덕션 환경에서는 절대 활성화하지 마세요. | — |
ALLOWED_ORIGINS | ❌ | http://localhost:3000,http://localhost:7860 | 쉼표로 구분된 CORS 허용 오리진 (production 환경에서만 적용됨). | 배포된 도메인(들) |
DATABASE_URL | ❌ | sqlite:///./data/app.db | SQLAlchemy 데이터베이스 연결 문자열 (connection string). | SQLite (기본값), 또는 Postgres/MySQL 연결 문자열 |
JWT_ALGORITHM | ❌ | HS256 | JWT 서명 알고리즘. | — |
JWT_EXPIRY_HOURS | ❌ | 72 | 재로그인이 필요하기 전까지의 JWT 토큰 유효 시간 (시간 단위). | — |
GOOGLE_CLIENT_ID | ❌ | — | FastAPI가 ID 토큰을 검증하는 데 사용하는 Google OAuth 웹 클라이언트 ID. | Google Cloud Console |
NEXT_PUBLIC_GOOGLE_CLIENT_ID | ❌ | — | Next.js Google 로그인 버튼에 노출되는 Google OAuth 웹 클라이언트 ID. | Google Cloud Console |
EMAIL_VERIFICATION_TOKEN_EXPIRE_HOURS | ❌ | 24 | 이메일 인증 토큰의 유효 시간 (시간 단위). | — |
| — |
MAIL_USERNAME | ❌ | — | 계정 인증 이메일을 위한 SMTP 사용자 이름 (username). | SMTP 제공업체 또는 Gmail 앱 비밀번호 설정 |
MAIL_PASSWORD | ❌ | — | SMTP 비밀번호 또는 Gmail 16자리 앱 비밀번호 (App Password). | SMTP 제공업체 또는 Gmail 앱 비밀번호 설정 |
MAIL_FROM | ❌ | — | 인증 이메일의 발신자 이메일 주소. | 인증된 발신자 주소 |
MAIL_SERVER | ❌ | — | SMTP 서버 호스트 이름 (예: smtp.gmail.com). | SMTP 제공업체 |
MAIL_PORT | ❌ | 587 | SMTP 서버 포트. | SMTP 제공업체 |
MAIL_STARTTLS | ❌ | True | SMTP를 위한 STARTTLS 활성화. | SMTP 제공업체 |
MAIL_SSL_TLS | ❌ | False | SMTP를 위한 SSL/TLS 활성화. | SMTP 제공업체 |
CELERY_BROKER_URL | ❌ | redis://localhost:6379/0 | FastAPI가 문서 인제스션 (Ingestion) 작업을 큐에 넣기 위해 사용하는 Redis 브로커 (Broker) URL. | Redis |
CELERY_RESULT_BACKEND | ❌ | redis://localhost:6379/1 | Celery가 작업 상태 및 결과를 저장하기 위해 사용하는 Redis 백엔드 (Backend) URL. | Redis |
UPLOAD_DIR | ❌ | ./data/uploads | 업로드된 문서를 저장하기 위한 로컬 디렉토리. | — |
MAX_FILE_SIZE_MB | ❌ | 50 | 허용되는 최대 업로드 파일 크기 (MB 단위). | — |
ALLOWED_EXTENSIONS | ❌ | pdf,docx,txt,md | 허용된 파일 확장자 목록 (쉼표로 구분). | — |
CHROMA_PERSIST_DIR | ❌ | ./data/chroma_db | ChromaDB가 벡터 인덱스 (Vector Index)를 영구 저장하는 디렉토리. | — |
LLM_MODEL | ❌ | Qwen/Qwen2.5-72B-Instruct | 답변 생성을 위한 HuggingFace 모델 ID. | huggingface.co/models |
LLM_TEMPERATURE | ❌ | 0.3 | LLM 샘플링 온도 (0 = 결정론적 (Deterministic), 1 = 창의적 (Creative)). | — |
LLM_MAX_NEW_TOKENS | ❌ | 1024 | LLM 응답당 최대 토큰 수. | — |
EMBEDDING_MODEL | ❌ | sentence-transformers/all-MiniLM-L6-v2 | 로컬 임베딩 (Embedding)을 위한 SentenceTransformer 모델 (외부 API 미사용). | huggingface.co/sentence-transformers |
EMBEDDING_DIMENSION | ❌ | 384 | 임베딩 벡터 차원 (모델과 일치해야 함). | — |
RERANKER_MODEL | ❌ | cross-encoder/ms-marco-MiniLM-L-6-v2 | 검색된 청크 (Chunk)를 관련성에 따라 재순위화 (Reranking)하기 위한 크로스 인코더 (Cross-encoder) 모델.
| huggingface.co/cross-encoder |
CHUNK_SIZE | ❌ | 1000 | 문서 청크당 문자 수. 크기가 클수록 더 많은 컨텍스트를 얻고, 작을수록 정밀도가 높아집니다. | — |
CHUNK_OVERLAP | ❌ | 200 | 연속된 청크 간의 중복(Overlap)으로 경계 컨텍스트 유지. | — |
TOP_K_RETRIEVAL | ❌ | 10 | 의미론적 검색 과정에서 벡터 스토어로부터 검색되는 후보 청크 수. | — |
TOP_K_RERANK | ❌ | 5 | 재순위화(reranking) 후 LLM에 전달되는 최종 청크 수 (반드시 TOP_K_RETRIEVAL 이하여야 함). | — |
| 명령어 | 설명 |
|---|---|
uvicorn app.main:app --reload | 핫 리로드를 사용하여 FastAPI 시작 |
uvicorn app.main:app --port 8000 | 포트 8000에서 FastAPI 시작 |
python scripts/run_ragas_eval.py --user-id <user-id> | 벡터 검색과 GraphRAG에 대한 50개 질문의 RAGAS 비교 실행 |
RAGAS 스크립트는 backend/evaluation/ragas_sample_questions.jsonl에서 읽어와, 표준 벡터 컨텍스트 및 벡터+GraphRAG 컨텍스트로부터 답변을 생성한 후, 집계 점수를 backend/evaluation/ragas_results.json에 작성합니다.
문서 하나를 평가하려면 --document-id <document-id>를 전달하세요.
| 명령어 | 설명 |
|---|---|
npm run dev | Next.js 개발 서버 시작 |
npm run build | 프로덕션 빌드 → out/ (정적 내보내기) |
npm run lint | ESLint 실행 |
npm run test:e2e | Playwright 엔드-투-엔드 테스트 실행 |
| 명령어 | 설명 |
|---|---|
docker compose --profile cpu up --build | 전체 스택 빌드 및 시작 (CPU 전용, GPU 불필요) |
docker compose --profile gpu up --build | NVIDIA GPU 가속을 사용하여 전체 스택 빌드 및 시작 |
docker compose --profile debug up | http://localhost:5050에서 pgAdmin도 함께 시작 |
docker compose down | 모든 컨테이너 중지 |
CPU 프로필— 어떤 기기에서도 작동합니다. 임베딩은 all-MiniLM-L6-v2를 통해 CPU에서 실행됩니다.
GPU 프로필— NVIDIA Container Toolkit이 필요합니다. 가속화된 임베딩 추론을 위해 DEVICE=cuda가 설정됩니다.
본 프로젝트는 Docker를 사용하여 HuggingFace Spaces에 배포되었습니다.
-
이 저장소(repo)를 Fork한 후 huggingface.co/new-space에서 새로운 Space를 생성하세요 (SDK: Docker)
-
다음 Space secrets를 설정하세요:
HF_TOKEN— 귀하의 HuggingFace API 토큰
SECRET_KEY— 강력한 무작위 문자열 -
hf원격(remote)으로 Push하면 Space가 자동으로 빌드됩니다.
git remote add hf https://<username>:<HF_TOKEN>@huggingface.co/spaces/<username>/<space-name>
git push hf main
docker compose up -d --build
# 앱은 http://your-server:7860 에서 사용 가능합니다
이 프로젝트는 GirlScript Summer of Code에 참여하고 있습니다! 모든 숙련도의 기여자(contributor)를 환영합니다.
브랜치 전략 (Branch Strategy):
| 브랜치 (Branch) | 목적 (Purpose) |
|---|---|
main | 프로덕션 (Production) — HuggingFace에 배포됨 (관리자 전용) |
dev | 모든 기여자의 PR(Pull Request) 대상 |
feature/* / fix/* / docs/* | 작업용 브랜치 |
# 항상 dev에서 브랜치를 생성하세요
git checkout -b feature/my-feature upstream/dev
빠른 링크 (Quick links):
**MIT 라이선스 (MIT License)**에 따라 배포됩니다. 자세한 내용은 LICENSE를 참조하세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 GitHub AI Tools의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기