Let's Talk

Feel free to reach out. I'll get back to you as soon as possible.

Study15 min

AWS Project4 - AI Chatbot

AWS+Terraform로 구축한 고객 서비스 AI 챗봇에 대해 설명합니다.

AWS Project4 - AI Chatbot

Project 4: 고객 서비스 AI 챗봇 (Lambda + Gemini/Bedrock + DynamoDB)

Terraform으로 구축한 고객 서비스 AI 챗봇 인프라입니다. 사용자가 웹 UI 또는 REST API로 메시지를 보내면 Lambda가 DynamoDB에서 최근 대화 이력을 불러와 Google Gemini 또는 AWS Bedrock Claude에 전달하고, AI 응답을 반환합니다. 대화 이력은 TTL 24시간으로 자동 만료되어 세션별 다중 턴(Multi-turn) 대화가 자연스럽게 이어집니다.

상담원 연결 요청이나 욕설이 감지되면 SNS를 통해 담당자 이메일로 즉시 에스컬레이션 알림이 발송됩니다. 웹 UI는 S3(비공개 버킷) + OAC + CloudFront HTTPS로 서빙되어 안전하게 브라우저에서 접근할 수 있습니다. AI 엔진은 variables.tf 한 줄로 Gemini와 Bedrock 간 전환이 가능하여, 무료 할당량 소진 시 유연하게 대응할 수 있습니다.


아키텍처

[웹 UI]                  [REST API]
 브라우저                  curl / 외부 앱
    │                          │
    └──────────┬───────────────┘

        API Gateway (HTTP v2)

        Lambda (챗봇 로직)
        ┌──────────────────────────────────────────────┐
        │ 1. DynamoDB 대화 이력 조회 (최근 10턴)         │
        │ 2. System Prompt + 이력 조립                  │
        │ 3. AI 호출 (Gemini / Bedrock)                 │
        │    └─ Gemini 키: SSM Parameter Store          │
        │       (Cold Start 시 1회 조회 후 캐시)         │
        │ 4. 응답 라우팅                                 │
        │    (정상 · 에스컬레이션 · 욕설 · fallback)      │
        │ 5. DynamoDB 대화 이력 저장 (TTL 24h)           │
        └──────────────────────────────────────────────┘
             │                    │
         DynamoDB            Gemini API
         (대화 이력)           or Bedrock

             ▼ (에스컬레이션 / 욕설 감지 시)
           SNS → 이메일 알림

웹 UI: S3 (비공개) ─── OAC ───▶ CloudFront (HTTPS)

주요 구성 요소

리소스 설명 비용
Lambda (챗봇) API Gateway 요청 수신 → DynamoDB 이력 조회 → AI 호출 → 응답 라우팅 → 이력 저장. 5단계 로직을 단일 함수에서 처리 프리 티어: 월 1,000,000 요청
DynamoDB 세션 ID 기반 대화 이력 저장. TTL 24시간 자동 만료로 스토리지 누적 없음 프리 티어: 25GB / 월
API Gateway (HTTP v2) 웹 UI·curl 요청을 Lambda에 프록시 통합으로 전달하는 HTTP API(v2). /v1/chat 엔드포인트 프리 티어: 월 1,000,000 호출
S3 + CloudFront (OAC) S3 버킷을 비공개로 유지하고 OAC(Origin Access Control)를 통해 CloudFront에서만 접근. HTTPS 강제 제공 프리 티어: S3 5GB / 월
SSM Parameter Store Gemini API 키를 SecureString으로 안전하게 저장. Lambda는 Cold Start 시 1회 조회 후 컨테이너 수명 동안 메모리에 캐시 표준 파라미터: 무료
SNS 에스컬레이션·욕설 감지 시 등록 이메일로 즉시 알림 발송 프리 티어: 월 1,000건 이메일
CloudWatch Lambda 실행 로그, 호출 수, 응답 시간 대시보드 제공 프리 티어: 5GB 로그 수집

사전 준비

IAM 사용자 생성

AWS CLI와 Terraform이 AWS 리소스를 생성할 수 있도록 프로그래밍 방식 액세스 권한을 가진 IAM 사용자가 필요합니다.

1단계: IAM 사용자 생성

AWS 콘솔에서 IAM → 사용자 → 사용자 생성으로 이동합니다. 사용자 이름(예: terraform-admin)을 입력하고, AWS Management Console 액세스는 체크하지 않습니다 (CLI 전용 사용자이므로 콘솔 로그인 권한 불필요).

