onschan.me
테마 변경

RAG 아키텍처로 포트폴리오 AI 챗봇 구현하기

2025-08-21

💡 문서 기반 질의응답이 가능한 RAG 시스템을 구현하여 포트폴리오 사이트에 적용한 기술적 구현 과정을 다룹니다.

개인 포트폴리오나 기업 문서에 대한 질의응답 기능은 방문자에게 효율적인 정보 접근을 제공할 수 있는 유용한 기능입니다. 일반적인 FAQ나 정적 문서와 달리, AI 기반 질의응답 시스템은 자연어 질문에 대해 문서 내용을 기반으로 한 정확하고 맥락적인 답변을 제공할 수 있습니다.

본 글에서는 RAG(Retrieval-Augmented Generation) 아키텍처를 활용하여 문서 학습 기반 질의응답 시스템을 구현한 과정을 기술적으로 분석하고, 실제 구현에서 마주한 주요 이슈들과 최적화 방법을 공유합니다.


RAG란 무엇인가

RAG(Retrieval-Augmented Generation)는 "검색 강화 생성"이라고 번역할 수 있습니다. 간단히 말하면 AI가 답변하기 전에 관련 문서를 먼저 찾아보고, 그 내용을 바탕으로 답변을 생성하는 방식입니다.

기존 AI vs RAG의 차이점

일반적인 ChatGPT 같은 LLM:

  • 학습된 데이터만으로 답변
  • 최신 정보나 특정 개인 정보는 모름
  • 때로는 그럴듯한 거짓말(환각)을 만들어냄

RAG 시스템:

  • 외부 문서에서 관련 정보를 실시간으로 검색
  • 검색된 내용을 바탕으로 답변 생성
  • 근거가 있는 답변이므로 신뢰성 높음

RAG 동작 원리

오프라인: 문서 수집 → 텍스트 분할 → 벡터로 변환 → 데이터베이스 저장

온라인: 사용자 질문 → 질문을 벡터로 변환 →
       유사한 문서 검색 → 문서 + 질문을 AI에 전달 → 답변 생성

핵심은 벡터 임베딩을 통한 의미 검색입니다. 예를 들어:

  • "개발자"와 "프로그래머"는 다른 단어지만 의미가 비슷
  • 벡터 공간에서는 가까운 위치에 배치됨
  • "프론트엔드 개발자"를 검색하면 "React 개발", "웹 개발" 등도 함께 찾아줌

이렇게 키워드 매칭이 아닌 의미 기반 검색이 가능해집니다.


기술 스택 선택과 고민

AI 모델 선택: Gemini를 택한 이유

여러 AI 모델을 비교해봤는데, 결정적인 요인은 비용이었습니다.

비용 비교 (2025년 기준):

  • Gemini: 하루 1,500회 요청 무료 (Flash 모델), Pro 모델도 25-100회 무료
  • OpenAI GPT-4: 무료 플랜 없음, 토큰당 비용이 상대적으로 높음
  • Claude: 제한적인 무료 사용량, 유료 시 비쌈

개인 프로젝트에서 매달 API 비용을 지불하기는 부담스러웠습니다. Gemini의 무료 할당량이 가장 넉넉했고, 임베딩과 텍스트 생성을 하나의 API로 처리할 수 있어서 개발도 편했습니다.

프로덕션 환경에서는 API 호출량과 비용 효율성을 종합적으로 고려해야 합니다.

전체 아키텍처

포트폴리오 문서 (PDF, 텍스트)
NestJS 백엔드 (문서 처리 + RAG 파이프라인)
Pinecone (벡터 데이터베이스)
Svelte 프론트엔드 (채팅 UI)
Gemini API (임베딩 + 텍스트 생성)

기술 스택:

  • 백엔드: NestJS (TypeScript)
  • 프론트엔드: Svelte (TypeScript)
  • 벡터 DB: Pinecone
  • AI 모델: Google Gemini
  • 배포: Vercel

벡터 데이터베이스 선택: ChromaDB vs Pinecone

벡터 데이터베이스로는 두 가지 옵션을 고려했습니다.

