Mova 채팅 로그 실측 개선과 RAG 부활

요약

영역 내용
실측 프로덕션 zero-rec 응답 13건(33%)을 전수 분류 — 추측 대신 로그가 우선순위를 정함
수정 3종 언어 허용목록 과차단 · dedup 소진 풀 확장 · 불만 발화 라우팅
RAG 8/7부터 조용히 죽어 있던 시맨틱 검색을 Gemini 임베딩 전환으로 부활
인프라 pytest·lint-imports·eslint·pre-commit 전부 죽어 있던 검증 파이프라인 복구

로그가 가설을 뒤집었다

원래 계획은 ATS 팀프로젝트의 엔티티 해석 레이어(편집거리·초성 매칭)를 채팅에 이식하는 것이었다. 그런데 프로덕션 로그를 전수 분류해 보니 제목·배우 오타 질의가 0건 — 사용자들은 배우명을 정타로 치고 연도를 숫자로 입력하고 있었다. 도입 보류(YAGNI), 대신 로그가 가리킨 진짜 문제 3개를 고쳤다.

① “일본 애니메이션 영화 추천” → 0건의 진범

카탈로그에 일본 애니가 79편 있는데도 0건. 원인은 동의어도 태그도 아닌 언어 허용목록(ko·en) — “맥락 없는 외국어 영화 노출 방지”용 정책이 사용자가 국가를 명시한 요청까지 차단하고 있었다. 국가 필터가 명시된 경우에만 허용목록을 우회하도록 수정 → 너의 이름은·센과 치히로가 정상 반환.

② “다른것도 추천해줘”의 빈손 응답

후속 질의에서 첫 후보 16편이 전부 이미 소개된 영화면 안내 문구만 반복됐다(실측 4건). 같은 조건으로 후보 풀만 16→48로 넓혀 한 번 재검색하는 대안 행동을 추가 — 새 후보가 있으면 서빙, 없으면 기존의 정직한 0카드 유지.

③ “똑같은 말 반복하지마”가 추천 파이프라인으로

봇에 대한 불만이 추천 요청으로 오분류돼 빈 카드만 또 나가던 것(실측 2건). 분류기에 결정론 가드를 넣어 LLM 라우터 없이 general(대화) 경로로 보내고, general 응답에는 최근 6턴 히스토리를 전달해 맥락 있는 사과·안내가 나가게 했다.

RAG 부활 — 8/7부터 조용히 죽어 있던 시맨틱 검색

EC2의 임베딩 백엔드가 ollama로 설정돼 있었는데 EC2엔 Ollama가 없다. 쿼리 임베딩이 매번 실패해 벡터 검색 경로 전체가 조용히 죽고, 모든 질의가 태그 키워드 폴백으로만 돌고 있었다 — 색인된 지식 1,606건이 통째로 놀던 상태.

Gemini 임베딩으로 전환하고 카탈로그를 재임베딩하자 시맨틱 검색이 살아났다: “우주에서 살아남는 이야기” → 그래비티, 라이프. 태그 매칭으로는 불가능한, 의미 기반 결과다.

재임베딩 과정에서 사고도 하나 잡았다. 색인 인터랙터가 임베딩 실패(레이트리밋 429)를 조용히 삼켜 2,083건이 생략됐는데 스크립트는 “성공 2,972”를 출력하고 있었다. 색인 여부를 반환값으로 노출하고, 지수 백오프 재시도와 이어하기 옵션을 추가했다. Gemini 무료 티어의 일일 쿼터(1,000회)는 실측으로 확인 — EC2 cron이 매일 쿼터 리셋 직후 자동 재개해 이틀 내 전량 색인 예정이다.

죽어 있던 검증 파이프라인도 복구

이날 오전 “전체 코드 정리” 요청에서 시작해 발견한 것들: 전체 pytest에서만 나는 수집 충돌(패키지 섀도잉), 낡은 테스트 6건, 실행 불능이던 lint-imports, devDependencies에서 사라진 eslint, 그리고 아예 설치돼 있지 않던 pre-commit — 이 드리프트들이 쌓인 근본 원인이었다. 전부 복구해 pytest 633 passed, 아키텍처 계약 6개 KEPT, eslint 0 errors, 커밋 게이트 상시 작동 상태로 만들었다.

검증

수정마다 회귀 테스트를 추가(총 +8건)하고, EC2 배포 후 실제 질의로 라이브 검증했다. 전 과정이 “로그 실측 → 근본 원인 → 최소 수정 → 테스트 → 배포 → 라이브 재검증” 사이클로 진행됐다.