2단계: AdministratorAccess 권한 부여

권한 설정 단계에서 직접 정책 연결을 선택하고 AdministratorAccess 정책을 검색하여 체크합니다.

⚠️ AdministratorAccess는 실습/테스트용 편의 설정입니다. 실제 운영 환경에서는 최소 권한 원칙에 따라 필요한 서비스만 허용하는 커스텀 정책을 사용하세요.

3단계: 액세스 키(Access Key) 발급 및 저장

사용자 생성 후 해당 사용자 → 보안 자격 증명 → 액세스 키 만들기로 이동합니다. 사용 사례로 **Command Line Interface(CLI)**를 선택합니다. 발급된 액세스 키 ID시크릿 액세스 키는 이 화면에서만 확인 가능하므로, CSV를 다운로드하거나 별도로 메모해 두세요. 화면을 닫으면 시크릿 키는 다시 볼 수 없습니다.


AWS CLI v2 설치

# Linux / macOS의 경우
brew install awscli
aws --version
# Windows의 경우
winget install Amazon.AWSCLI
aws --version

Terraform 설치

# Linux / macOS의 경우

# 1. HashiCorp 저장소 추가
brew tap hashicorp/tap

# 2. Terraform 설치
brew install hashicorp/tap/terraform
terraform --version
# Windows의 경우
winget install Hashicorp.Terraform
terraform --version

설치 후 주의사항

  • Windows winget 약관 동의: winget 명령어를 처음 사용하면 중간에 ‘소스 약관에 동의하십니까?’ 라는 질문(Y/N)이 뜰 수 있습니다. Y를 입력하고 엔터를 누르면 계속 진행됩니다.

  • 버전 확인 에러 발생 시: 설치가 완료된 직후 aws --version이나 terraform --version을 입력했을 때 *‘명령어를 찾을 수 없다’*고 나온다면, 터미널(또는 PowerShell) 창을 완전히 닫고 새로 열어 다시 입력해 보세요. 환경 변수가 새로고침되어 정상 동작합니다.

  • VSCode 사용 시: 터미널 탭만 닫는 것이 아니라 VSCode 창 전체를 완전히 껐다가 다시 켜야 합니다.


Google Gemini API 키 발급

이 프로젝트의 기본 AI 엔진은 Google Gemini입니다. 배포 전에 API 키를 먼저 발급받아야 합니다.

  1. https://aistudio.google.com/apikey 에 접속합니다.
  2. “Create API Key” 버튼을 클릭합니다.
  3. 생성된 키(AIzaSy... 형태)를 복사해 두세요.

Google 계정으로 로그인되어 있어야 합니다. API 키는 이 화면에서 언제든 재확인할 수 있습니다.


배포 가이드

Step 0. AWS CLI 자격증명 등록

aws configure
# AWS Access Key ID:     <발급받은 Access Key ID>
# AWS Secret Access Key: <발급받은 Secret Access Key>
# Default region name:   ap-northeast-2
# Default output format: json

연결 확인:

aws sts get-caller-identity

Step 1. Gemini API 키 발급

https://aistudio.google.com/apikey 에 접속하여 “Create API Key” 를 클릭하고 키를 복사합니다.


Step 2. Gemini API 키를 SSM Parameter Store에 저장

aws ssm put-parameter `
  --name "/cloud-portfolio/gemini-api-key" `
  --value "<your-gemini-api-key>" `
  --type SecureString `
  --region ap-northeast-2
  • 이미 파라미터가 존재하는 경우 --overwrite 플래그를 추가하세요.
  • Lambda는 Cold Start 시 이 경로에서 키를 읽고 컨테이너 수명 동안 메모리에 캐시합니다. 재배포 없이 키를 교체하면 다음 Cold Start 시 자동으로 새 키가 로드됩니다.

Step 3. variables.tf 수정

project4-ai-chatbot/variables.tf 파일을 열어 아래 세 변수를 수정합니다.

변수 설명 예시
suffix S3 버킷 이름 뒤에 붙는 고유 식별자. 전 세계에서 유일해야 하므로 이름+날짜 조합 권장 <your-name>-<date>
alert_email 에스컬레이션·욕설 감지 시 알림을 받을 이메일 주소 your@email.com
company_name 챗봇 System Prompt에 표시될 서비스 이름 (선택) 내 쇼핑몰

