Concurrency & Execution

AI 에이전트 on AWS Lambda — cold start 줄이는 5가지 패턴

CoderNo.905 2026. 5. 19. 19:00

AI 에이전트를 Lambda에 올리면 LLM SDK 임포트와 시크릿 페치가 Init phase에 누적되어 cold start가 일반 함수보다 수 배로 늘어난다. AWS가 공식 지원하는 5가지 패턴(SnapStart, Provisioned Concurrency, Init 최적화, Container Image, arm64 Graviton)으로 이 비용을 잡는다.

왜 AI 에이전트 cold start가 더 비싼가

Lambda cold start는 Init → Invoke 두 단계(SnapStart 사용 시 중간에 Restore)로 구성되며, AWS는 Init을 "function's static initialization code" 실행 구간으로 정의한다.1 AI 에이전트 함수에서는 이 구간이 다음 세 가지 이유로 부풀어 오른다.

  • LLM SDK 임포트 — boto3, anthropic, langchain 패키지는 임포트 시점에 수십 개의 트랜지티브 의존성을 로딩한다. 압축 해제·바이트코드 컴파일 비용이 Init에 집중된다.
  • 시크릿/구성 페치 — Secrets Manager·SSM Parameter Store 호출을 Init에 묶으면 네트워크 RTT가 그대로 cold start에 더해진다.
  • 프롬프트 캐시 미스 — 새 실행 환경은 이전 환경의 in-memory 캐시(토크나이저, 임베딩, 시스템 프롬프트)를 공유하지 않는다. Bedrock 측 prompt caching은 별도이며, Lambda 인스턴스 간 캐시 동기화는 불가능하다.

Init phase에는 또한 10초 타임아웃이 적용된다. 모델 가중치를 Init에서 다운로드하는 식의 설계는 이 한도에 부딪힌다.1

패턴 1 — SnapStart로 Init phase 스냅샷 재사용

SnapStart는 Init이 끝난 시점의 메모리·디스크 상태를 스냅샷으로 저장하고, 이후 cold start에서 그 스냅샷을 복원(Restore)하므로 Init을 건너뛴다. 결과적으로 Init이 무거운 함수의 cold start가 크게 줄어든다.

지원 런타임: Java 11+, Python 3.12+, .NET 8+2

sequenceDiagram participant AWS as Lambda Service participant Env as Execution Environment participant Handler as Your Code rect rgb(240, 240, 240) Note over AWS, Handler: Standard Cold Start AWS->>Env: Download Code AWS->>Env: Start Runtime Env->>Handler: Init phase (Import SDK, Fetch Secrets) Env->>Handler: Invoke phase end rect rgb(220, 255, 220) Note over AWS, Handler: With SnapStart AWS->>Env: Restore from Snapshot Note right of Env: (Skips Init Phase) Env->>Handler: Invoke phase end
# AWS SAM — SnapStart 활성화
Resources:
  AgentFunction:
    Type: AWS::Serverless::Function
    Properties:
      Runtime: python3.12
      SnapStart:
        ApplyOn: PublishedVersions   # 배포된 버전에만 적용
      Handler: agent.handler
      CodeUri: src/
      MemorySize: 1024

주의 1 — uniqueness 함정. 스냅샷이 여러 인스턴스로 복원되면 PRNG seed, UUID, TLS 세션 키처럼 인스턴스별로 달라야 할 값이 동일해진다. beforeCheckpoint/afterRestore 라이프사이클 훅에서 재생성해야 한다.2

주의 2 — 네트워크 핸들 함정. Init에서 만든 HTTPS 커넥션·DB 풀은 스냅샷에 박제된다. 복원 직후 대상 서버가 keep-alive를 끊었을 가능성이 높으므로, afterRestore에서 클라이언트를 재초기화하거나 lazy-init으로 미루는 패턴이 안전하다.

패턴 2 — Provisioned Concurrency로 항상 warm 유지

Provisioned Concurrency(PC)는 지정한 수의 실행 환경을 미리 초기화하고 warm 상태로 유지한다. Invoke 시점에 Init이 완료된 환경이 대기하므로 cold start latency가 사실상 사라진다.3

import boto3

client = boto3.client('lambda')
client.put_provisioned_concurrency_config(
    FunctionName='my-agent-function',
    Qualifier='PROD',
    ProvisionedConcurrentExecutions=5,
)
graph LR subgraph OnDemand [On-Demand] R1[Request] -.-> C1(Cold Start: Init + Invoke) R2[Request] --> W1(Warm: Invoke) end subgraph Provisioned [Provisioned Concurrency] R3[Request] --> W2(Pre-Warmed: Invoke) R4[Request] --> W3(Pre-Warmed: Invoke) end style C1 fill:#f96,stroke:#333 style W2 fill:#9f9,stroke:#333 style W3 fill:#9f9,stroke:#333

선택 가이드 (수치는 실측 시나리오에 따라 다름, 일반적 경향):

