[9주차] Generative AI on Amazon EKS

Minn·2026년 5월 17일

본 글은 AEWS 스터디 및 AWS Workshop Amazon EKS에서 고급 Agentic AI 플랫폼 설계 및 배포 실습 내용을 정리한 글입니다.


0. 전체 구조

이번 워크숍의 핵심은 EKS 위에 단순 LLM 하나 띄우는 게 아니라, 모델 서빙 + AI Gateway + 관측성 + Agent 애플리케이션까지 한 번에 구성하는 것이다.

사용자
 │
 ▼
Open WebUI (채팅 UI)
 │
 ▼
LiteLLM Gateway (모델 라우팅)
 ├─ vLLM on EKS (Qwen 3 8B / Neuron)
 └─ Amazon Bedrock (Claude 4.5 Sonnet)
 │
 ▼
Langfuse (LLM Observability)
모듈핵심
Module 1모델 호출 - Open WebUI에서 vLLM, Bedrock 모델 사용
Module 2플랫폼 컴포넌트 - LiteLLM Gateway + Langfuse 관측성
Module 3Agentic AI 앱 - LangGraph + MCP 서버로 Agent 구축

1. 실습 환경

1.1 EKS Auto Mode

• 워크숍 환경은 Amazon EKS Auto Mode 기반
• 노드 프로비저닝, 스케일링, 패치를 AWS가 관리하는 방식

kubectl cluster-info

kubectl get nodes -L eks.amazonaws.com/compute-type

1.2 Node Pool

AI 워크로드는 일반 웹 서비스와 노드 요구사항이 다르다.

Node Pool용도
General PurposeOpen WebUI, LiteLLM, Langfuse 등 일반 서비스
GPU AcceleratedGPU 기반 모델 추론
AWS NeuronInferentia/Trainium 기반 추론 (inf2, trn1)
kubectl get nodepools -o wide

1.3 Storage

• 모델 파일은 크기 때문에 매번 다운로드하면 Pod 기동 시간이 길어짐
• EFS 기반 공유 스토리지로 모델 캐시 재사용

kubectl get storageclass
kubectl get pv | grep efs

1.4 사전 배포 컴포넌트 확인

kubectl get pods -A | grep -E "litellm|langfuse|openwebui|vllm"
kubectl get svc -A | grep -E "litellm|langfuse|openwebui|vllm"

모든 Pod가 Running 상태여야 이후 실습이 의미 있다.


2. Module 1 - 모델과 상호작용하기

2.1 요청 흐름

Open WebUI → LiteLLM Gateway → vLLM (self-hosted)
                              → Bedrock (managed)

Open WebUI는 모델을 직접 바라보지 않는다. LiteLLM만 바라보고, LiteLLM이 백엔드를 라우팅한다.

2.2 Open WebUI 접속

echo "Open WebUI: http://$(kubectl get ingress -n openwebui openwebui -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')"

• 첫 접속 시 관리자 계정 생성
• 모델 선택 드롭다운에서 vLLM / Bedrock 모델 확인

핵심 설정

openaiBaseApiUrl: http://litellm.litellm:4000/v1

extraEnvVars:
  - name: OPENAI_API_KEY
    value: ${LITELLM_API_KEY}

ollama:
  enabled: false

→ Open WebUI는 LiteLLM의 OpenAI 호환 API를 사용한다.

2.3 vLLM - Self-hosted 모델

vLLM은 EKS 위에서 직접 모델을 서빙하는 방식이다.

kubectl get pods -n vllm
kubectl get deployments -n vllm -o wide

Deployment 핵심

nodeSelector:
  eks.amazonaws.com/instance-family: inf2

resources:
  requests:
    cpu: 3
    memory: 12Gi
    aws.amazon.com/neuroncore: 2
  limits:
    aws.amazon.com/neuroncore: 2

• Neuron Core가 있는 인스턴스에만 스케줄링
• 일반 노드에 뜨면 안 되는 구조

