프로젝트 상세
tan-kim
개인 포트폴리오 · 블로그 · RAG 챗봇 시스템
pnpm 모노레포 기반으로 프론트엔드, API 게이트웨이, RAG 파이프라인, 벡터 DB 래퍼를 각 독립 서비스로 분리해 설계했습니다. 블로그 콘텐츠는 외부 레포에서 자동 동기화되며, 챗봇은 해당 콘텐츠를 벡터 검색으로 참조해 답변합니다.
서비스 구성
| 서비스 | 역할 | 배포 |
|---|---|---|
| apps/frontend/ | Next.js 포트폴리오 · 블로그 · RAG 챗봇 UI | Vercel |
| apps/backend/ | Hono API 게이트웨이 | Oracle Cloud :3005 |
| apps/rag-search/ | RAG 질의 파이프라인 | Oracle Cloud :3003 |
| apps/rag-embed/ | 콘텐츠 임베딩 인덱서 | Oracle Cloud :3001 |
| apps/vector-db/ | Qdrant REST 래퍼 | Oracle Cloud :3002 |
서비스별 상세
Next.js 포트폴리오 · 블로그 · RAG 챗봇 UI
Next.js 16 App Router 기반 SSG 사이트
- >포트폴리오, 마크다운 블로그, 개발 도구 모음, RAG 챗봇 UI 제공
- >블로그 콘텐츠는 GitHub Actions(sync-content.yml)이 6시간마다 외부 지식베이스 레포에서 자동 동기화
- >backend /api/chat 프록시를 통해 스트리밍 챗봇 응답 수신
Hono API 게이트웨이
frontend와 RAG 서비스 사이의 경량 API 게이트웨이
- >POST /chat: OpenAI Moderation API로 입력 필터링 후 rag-search /query로 프록시
- >POST /playground: LLM 직접 호출 엔드포인트
- >Caddy 리버스 프록시를 통해 외부 노출, rag-search는 내부 네트워크에서만 접근
RAG 질의 파이프라인
질문을 받아 벡터 검색 후 LLM으로 스트리밍 답변을 생성하는 파이프라인 서버
- >Jina AI v3 API로 질문 임베딩(retrieval.query 태스크, 1024dim)
- >vector-db를 통해 Qdrant에서 blog · projects · about 컬렉션 유사도 검색(topK=5)
- >@tan-kim/llm-core를 통해 llm.tan-kim.com LLM 게이트웨이 호출 (기본 모델 gemini-2.5-flash, 폴백은 게이트웨이 내부 처리)
- >Hono streamText로 스트리밍 답변 반환
콘텐츠 임베딩 인덱서
GitHub 지식베이스 레포의 마크다운을 청킹·임베딩해 Qdrant에 인덱싱하는 배치 서버
- >GitHub Actions embed-schedule.yml이 매일 03:00 KST에 POST /trigger 자동 호출
- >지식베이스 레포에서 마크다운 git clone → 헤더(# ##) 단위 청킹, 50자 미만 청크 제외
- >Jina AI v3 API 배치 임베딩(retrieval.passage 태스크)
- >Qdrant 컬렉션 recreate 후 전체 upsert(증분 없음, 완전 재인덱싱)
Qdrant REST 래퍼
Qdrant 벡터 DB의 HTTP 래퍼. internal 네트워크 전용으로 외부에 미노출
- >컬렉션: blog / projects / about (각 1024dim, Jina v3 고정)
- >POST /search, POST /upsert, POST /collections 엔드포인트
- >rag-search와 rag-embed에서만 접근 가능, 직접 외부 노출 없음
RAG 시스템
데이터 인덱싱 흐름
GitHub 지식베이스 레포의 마크다운을 청킹·임베딩해 Qdrant에 저장합니다. 매일 GitHub Actions가 rag-embed를 트리거하며, 컬렉션 전체를 재생성합니다.
질의 응답 흐름
사용자 질문이 들어오면 동일 모델로 쿼리를 임베딩해 유사 청크를 검색하고, 해당 컨텍스트를 LLM에 전달해 스트리밍 답변을 생성합니다.
인프라 구조
모든 백엔드 서비스는 Oracle Cloud 단일 VM에서 Docker Compose로 운영됩니다. 내부 서비스 간 통신은 internal 네트워크로 격리하고, 외부 노출이 필요한 서비스만 Caddy가 관리하는 edge 네트워크에 연결합니다.