Skip to content

Hateslop 3기 엔지니어 x 프로듀서 합동 AI 캐릭터 챗봇 프로젝트

Notifications You must be signed in to change notification settings

zzmnxn/3-character-chat

 
 

Repository files navigation

HateSlop 3기 엔지니어x프로듀서 합동 캐릭터 챗봇 프로젝트

1. 📐 시스템 아키텍처

데이터 흐름

사용자 입력 → Flask API → ChatbotService → RAG 검색 (ChromaDB) → OpenAI API → 응답 생성

핵심 컴포넌트

  • ResponseGenerator: 11단계 응답 생성 파이프라인을 관리합니다.
    • 초기 메시지 처리
    • 중단 요청 처리
    • 주제 이탈 감지
    • 감정 분석 수행
    • 상태 전환 관리
    • LLM 호출
    • 리포트 생성
    • 이미지 선택
  • ChatbotService: 대화 상태 및 플로우를 관리합니다.
    • 상태 머신 (DSM): INITIAL_SETUPRECALL_UNRESOLVEDRECALL_ATTACHMENT → ...
    • 고정 질문 시스템: 각 상태별 사전 정의된 질문
    • 턴 수 관리 및 안전장치
  • RAGService: 벡터 검색 및 임베딩을 담당합니다.
    • OpenAI text-embedding-3-large 모델 사용
    • ChromaDB PersistentClient로 영속성 보장
    • 유사 사례 검색 (analyzed_cases.jsonl)
  • EmotionAnalyzer: 미련도를 분석합니다.
    • 키워드 기반 초기 분석
    • RAG 기반 정규화 (LLM-as-a-Grader)
    • 5가지 지표: 애착도, 후회도, 미해결감, 비교 기준, 회피/접근
  • ReportGenerator: 개인화된 리포트를 생성합니다.
    • LLM 기반 리포트 생성
    • 유사 사례를 참고하여 공감 표현

2. 🛠️ 사용한 기술 스택

Backend

  • Flask 3.0: RESTful API 서버
  • OpenAI API (gpt-4o-mini): 대화 생성 엔진
  • ChromaDB: 벡터 데이터베이스 (임베딩 저장/검색)

Frontend

  • Vanilla JavaScript: 프레임워크 없는 순수 JS
  • HTML5/CSS3: 반응형 UI

Infrastructure

  • Docker: 컨테이너화
  • Render.com: 클라우드 배포

3. 💡 기술 선택 이유

ChromaDB를 선택한 이유

  • Python 네이티브 지원으로 Flask와 통합이 쉬웠습니다.
  • 별도 서버 설치 없이 임베디드 모드로 사용 가능하여 설정이 간편했습니다.
  • 벡터 유사도 검색이 빠르고 정확했습니다.

RAG 패턴을 적용한 이유

  • 문제 인식: LLM은 학습 데이터에 없는 최신 정보나 특정 도메인 지식에 약합니다.
  • 해결 방법: ChromaDB에 관련 지식을 저장하고, 관련 정보를 검색하여 프롬프트에 포함시켰습니다.
  • 효과: 환각(Hallucination)을 줄이고 정확한 답변 생성이 가능했습니다.

상태 머신(DSM) 패턴을 적용한 이유

  • 문제 인식: 자유로운 대화만으로는 체계적인 인터뷰가 어렵고, 사용자가 주제를 이탈하거나 대화를 중단할 수 있습니다.
  • 해결 방법: 상태별로 고정 질문을 정의하고, 턴 수, 점수 임계값, 질문 소진 등 명확한 상태 전환 조건을 설정했습니다. 주제 이탈 감지 및 자동 리다이렉트 기능도 추가했습니다.
  • 효과: 체계적인 데이터 수집과 자연스러운 대화 흐름 유지를 통해 사용자 경험을 개선했습니다.

LLM-as-a-Grader 패턴 적용

  • 문제 인식: 키워드 기반 분석만으로는 사용자의 복잡한 맥락을 파악하기에 부족했습니다.
  • 해결 방법: RAG로 검색한 유사 사례를 LLM이 참고하여 점수를 재평가하도록 했습니다.
  • 효과: 더 정확하고 일관된 감정 분석 결과를 도출할 수 있었습니다.

4. ⚠️ 개발 시 겪은 문제점

문제 1: 상태 머신 복잡도 증가로 인한 버그

  • 현상: 상태 전환 시 질문이 중복되거나 대화 흐름이 끊기는 문제가 발생했습니다.
  • 원인: 상태 전환 조건이 턴 수, 질문 소진, 점수 임계값 등 여러 개로 나뉘고, 고정 질문과 꼬리 질문 관리 로직이 복잡하게 얽혔습니다.
  • 증상: 같은 질문이 반복되거나 상태가 예상치 못하게 전환되었습니다.

문제 2: RAG 검색 결과의 품질 문제

  • 현상: 사용자 답변과 무관한 사례가 검색되었습니다.
  • 원인: 임베딩 모델이 한국어의 미묘한 유사도를 항상 정확히 판단하지 못했고, 유사도 임계값이 너무 낮게 설정되어 있었습니다.
  • 증상: "미련이 없어"라는 답변에 "강한 미련" 사례가 검색되는 등 정반대의 결과가 나왔습니다.