로그 확인

kubectl logs -f --tail=0 -n vllm deployment/qwen3-8b-neuron

Open WebUI에서 vLLM 모델 선택 후 질문을 보내면 로그에서 확인 가능:

지표의미
Prompt throughput입력 토큰 처리 속도
Generation throughput출력 토큰 생성 속도
KV cache usage캐시 사용률
Running / Waiting처리 중 / 대기 중 요청

2.4 Amazon Bedrock - 관리형 모델

Bedrock은 모델 인프라를 직접 운영하지 않고 API로 호출하는 방식이다.

Open WebUI에서 bedrock/claude-4.5-sonnet 선택 후 테스트:

Explain the concept of Kubernetes operators and provide a simple example.

vLLM vs Bedrock

구분vLLMBedrock
운영직접관리형
비용인스턴스 기반토큰 기반
제어권높음제한적
운영 부담높음낮음

정답은 없다. 모델 런타임까지 책임질 수 있으면 vLLM, 빠르게 붙이고 싶으면 Bedrock.

2.5 모델 비교

Open WebUI에서 모델 이름 옆 + 버튼으로 여러 모델 동시 비교 가능.

What is square root of 144 divided by 29 multiplied by pi?

• 응답 속도, 설명 방식, 정확성 비교

2.6 RAG 실습

Open WebUI의 Knowledge Base 기능으로 간단한 RAG 확인.

cat > super-secret.txt << 'EOF'
Super Secret Document
Project Codename: Nightfall
Objective: Develop an untraceable communication device.
Status: In progress
EOF
  1. Knowledge Base 생성 → 파일 업로드
  2. RAG 없이 질문 → 모델이 모름
  3. RAG 연결 후 질문 → 문서 기반 답변

같은 모델, 같은 질문이어도 컨텍스트가 있느냐에 따라 답변이 완전히 달라진다.


3. Module 2 - GenAI 플랫폼 컴포넌트

Module 1이 "모델이 답한다"를 확인하는 단계라면, Module 2는 "플랫폼답게 운영할 수 있는가"를 보는 단계다.

3.1 LiteLLM - AI Gateway

여러 모델 Provider를 OpenAI 호환 API로 통합해주는 Gateway.

kubectl get pods -n litellm
컴포넌트역할
litellm모델 요청 라우팅
postgresql설정/사용량 저장
redis캐시

모델 설정 확인

grep -A 16 "model_list:" /workshop/components/ai-gateway/litellm/values.rendered.yaml
model_list:
  - model_name: bedrock/claude-4.5-sonnet
    litellm_params:
      model: bedrock/global.anthropic.claude-sonnet-4-5-20250929-v1:0
      aws_region_name: us-west-2

  - model_name: vllm/qwen3-8b-neuron
    litellm_params:
      model: openai/qwen3-8b-neuron
      api_key: fake-key
      api_base: http://qwen3-8b-neuron.vllm:8000/v1

vLLM도 LiteLLM 관점에서는 OpenAI 호환 API로 등록된다. 애플리케이션은 백엔드가 뭔지 몰라도 된다.

LiteLLM Admin UI

echo "LiteLLM: http://$(kubectl get ingress -n litellm litellm -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')/ui"
메뉴확인 내용
Models + Endpoints등록된 모델 목록
Usage요청 수, 토큰, 비용
Playground모델 직접 호출 테스트
Virtual Keys앱용 API Key 생성

3.2 모델 추가

새 Bedrock 모델을 LiteLLM에 추가하는 흐름:

# 사용 가능한 모델 조회
aws bedrock list-foundation-models \
  --query "modelSummaries[?contains(modelId, 'gpt-oss')].{ModelId:modelId,ModelName:modelName}" \
  --output table

values에 추가:

- model_name: bedrock/gpt-oss-20b
  litellm_params:
    model: bedrock/openai.gpt-oss-20b-1:0
    aws_region_name: us-west-2

적용:

