Cursor-first로 챗봇 데모 패치 후기 (엔티티 정규화와 QA)

지난해 추석 연휴에 만들었던 현대차 챗봇 데모를 다시 손보았습니다. 겉으로 보면 막바지 안정화 작업처럼 보일 수 있지만, 실제로는 챗봇 서비스에서 중요한 핵심 계층을 다시 점검한 5시간의 밀도 높은 패치 작업이었습니다. 단순히 코드를 고치는 것을 넘어, 불안정한 원인을 좁히고 핵심 엔티티(Entity)의 인식 안정성을 높이며, QA를 통해 일관성을 확보하는 데 집중했습니다.

작업 방식의 변화: Cursor-first

이번에는 ChatGPT와 코드를 복붙하며 왕복하는 방식에서 벗어나, Cursor(Composer 2.0)를 전면에 내세웠습니다. 작은 범위의 패치와 반복 검증 루프를 돌리는 데 있어 매우 효율적이었으며, ChatGPT는 중간중간 방향을 점검하는 전략적 보조 역할로 활용했습니다.

Demo: hyundai-chatbot-demo.vercel.app


왜 다시 손봤나: “동작”을 넘어 “신뢰”의 단계로

기존 데모도 이미 어느 정도 완성된 상태였습니다. Rule과 RAG가 결합된 하이브리드 구조가 있었고, FAQ 기반 검색과 응답 흐름도 기본적으로는 동작하고 있었습니다. StackBlitz에서 확인하고, Vercel에 배포해 실제 사용 흐름도 어느 정도 확인할 수 있는 수준까지 만들어둔 상태였습니다.

하지만 테스트할수록 “동작만 하는 데모”와 “안정적으로 동작하는 데모”는 다르다는 점이 확실해졌습니다. 소위 ‘바이브 코딩’은 아이디어를 빠르게 구현하는 데는 유리하지만, 서비스가 복잡해질수록 검증 비용이 커집니다. 특히 챗봇은 질문 해석 → 엔티티 인식 → Retrieval → Fallback → UI 흐름이 사슬처럼 엮여 있어, 마지막 5~10%의 완성도를 올리는 데 훨씬 세밀한 점검이 필요했습니다.


핵심 문제: 사용 흐름을 끊는 두 가지 문제

마지막까지 마음에 걸렸던 문제는 다음과 같습니다.

  1. UI 안정성: 간헐적인 바텀시트 프리징
    • 재현 빈도는 낮지만, 발생 시 사용 흐름을 끊어버리는 버그였습니다. 단순히 닫기 처리의 문제가 아니라 리스트 렌더링, Key 충돌, Hook 순서 등이 미묘하게 얽혀 있었습니다.
  2. 검색 품질: RAG의 엔티티 흡수력 부족
    • 사용자의 자연스러운 질의(아반테, 그랜져, g 80 등)를 시스템이 정규화하지 못해 Retrieval Hit가 약해지거나 Fallback으로 빠지는 현상이 발생했습니다.

어떻게 해결했나

① 바텀시트: “화려함”보다 “안정성”

먼저 바텀시트 쪽은 욕심을 줄였습니다.
이번 목표는 더 화려하게 만드는 것이 아니라, 사용 도중 멈추지 않게 하는 것이었습니다.

브라우저 콘솔을 보면서 React 경고를 추적했고, 그 결과 overlay 렌더링과 리스트 렌더링 쪽에서 불안정 요소를 좁혀갈 수 있었습니다. 중복 key 경고, 조건부 hook 구조, 중복 렌더링에 가까운 코드 등을 점검했고, overlay와 네트워크 검색 시트가 더 안정적으로 동작하도록 최소 수정만 적용했습니다.

겉으로는 단순한 UI 프리징처럼 보였지만, 실제로는 렌더링 identity와 상태 전환의 문제라는 점을 다시 확인할 수 있었습니다.

② 엔티티 정규화: “질문을 잘 읽는 법”

RAG 품질을 높이기 위해 모델을 바꾸거나 프롬프트를 크게 바꾸기보다는, 먼저 질문을 더 잘 읽도록 만드는 작업에 집중했습니다.

예를 들어 “소나타”라고 입력해도 내부적으로는 “쏘나타”로,
“g 80”이라고 입력해도 “G80”으로,
“아이오닉9”라고 입력해도 “아이오닉 9”로
안정적으로 수렴되도록 정규화 기준을 정리했습니다.

중요했던 건 alias를 몇 개 더 넣는 것 자체가 아니었습니다.
핵심은 정규화 기준이 retrieval과 응답 생성 흐름 전체에서 일관되게 적용되도록 만드는 것이었습니다. 같은 질문이 들어왔을 때 어떤 경로를 타더라도 최소한 같은 모델명으로 정리되어 인식되어야, retrieval도 안정적으로 동작할 수 있기 때문입니다.

