멀티테넌트 RAG 고객응대 챗봇
문서 입력부터 답변 생성까지 구축하고, 기기별 검색 범위와 고유명사 검색 품질을 다룬 고객응대 RAG 프로젝트입니다.
- 기간
- 2026.01 ~ 2026.02
- 역할
- 풀스택 개발 (1인)
- 구분
- B2B/사내 프로젝트
- 스택
- React, TypeScript, FastAPI, LangChain
프로젝트 배경
관리자가 등록한 문서를 근거로 고객 질문에 답하는 시스템을 1인 풀스택으로 구축했습니다. 기기마다 담당 매장의 지식만 검색해야 했고, 문서의 고유명사와 짧은 키워드도 찾아야 했습니다. 이미지·PDF에서 추출한 텍스트의 품질과 다국어 응답도 함께 다뤘습니다.
핵심 구현
- ▶React 관리자 화면과 FastAPI의 문서 관리·AI Core·OCR 서비스를 연결했습니다.
- ▶문서 파싱 결과를 관리자가 확인·수정한 뒤 문장 경계를 고려해 청킹하고 임베딩해 Qdrant에 저장했습니다.
- ▶디바이스 코드에서 매장 ID를 조회하고, 벡터 검색의 Qdrant payload와 BM25 인덱스를 매장별로 제한했습니다.
- ▶BM25와 벡터 검색 후보를 RRF로 합친 뒤 리랭커로 재정렬하고, 검색 결과를 근거로 답변을 생성했습니다.
- ▶요청된 응답 언어를 프롬프트에 명시하고, 결과가 없으면 안내 템플릿을 사용했습니다.
성과
- ▶관리자 문서 등록부터 OCR·검수·인덱싱, 검색과 답변 생성까지 한 흐름으로 연결했습니다.
- ▶고유명사·짧은 키워드 질의에 대응하도록 BM25를 추가하고, 매장별 검색 범위를 적용했습니다.
- ▶첫 RAG 프로젝트에서 검색·문서 처리·모델 서빙을 직접 구현했습니다.
트러블슈팅
사례 1. 고유명사 검색과 매장별 검색 범위
현상: 벡터 검색만으로는 고유명사나 짧은 키워드가 포함된 질문에서 관련 문서가 밀렸고, 기기별로 검색 범위를 구분해야 했습니다.
원인과 선택: 의미 유사도만으로 정확한 단어 일치를 다루기 어려워 BM25를 추가했습니다. 별도 컬렉션을 늘리는 대신 매장 ID를 문서 payload에 두고 검색 시 적용했습니다.
구현: 디바이스 코드에서 매장 ID를 조회해 Qdrant 검색 필터와 매장별 BM25 인덱스에 전달했습니다. 두 검색 결과는 RRF로 합치고 리랭커로 재정렬했습니다. 결과가 비면 안내 템플릿을 반환합니다.
결과와 배움: 매장별 검색 범위와 두 검색 방식의 후보 결합을 한 파이프라인에 담았습니다. 검색 품질과 접근 범위는 답변 생성 이전의 검색 단계에서 다뤄야 한다는 점을 배웠습니다.
사례 2. OCR 입력 품질과 다국어 답변
현상: 이미지·PDF 문서의 추출 텍스트는 그대로 인덱싱하면 읽기 순서나 문맥이 어긋날 수 있고, 다른 언어로 답할 때는 한국어 근거 문서의 영향을 받을 수 있었습니다.
구현: PaddleOCR로 추출한 텍스트를 관리자에게 먼저 보여주고 수정·확정 후 인덱싱했습니다. 청킹은 문장 경계를 우선해 길이를 제한했습니다. 응답 언어는 요청값을 사용하고 RAG 프롬프트 끝에 해당 언어 지시를 넣었습니다.
결과와 배움: 자동 추출 결과를 검수한 뒤 인덱싱할 수 있게 하고, 요청 언어를 답변 생성 지침에 반영했습니다. 문서 입력의 품질과 응답 지시를 함께 설계해야 한다는 점을 배웠습니다.