helm upgrade litellm oci://ghcr.io/berriai/litellm-helm \
  --namespace litellm \
  -f /workshop/components/ai-gateway/litellm/values.rendered.yaml

kubectl rollout status deployment/litellm -n litellm

코드 수정 없이 설정 변경만으로 모델 추가 가능. 이게 Gateway의 가치다.

3.3 Virtual Key

애플리케이션에서 LiteLLM을 호출할 때 사용하는 키.

LiteLLM UI → Virtual Keys → + Create New Key

이유설명
접근 제어앱별 사용 가능 모델 제한
비용 추적키 단위 사용량 확인
운영 분리환경/앱별 분리
폐기 용이문제 키만 비활성화

Master Key를 앱에 직접 넣으면 안 된다. Virtual Key를 쓰는 게 맞다.

3.4 Langfuse - LLM Observability

LLM 요청을 추적하는 관측성 플랫폼.

kubectl get pods -n langfuse
컴포넌트역할
langfuse-webUI
langfuse-worker비동기 작업
postgresql메타데이터
clickhouseTrace/Analytics
redis캐시

LiteLLM ↔ Langfuse 연동

litellm_settings:
  callbacks: ["langfuse"]
  success_callback: ["langfuse"]
  failure_callback: ["langfuse"]

→ LiteLLM을 거친 모든 모델 호출이 Langfuse에 기록된다.

Langfuse에서 확인할 것

echo "Langfuse: http://$(kubectl get ingress -n langfuse langfuse -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')"
항목설명
Input/Output프롬프트와 응답
Latency응답 지연시간
Token Usage입력/출력 토큰 수
Cost호출 비용
Error실패 요청

LLM은 HTTP 200이어도 응답 품질이 낮거나 비용이 과도할 수 있다. 그래서 일반 로그만으로는 부족하고 LLM 전용 관측성이 필요하다.


4. Module 3 - Agentic AI 애플리케이션

앞에서 만든 플랫폼 위에 실제 Agent 애플리케이션을 올린다.

4.1 유스케이스: Loan Buddy

대출 담당자가 수작업으로 처리하던 대출 신청 검토를 AI Agent가 자동화하는 시나리오.

대출 신청서 이미지 업로드
 │
 ▼
Loan Buddy Agent (LangGraph)
 ├─ Image Processor MCP → 신청서에서 데이터 추출
 ├─ Address Validator MCP → 주소 검증
 └─ Employment Validator MCP → 고용/소득 검증
 │
 ▼
최종 승인/거절 판단 + Langfuse Trace

4.2 아키텍처

컴포넌트역할
Loan Buddy Web App신청서 업로드
Loan Processing AgentLangGraph 기반 워크플로우 오케스트레이션
LiteLLM Gateway모델 호출
Image Processor MCP이미지에서 데이터 추출
Address Validator MCP주소 검증
Employment Validator MCP고용/소득 검증
LangfuseAgent workflow 추적

4.3 LangGraph + LangChain

Agent의 핵심 코드 구조:

from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent

model = ChatOpenAI(
    model="bedrock/claude-4.5-sonnet",
    api_key=model_key,
    base_url="http://litellm.litellm.svc.cluster.local:4000"
)

graph = create_react_agent(model, tools, debug=True)

Agent는 Bedrock을 직접 호출하지 않는다. LiteLLM Gateway를 통해 호출한다. 그래야 키 관리, 관측성이 그대로 적용된다.

4.4 MCP 서버

Image Processor MCP

• S3에서 신청서 이미지를 가져와 Claude vision으로 데이터 추출

{
  "name": "John Michael Doe",
  "date_of_birth": "March 15, 1985",
  "employer": "Tech Solutions Inc",
  "annual_income": 75000,
  "loan_amount": 8500,
  "loan_purpose": "Home Improvement"
}

Address Validator MCP

• 주소 형식 확인, 주거지 여부, 위험 점수 계산

Employment Validator MCP

