본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 07. 22:22

나의 AI 음성 에이전트가 환각(Hallucination)을 일으켰던 이유와 해결 방법

요약

AI 음성 에이전트가 발생하는 환각 현상의 원인을 분석하고 이를 해결하기 위한 설계 전략을 다룹니다. 음성 인터페이스의 특수성으로 인한 위험성을 지적하며, 시스템 프롬프트 개선 및 데이터 검증을 통한 해결 방안을 제시합니다.

핵심 포인트

  • 음성 에이전트는 시각적 검증이 어려워 환각이 더 치명적임
  • 시스템 프롬프트에 명확한 지식 경계를 설정해야 함
  • 런타임에 검증된 컨텍스트를 주입하여 출력 범위를 제한해야 함
  • 명시적인 폴백(Fallback) 동작 설계가 필수적임

AI 음성 에이전트의 환각(Hallucination)은 언어 모델(Language Model)이 실시간의 구조화된 데이터(Structured Data)에 기반을 두지 못해, 그럴듯하게 들리지만 사실과 다른 응답을 생성할 때 발생합니다. 음성 에이전트는 사용자가 그 즉시 주장을 확인할 수 있는 시각적 인터페이스가 없기 때문에 유독 취약합니다. 이를 해결하려면 모델의 출력 범위(Output Scope)를 제한하고, 런타임(Runtime)에 검증된 컨텍스트(Context)를 주입하며, 명시적인 폴백(Fallback) 동작을 설계해야 합니다.

나의 음성 에이전트는 실제 배송 기간이 7~10일임에도 불구하고, 사용자에게 주문이 "영업일 기준 2일 이내"에 도착할 것이라고 말했습니다. 자신 있게, 따뜻하게, 하지만 완전히 틀린 정보였습니다.

그 순간 나는 AI 음성 에이전트의 환각을 예외적인 사례(Edge Case)로 취급하는 것을 멈추고, 내가 시스템에 직접 구축한 설계 결함(Design Flaw)으로 취급하기 시작했습니다.

이 글에서는 내 파이프라인(Pipeline)에서 환각을 일으켰던 정확한 원인, 여러 번의 디버깅(Debugging) 세션을 통해 찾아낸 다섯 가지 근본 원인, 그리고 환각 사고를 거의 제로(Zero)에 가깝게 줄인 구체적인 변경 사항들을 다룹니다. 만약 여러분이 GPT-4o, Claude 3.5 Sonnet, 또는 Gemini 1.5 Pro와 같은 LLM(Large Language Model)을 사용하여 음성 에이전트를 구축하고 있다면, 이 분석이 배포 후 겪게 될 수 시간의 고통스러운 디버깅 시간을 아껴줄 것입니다.

AI 음성 에이전트의 환각이란 무엇인가?

AI 음성 에이전트의 환각은 사실과 다르거나, 시대에 뒤떨어지거나, 또는 완전히 조작된 정보를 포함하면서도 자신감 있고 유창하게 응답을 생성하는 것으로 정의됩니다. 환각은 모델이 사실에 기반한 토큰(Token)을 예측하기보다 통계적으로 가장 확률이 높은 다음 토큰을 예측함으로써 작동하며, 이로 인해 권위 있게 들리지만 검증된 데이터와는 연결되지 않은 출력을 생성하게 됩니다.

"환각(Hallucination)"

텍스트 기반 인터페이스(Text-based interfaces)에서는 사용자가 주장을 멈추거나, 다시 읽거나, 교차 검증(Cross-check)할 수 있습니다. 하지만 음성(Voice)에서는 불가능합니다. 에이전트는 말하고 사용자는 듣게 되며, 만약 정보가 틀렸다면 사용자는 검증할 기회를 갖기도 전에 그 정보에 따라 행동하게 됩니다. 이러한 비대칭성(Asymmetry)이 음성 환경에서 환각(Hallucination)을 특히 더 치명적으로 만드는 원인입니다.

근본 원인 1: 시스템 프롬프트(System Prompt)에 지식 경계가 없었음

제가 가장 먼저 확인한 것은 시스템 프롬프트(System prompt)였으며, 돌이켜보니 발견한 내용은 당혹스러울 정도였습니다.

제 프롬프트는 다음과 같은 식이었습니다: "당신은 [Company]의 유능한 고객 서비스 에이전트입니다. 모든 고객의 질문에 친절하고 전문적으로 답변하세요."

