Amazon Connect에 음성 기반 챗봇

Amazon Connect 음성 챗봇 구현기: LEX (CODEHOOK) 부터 Bedrock 연동까지

Intro

목표
Amazon Connect를 기반으로 음성 챗봇 시스템을 구축하였다. 고객의 발화를 LEX로 처리하고, 의도를 인식하지 못한 fallback 상황에서는 Bedrock을 활용한 LLM을 통해 자연스러운 대화를 이어가는 것이 주 목적이었다.

기술 스택

    • Amazon Connect (음성 기반 콜센터 플랫폼)

    • Amazon Lex V2 (Intent 기반 NLU)

    • Amazon Bedrock (LLM 기반 Open Domain 질의 응답)

    • Lambda (Lex CodeHook 처리)

    • Claude 3 Haiku (LLM 모델)

🛠️ 전체 아키텍처 개요

음성 입력 → Connect Contact Flow → Lex → Lambda (Bedrock 호출) → 응답 생성 → Connect로 응답 전달

🎯 Contact Flow 구성

핵심 블록 흐름

  1. Set Voice

  2. Play Prompt (웰컴 메시지)

  3. Get Customer Input (barge-in 허용)

  4. Invoke Lex Bot

  5. Resume & Redirect (Lambda 응답 기반 재흐름)

  6. Play Prompt (LLM 응답 출력)

💡 포인트

  • FallbackIntent에서 Lambda를 호출

  • Lambda에서 Claude 호출 후 응답 생성

🧩 Lambda Code

 

import json
import boto3

# 서울 리전 Bedrock 클라이언트
bedrock = boto3.client(“bedrock-runtime”, region_name=“ap-northeast-2”)

def lambda_handler(event, context):
    print(“[INFO] Full Lex Event:\n, json.dumps(event, indent=2, ensure_ascii=False))

    # 1. 사용자 발화 추출 (V2 구조 대응 포함)
    user_input = (
        event.get(“inputTranscript”) or
        event.get(“sessionState”, {}).get(“intent”, {}).get(“slots”, {}).get(“utterance”, {}).get(“value”, {}).get(“interpretedValue”) or
        “”
    ).strip()

    print(f“[DEBUG] userInput = {user_input})

    # 2. 발화 없으면 기본 응답
    if not user_input:
        return build_response(
            message=“죄송합니다. 말씀을 정확히 인식하지 못했어요. 다시 말씀해 주세요.”,
            intent_name=event.get(“sessionState”, {}).get(“intent”, {}).get(“name”, “FallbackIntent”)
        )

    # 3. Bedrock용 메시지 구성
    messages = [{ “role”: “user”, “content”: user_input }]
    payload = {
        “anthropic_version”: “bedrock-2023-05-31”,
        “max_tokens”: 512,
        “temperature”: 0.7,
        “messages”: messages
    }

    # 4. Bedrock 호출
    try:
        response = bedrock.invoke_model(
            modelId=“anthropic.claude-3-haiku-20240307-v1:0”,
            body=json.dumps(payload),
            contentType=“application/json”,
            accept=“application/json”
        )
        result = json.loads(response[“body”].read())
        message = result.get(“content”, [{}])[0].get(“text”, “”)
    except Exception as e:
        print(f“[ERROR] Bedrock 호출 실패: {str(e)})
        message = “죄송합니다. 지금은 답변할 수 없어요. 잠시 후 다시 시도해 주세요.”

    # 5. 응답 반환
    return build_response(
        message=message,
        intent_name=event.get(“sessionState”, {}).get(“intent”, {}).get(“name”, “FallbackIntent”)
    )

# ✅ Lex 응답 포맷 생성 함수 (대화 유지)
def build_response(message: str, intent_name: str):
    return {
        “sessionState”: {
            “dialogAction”: {
                “type”: “ElicitIntent”  # ← 핵심 변경: 대화 유지
            },
            “intent”: {
                “name”: intent_name,
                “state”: “Fulfilled”
            }
        },
        “messages”: [
            {
                “contentType”: “PlainText”,
                “content”: message
            }
        ]
    }

🧪 테스트 시나리오

 

  • “여기는 어디야?” → LEX 인식 실패 → Claude가 “여기는 AI 음성봇입니다” 등 자연어 응답

  • “배송 조회하고 싶어” → LEX가 TrackOrderIntent 인식 → 일반 시나리오 흐름

댓글 달기

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

위로 스크롤