• 고용 상태, 소득 검증, 근속 기간, 안정성 점수

4.5 배포

cd /workshop/workshops/eks-genai-workshop/static/code/module3/credit-validation

chmod +x deploy-workshop-app.sh
./deploy-workshop-app.sh

스크립트가 하는 일:
1. S3 bucket, Region, LiteLLM Key, Langfuse Key 설정
2. workshop namespace 생성
3. ServiceAccount + Pod Identity 설정
4. Loan Buddy + MCP 서버 배포

kubectl get pods -n workshop

예상 Pod:

loan-buddy-agent-xxx
mcp-address-validator-xxx
mcp-employment-validator-xxx
mcp-image-processor-xxx

4.6 테스트

# Agent 로그 (별도 터미널)
kubectl logs -f deployment/loan-buddy-agent -n workshop

# 포트포워딩
kubectl port-forward service/loan-buddy-agent 8080:8080 -n workshop &

# 신청서 처리
curl -X POST -F "image_file=@./example1.png" \
  http://localhost:8080/api/process_credit_application_with_upload \
  | jq

4.7 Langfuse에서 Agent Trace 확인

Langfuse Tracing 메뉴에서 최근 trace 확인:

• 전체 처리 시간
• 호출된 MCP 도구와 순서
• 각 도구의 입력/출력
• 모델 호출 내용
• 토큰 사용량, 비용
• 최종 판단 근거

Agentic AI의 핵심은 "모델 답변"이 아니라 도구 호출과 의사결정 흐름의 추적 가능성이다.


5. 정리

모듈핵심
Module 1모델을 직접 써본다
Module 2모델을 플랫폼으로 묶는다
Module 3플랫폼 위에 Agent를 올린다

개인적으로 본 포인트

• Open WebUI는 UI일 뿐, 핵심은 LiteLLM Gateway 구조
• vLLM은 자유도 높지만 운영 부담도 같이 감
• Bedrock은 빠르게 붙일 수 있지만 비용/리전 제약 확인 필요
• Langfuse 없이 LLM 운영하면 장애 분석과 비용 추적이 어려움
• MCP로 도구를 분리하면 Agent prompt가 비대해지는 문제 완화
• 결국 Agentic AI 플랫폼은 모델보다 라우팅 + 관측성 + 도구 계층이 더 중요

주의할 점

• 워크숍 모델명은 시점에 따라 바뀔 수 있음 → 실제 model_list 확인
• Bedrock 모델은 리전별 가용성이 다름
• Self-hosted 모델은 토큰당 비용이 바로 안 보임 → 인프라 비용 기준 산정 필요
• Virtual Key는 생성 후 즉시 저장
• 워크숍 기본 계정/패스워드는 운영에서 절대 그대로 쓰면 안 됨


6. 확인 명령 모음

# 전체 컴포넌트
kubectl get pods -A | grep -E "litellm|langfuse|openwebui|vllm"

# Open WebUI
echo "Open WebUI: http://$(kubectl get ingress -n openwebui openwebui -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')"

# vLLM
kubectl get pods -n vllm
kubectl logs -f --tail=0 -n vllm deployment/qwen3-8b-neuron

# LiteLLM
kubectl get pods -n litellm
echo "LiteLLM: http://$(kubectl get ingress -n litellm litellm -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')/ui"
grep -A 16 "model_list:" /workshop/components/ai-gateway/litellm/values.rendered.yaml

# Langfuse
kubectl get pods -n langfuse
echo "Langfuse: http://$(kubectl get ingress -n langfuse langfuse -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')"

# Loan Buddy
kubectl get pods -n workshop
kubectl logs -f deployment/loan-buddy-agent -n workshop
kubectl port-forward service/loan-buddy-agent 8080:8080 -n workshop &

# 신청서 처리
curl -X POST -F "image_file=@./example1.png" \
  http://localhost:8080/api/process_credit_application_with_upload | jq

참고

profile
클라우드 왕초보

0개의 댓글