※ 본 글과 토이 프로젝트는 사내 업무 및 정보와 상관없는 전부 오픈된 정보로만 작성하였으며, 해당 업무 관련 담당자가 아니라 실제로 어떤식으로 운영되는지 아는 바가 없습니다.
학습 데이터 스케일링이 한계에 달했다는 비관적인 예측에도 불구하고, 2025년은 LLM 성능의 폭발적 성장이 빛이 난 한 해였던 것 같습니다. 특히 멀티모달 기술의 발전으로 이미지 및 동영상 생성에 많은 대중적 관심과 이슈를 끌었는데요, 그럼에도 불구하고 음성인식, 음성합성 분야에서는 End-to-End로 사용 가능한 오픈소스 LLM은 아직 더 나아갈 부분이 보입니다.
Chatterbox라는 TTS가 Apple Silicon에서 사용 가능하게 되어서, 겸사겸사 STT-LLM-TTS (그리고 중간에 RAG를 곁들인) 은행용 콜봇을 한번 만들어보려고 합니다.
https://huggingface.co/mlx-community/chatterbox-fp16
mlx-community/chatterbox-fp16 · Hugging Face
mlx-community/chatterbox-fp16 This model was converted to MLX format from ResembleAI/chatterbox-turbo using mlx-audio version 0.2.7. Refer to the original model card for more details on the model. Use with mlx pip install -U mlx-audio Voice Cloning: mlx_au
huggingface.co

