FastAPI - 카드 상담 챗봇 구현

안유민·2025년 11월 16일

1. 프로젝트 개요

이번 구현은 FastAPI를 활용한 카드 상담 챗봇 서버이다.
추천 → 비교 → 선택 → 질의응답 → 답변 간단화라는 흐름을 한 시스템 안에 담아내는 것이 목표였다.


사용자는 원하는 카드 조건입력한다. 예를 들어:

  • “반려동물 관련된 카드 추천해줘”
  • “병원 방문이 잦은 40대 남성에게 적합한 카드 추천해줘”

이렇게 입력하면 서버는 FAISS 기반 RAG Retriever를 통해 적합한 카드들을 찾아 추천해주고, 동시에 비교 분석을 제공한다.
그 다음 사용자가 마음에 드는 카드를 선택하면, 선택된 카드의 약관 원문을 바탕으로 질의응답이 가능해진다.

또한 답변이 복잡하게 느껴질 경우, GPT 모델을 활용해 “이 답변을 쉽게 설명해줘”라는 기능도 제공한다.
즉, 이 프로젝트는 단순 REST API 서버를 넘어 실제 상담 챗봇에 가까운 기능을 담고 있다.


2. FastAPI 서버 구조

FastAPI 서버는 크게 네 가지 파트로 구성되어 있다.

1) 환경 설정 및 초기화

  • dotenv로 환경 변수 로드
  • 전역에서 한 번만 생성되는 CardGenerator 객체 초기화
  • Retriever는 지연 초기화 방식(get_retriever())으로 필요할 때만 불러오기

2) 정적 파일 및 기본 엔드포인트

  • /static 폴더를 mount 해서 HTML, CSS, JS 파일 제공
  • / 경로에서는 example.html 파일 반환 → 브라우저에서 챗봇 UI 로딩
  • /healthz 엔드포인트는 서버 상태 확인용

3) 추천/선택/질의응답 API

  • /recommend : 입력을 기반으로 카드 추천
  • /select : 사용자가 카드 선택
  • /rag : 선택된 카드 기반 질문에 답변 생성

4) 후처리 기능

  • /simplify : OpenAI API를 통해 답변을 쉽게 풀어서 다시 설명

▶ 이런 구조를 통해 서버는 단순한 API 서버를 넘어 대화형 상담 시스템의 백엔드 역할을 수행한다.


3. 주요 API 엔드포인트

◽/recommend 카드 추천

  • 입력 파라미터
    • user_input: 사용자가 입력한 카드 조건 (예: “병원 관련 카드 추천”)
    • card_type: 카드 유형 (all, credit, check)
    • top_k: 추천 개수 (기본값 5)
  • 처리 과정
    • Retriever가 user_input과 의미적으로 유사한 카드를 검색
    • 추천된 카드 목록을 last_recommendations 전역 변수에 저장
    • CardGenerator를 활용해 추천된 카드들을 비교하는 Markdown 생성
  • 출력
    • 추천된 카드 리스트(items)
    • 카드 비교 결과(comparison)

▶ 즉, /recommend챗봇의 첫 단계“추천 + 비교” 역할을 맡는다.

@app.post("/recommend")
def recommend(user_input: str = Form(...), card_type: Literal["all","credit","check"]="all", top_k: int = Form(5)):
    r = get_retriever()
    items, _ = r.find_similar_cards(user_input, card_type, top_k)
    comparison = generator.generate_comparison(items, top_k=top_k)
    return JSONResponse({"items": items, "summary_text": "", "comparison": comparison})

◽/select 카드 선택

  • 입력 파라미터
    • card_name: 사용자가 고른 카드 이름
    • card_type: 카드 유형 (전체/신용/체크)
    • keyword: 선택 시 함께 입력한 키워드
  • 처리 과정
    • 추천 리스트 중에서 선택된 카드를 찾아 selected_card 전역 변수에 저장
    • selected_cards.json 파일에 선택 이력을 기록 (타임스탬프 포함)
  • 출력
    • 선택된 카드 정보 JSON

▶ 이 과정 덕분에 사용자는 추천 → 선택 → 후속 질의응답 흐름을 이어갈 수 있다.

@app.post("/select")
def select(card_name: str = Form(...), card_type: Literal["credit","check"]="credit", keyword: str = Form("")):
    selected_card = {...}
    save_selected_card(selected_card)
    return JSONResponse({"ok": True, "selected": selected_card})