설정 Cold start 추가 비용 적합 워크로드
기본 가장 느림 없음 비정기 배치
SnapStart 중간 없음 버스트 트래픽
PC 사실상 0 시간당 PC 단가 × 인스턴스 수 p99 SLA 엄격
PC + SnapStart 사실상 0 PC 단가만 일관성 최우선

PC는 Application Auto Scaling과 결합해 시간대·트래픽 패턴에 맞춰 인스턴스 수를 자동 조정할 수 있다.3 인터랙티브 챗봇처럼 p99 응답시간이 SLA인 워크로드에 적합하지만, 항상 warm 상태이므로 비용 분석이 선결 조건이다.

패턴 3 — Init phase에서 무거운 작업 선점 실행

핸들러 바깥의 코드는 Init에서 한 번 실행되고 실행 환경이 재사용되는 동안 캐시된다. AWS 공식 베스트 프랙티스는 "initialize SDK clients and database connections outside of the function handler"를 명시적으로 권장한다.4

import boto3
from anthropic import Anthropic

# Init phase: 실행 환경 생성 시 1회 실행
_secrets = boto3.client('secretsmanager')
_api_key = _secrets.get_secret_value(
    SecretId='prod/anthropic/api-key'
)['SecretString']

_llm = Anthropic(api_key=_api_key)
_bedrock = boto3.client('bedrock-runtime')


def handler(event, context):
    # Invoke phase: 요청마다 실행
    response = _llm.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[{"role": "user", "content": event['prompt']}],
    )
    return {"statusCode": 200, "body": response.content[0].text}

_llm, _bedrock을 모듈 레벨에 둠으로써 warm invoke의 SDK 재초기화 비용이 제거된다. SnapStart와 결합하면 cold start에서도 이 비용이 0에 수렴한다.

패턴 4 — Container Image로 레이어 캐시 활용

Lambda 컨테이너 이미지는 최대 10 GB까지 허용되며, ECR에서 동일 이미지를 재사용하는 환경은 레이어를 캐시한다.5 AI 에이전트 워크로드에서 컨테이너가 유리한 이유는 세 가지다.

  • ML 라이브러리(torch, transformers)가 ZIP 250 MB 한계를 자주 넘는다
  • 의존성 레이어를 공유하면 대용량 패키지를 한 번만 pull한다
  • 동일 Dockerfile로 로컬·CI·Lambda 환경을 통일할 수 있다
FROM public.ecr.aws/lambda/python:3.12

# 의존성 레이어: 자주 안 바뀜 → 캐시 최우선
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 애플리케이션 코드: 자주 바뀜 → 최후 레이어
COPY src/ ${LAMBDA_TASK_ROOT}/

CMD ["agent.handler"]

의존성 레이어를 코드 레이어보다 먼저 두는 것이 핵심이다. 코드만 바뀌었을 때 의존성 레이어 캐시가 유지되어 ECR pull 시간과 cold start 이미지 페치 시간이 함께 줄어든다.

패턴 5 — arm64 Graviton으로 비용·성능 개선

Lambda는 x86_64 외에 arm64(Graviton2) 아키텍처를 지원한다. AWS는 동일 메모리 구성에서 arm64가 x86_64 대비 가격·성능 면에서 유리한 워크로드가 있다고 안내한다(실제 효과는 워크로드별 측정 필요).6

Resources:
  AgentFunction:
    Type: AWS::Serverless::Function
    Properties:
      Runtime: python3.12
      Architectures: [arm64]
      MemorySize: 1024
      SnapStart:
        ApplyOn: PublishedVersions

arm64 전환 시 점검 포인트

  • 순수 Python·Node.js 코드는 대체로 그대로 동작
  • C 확장(numpy, pydantic-core, torch)은 arm64용 wheel이 필요
  • 컨테이너 이미지는 docker buildx build --platform linux/arm64로 빌드

워크로드별 패턴 선택 가이드

패턴 결정 매트릭스

flowchart TD Start([Which Pattern to Choose?]) --> SLA{Strict p99 SLA?} SLA -- Yes --> PC[Provisioned Concurrency] SLA -- No --> Runtime{Using Java/Python 3.12+?} Runtime -- Yes --> Snap[SnapStart] Runtime -- No --> Large{Large ML Libs?} Large -- Yes --> Cont[Container Image] Large -- No --> Init[Init Phase Optimization] Snap --> Cost[+ arm64 Graviton for Cost] PC --> Cost Cont --> Cost Init --> Cost
워크로드 권장 조합 이유
실시간 챗봇 (p99 < 200 ms) PC + arm64 항상 warm + 비용 절감
버스트 API SnapStart + arm64 cold start 최소, PC 비용 없음
배치 AI 파이프라인 Container image + arm64 대용량 ML 의존성, 비용 우선
Init 무거운 에이전트 Init 최적화 + SnapStart SDK 초기화 1회, 스냅샷 재사용
온디맨드 모델 추론 Container image + PC 모델 가중치 warm 유지