1. 프로젝트 개요
이번 프로젝트의 목표는 국민은행 금융 상품에 대한 고객 문의를 처리할 수 있는 음성 기반 상담 봇을 구현하는 것입니다. 단순한 FAQ 봇이 아닌, 실제 상품설명서와 안내장을 기반으로 정확한 정보를 제공하는 RAG 시스템을 결합했습니다.
핵심 설계 원칙은 레이턴시 최적화입니다. Voice AI 분야에서 응답 지연은 사용자 경험을 좌우하는 가장 중요한 요소입니다. 인간의 자연스러운 대화에서 발화 간 간격은 약 200-300ms 정도인데 이 간격이 500ms를 넘어가면 사용자는 "느리다"고 인식하기 시작하고, 1초를 넘으면 연결에 문제가 있다고 느끼게 됩니다. 현재 대부분의 Voice AI 플랫폼은 2~3초 왕복 지연을 보이는데, 이번 프로젝트에서는 1.5초 이내의 응답 시간을 목표로 설정했습니다.
2. 레이턴시 목표
각 단계별 예상 소요 시간을 정리하면 다음과 같습니다:
| 단계 | 예상 시간 | 비고 |
| VAD + 발화 종료 감지 | 100-200ms | 너무 짧으면 끊김, 너무 길면 지연 |
| STT(Whisper V3 Large) | 200-400ms | 발화 길이에 따라 변동 |
| RAG 검색 + 리랭킹 | 100-200ms | 로컬 실행, 캐싱 적용 |
| LLM 응답 (GPT-4o-mini) | 300-500ms | TTFT 기준, 네트워크 상태 의존 |
| TTS (Chatterbox) | 200-400ms | 첫 청크 생성 기준 |
| 총 예상 시간 | 900-1700ms | 목표 범위 내 |
물론 이는 이상적인 시나리오이고, 실제로는 네트워크 상태, 발화 길이, 질문 복잡도 등에 따라 달라질 수 있습니다. 지속적인 모니터링과 최적화가 필요한 부분입니다. 콜봇에서 1.5초 이내의 응답 시간을 달성하기 위해 다음과 같은 최적화 전략을 적용합니다.
1️⃣ 스트리밍 처리
STT의 경우 VAD를 활용하여 발화 종료를 빠르게 감지하고, TTS 역시 전체 응답을 기다리지 않고 첫 문장이 생성되는 즉시 음성 합성을 시작하는 방식으로 체감 지연을 줄입니다.
2️⃣ 프리페칭 & 캐싱
자주 사용되는 인사말, 확인 문구 등은 미리 음성을 생성해두고 캐싱합니다. "네, 알겠습니다", "잠시만 기다려주세요" 같은 filler 문구를 즉시 재생하면서 실제 응답을 준비하면 사용자 체감 대기 시간을 크게 줄일 수 있습니다.
3️⃣ 모델 최적화
M3의 18GB 통합 메모리 환경에서 여러 모델을 동시에 올리기 위해, 가능한 경우 양자화된 모델을 사용합니다. Whisper는 mlx 최적화 버전을, BGE-M3는 FP16으로 로드하여 메모리 사용량을 관리합니다.
4️⃣ 파이프라인 병렬화
STT → RAG → LLM → TTS의 순차 처리 대신, 가능한 부분을 병렬로 진행합니다. 예를 들어 STT가 부분 결과를 출력하는 시점에 RAG 검색을 미리 시작할 수 있습니다.
3. 기술 스택
개인적을 보유한 MacBook Pro M3, 18GB 통합 메모리라는 제약 조건하에서 LLM API(GPT-4o-mini) 호출을 제외한 나머지를 로컬에서 서빙할 예정입니다. 해당 프로젝트의 아키텍처는 크게 (1) 음성파이프라인 (2) RAG 파이프라인으로 구성되어 있습니다.
(1) 음성 파이프라인
| 구성요소 | 선택모델 | 역할 |
| STT(Speech-to-Text) | Whisper V3 Large | 고객 음성을 텍스트로 변환 |
| LLM | GPT-4o-mini | 문맥 이해 및 응답 생성 |
| TTS(Text-to-Speech) | Chatterbox | 응답 텍스트를 음성으로 합성 |
- STT: Whisper V3 Large
OpenAI의 Whisper는 현재 오픈소스 STT 모델 중 가장 검증된 선택지입니다. V3 Large 모델은 한국어 인식 성능이 우수하며, mlx-whisper를 통해 Apple Silicon에서 최적화된 추론이 가능합니다. 실시간 스트리밍 방식으로 음성을 처리하면 전체 발화가 끝나기 전에 부분적인 transcription을 얻을 수 있어 레이턴시를 줄일 수 있습니다.
- LLM: GPT-4o-mini
로컬 LLM 대신 GPT-4o-mini를 선택한 이유는 명확합니다. 콜봇 시나리오에서는 한국어 자연어 이해 능력과 응답 품질이 중요한데, 현재 로컬에서 구동 가능한 7B-13B 급 모델들은 아직 이 수준에 미치지 못합니다. GPT-4o-mini는 빠른 응답 속도(TTFT 기준 200-400ms)와 합리적인 비용, 그리고 안정적인 한국어 성능을 제공합니다.
- TTS: Chatterbox
Resemble AI에서 공개한 Chatterbox는 MIT 라이선스의 오픈소스 TTS로, 한국어를 포함한 23개 언어를 지원합니다. 특히 최근 출시된 Chatterbox-Turbo 모델은 350M 파라미터의 경량화된 아키텍처로, 음성 합성 속도를 크게 개선했습니다. Apple Silicon에서 MPS 가속을 활용할 수 있어, M3 맥북에서도 실시간에 가까운 음성 생성이 가능합니다.
Chatterbox의 또 다른 장점은 Voice Cloning 기능입니다. 10초 정도의 참조 음성만 있으면 해당 목소리를 복제하여 일관된 상담원 음성을 유지할 수 있습니다. 은행 콜봇의 경우 전문적이고 친근한 느낌의 표준 음성을 미리 녹음해두고 사용할 계획입니다.
(2) RAG 파이프라인