◽/rag 카드 질의응답

  • 입력 파라미터
    • question: 사용자의 질문 (ex. “이 카드의 주요 약관은 뭐야?”)
    • mode: detailed/simple (간단 모드에서는 쉬운 답변을 우선 제공)
  • 처리 과정
    • 선택된 카드가 없으면 오류 반환 (“먼저 카드를 선택해 주세요.”)
    • Hybrid-Retriever로 해당 카드의 원문 약관에서 답변 생성
  • 출력
    • 카드 이름
    • 답변 텍스트

▶ 이 API는 챗봇의 핵심문서 기반 질의응답(RAG) 기능을 담당한다.

@app.post("/rag")
def rag(question: str = Form(...), mode: Literal["detailed","simple"]="detailed"):
    engine = FAISSRAGRetriever()
    resp = engine.query(card_name=selected_card["card_name"], question=question, explain_easy=(mode=="simple"))
    return JSONResponse({...})

◽/simplify 답변 간단화

  • 입력 파라미터
    • text: GPT가 간단하게 풀어쓸 원문 답변
  • 처리 과정
    • OpenAI API(gpt-4)를 호출해 “쉬운 한국어”로 다시 작성
    • 응답을 받아 JSON으로 반환
  • 출력
    • simplified: 간단화된 답변 텍스트

▶ 이 기능은 원문이 너무 딱딱하거나 법적 용어가 많을 때, 사용자가 쉽게 이해할 수 있도록 돕는다.

@app.post("/simplify")
def simplify(text: str = Form(...)):
    msg = [{"role":"system","content":"아래 글을 사용자가 쉽게 이해하도록 재작성해."},{"role":"user","content":text}]
    res = client.chat.completions.create(model="gpt-4o", messages=msg)
    return {"simplified": res.choices[0].message.content.strip()}

4. 프론트엔드 (example.html) 동작 구조

HTML채팅 UI를 제공하며, JavaScript를 통해 FastAPI 서버와 통신한다.

◽주요 기능

1) 입력 폼

  • 사용자가 텍스트로 카드 조건 입력 → /recommend API 호출

2) 추천 결과 표시

  • 추천 카드 리스트와 비교 분석을 말풍선으로 출력
  • 각 카드에는 "✅ 선택" 버튼 → /select API 호출

3) 질의응답 인터페이스

  • 카드 선택 후 질문 입력 시 /rag API 호출
  • 질문 답변이 말풍선으로 나타남
  • 답변 아래에는
    • 💡 “이 답변을 쉽게 설명해줘” → /simplify API 호출
    • 📝 “이 답변에 대해 질문하기” → 후속 질문 모드 전환

◽시각적 구성

  • 사용자 말풍선: 파란색 배경, 오른쪽 정렬
  • 봇 말풍선: 회색 배경, 왼쪽 정렬
  • 카드 비교/선택 UI: 카드명, 태그, 혜택, 조건, 연회비 등 구조화된 박스로 표시

5. 실행 및 사용 방법

◽실행

uvicorn main:app --reload

--reload 옵션 덕분에 코드 수정 시 서버가 자동으로 재시작되어 개발 효율이 높다.

◽접속

브라우저에서

http://127.0.0.1:8000/

로 들어가면 챗봇 화면이 나타난다.

◽사용 예시

1) 추천 요청
“병원 관련 카드 추천해줘” 입력
→ 서버가 관련 카드 K개 추천 + 비교 분석 결과 출력

2) 카드 선택
추천된 카드 중 하나를 클릭
→ “🎯 ‘OO카드’를 선택했어요. 이제 질문해보세요” 메시지 출력

3) 질문하기
“이 카드의 주요 약관은 뭐야?” 입력
→ RAG 기반 답변 + 출처 표시

4) 답변 간단화
답변 아래 “💡 이 답변을 쉽게 설명해줘” 버튼 클릭
→ GPT가 간단히 풀어쓴 설명 제공

이런 흐름을 통해 실제 상담과 유사한 경험을 얻을 수 있다.


💭 My Thoughts

이번 구현을 통해 FastAPI의 장점을 많이 체감했다.

  • 구현 속도: 라우팅, 폼 처리, JSON 응답이 매우 직관적이었다.
  • 데이터 검증: Pydantic을 쓰지 않아도 Form 파라미터로 손쉽게 처리 가능했는데, 덕분에 API 설계가 단순해졌다.
  • 프론트 연동: fetch API와 FastAPI가 잘 맞아떨어져, 프론트-백 간 연결이 깔끔했다.
  • 확장성: "추천 → 선택 → RAG 질의응답 → 답변 간단화"라는 파이프라인을 하나의 서버에 자연스럽게 녹여낼 수 있었다.

0개의 댓글