gemini_api_keyvariables.tf에 없습니다 — Step 2에서 SSM Parameter Store에 저장합니다.


Step 4. 인프라 배포

프로젝트 폴더로 이동 후 순서대로 실행합니다.

cd project4-ai-chatbot
terraform init    # Provider 플러그인 다운로드 (최초 1회)
terraform plan    # 생성될 리소스 미리보기
terraform apply   # 실제 배포, 확인 프롬프트에 'yes' 입력

배포가 완료되면 터미널에 Outputs이 출력됩니다. 아래 값들을 메모해 두세요.

chat_api_endpoint          = "https://<api-id>.execute-api.ap-northeast-2.amazonaws.com/v1/chat"
chatbot_ui_url             = "https://<distribution-id>.cloudfront.net"
ui_upload_command          = "aws s3 sync ./website/ s3://p4-chatbot-ui-<suffix>/ --delete"
cache_invalidation_command = "aws cloudfront create-invalidation --distribution-id <distribution-id> --paths '/*'"
dynamodb_table             = "p4-chatbot-sessions"

p4-terraform1

p4-terraform2

p4-terraform3


Step 5. SNS 구독 확인 이메일 클릭

terraform apply 완료 후 alert_emailSNS Subscription Confirmation 이메일이 옵니다. 메일 안의 “Confirm subscription” 링크를 클릭해야 에스컬레이션 알림이 실제로 수신됩니다.

이 단계를 건너뛰면 테스트 시나리오 ③ (에스컬레이션 트리거)에서 이메일이 오지 않습니다.


Step 6. 웹 UI API 엔드포인트 설정

website/index.html을 열어 아래 줄을 Step 4 출력의 chat_api_endpoint 값으로 교체합니다.

// 수정 전
const API_ENDPOINT = "https://xxxxx.execute-api.ap-northeast-2.amazonaws.com/v1/chat";

// 수정 후 (terraform output chat_api_endpoint 값으로 교체)
const API_ENDPOINT = "https://abc12345de.execute-api.ap-northeast-2.amazonaws.com/v1/chat";

Step 7. 웹 UI S3 업로드 + CloudFront 캐시 무효화

# Step 4 출력의 ui_upload_command 실행
aws s3 sync ./website/ s3://p4-chatbot-ui-<suffix>/ --delete

# Step 4 출력의 cache_invalidation_command 실행
aws cloudfront create-invalidation --distribution-id <distribution-id> --paths "/*"

Step 8. 브라우저 접속

Step 4 출력의 chatbot_ui_url을 브라우저에서 열면 채팅 UI가 표시됩니다.

예: https://<distribution-id>.cloudfront.net

테스트 시나리오

테스트 전 아래 명령으로 chat_api_endpoint 값을 확인하고 메모해 두세요. 아래 예시의 <api-id> 자리에 실제 값을 넣어 사용합니다.

cd project4-ai-chatbot
terraform output -raw chat_api_endpoint

Windows PowerShell 참고: curl.exe-d 인자로 JSON을 전달할 때 내부 따옴표는 \" 로 이스케이프해야 합니다. 아래 예시는 모두 이 방식을 사용합니다.


① 기본 대화

챗봇이 정상 응답하는지 확인합니다.

curl.exe -X POST "https://<api-id>.execute-api.ap-northeast-2.amazonaws.com/v1/chat" `
  -H "Content-Type: application/json" `
  -d '{\"message\": \"반품은 어떻게 하나요?\", \"session_id\": \"test-001\"}'

예상 응답:

{"response": "반품 정책 안내 메시지...", "session_id": "test-001", "escalated": false}

escalated: false 가 포함되어 있으면 정상입니다.


② 대화 이력 연속성 확인

같은 session_id로 두 번 연속 요청하여 두 번째 응답이 첫 번째 메시지 내용을 기억하는지 확인합니다.

# 1번째 메시지 — 주문 번호 전달
curl.exe -X POST "https://<api-id>.execute-api.ap-northeast-2.amazonaws.com/v1/chat" `
  -H "Content-Type: application/json" `
  -d '{\"message\": \"제 주문 번호는 12345입니다.\", \"session_id\": \"test-003\"}'