이 지침은 모델에게 모든 것에 답변하라고 말하는 것과 같습니다. 모델에게 무엇을 알지 못하는지, 무엇을 추측해서는 안 되는지, 그리고 언제 멈추고 상담원에게 연결(Escalate)해야 하는지에 대한 신호를 전혀 주지 않습니다. 정의된 지식 경계(Knowledge boundary)가 없는 모델은 학습 데이터(Training data)와 합리적인 추론(Inference)을 기본값으로 사용하며, 이는 배송 시간, 가격, 제품 사양과 같은 구체적인 세부 사항을 매우 확신에 찬 태도로 꾸며낼 것임을 의미합니다.

해결 방법: 시스템 프롬프트(System prompt)를 다시 작성하여 경계를 명시적으로 정의하십시오.

당신은 [Company]의 고객 서비스 음성 에이전트입니다. 당신은 오직 아래의 컨텍스트(Context)에 제공된 정보만을 사용하여 질문에 답변해야 합니다. 만약 질문이 제공된 컨텍스트에 포함되어 있지 않다면, 반드시 다음과 같이 말해야 합니다: "현재 해당 구체적인 정보를 가지고 있지 않습니다. 도움을 드릴 수 있는 팀원에게 연결해 드리겠습니다." 컨텍스트에 명시적으로 언급되지 않은 세부 사항을 추정, 추측 또는 추론하지 마십시오.

다른 어떤 수정 사항을 적용하기 전, 이 단 한 번의 변경만으로도 테스트 과정에서 환각(Hallucination) 발생 빈도가 크게 줄어들었습니다. 모델에게 "모릅니다"라고 말할 수 있는 명시적인 허용을 주지 않으면, 모델은 그 공백을 그럴듯한 허구로 계속 채우려 할 것입니다.

다음 글을 읽어보세요: 실제로 작동하는 LLM 시스템 프롬프트 작성하기 (Writing LLM System Prompts That Actually Work)

근본 원인 2: 실시간 컨텍스트 주입 (Real-Time Context Injection) 부재

제 에이전트는 주문, 재고, 가격에 관한 질문에 대해 실제 데이터 소스에 연결되지 않은 상태로, 학습 데이터 (Training Data)와 추론 (Inference)에만 의존하여 답변하고 있었습니다.

지나고 보니 당연한 소리처럼 들릴 것입니다. 하지만 음성 에이전트를 빠르게 배포하려고 서두르다 보면, 데이터 통합 (Data Integration) 단계를 뒤로 미루고 모델이 "충분히 잘 해낼 것"이라고 가정하기 쉽습니다. 하지만 모델은 그렇게 하지 않습니다. 모델은 완전한 확신을 가지고 구체적인 허구 내용을 지어낼 것입니다.

제가 놓치고 있었던 아키텍처는 검색 증강 생성 (Retrieval-Augmented Generation, RAG)이라고 불리며, 음성 에이전트에서는 다음과 같이 작동합니다:

1단계: 사용자의 음성이 텍스트로 전사 (Transcribed)됩니다 (Whisper 또는 Deepgram을 통해).

2단계: LLM이 전사된 질의를 받기 전에, 검색 레이어 (Retrieval Layer)가 구조화된 데이터베이스, 지식 베이스 (Knowledge Base) 또는 API를 검색하여 관련 있는 실시간 컨텍스트 (Real-time Context)를 찾아냅니다.

3단계: 해당 컨텍스트가 명시적이고 출처가 있는 정보로서 프롬프트 (Prompt)에 주입됩니다.

4단계: LLM은 위에서 언급한 시스템 프롬프트 규칙에 따라, 오직 검색된 컨텍스트만을 사용하여 응답을 생성합니다.