③ KB 보강: RAG 응답력의 기초

중간에는 핵심 차량이나 인물 질의를 Rule로 우회하는 방향도 잠시 시도했습니다.
안정성은 높아졌지만 답변이 지나치게 얕아졌고, 제가 원했던 방향과는 조금 달랐습니다. 제가 원했던 것은 “무조건 반응하는 데모”보다 RAG가 실제로 의미 있게 동작하는 데모였습니다.

그래서 다시 방향을 바꿨습니다.
핵심 차량, 브랜드, 인물에 대해 짧지만 검색 친화적인 KB를 보강하고, retrieval이 더 잘 걸리도록 조정했습니다.

차량명 유사 발화에 대한 RAG 응답 예시

여기서 말하는 KB는 쉽게 말하면 챗봇이 참고하는 지식 베이스입니다.
같은 질문이 어떤 때는 되고 어떤 때는 안 되는 이유는 단순히 모델 성능만의 문제가 아니었습니다. 실제로는 아래 세 가지가 함께 영향을 줬습니다.

  1. 질문이 어떤 형태로 정규화되는지
  2. 그 질문이 어떤 KB 문서와 연결되는지
  3. 검색 점수가 애매할 때 fallback으로 빠지는 조건이 어떻게 설정되어 있는지

즉, RAG 품질은 모델 그 자체보다 질문과 지식을 연결하는 방식의 영향을 더 크게 받습니다. 질문이 잘 정규화되어도 연결되는 KB가 약하거나, fallback 조건이 거칠면 응답은 쉽게 흔들립니다. 결국 좋은 RAG는 “모델이 좋다”보다, 질문·지식·fallback 조건이 잘 맞물려 있느냐에서 시작된다고 느꼈습니다.


어떻게 검증했나: Headless QA와 회귀 테스트

이번 작업에서 가장 만족스러웠던 부분은 구현보다 검증 방식이었습니다.
이번에는 headless QA를 두 차례 별도로 돌렸고, 그와 별개로 수동 QA도 직접 반복했습니다.

자동화된 headless QA에서는 차량, 인물, 브랜드, OOD 질의를 나눠 regression 체크를 만들었습니다.

구분대표 입력기대 결과
차량 질의소나타, 아반떼N, g 80, gv70RAG 응답 정상, 불필요한 CTA 미노출
인물 질의정주영, 정몽구, 정의선응답 정상
브랜드 질의제네시스응답 정상
OOD 질의비트코인 시세, 오늘 날씨Fallback 로직 유지
  • 결과: 회귀 테스트 11개 항목 모두 PASS 확인.

  • 수동 QA: 반복 질의 시 RAG 결과의 일관성, 바텀시트 동작 안정성, 응답 톤의 자연스러움 확인.


무엇을 배웠나

이번 패치를 통해 다시 확인한 것은 세 가지입니다.

첫째, 검색·챗봇 서비스에서 중요한 건 결국 엔티티 해석입니다.
좋은 모델을 붙이는 것도 중요하지만, 실제 서비스에서는 사용자의 질문을 어떤 개체로 읽고 어떤 지식에 연결하느냐가 먼저입니다. 엔티티 정규화, alias 설계, retrieval 연결이 생각보다 훨씬 더 큰 영향을 줍니다.

둘째, RAG 품질은 모델보다 질문-지식 연결 방식의 영향을 더 크게 받습니다.
질문이 잘 정규화되어도 연결되는 KB 문서가 약하거나, 검색 점수가 애매할 때 fallback으로 빠지는 조건이 불안정하면 응답은 쉽게 흔들립니다. 결국 좋은 RAG는 “모델이 좋다”보다 “질문과 지식을 얼마나 잘 연결하느냐”에서 시작된다고 느꼈습니다.

셋째, 바이브 코딩도 결국은 체크포인트와 QA가 완성도를 만듭니다.
Cursor-first로 작업하면서 실행 속도는 확실히 좋아졌지만, 마지막 품질을 결정한 것은 결국 검증과 중간 체크포인트 관리였습니다. 이번에 특히 절실히 느낀 건, 좋은 상태를 한 번 놓치면 다시 찾는 시간이 버그 수정 시간보다 더 길 수 있다는 점이었습니다.


마무리

이번 5시간 패치는 단순 업데이트라기 보다, 검색·챗봇 서비스에서 중요한 핵심 층을 다시 점검한 시간이었습니다.

  • 바텀시트 안정화
  • 엔티티 정규화
  • KB 보강을 통한 RAG 품질 개선
  • headless QA와 수동 QA를 통한 검증

결국 이런 작은 층위들이 단단하게 쌓여야, 사용자에게 “자연스럽고 신뢰할 수 있는 경험”을 줄 수 있음을 다시 한번 확인했습니다.

 

Similar Posts

One Comment

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다