# 2번째 메시지 — 이전 대화 기억 여부 확인
curl.exe -X POST "https://<api-id>.execute-api.ap-northeast-2.amazonaws.com/v1/chat" `
  -H "Content-Type: application/json" `
  -d '{\"message\": \"제 주문 번호가 뭐였죠?\", \"session_id\": \"test-003\"}'

2번째 응답에서 “12345” 를 언급하면 DynamoDB 대화 이력이 정상 동작하는 것입니다.


③ 에스컬레이션 트리거

상담원 연결 요청 문구를 보내 escalated: true 응답과 이메일 알림을 확인합니다.

curl.exe -X POST "https://<api-id>.execute-api.ap-northeast-2.amazonaws.com/v1/chat" `
  -H "Content-Type: application/json" `
  -d '{\"message\": \"상담원 연결해 주세요.\", \"session_id\": \"test-002\"}'

예상 응답:

{"response": "상담원에게 연결 중입니다...", "session_id": "test-002", "escalated": true}

alert_email로 설정한 주소로 에스컬레이션 알림 이메일이 수신되는지 함께 확인하세요.


④ DynamoDB 대화 이력 직접 확인

DynamoDB에 대화 이력이 실제로 저장되었는지 CLI로 직접 조회합니다.

aws dynamodb query `
  --table-name p4-chatbot-sessions `
  --key-condition-expression "session_id = :sid" `
  --expression-attribute-values "{\":sid\":{\"S\":\"test-003\"}}" `
  --region ap-northeast-2

test-003 세션의 대화 항목들이 출력되면 정상입니다.


검증 체크리스트

  • terraform outputchat_api_endpoint, chatbot_ui_url 값이 출력됨
  • curl 기본 대화 테스트에서 escalated: false 응답 확인
  • 같은 session_id로 연속 호출 시 이전 대화 내용(주문 번호 등) 기억 확인
  • “상담원 연결해 주세요” 요청 시 escalated: true 응답 + 이메일 알림 수신 확인
  • DynamoDB query 명령으로 대화 이력 레코드 저장 확인
  • 브라우저에서 CloudFront URL 접속 시 웹 UI 채팅 정상 동작 확인

⚠️ 비용 관리

서비스별 프리 티어 범위

서비스 프리 티어 한도 초과 시 단가
Lambda 월 1,000,000 요청 / 400,000 GB-초 $0.20 / 백만 요청
DynamoDB 25GB 스토리지 / 월 200만 읽기·쓰기 $0.25 / WCU, $0.10 / RCU
API Gateway (HTTP v2) 월 1,000,000 호출 (12개월) $1.00 / 백만 호출
S3 (UI 버킷) 5GB 스토리지 / 월 20,000 GET, 2,000 PUT $0.023 / GB
CloudFront 월 1TB 전송 / 10,000,000 요청 (12개월) $0.0085 / GB
SSM Parameter Store 표준 파라미터 무제한 고급 파라미터: $0.05 / 파라미터-월
SNS 월 1,000건 이메일 $2.00 / 100,000건
CloudWatch 5GB 로그 수집 / 3개 대시보드 $0.50 / GB
Gemini API 무료 할당량 제공 (aistudio.google.com 에서 확인) 모델별 상이
Bedrock Claude (전환 시) 프리 티어 없음 테스트 규모 기준 약 $1~3/월

Gemini 무료 할당량: Google AI Studio의 Gemini API는 일정 수준의 무료 호출 할당량을 제공합니다. 현재 한도는 aistudio.google.com/apikey 에서 확인할 수 있습니다. 소규모 테스트 기준으로는 무료 범위 내에서 충분히 사용 가능합니다.

Bedrock 전환 시 주의: Bedrock Claude는 프리 티어가 없으므로 토큰 사용량에 따라 비용이 발생합니다. 테스트 규모(수십수백 회 호출)에서는 $13/월 수준입니다.


트러블슈팅 노트

1. Gemini API 키가 로드되지 않음 — ParameterNotFound

증상: Lambda가 실행되나 AI 응답 대신 오류가 반환되고, CloudWatch Logs에 ParameterNotFound 에러가 찍힘.

원인: SSM Parameter Store에 /cloud-portfolio/gemini-api-key 경로로 파라미터가 없거나 오타가 있습니다.

해결: Step 2의 명령어를 재실행하여 파라미터를 저장합니다. 이미 존재하는 경우 --overwrite를 추가하세요.