def build_prompt_with_context(user_query: str, retrieved_context: dict) -> str:
    context_block = f"""
검증된 컨텍스트 (답변 시 이 정보만 사용하십시오):
...

여기서 핵심 패턴은 검색 레이어가 채울 수 없는 모든 필드에 대해 "사용 불가능 (Not available)"을 명시적인 폴백 (Fallback)으로 설정하는 것입니다. 모델이 "사용 불가능"을 보게 되면, 추측하는 대신 에스컬레이션 (Escalation) 응답을 트리거해야 함을 인지하게 됩니다.

LangChain RAG documentation — 검색 증강 생성 (Retrieval-Augmented Generation)에 관한 LangChain 공식 문서입니다.

근본 원인 3: 사실 기반 작업에 비해 너무 높게 설정된 온도 (Temperature)

Temperature(온도)는 모델의 출력이 얼마나 "창의적(creative)"이거나 "무작위적(random)"인지를 제어하는 파라미터(parameter)입니다. Temperature가 0.0이면 모델은 결정론적(deterministic)으로 동작하여 항상 가장 확률이 높은 토큰(token)을 선택합니다. Temperature가 1.0이면 상당한 무작위성이 도입됩니다.

제 음성 에이전트는 Temperature 0.8로 실행되고 있었습니다. 이는 카피라이팅이나 브레인스토밍과 같은 창의적인 작업에는 합리적인 설정입니다. 하지만 실제 데이터를 바탕으로 질문에 답하는 고객 서비스 에이전트에게는 너무 높습니다.

Temperature가 높을수록 모델은 확률이 낮은 토큰을 샘플링할 가능성이 커지며, 이는 실제로 모델이 강력한 근거(grounding)를 가지고 있지 않을 때 그럴듯하지만 틀린 세부 정보를 생성할 가능성이 높음을 의미합니다. 이는 "흥미로운 아이디어"를 내는 의미에서의 창의성이 아니라, "자신 있게 말을 지어내는" 의미에서의 창의성입니다.

해결 방법:

고객 서비스 음성 에이전트와 같이 사실에 기반한 구조화된 작업의 경우, Temperature를 0.0에서 0.2 사이로 설정하십시오. 문구에 어느 정도 자연스러운 변화를 주어 매번 똑같은 문장만 반복하는 로봇처럼 들리지 않게 해야 하는 에이전트의 경우, 0.1에서 0.3 사이가 실질적인 최적의 지점(sweet spot)입니다.

response = openai.chat.completions.create(
    model="gpt-4o",
    messages=messages,
...

또한 여기에 max_tokens=150을 추가했습니다. 음성 응답은 짧아야 합니다. 응답이 길어지면 환각(hallucination)이 발생할 수 있는 영역이 넓어지고, 실제로 소리 내어 말할 때 부자연스럽게 들립니다.

근본 원인 4: 신뢰도 임계값(Confidence Threshold) 또는 불확실성 신호(Uncertainty Signaling)의 부재

이것은 가장 미묘한 문제였으며, 진단하는 데 가장 오랜 시간이 걸린 문제였습니다.

잘 제약된 시스템 프롬프트(system prompt)와 RAG 컨텍스트 주입(context injection)이 있더라도, 모델은 검색된 컨텍스트(retrieved context)로부터 부분적으로만 답할 수 있는 쿼리(query)를 가끔 받게 됩니다. 모델은 불확실성을 신호하는 대신, 실제 검색된 데이터와 추론된 세부 정보를 혼합하여 일부는 정확하고 일부는 조작된 하이브리드 응답을 생성하곤 했습니다.

사용자는 어떤 부분이 실제인지 알 방법이 없었습니다.

해결 방법은 두 부분으로 나뉩니다.

첫째, 시스템 프롬프트(System Prompt)에서 모델이 자신의 확신도를 명시적으로 라벨링하도록 지시하십시오:

답변할 때, 응답의 어떤 부분이 제공된 컨텍스트(Context)에 직접적으로 명시되지 않은 정보에 기반하고 있다면, 해당 내용을 말하기 전에 반드시 "이 부분에 대해서는 확신할 수 없습니다"라고 말해야 합니다. 단일 응답 내에서 하나 이상의 세부 사항에 대해 확신이 없다면, 추측하는 대신 쿼리 전체를 에스컬레이션(Escalation, 상위 단계로 전달)하십시오.

둘째, 응답이 음성 합성(Text-to-Speech, TTS)으로 넘어가기 전에 출력 검증(Output Validation) 단계를 추가하십시오. 구조화된 응답(주문 상태, 가격, 날짜 등)의 경우, 출력을 파싱(Parse)하고 이를 말하기 전에 알려진 유효 범위와 대조하여 확인하십시오:

def validate_response(response: str, context: dict) -> str:
    # 날짜 일관성 확인
    if context.get('delivery_date') and context['delivery_date'] not in response:
...

이는 간단한 패턴이지만, 제 파이프라인(Pipeline)에서 가장 흔하게 발생하는 환각(Hallucination) 범주인 날짜 및 시간 범위 조작을 잡아냅니다.

읽어보기: How to Build a Reliable RAG Pipeline for Production

근본 원인 5: 모델에 정의된 에스컬레이션 경로가 없었음

제 에이전트의 임무는 모든 질문에 답하는 것이었습니다. 저는 탈출로(Exit ramp)를 만들어 두지 않았습니다.

음성 에이전트에 에스컬레이션 경로가 없으면, 모델은 모든 쿼리를 반드시 답변해야 하는 것으로 취급합니다. 이는 환각 제조 공장과 같습니다. 모델은 악의적인 것이 아니라, 설계된 대로 작업을 수행하고 있는 것입니다. 만약 작업이 "이 질문에 답하라"이고 설계에 "거절 및 에스컬레이션" 옵션이 없다면, 모델은 답하지 말아야 할 때조차 답변을 하게 됩니다.

해결 방법: 에스컬레이션을 일급 객체(First-class) 응답 유형으로 설계하십시오.

저는 시스템 프롬프트에 세 가지 명시적인 에스컬레이션 트리거(Trigger)를 추가했습니다:

  • 검색된 컨텍스트 (Context)에 없는 특정 거래, 주문 또는 계정에 관한 모든 질문
  • 인간의 승인이 필요한 약속(환불, 교체, 배송 보장)에 대한 모든 요청
  • 모델이 내부적으로 불확실하다고 판단한 모든 질의 (근본 원인 4의 신뢰도 신호 (Confidence signaling) 사용)

그리고 저는 에스컬레이션 (Escalation) 응답을 텍스트 음성 변환 (TTS) 파이프라인 내에 전용 경로로 구축했습니다:

ESCALATION_PHRASES = [
    "해당 정보를 확인할 수 없습니다",
    "담당자를 연결해 드리겠습니다",
...

초기에는 에스컬레이션 비율이 높게 느껴졌습니다. 이 변경 사항을 적용한 첫 주에는 질의의 약 15%가 상담원에게 전달되었습니다. 하지만 대안은 15%의 환각 (Hallucination) 비율이었으며, 환각을 일으키는 음성 에이전트는 "도움을 줄 수 있는 사람을 연결해 드리겠습니다"라고 말하는 에이전트보다 사용자 신뢰에 훨씬 더 큰 해를 끼칩니다.

:::tip
에스컬레이션 비율을 실패 지표가 아닌 건강 지표 (Health metric)로 추적하십시오. 실제 운영 중인 음성 에이전트에서 에스컬레이션 비율이 0이라는 것은 성공의 신호가 아니라 위험 신호 (Red flag)입니다. 이는 대개 에이전트가 답변해서는 안 되는 질문을 포함하여 모든 것에 답변하고 있음을 의미합니다.
:::

전체 해결책: 수정된 아키텍처 (Architecture)의 모습

다섯 가지 해결책을 모두 구현한 후, 저의 음성 에이전트 파이프라인은 다음과 같은 모습이 되었습니다:

1단계 — 전사 (Transcription): 사용자의 음성을 캡처하여 전사 (Transcription)를 위해 Whisper 또는 Deepgram으로 전송합니다.

2단계 — 의도 분류 (Intent Classification): 메인 LLM (Large Language Model)에 도달하기 전에 경량 분류기 (Lightweight classifier)가 질의를 분류합니다 (주문 상태, 가격, 일반 FAQ, 에스컬레이션 트리거).

3단계 — 컨텍스트 검색 (Context Retrieval): 의도에 따라 검색 레이어 (Retrieval layer)가 관련 소스 (주문 관리 시스템, 제품 데이터베이스, FAQ 지식 베이스)에서 검증된 데이터를 가져옵니다. 찾을 수 없는 필드는 명시적으로 "사용 불가"로 표시됩니다.

4단계 — 제약 조건이 있는 프롬프트 구성 (Constrained Prompt Construction): 검색된 컨텍스트와 제약 조건이 있는 시스템 프롬프트 (System prompt)를 결합하여 최종 프롬프트를 생성합니다. 온도는 0.1로 설정됩니다.

Step 5 — 출력 검증 (Output Validation): 모델의 응답이 음성 합성 (Text-to-speech) 단계로 넘어가기 전, 검색된 컨텍스트 (Retrieved context)와 구조적 일관성이 있는지 확인합니다.

Step 6 — 에스컬레이션 라우팅 (Escalation Routing): 불확실성 마커 (Uncertainty markers)를 포함하는 응답은 음성으로 출력되는 대신 상담원 대기열 (Human agent queue)로 라우팅됩니다.

Step 7 — 음성 합성 (Text-to-Speech): 검증된 응답은 합성 및 전달을 위해 ElevenLabs 또는 PlayHT로 전송됩니다.


대체 텍스트: "RAG 컨텍스트 주입 및 환각 방지 기능이 포함된 수정된 AI 음성 에이전트 아키텍처"

대부분의 음성 에이전트 튜토리얼이 잘못하고 있는 것

대부분의 튜토리얼은 음성 인식 (Speech-to-text), LLM, 음성 합성 (Text-to-speech)의 세 단계로 음성 에이전트를 구축합니다. 그것은 개념 증명 (Proof of concept)일 뿐, 실제 운영 시스템 (Production system)이 아닙니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0