| 구성요소 | 선택모델 | 역할 |
| PDF 파싱 | Docling + GPT-4o-mini | 문서 구조 추출 및 재파싱 |
| Embedding | BGE-M3 | 문서 및 쿼리 벡터화 |
| Reranker | bge-reranker-v2-m3 | 검색 결과 재순위화 |
| Vector DB | Qdrant | 임베딩 벡터 저장 및 검색 |
- Embedding & Reranking: BGE-M3 계열
BGE-M3는 다국어 지원이 뛰어난 임베딩 모델로, 한국어 금융 문서에 대해서도 좋은 성능을 보입니다. Dense, Sparse, Multi-vector 세 가지 검색 방식을 모두 지원하여 하이브리드 검색 구현에 유리합니다.
Reranking에는 bge-reranker-v2-m3를 사용합니다. 임베딩 기반 검색이 recall은 높지만 precision이 떨어지는 경우가 많은데, cross-encoder 기반의 리랭커가 이를 보완해줍니다. 특히 금융 상품처럼 정확한 정보 전달이 중요한 도메인에서는 리랭킹 단계가 답변 품질에 큰 영향을 미칩니다.
- Vector DB: Qdrant
Qdrant는 Rust로 작성된 고성능 벡터 데이터베이스로, 로컬 환경에서 Docker 없이도 간편하게 실행할 수 있습니다. BGE-M3의 Dense, Sparse 벡터를 모두 저장하고 하이브리드 검색을 수행하는 데 적합하며, 필터링과 페이로드 기능이 잘 갖춰져 있어 상품명, 카테고리 등 메타데이터 기반 필터링에 유리합니다. 무엇보다 Python 클라이언트가 직관적이고 문서화가 잘 되어 있어 빠른 프로토타이핑에 적합합니다.
4. 구현 단계
[RAG 파이프라인]
(1) 구현 1: PDF 파싱 - Docling + GPT-4o 2단계 파싱
- 왜 2단계 파싱인가?