문제 3: LLM 응답에서 역할 이탈

  • 현상: LLM이 'PD 친구' 캐릭터에서 벗어나 '분석가'처럼 딱딱하게 말하는 경우가 발생했습니다.
  • 원인: 시스템 프롬프트가 충분히 강력하지 않았고, "미련도 계산법이 뭐야?" 같은 Prompt Injection 공격에 취약했습니다.
  • 증상: 시스템 정보를 노출하거나 캐릭터의 말투를 잃어버렸습니다.

5. ✅ 문제 해결 방법

문제 1 해결: 상태 관리 로직 보완

복잡한 상태 전환 로직을 체계화하기 위해 챗봇이 대화의 맥락을 기억하도록 보완했습니다. state_turns(현재 상태 턴)와 turn_count(전체 턴)를 분리하여 관리하여 질문이 중복되는 현상을 방지했습니다. 또한, max_state_turns 도달 시 자동 상태 전환, max_total_turns 도달 시 리포트 제안, low_regret_threshold 기반 조기 종료 등 명확한 안전장치를 추가하여 대화 흐름을 안정적으로 제어했습니다.

문제 3 해결: CRITICAL_RULE 추가 및 Prompt Injection 방어

LLM의 역할 이탈을 방지하기 위해, 시스템 프롬프트 최상단에 CRITICAL_RULE을 추가했습니다. 이 규칙은 '환승연애 PD 친구' 역할을 절대 벗어나지 않도록 강제하며, 역할 변경이나 시스템 정보 질문 같은 Prompt Injection 공격이 들어올 시 PD 페르소나를 유지하며 친근하게 거부하도록 지시합니다.


6. 🚀 성능 개선 노력

개선 1: 응답 속도 최적화

  • Before: 평균 5초 소요 (매 턴 RAG 검색 + LLM 호출)
  • After: 평균 2초로 단축 (60% 개선)
  • 방법:
    • 대화 중에는 RAG 없이 키워드 기반 분석만 수행 (use_rag=False)
    • 최종 리포트 생성 시에만 누적된 대화록 전체로 RAG 수행 (use_rag=True)

개선 2: 메모리 사용량 감소

  • Before: Docker 컨테이너 메모리 800MB 사용
  • After: 400MB로 절반 감소
  • 방법: 불필요한 라이브러리를 제거하고, Dockerfile에서 경량 베이스 이미지(python:3.11-slim)를 사용했습니다.

7. 😔 아쉬웠던 점

1. 테스트 코드 부족

  • 현황: 핵심 로직에 대한 단위 테스트가 없습니다.
  • 문제: 리팩토링 시 기존 기능의 동작을 보장하기 어렵고, 특히 상태 머신 로직 변경 시 사이드 이펙트를 파악하기 어려웠습니다.
  • 교훈: TDD(Test-Driven Development) 방식의 도입 필요성을 느꼈습니다.

2. 프롬프트 엔지니어링 최적화 부족

  • 현황: 시스템 프롬프트를 여러 번 수정했지만, A/B 테스트 없이 감에 의존해 진행했습니다.
  • 문제: 어떤 프롬프트가 가장 효과적인지 정량적으로 측정하지 못했습니다.
  • 향후 계획: 사용자 피드백 수집 시스템을 도입하고 프롬프트 버전별 성능을 비교하는 프로세스를 구축하고 싶습니다.

8. 🤔 회고 및 성찰

기술적 성장

  • RAG 이해도 향상: 이론으로만 알던 RAG를 실제 구현하며 내부 동작 원리를 이해했고, ChromaDB의 distancesimilarity 개념 차이를 학습했습니다.
  • LLM-as-a-Grader: RAG와 LLM을 결합해 점수를 정규화하는 패턴을 적용하며 LLM의 활용성을 체감했습니다.
  • 프롬프트 엔지니어링: 시스템 프롬프트 최적화와 Prompt Injection 방어 기법을 통해 답변 품질과 안정성을 높이는 경험을 했습니다.
  • 상태 머신 설계: 복잡한 대화 흐름을 상태 머신으로 체계화하고, 턴 수 및 임계값 기반의 안전장치를 추가하는 경험을 했습니다.

협업 경험

  • Git 협업: PR과 코드 리뷰를 통해 코드 품질을 향상시켰습니다.
  • 역할 분담: 프로듀서(기획)와 엔지니어(개발) 간의 명확한 업무 분담으로 효율성을 높일 수 있었습니다.

개선 방향

  • 시간 관리: 초반에 프롬프트 흐름과 상태 머신을 더 꼼꼼히 설계했다면 개발 후반부의 리팩토링 시간을 단축할 수 있었을 것입니다.
  • 문서화: 개발 중 문서화를 소홀히 하여 이미 정했던 정책을 잊는 경우가 있었습니다. 개발과 문서화를 동시에 진행하는 습관이 필요합니다.
  • 다음 프로젝트: 기획 단계에서 Flowchart를 더 명확히 확립한 후 개발을 시작하고, 1주 단위 스프린트와 같은 애자일 방식을 도입해보고 싶습니다.

9. 📦 배포 정보

About

Hateslop 3기 엔지니어 x 프로듀서 합동 AI 캐릭터 챗봇 프로젝트

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 75.2%
  • HTML 17.1%
  • JavaScript 4.7%
  • CSS 2.3%
  • Dockerfile 0.7%