ChromaDB

  • 장점: 무료, 로컬 개발 환경에서 쉬운 설정, Docker로 간단 실행
  • 단점: 서버리스 환경에서 지속적 운영 어려움, 데이터 영속성 문제
  • 적합한 환경: 로컬 개발, 프로토타이핑, 자체 서버 운영

개발 초기에는 ChromaDB를 로컬 Docker로 실행했습니다. 설정이 간단하고 무료라서 프로토타이핑에는 완벽했습니다.

하지만 Vercel 같은 서버리스 환경에서는 Docker 컨테이너를 지속적으로 유지할 수 없습니다. 함수가 실행될 때마다 새로운 컨테이너가 생성되고 사라지기 때문에, ChromaDB에 저장한 데이터가 사라지는 문제가 있었습니다.

Pinecone

  • 장점: 클라우드 네이티브, 서버리스 환경에 최적화, 높은 성능과 확장성
  • 단점: 유료 (무료 플랜 제한적), 외부 서비스 의존성
  • 적합한 환경: 프로덕션 배포, 서버리스 아키텍처, 확장 가능한 서비스

Pinecone은 관리형 벡터 데이터베이스 서비스로, AWS/GCP 같은 클라우드 환경에 최적화되어 있습니다. 무료 플랜도 개인 프로젝트에는 충분했고, 서버리스 환경에서 안정적으로 동작합니다.

최종적으로 배포를 고려해서 Pinecone으로 전환했습니다.


구현 과정과 주요 이슈들

1. 문서 처리: 청킹(Chunking)의 중요성

첫 번째로 마주한 문제는 "문서를 어떻게 나눌 것인가"였습니다.

처음에는 포트폴리오 문서 전체를 하나의 임베딩으로 만들었습니다. 그런데 실제로 테스트해보니 결과가 엉망이었습니다.

문제상황:

  • "React 프로젝트 경험이 있나요?" → "저는 다양한 기술을 다룹니다" (엉뚱한 답변)
  • "어떤 회사에서 일했나요?" → "여러 프로젝트를 진행했습니다" (구체적이지 않음)

원인 분석: 문서가 너무 크면 임베딩할 때 세부 정보가 뭉개집니다. 5000자짜리 문서를 하나의 벡터로 만들면, "React"라는 키워드가 있어도 전체 맥락에 묻혀서 검색이 제대로 안 됩니다.

해결책: 문서를 1000자 단위로 분할(청킹)해서 각각 임베딩을 만들었습니다.

private splitTextIntoChunks(text: string): string[] {
  const chunkSize = 1000;
  const overlap = 100; // 앞뒤 100자씩 겹치게 해서 맥락 유지
  const chunks: string[] = [];

  for (let i = 0; i < text.length; i += chunkSize - overlap) {
    chunks.push(text.substring(i, i + chunkSize));
  }
  return chunks;
}

결과: 청킹 후에는 훨씬 정확한 답변이 나오기 시작했습니다.

  • "React 경험이 있나요?" → "React로 XX 프로젝트를 진행했습니다" (구체적이고 정확함)

2. 벡터 검색 최적화

두 번째 이슈는 검색 결과를 몇 개나 가져올 것인가였습니다.

실험 결과:

  • 1개: 너무 적어서 맥락이 부족
  • 5개 이상: 너무 많아서 관련 없는 내용까지 포함
  • 3개: 적당히 관련성 높으면서도 충분한 정보 제공

최종적으로 상위 3개 검색 결과를 사용하기로 했습니다.

// Pinecone에서 유사한 문서 3개 검색
const results = await this.pineconeService.queryVectors(queryEmbedding, 3);
const relevantDocuments = results.map((match) => match.metadata.text);

3. 프롬프트 엔지니어링: 일관성 확보

세 번째 문제는 AI 응답의 일관성이었습니다.

초기 문제점:

  • 같은 질문에도 매번 다른 스타일로 답변
  • 때로는 존댓말, 때로는 반말
  • 문서에 없는 내용을 상상해서 답변하기도 함

해결 과정: 매우 구체적이고 상세한 프롬프트를 작성했습니다.