aws ssm put-parameter `
  --name "/cloud-portfolio/gemini-api-key" `
  --value "<your-gemini-api-key>" `
  --type SecureString `
  --region ap-northeast-2 `
  --overwrite

2. 웹 UI가 이전 버전으로 표시됨

증상: website/index.html을 수정하고 S3에 업로드했으나 브라우저에 반영되지 않음.

원인: CloudFront 엣지 캐시가 살아있어 이전 파일을 계속 제공합니다.

해결: 캐시 무효화 명령을 실행합니다.

aws cloudfront create-invalidation --distribution-id <distribution-id> --paths "/*"

무효화는 보통 1~3분 내에 완료됩니다.


3. Bedrock AccessDeniedException: subscription required

증상: ai_provider = "bedrock"으로 전환 후 Lambda가 AccessDeniedException 오류를 반환함.

원인: AWS Bedrock에서 사용할 모델을 계정 레벨에서 먼저 활성화(구독)해야 합니다.

해결:

  1. AWS 콘솔 → Amazon Bedrock 서비스로 이동합니다.
  2. 왼쪽 메뉴에서 Model catalog (또는 Model access) 를 선택합니다.
  3. 사용할 모델(예: Claude 3 Haiku) 옆 Request access 버튼을 클릭하고 승인을 기다립니다.
  4. 승인 완료 후 Lambda를 다시 호출합니다.

모델 접근 승인은 즉시 또는 수 분 내에 완료되는 경우가 많습니다.


4. PowerShell curl.exe JSON 이스케이프 오류

증상: curl.exe -d 에 JSON을 직접 입력하면 Invalid JSON 또는 400 Bad Request 응답이 돌아옴.

원인: PowerShell에서 -d 인자 안의 큰따옴표를 이스케이프하지 않으면 JSON이 깨집니다.

해결: -d 인자 안의 모든 내부 큰따옴표를 \" 로 이스케이프합니다.

# ❌ 문제가 생기는 방식
curl.exe -X POST $endpoint -d '{"message": "안녕하세요", "session_id": "test-001"}'

# ✅ 올바른 방식 — 내부 따옴표를 \" 로 이스케이프
curl.exe -X POST $endpoint `
  -H "Content-Type: application/json" `
  -d '{\"message\": \"안녕하세요\", \"session_id\": \"test-001\"}'

Bedrock으로 전환 (선택 사항)

기본값은 Google Gemini입니다. AWS Bedrock Claude로 전환하려면 variables.tf를 수정 후 재배포합니다.

# project4-ai-chatbot/variables.tf
variable "ai_provider" {
  default = "bedrock"   # "gemini" → "bedrock" 으로 변경
}
cd project4-ai-chatbot
terraform apply

서울 리전 미지원 주의: AWS 서울 리전(ap-northeast-2)은 Claude 모델을 지원하지 않습니다. variables.tfbedrock_region은 기본값 "us-east-1"(버지니아 북부)을 유지하세요.

variable "bedrock_region" {
  default = "us-east-1"   # 서울 미지원 → 버지니아 북부 사용
}

Bedrock 전환 전 반드시 AWS Bedrock 콘솔에서 해당 모델의 Model access(구독)를 활성화해야 합니다.


인프라 삭제

# 1. S3 UI 버킷 비우기 (오브젝트가 남아있으면 terraform destroy 실패)
aws s3 rm s3://p4-chatbot-ui-<suffix> --recursive

# 2. Terraform 리소스 전체 삭제
cd project4-ai-chatbot
terraform destroy

SSM Parameter Store 수동 삭제: Gemini API 키는 Terraform이 관리하지 않으므로 terraform destroy 이후에도 남아 있습니다. 아래 경로에서 수동으로 삭제하세요.

AWS 콘솔 → Systems ManagerParameter Store/cloud-portfolio/gemini-api-key삭제

Lambda 함수, DynamoDB 테이블, API Gateway, S3 버킷, CloudFront 배포, SNS 토픽, CloudWatch 대시보드 등 Terraform이 생성한 모든 리소스가 삭제됩니다.


기술 스택

Terraform · AWS Lambda · AWS DynamoDB · AWS API Gateway · AWS S3 · AWS CloudFront · AWS SSM Parameter Store · AWS SNS · AWS CloudWatch · AWS IAM · Amazon Bedrock · Google Gemini API · Python