정비소를 위한 AI 전화 접수원 만들기 (RAG + Voice Agent 실전 구현)
I built an AI receptionist for a mechanic shop
TL;DR Highlight
형의 자동차 정비소가 전화를 못 받아 매달 수천 달러를 잃고 있다는 문제를 해결하기 위해, RAG 파이프라인과 Vapi 음성 플랫폼을 조합해 실제 전화를 받는 AI 접수원을 직접 구현한 사례다.
Who Should Read
소규모 비즈니스용 AI 음성 에이전트나 전화 자동화 시스템을 만들어보려는 개발자, 또는 RAG 파이프라인을 실제 프로덕션 수준의 앱에 연결하는 흐름을 처음 배우고 싶은 백엔드 개발자.
Core Mechanics
- 문제의 출발점은 단순했다. 형이 하루 종일 차 밑에서 작업하느라 전화를 못 받고, 고객은 그냥 끊고 다른 곳에 전화한다. 브레이크 교체 $450짜리, 엔진 수리 $2,000짜리 일감이 그냥 날아가는 상황이었다.
- 날것의 LLM을 그대로 쓰면 위험하다. 고객이 '브레이크 얼마예요?'라고 물었을 때 실제 가격은 $450인데 모델이 $200로 추측해서 답하면 고객 신뢰가 깨진다. 이 문제를 막기 위해 RAG(Retrieval-Augmented Generation, 실제 지식 문서를 검색해서 답변하는 방식)를 도입했다.
- 지식 베이스 구축은 형의 웹사이트를 스크래핑해서 마크다운 파일로 만드는 것부터 시작했다. 서비스 종류, 가격, 소요 시간, 영업시간, 결제 방법, 취소 정책, 보증 정보, 대차 차량 여부, 취급 차종 등 21개 이상의 문서로 정리했다.
- 각 문서는 Voyage AI의 voyage-3-large 모델로 1024차원 벡터로 변환해 MongoDB Atlas에 저장했다. Atlas Vector Search 인덱스를 걸어두면, 고객 질문도 같은 모델로 벡터화한 뒤 의미적으로 가장 유사한 문서 상위 3개를 가져온다. '브레이크 작업 얼마야?'처럼 정확히 같은 단어가 없어도 관련 문서를 찾아낸다.
- 검색된 문서 3개를 컨텍스트로 Anthropic Claude(claude-sonnet-4-6)에게 넘기고, 시스템 프롬프트로 '지식 베이스에 있는 내용만 답하고, 모르면 모른다고 하고 콜백 정보를 받아라'고 제한을 걸었다. 파트 1 완료 시점에서 터미널에 질문하면 정확한 답이 나왔다. 예: '오일 교환 얼마예요?' → '일반 오일 $45, 합성 오일 $75입니다. 오일 필터 교체, 오일 보충, 타이어 공기압 점검 포함이며 약 30분 소요됩니다.'
- 음성 인프라는 Vapi를 선택했다. Vapi 하나로 전화번호 구매, 음성 인식(Deepgram), 텍스트 음성 변환(ElevenLabs), 실시간 함수 호출까지 전부 처리된다. 개발자는 Vapi가 호출할 웹훅 서버만 만들면 된다.
- 서버는 FastAPI로 구현했다. 고객이 질문하면 Vapi가 /webhook 엔드포인트에 tool-calls 요청을 보내고, 서버는 RAG 파이프라인으로 답을 뽑아서 반환하면 Vapi가 음성으로 읽어준다. 개발 중에는 Ngrok으로 로컬 포트 8000을 외부에 노출해서 Vapi와 연결했다.
- Vapi 어시스턴트 설정에서 인사말('안녕하세요, Dane's Motorsport입니다, 무엇을 도와드릴까요?')과 두 가지 툴(answerQuestion: RAG 기반 답변, saveCallback: 이름과 연락처 수집)을 연결해서 정보를 모를 때는 콜백 메시지를 남길 수 있게 했다.
Evidence
- 전직 서비스 어드바이저 출신 댓글러가 실용성에 심각한 문제를 제기했다. 부품 가격은 실시간으로 변하고 재고도 매일 다르기 때문에 정확한 견적을 미리 답하는 건 불가능에 가깝다는 것. 일부 주에서는 부정확한 견적이 법적 문제로 이어질 수도 있다고 했다. 이 시스템이 유용한 영역은 '차 수리가 완료됐으니 픽업하세요' 같은 단방향 알림 정도라는 의견이었다.
- RAG가 꼭 필요한 게 맞냐는 의문도 나왔다. 가격표, 영업시간 같은 정보는 양이 적어서 요즘 LLM 컨텍스트 윈도우에 전부 다 넣어도 충분한데 굳이 벡터 검색을 쓸 필요가 있냐는 지적이었다. 서비스 매뉴얼 전체를 넣는 게 아니니까 RAG 오버헤드가 불필요할 수 있다는 주장이다.
- 아웃소싱 리셉션 서비스를 쓰는 게 더 현실적이지 않냐는 댓글도 있었다. 월 $500짜리 외부 전화 응대 서비스를 쓰면 됐을 텐데, AI 시스템을 직접 구축·유지하는 비용과 비교했을 때 ROI가 어떻게 될지 따져봐야 한다는 의견이었다.
- AI 전화 응대에 대한 사용자 반응은 엇갈렸다. 민트 모바일 AI 상담원이 대기 없이 1분 안에 문제를 해결해줬다는 긍정 경험이 있는 반면, 지역 에어컨 업체 AI 응대가 '언캐니 밸리' 느낌을 줘서 불신이 생겨 사람을 찾아 헤맸다는 부정 경험도 공유됐다. 로봇이라는 걸 알면 그냥 끊어버리겠다는 댓글도 여럿 있었다.
- 부정적인 댓글이 쏟아지는 상황에서 '이 특정 사례에 쓸 만하냐'가 핵심이 아니라 '여기서 배운 기술을 내 프로젝트에 어떻게 쓸 수 있냐'가 더 중요하다는 옹호 댓글도 있었다. TTS를 위한 텍스트 포맷팅 처리 같은 실질적인 팁을 얻었다는 반응도 있었다. 한편 실제로 해당 번호에 전화해봤더니 챗봇이 아직 배포도 안 됐다며 'HN에서 본 최악의 테크 데모'라는 혹평도 있었다.
How to Apply
- 소규모 자영업자(식당, 정비소, 미용실 등) 대상 AI 전화 에이전트를 만들려는 경우, 이 글의 스택(Vapi + FastAPI + MongoDB Atlas Vector Search + Voyage AI 임베딩 + Claude)을 그대로 참고해 빠르게 프로토타입을 만들 수 있다. 단, 댓글에서 지적된 것처럼 가격이 동적으로 변하는 서비스라면 실시간 가격 조회 API 연동을 별도로 고려해야 한다.
- RAG 파이프라인을 음성 인터페이스에 연결하려고 할 때, Vapi의 tool-calls 웹훅 방식은 기존 HTTP 서버를 그대로 재사용할 수 있어서 진입 장벽이 낮다. 로컬 개발 단계에서는 Ngrok으로 즉시 외부 노출이 가능하므로, Vapi 대시보드에 ngrok URL을 붙여넣는 것만으로 실제 전화 테스트가 가능하다.
- 지식 베이스 양이 적고(수십 개 문서 이하) 내용이 자주 바뀌지 않는다면, 이 글처럼 RAG를 구현하는 대신 전체 내용을 시스템 프롬프트에 직접 넣는 방식도 검토할 것. 벡터 DB 설정과 임베딩 비용을 아낄 수 있고 오히려 레이턴시도 줄어들 수 있다.
- AI가 모르는 질문에 대응하는 fallback 설계는 필수다. 이 글에서는 saveCallback 툴로 이름과 연락처를 수집하는 방식을 썼는데, 음성 에이전트에서 '모르면 그냥 죄송하다고만 하는' 것보다 훨씬 실용적이다. 유사한 프로젝트라면 이 패턴을 복사해서 쓸 수 있다.
Terminology
RAGLLM이 답을 '기억'에서 꺼내는 대신, 미리 준비한 문서 데이터베이스를 검색해서 그 내용을 근거로 답하게 만드는 방식. 환각(hallucination)을 줄이는 데 효과적이다.
Vector Embedding텍스트를 수백~수천 개의 숫자 배열로 변환한 것. 비슷한 의미의 문장은 숫자 배열도 서로 가까워지기 때문에, 키워드가 달라도 의미적으로 유사한 문서를 찾을 수 있다.
Vapi전화 인프라(번호 구매, 음성 인식, TTS, 실시간 함수 호출)를 API로 제공하는 서비스. 개발자는 비즈니스 로직만 담은 웹훅 서버만 만들면 된다.
Ngrok로컬 개발 서버를 인터넷에 임시로 노출시켜주는 터널링 도구. `ngrok http 8000` 한 줄로 외부에서 접근 가능한 HTTPS URL을 즉시 만들어준다.
Tool CallingLLM이 답변 도중 외부 함수나 API를 직접 호출하도록 하는 기능. 이 글에서는 Vapi가 고객 질문을 받을 때 answerQuestion, saveCallback 같은 함수를 실시간으로 호출한다.
Uncanny ValleyAI나 로봇이 사람과 거의 비슷하지만 어딘가 어색할 때 느껴지는 불쾌하고 불신스러운 감정. AI 음성 에이전트가 너무 사람 같으면서도 티가 날 때 사용자가 오히려 거부감을 느끼는 현상을 설명할 때 쓰인다.