국민은행 상품설명서의 특성상 단순한 PDF 파서로는 한계가 있습니다. 금융 문서들은 대체로 다단 레이아웃, 복잡한 표, 박스 안의 주의사항, 각주 등이 뒤섞여 있어서 일반적인 텍스트 추출로는 문맥이 깨지기 쉽습니다. 예를 들어 "금리 연 3.5%"라는 정보가 어떤 조건에 해당하는지, 표의 어느 행에 속하는지가 중요한데, 단순 추출로는 이런 관계가 사라집니다.
이 문제를 해결하기 위해 요즘 많이 사용하는 방식인 2단계 파싱을 적용했습니다.
- 1단계: Docling으로 구조 추출
IBM에서 개발한 Docling은 PDF의 레이아웃을 분석하여 테이블, 섹션, 리스트 등의 구조를 인식합니다. 특히 테이블 추출 성능이 뛰어나서 금융 문서의 금리표, 수수료표 등을 잘 잡아냅니다. Docling은 CPU 기반으로 동작하기 때문에 M3 맥북에서도 무리 없이 실행됩니다.
Docling의 출력은 Markdown 형태로 얻을 수 있는데, 이 단계에서 대략적인 구조는 잡히지만 다단 레이아웃이 섞인 부분이나 복잡한 박스 구조는 여전히 정리가 필요합니다.
- 2단계: GPT-4o로 재파싱
Docling의 출력물과 원본 PDF 페이지 이미지를 함께 GPT-4o에 전달하여 재파싱합니다. GPT-4o의 비전 능력을 활용하면 Docling이 놓친 레이아웃 관계나 문맥을 보완할 수 있습니다. 프롬프트에서는 금융 문서의 특성을 명시하고, 조건별 금리, 우대 조건, 주의사항 등의 관계를 명확히 구분해달라고 지시합니다.
이 방식의 장점은 VLM이 시각적 레이아웃을 직접 보면서 판단하기 때문에, "이 금리가 어떤 조건에 해당하는지" 같은 맥락을 더 정확하게 파악한다는 점입니다. 비용이 추가로 들지만, 금융 정보의 정확성이 중요한 만큼 충분히 가치 있는 투자입니다.
PARSING_PROMPT = """
## 작업 지시
Docling으로 1차 파싱한 마크다운과 원본 PDF 이미지를 비교하여,
더 정확하고 구조화된 마크다운으로 재작성해주세요.
### 1차 파싱 결과
```markdown
{docling_markdown}
```
### 재파싱 원칙
1. **정보 보존**: 원본의 모든 정보를 빠짐없이 포함
2. **구조 교정**: 다단 레이아웃으로 인해 잘못 연결된 텍스트 수정
3. **테이블 정확성**: 표의 헤더-데이터 관계가 맞는지 이미지와 대조하여 검증. 통합셀이 있을 경우 어떤게 어떤 것의 하위 내용인지를 명확히 파악.
4. **테이블 평문화**: 테이블은 풀어서 평문 또는 또는 나열식으로 작성. 이미지에 없는 말은 적으면 안 됨.
5. **섹션 구분**: 명확한 헤딩(##, ###)으로 섹션 구분
6. **원문 유지**: 금리, 금액, 조건 등은 원본 표현 그대로 유지
### 출력 형식
- 정제된 마크다운만 출력
- 추가 설명이나 코멘트 없이 문서 내용만
- 섹션별로 적절한 헤딩 레벨 사용
- 불릿/번호 리스트 적절히 활용"""
```
상단의 프롬프트가 바로 GPT-4o-mini를 이용하여 재파싱할 때 사용하는 프롬프트입니다. docling을 이용해 파싱한 텍스트와 pdf를 이미지로 함께 입력하여 문서에 대한 더욱 깊이 있는 이해와 해석을 담아 파싱 작업을 수행합니다. 아래는 2단계 파싱을 통해 KB내맘대로적금 안내장을 마크다운으로 정제한 결과입니다. 다양한 이미지, 다단 등으로 docling, pymupdf 같은 일반 OCR로는 쉽지 않았던 문서가 온전히 파싱된 것을 볼 수 있습니다.
## KB내맘대로적금
### 상품 개요
- **가입대상**: 만 14세 이상의 실명의 개인 (공동명의 불가)
- **가입금액**: 1만원 이상
- **가입기간**: 6개월부터 36개월까지 선택 가능
- **금리**: 최고 연 3.55% (36개월 기준, 2025.12.24 기준, 세금공제 전, 우대금리 포함)
### 금리 안내
**기본금리:**
- 6개월: [기본금리 명시 필요]
- 12개월: [기본금리 명시 필요]
- 24개월: [기본금리 명시 필요]
- 36개월: 연 3.55%
**우대금리:**
- 특정 조건 충족 시 우대금리 제공 (조건 상세 필요)
### 주요 특징
- 고객이 직접 상품 요건을 설계하여 가입할 수 있는 비대면 채널 전용 DIY(Do-It-Yourself)형 상품
- 다양한 옵션(우대이율, 부가서비스 등)을 제공
### 저축 방법
- **자유적립식**: 매월 1만원 이상 300만원 이하 금액을 자유롭게 저축
- **정액적립식**: 신규 시 약정한 월 1만원 이상의 저축금액을 매월 약정한 날짜에 동일하게 저축
### 부가서비스
- **보험서비스**: 신규 시 보험가입 및 개인(신용)정보의 제3자 제공에 동의한 고객 대상
- 보장기간: 보험개시일로부터 1년 (1년 단위 갱신, 적금 계약기간 초과 불가)
- 보험내용: 4가지 플랜 중 선택 가능
- **플랜A[휴대폰]**: 휴대폰 수리비 보상보험, 최대 30만원 (1인당/사고 당)
- **플랜B[피싱]**: 보이스피싱, 최대 1천만원
- **플랜C[교통]**: 교통상해사망 후유장해, 최대 3천만원
- **플랜D[여행]**: 해외여행 중 상해사망 후유장해, 최대 1억원
### 가입 방법
- **신규**: KB스타뱅킹, 개인 인터넷뱅킹
- **해지**: KB스타뱅킹, 인터넷뱅킹, 영업점, 고객센터
### 유의사항
- 만기 자동해지 신청 가능
- 예금은 공동명의로 가입할 수 없음
- 전자금융거래 제한계좌 등록 불가
- 통장 발행을 원하는 경우 영업점 방문 필요 (수수료 부과)
- 만기 전 해지 시 중도해지이율 적용
### 기타
- **예금자 보호**: 예금자보호법에 따라 원금과 소정의 이자를 합하여 1인당 1억원까지 보호
- **세제혜택**: 비과세종합저축으로 가입 가능 (세법 개정 시 세율 변경 가능)
- **상품내용 변경**: 2022.3.8, 2022.11.11, 2024.1.19, 2024.02.22에 변경 사항 있음
(2) 구현 2: 의미 단위 청킹과 합성 Q&A 데이터
1️⃣ 청킹 전략(Semantic Chunking)
금융 문서는 자연스러운 의미 단위가 명확한 편입니다. 상품 개요, 가입 대상, 금리, 우대 조건, 수수료, 유의사항 등 섹션이 구분되어 있어서 이를 기준으로 청킹합니다.
고정 토큰 수로 자르는 방식은 "금리는 연 3.5%이며"와 "우대금리 적용 시 최대 4.0%입니다"가 서로 다른 청크로 분리되는 문제가 생길 수 있습니다. 의미 단위 청킹은 이런 정보가 하나의 청크에 포함되도록 보장합니다.
다만 의미 단위가 너무 길 경우(예: 긴 약관 섹션) 적절히 분할하되, 문맥이 유지되도록 오버랩을 적용합니다. 시멘틱 청킹의 경우, langchain 등 라이브러리에서 일반적인 방법론을 제공해주지만, 은행 상품안내장에 특화하는 방법을 찾아볼 예정입니다.
2️⃣ 합성 Q&A 데이터 생성
콜봇의 특성상 사용자 쿼리는 구어체입니다. "이 적금 중도해지하면 이자 어떻게 돼요?", "비대면으로 가입 가능해?" 같은 표현을 사용하는데, 원본 문서는 "중도해지 시 중도해지이율 적용", "영업점 및 비대면 채널 가입 가능"처럼 문어체입니다. 이 간극 때문에 임베딩 기반 검색에서 매칭이 잘 안 되는 경우가 많습니다.
이 문제를 해결하기 위해 각 청크에서 합성 Q&A 데이터를 생성합니다. GPT-4o를 사용하여 각 청크의 내용을 바탕으로 고객이 실제로 물어볼 법한 질문들을 생성하고, 해당 청크의 정보를 활용한 답변을 함께 만듭니다.
생성 시 질문 유형을 다양화합니다:
- 단순 조회형: "금리가 얼마야?", "가입 기간이 어떻게 돼?"
- 비교형: "다른 적금이랑 뭐가 달라?", "예금이랑 뭐가 좋아?"
- 조건 확인형: "비대면으로도 가입 돼?", "20대도 가입할 수 있어?"
- 상황형: "중도해지하면 어떻게 돼?", "만기 전에 돈이 필요하면?"
이렇게 생성된 Q&A 쌍을 원본 청크와 함께 저장하면, 사용자의 구어체 질문이 들어왔을 때 유사한 합성 질문과 매칭되어 관련 청크를 더 잘 찾아올 수 있습니다.
3️⃣ 메타데이터 태깅
각 청크와 Q&A에는 다음 메타데이터를 태깅합니다:
- 상품명, 상품 카테고리 (예금, 적금, 대출 등)
- 섹션 유형 (금리, 가입조건, 우대조건, 유의사항 등)
- 문서 갱신일
- 질문 유형 (단순조회, 비교, 조건확인, 상황 등)
이 메타데이터는 Qdrant의 필터링 기능과 결합하여, 예를 들어 "적금 상품의 금리 관련 정보만 검색"하는 식으로 검색 범위를 좁힐 수 있게 해줍니다.
[음성 파이프라인]
(3) 구현 3: 음성 파이프라인 - STT-LLM-TTS
- 전체 흐름
사용자가 말을 시작하면 다음과 같은 흐름으로 처리됩니다:

- 음성 입력 감지: VAD로 발화 시작/종료 감지
- STT 처리: Whisper V3 Large로 음성→텍스트 변환
- RAG 검색: 변환된 텍스트로 관련 문서 검색 + 리랭킹
- LLM 응답 생성: 검색 결과와 함께 GPT-4o-mini로 응답 생성
- TTS 합성: Chatterbox로 응답 텍스트→음성 변환
- 음성 출력: 생성된 음성 재생
- STT 구현 상세
Whisper V3 Large는 mlx-whisper를 통해 Apple Silicon에서 실행합니다. 핵심은 스트리밍 처리인데, 전체 발화가 끝날 때까지 기다리지 않고 VAD로 발화 종료를 감지하는 즉시 처리를 시작합니다.
VAD 설정이 중요합니다. 발화 종료 판정 시간(silence duration)을 너무 짧게 잡으면 사용자가 잠시 멈춘 것을 발화 종료로 오인하고, 너무 길게 잡으면 불필요한 대기 시간이 생깁니다. 보통 300~500ms 정도의 무음 구간을 발화 종료로 판정합니다.
- TTS 구현 상세
Chatterbox는 Apple Silicon에서 MPS 가속을 사용할 수 있지만, 현재 버전에서는 MPS 호환성 이슈가 있어 CPU 모드로 폴백되는 경우가 있습니다. 안정성을 위해 CPU 모드로 실행하되, Chatterbox-Turbo 모델을 사용하여 속도를 보완합니다.
레이턴시 최적화를 위해 응답 스트리밍을 적용합니다. LLM이 응답을 생성하는 동안, 첫 문장이 완성되면 바로 TTS를 시작합니다. 사용자는 전체 응답이 완성되기 전에 첫 부분을 먼저 듣게 되어 체감 대기 시간이 줄어듭니다.
- Voice Cloning 설정
콜봇의 일관된 목소리를 위해 참조 음성을 녹음합니다. 10초 분량의 표준 상담원 음성을 준비하여 Chatterbox의 voice cloning 기능을 활용합니다. 녹음 시에는 조용한 환경에서 명확한 발음으로 다양한 문장 유형(평서문, 의문문, 안내문)을 포함시킵니다.
5. 진행 단계(~25.12.28)

- UI를 구성하였고, 스트리밍으로 질문이 도달하는 것 까지 구현하였습니다.
- 다만 답변 생성이 생각보다 늦게 지연이 발생하고 있습니다.
- RAG의 파이프라인을 상품 안내장 원본 청크가 아닌, 상품 안내장을 보고 LLM이 만든 합성데이터Q&A로만 벡터DB를 구성하였습니다. 이런 형식이 콜봇의 답변 형태와 비슷할 것 같아서요. 그런데, 원본 청크도 넣는걸 테스트해보며 고려해봐야 할 것 같습니다.
- 좌측 고객 CRM의 하단에는 실시간 감성 분석 기능을 추가할 예정입니다.
'AI' 카테고리의 다른 글
| [26/1/8~]Agentic Design Patterns: a hands-on guide to building intelligent systems (0) | 2026.01.13 |
|---|---|
| [26/1/5][Book Review]알아서 잘하는 에이전틱 AI 시스템 구축하기(안자나바 비스와스,릭 탈루크다르) (0) | 2026.01.12 |
| [24.12.11]서강대학교 AI•SW대학원 데싸•인공지능전공 합격 (1) | 2024.12.13 |
| [AI]LLM을 활용한 실전 AI 애플리케이션 개발_2장.트랜스포머 아키텍쳐 (1) | 2024.10.04 |
| AI관련 참고자료 (1) | 2024.10.02 |