const prompt = `
당신은 문서 작성자입니다. 다음 지침을 반드시 따라주세요:

1. 페르소나: 문서 작성자의 입장에서 1인칭으로 답변
2. 어조: 정중하고 친근한 존댓말 사용
3. 길이: 100자 내외로 간결하게 답변
4. 제약: 아래 제공된 정보만을 사용하여 답변
5. 예외: 정보가 없으면 "해당 내용은 답변드리기 어렵습니다"라고 응답

제공된 정보:
${context}

질문: ${query}

답변:`;

개선 효과:

  • 일관된 어조와 스타일 유지
  • 근거 없는 추측 답변 크게 감소
  • 개발자 본인이 답변하는 느낌의 자연스러운 대화

4. 실제 성능 테스트

구현 완료 후 다양한 질문으로 테스트해봤습니다.

잘 동작하는 질문들:

  • "어떤 기술 스택을 사용하시나요?" → 기술 문서에서 정확히 찾아서 답변
  • "프로젝트 경험을 알려주세요" → 관련 프로젝트 정보를 적절히 요약해서 제공
  • "회사 경력이 궁금해요" → 경력 관련 문서에서 정확한 정보 추출

한계가 있는 질문들:

  • "개발자로서의 목표가 뭔가요?" → 추상적 질문은 문서 매칭이 어려움
  • "왜 이 기술을 선택했나요?" → 의사결정 배경은 문서에 없으면 답변 불가
  • "다른 개발자에게 조언해주세요" → 창의적 답변이 필요한 경우 제한적

정확도 평가: 약 80% 정도의 질문에는 만족할 만한 답변을 제공했습니다. 팩트 기반 질문에는 매우 강하지만, 개인적 견해나 추상적 내용에는 한계가 있었습니다.


실제 결과물

AI 챗봇 동작 예시

메뉴에 있는 AI Chatbot으로 접근하거나 해당 링크에서 직접 확인해볼 수 있습니다.


개발하면서 배운 것들

RAG는 생각보다 단순하다

처음에는 RAG가 복잡한 AI 기술일 줄 알았는데, 실제로는 "문서 검색 + AI 답변"의 단순한 조합이었습니다. 하지만 각 단계에서 세밀한 튜닝이 필요했습니다.

중요한 설계 포인트들:

  • 문서 청킹 크기 (1000자가 적절했음)
  • 검색 결과 개수 (3개가 최적)
  • 프롬프트 구성 (매우 구체적으로 작성해야 함)
  • 벡터 DB 선택 (배포 환경 고려 필수)

데이터 품질이 결과를 좌우한다

아무리 좋은 AI 모델을 써도 학습할 문서가 부실하면 답변도 부실합니다. 포트폴리오 문서를 정리하고 구조화하는 작업이 생각보다 중요했습니다.

좋은 문서 작성법:

  • 구체적인 수치와 사실 위주로 작성
  • 중복되는 내용 최소화
  • 질문될 만한 내용들을 미리 포함
  • 일관된 톤앤매너 유지

AI는 완벽하지 않다는 걸 받아들이기

RAG를 직접 구현해보니 AI의 한계가 명확히 보였습니다. 80% 정도의 질문에는 좋은 답변을 주지만, 나머지 20%는 여전히 어렵습니다.

현실적인 기대치 설정:

  • 팩트 기반 질문: 매우 잘함
  • 추상적/창의적 질문: 한계 있음
  • 대화 맥락 기억: 현재 버전에서는 불가능
  • 최신 정보: 문서에 없으면 답변 불가

마무리

RAG를 직접 구현해보면서 AI 기술이 점점 개인 개발자에게도 접근 가능해지고 있다는 걸 실감했습니다. 복잡해 보이지만 실제로는 기존 기술들의 조합이고, 조금만 공부하면 개인 프로젝트 수준에서도 충분히 만들 수 있습니다.

무엇보다 "내 데이터로 내만의 AI를 만들 수 있다"는 점이 흥미로웠습니다. ChatGPT처럼 범용적인 AI도 좋지만, 특정 도메인에 특화된 AI의 가능성도 크다고 생각합니다.

이번 프로젝트는 완벽하지 않지만, RAG라는 기술을 직접 경험해볼 수 있는 좋은 기회였습니다. 앞으로 이런 개인화된 AI 어시스턴트가 더 많아질 것 같고, 개발자로서도 흥미로운 영역이라고 생각합니다.

Profile picture

온승찬 | Frontend Developer