Skip to main content
Summary

이 장에서 배울 것

이번 장의 목표는 에이전트를 로컬 실험에서 실제 서비스로 옮기는 방법을 이해하는 것이다. 로컬에서는 python app.py로 충분할 수 있다. 그러나 프로덕션에서는 다르다. 사용자는 동시에 들어오고, 도구는 실패하며, LLM 응답은 느려질 수 있고, 장기 작업은 중간에 멈출 수 있다. 비용도 예측하기 어렵다.

이 장에서는 다음을 배운다.

  • 프로덕션 Agent Service의 기본 구성

  • API Gateway, LLM Router, Tool Registry, Workflow Engine, State Manager, Task Queue, Event Stream의 역할

  • Docker, Kubernetes, serverless, worker queue, durable execution engine 선택 기준

  • 운영 지표를 가용성, 지연 시간, 실패율, 재시도, 비용, 승인 대기 시간, 사용자 만족도로 나누는 방법

  • 간단한 에이전트를 컨테이너화하고 비동기 큐와 진행 이벤트를 붙이는 실습

핵심은 하나다. 프로덕션 에이전트 배포는 챗봇 엔드포인트 하나를 띄우는 일이 아니다. 상태 있는 장기 작업을 안전하게 실행하고 관찰하는 런타임을 만드는 일이다.

배포 runtime과 운영 지표

왜 이 주제가 중요한가

일반 웹 서비스는 입력 경로가 비교적 제한되어 있다. 버튼, 폼, API 스펙이 있고, 실패 지점도 어느 정도 예상할 수 있다. 반면 에이전트는 자연어 입력을 받는다. 같은 요청도 사용자가 수십 가지 방식으로 말할 수 있다. 또한 에이전트는 여러 단계에 걸쳐 생각하고, 도구를 호출하고, 검색하고, 승인 요청을 만들고, 다시 실행한다. 그래서 전통적인 APM이 보는 HTTP 200, 평균 응답 시간, 서버 CPU만으로는 충분하지 않다. 실제로 에이전트 운영에서는 프롬프트, 응답, 도구 호출, 중간 판단, 최종 결과까지 함께 보아야 한다1.

더 큰 문제는 실패가 조용히 일어난다는 점이다. 서버는 정상 응답을 반환했지만, 에이전트가 잘못된 문서를 인용했을 수 있다. 도구 호출은 성공했지만, 잘못된 고객 ID로 실행했을 수 있다. 비용도 마찬가지다. 에이전트는 한 번의 요청 안에서 계획, 검색, 재시도, 하위 에이전트 호출을 반복할 수 있다. 요청 수 제한만으로는 비용을 통제하기 어렵고, 작업·도구·모델별 예산이 필요하다2.

따라서 프로덕션 에이전트의 첫 번째 운영 원칙은 다음과 같다.

모델을 바꾸기 전에 로그, 타임아웃, 재시도, 롤백, 비용 한도부터 설계한다.

핵심 개념 설명

Agent Service는 여러 구성요소의 조합이다

프로덕션 Agent Service는 보통 다음 구성요소로 나뉜다.

구성요소역할반드시 기록할 것
API Gateway인증, 권한, 요청 제한, 테넌트 식별user_id, tenant_id, request_id
LLM Router모델 선택, fallback, 비용 정책 적용model, prompt_version, token 사용량
Tool Registry사용 가능한 도구 목록, 스키마, 권한 관리tool_name, tool_version, permission
Workflow Engine작업 단계 실행, 분기, 승인 대기, 재개workflow_id, step_id, status
State Manager대화 상태, 작업 상태, 체크포인트 저장task_state, memory_ref, checkpoint
Task Queue긴 작업 비동기 실행, 재시도, 작업 분산job_id, retry_count, queue_latency
Event Stream진행 상황을 사용자와 대시보드에 전달event_type, timestamp, payload

각 구성요소는 분리되어야 한다. 한 파일 안에 LLM 호출, 도구 실행, 상태 저장, 비용 계산, 이벤트 전송이 모두 들어가면 실험은 빠르지만 운영은 어렵다. 장애가 났을 때 어느 단계가 실패했는지 알 수 없고, 특정 도구만 막거나 특정 모델만 교체하기도 어렵다.

API Gateway: 모든 요청의 입구

API Gateway는 단순한 라우터가 아니다. 에이전트 시스템에서는 보안과 비용의 첫 번째 방어선이다.

Gateway는 다음을 처리한다.

  • 사용자 인증

  • 조직 또는 테넌트 식별

  • 에이전트별 권한 확인

  • 요청 크기 제한

  • 위험 작업에 대한 정책 확인

  • 요청 ID 발급

요청 ID는 중요하다. 하나의 사용자 요청은 여러 LLM 호출, 검색, 도구 실행, 승인 요청으로 나뉜다. 이 모든 기록을 다시 하나로 묶으려면 request_id, task_id, trace_id가 필요하다.

LLM Router: 모델 선택은 비용 정책이다

LLM Router는 어떤 모델을 쓸지 결정한다. 단순 질문은 저렴하고 빠른 모델로 보내고, 복잡한 계획 수립이나 중요한 문서 생성은 더 강한 모델로 보낼 수 있다. 장애가 발생하면 fallback 모델로 전환할 수도 있다.

하지만 Router의 핵심은 "가장 좋은 모델 선택"이 아니다. 작업 가치에 맞는 비용을 쓰게 하는 것이다. 예를 들어 FAQ 답변에 최고가 모델을 매번 쓰면 품질은 조금 좋아질 수 있지만 운영 비용은 크게 증가한다. 반대로 계약서 검토처럼 위험한 작업에는 저렴한 모델만 쓰는 것이 더 위험할 수 있다.

LLM Router는 다음 정책을 가져야 한다.

  • 작업 유형별 허용 모델

  • 최대 입력 토큰

  • 최대 출력 토큰

  • 요청당 비용 한도

  • 사용자 또는 조직별 일일 예산

  • fallback 순서

  • 모델 장애 시 차단 또는 다운그레이드 규칙

Tool Registry: 도구는 코드가 아니라 계약이다

Tool Registry는 에이전트가 사용할 수 있는 도구의 목록과 스키마를 관리한다. Tool use와 function calling에서 다룬 function calling이 "개별 도구 호출 계약"이었다면, 프로덕션의 Tool Registry는 그 계약들을 운영 가능한 형태로 묶는 저장소다.

Tool Registry에는 다음 정보가 있어야 한다.

  • 도구 이름

  • 설명

  • 입력 스키마

  • 출력 스키마

  • 실행 권한

  • 위험 등급

  • 타임아웃

  • 재시도 가능 여부

  • 멱등성 여부

  • 비용 추정치

  • 소유 팀

여기서 멱등성이란 같은 요청을 여러 번 실행해도 결과가 중복으로 망가지지 않는 성질이다. 예를 들어 "문서 조회"는 여러 번 실행해도 괜찮다. 그러나 "환불 실행", "메일 발송", "계약서 제출"은 중복 실행되면 문제가 된다. 이런 도구에는 idempotency key, 사람 승인, 실행 전 확인이 필요하다.

Workflow Engine: 에이전트의 장기 작업을 관리한다

에이전트 작업은 한 번에 끝나지 않을 수 있다. 사용자의 추가 입력을 기다리거나, 사람 승인을 기다리거나, 외부 API 장애로 나중에 재시도해야 할 수 있다. 이때 필요한 것이 Workflow Engine이다.

Workflow Engine은 다음을 담당한다.

  • 단계별 실행

  • 조건 분기

  • 승인 대기

  • 실패 시 재시도

  • 중단된 작업 재개

  • 단계별 상태 저장

  • 보상 작업 실행

보상 작업은 롤백과 비슷하다. 예를 들어 에이전트가 외부 시스템에 임시 예약을 만들었지만 결제 단계에서 실패했다면, 임시 예약을 취소하는 작업이 필요하다.

State Manager: 메모리와 작업 상태를 분리한다

Memory와 state 설계에서 메모리와 state를 구분했다. 프로덕션에서는 이 구분이 더 중요하다.

  • memory: 사용자 선호, 과거 대화 요약, 장기 지식

  • task state: 현재 작업의 단계, 중간 결과, 승인 상태, 실패 기록

작업 상태를 프로세스 메모리에만 두면 서버가 재시작되는 순간 사라진다. 따라서 중요한 상태는 Redis, PostgreSQL, DynamoDB, S3 같은 외부 저장소에 저장해야 한다. 특히 장기 작업은 각 단계가 끝날 때 checkpoint를 남겨야 한다.

Task Queue: 긴 작업은 비동기로 처리한다

에이전트 작업을 HTTP 요청 안에서 끝까지 실행하면 문제가 생긴다. LLM 호출이 느려지거나 도구가 지연되면 사용자는 계속 기다려야 한다. 서버 타임아웃이 발생하면 작업이 끝났는지 실패했는지도 애매해진다.

프로덕션에서는 보통 다음 흐름을 쓴다.

  1. 사용자가 작업 요청

  2. API는 task_id를 즉시 반환

  3. 작업은 queue에 들어감

  4. worker가 비동기로 실행

  5. 진행 이벤트를 Event Stream으로 발행

  6. 사용자는 SSE 또는 WebSocket으로 진행 상황 확인

  7. 완료되면 결과 조회

Task Queue는 단순히 작업을 쌓는 곳이 아니다. 재시도, 지연 실행, 우선순위, dead letter queue를 함께 관리해야 한다. dead letter queue는 여러 번 실패한 작업을 따로 모아 사람이 확인할 수 있게 하는 큐다.

Event Stream: 사용자는 진행 상황을 알아야 한다

에이전트는 여러 단계를 거친다. 사용자가 아무 피드백 없이 30초를 기다리면 서비스가 멈춘 것처럼 느낀다. 그래서 진행 이벤트가 필요하다.

예를 들어 승인형 문서 에이전트는 다음 이벤트를 보낼 수 있다.

{"type":"started","message":"문서 분석을 시작했습니다."}
{"type":"retrieval","message":"관련 정책 4개를 찾았습니다."}
{"type":"drafting","message":"초안을 작성하고 있습니다."}
{"type":"approval_required","message":"외부 발송 전 승인이 필요합니다."}
{"type":"completed","message":"검토용 문서가 준비되었습니다."}

SSE는 서버에서 클라이언트로 단방향 이벤트를 보내기에 단순하다. WebSocket은 양방향 상호작용이 필요할 때 적합하다. 처음에는 SSE로 시작해도 충분한 경우가 많다.

쉬운 비유: 에이전트 배포는 식당 운영과 비슷하다

로컬 실험은 요리사가 혼자 한 접시를 만들어보는 것과 같다. 재료도 직접 꺼내고, 조리도 직접 하고, 손님에게 설명도 직접 한다.

프로덕션 운영은 식당 전체를 여는 일이다. 입구에서 예약을 확인하는 직원이 있고, 주문을 주방으로 보내는 시스템이 있고, 조리 순서를 관리하는 주방장이 있고, 재료 창고가 있고, 음식이 늦어질 때 손님에게 알려주는 직원이 있다. 결제 오류, 재료 부족, 알레르기 표시, 환불 규칙도 필요하다.

에이전트도 같다. LLM 하나가 똑똑하다고 서비스가 운영되는 것은 아니다. 요청을 받고, 작업을 나누고, 상태를 저장하고, 도구를 안전하게 실행하고, 비용을 통제하고, 실패를 추적하는 운영 체계가 필요하다.

배포 방식 선택 기준

배포 방식은 유행이 아니라 작업 특성에 맞춰 고른다.

방식적합한 경우주의할 점
Docker 단일 서비스초기 MVP, 내부 도구, 낮은 트래픽장애 복구와 확장 한계
Kubernetes여러 서비스, 높은 트래픽, 세밀한 확장운영 복잡도 증가
Serverless짧고 상태 없는 요청, 이벤트 기반 작업실행 시간 제한, cold start, 장기 상태 관리 어려움
Worker Queue긴 작업, 비동기 처리, 재시도 필요중복 실행 방지, 큐 적체 모니터링 필요
Durable Execution Engine승인 대기, 며칠 걸리는 작업, 재개 필요설계 학습 비용, 상태 모델링 필요

선택 질문은 다음 네 가지면 충분하다.

  1. 작업이 몇 초 안에 끝나는가, 몇 분 이상 걸리는가?

  2. 중간에 실패해도 이어서 실행해야 하는가?

  3. 사람 승인이나 외부 이벤트를 기다리는가?

  4. 도구 실행이 중복되면 위험한가?

짧고 단순한 FAQ 에이전트는 serverless나 단일 컨테이너로도 충분하다. 반면 문서 생성, 승인, 외부 발송, 감사 로그가 포함된 에이전트는 queue와 workflow engine이 필요하다.

운영 지표 설계

운영 지표는 "서버가 살아 있는가"에서 끝나면 안 된다. 에이전트는 실행 품질과 비용까지 함께 봐야 한다.

1. 가용성

  • API 성공률

  • worker 정상 동작률

  • queue 처리 가능 상태

  • LLM provider 장애율

  • 주요 도구별 가동률

2. 지연 시간

  • API 응답 시간

  • task 완료 시간

  • LLM 호출 시간

  • 도구 호출 시간

  • queue 대기 시간

  • time-to-first-event

평균만 보면 안 된다. p95, p99를 함께 본다. 대부분의 사용자는 평균이 아니라 느린 순간을 기억한다.

3. 단계별 실패율

에이전트 실패는 최종 실패율 하나로 보면 원인을 찾기 어렵다.

  • planning 실패율

  • retrieval 실패율

  • tool schema validation 실패율

  • tool execution 실패율

  • approval timeout 비율

  • final response validation 실패율

4. 재시도 횟수

재시도는 안정성을 높이지만 비용을 늘린다. 재시도가 많다는 것은 외부 API가 불안정하거나, 도구 입력이 자주 틀리거나, timeout 설정이 잘못되었다는 신호다.

  • 평균 retry count

  • 도구별 retry count

  • retry 후 성공률

  • dead letter queue 유입량

5. 토큰 비용과 도구 비용

LLM 비용은 요청 수가 아니라 토큰과 모델 조합으로 결정된다. 그래서 다음 단위로 봐야 한다.

  • task당 평균 토큰

  • 사용자당 비용

  • 조직별 비용

  • 모델별 비용

  • 도구별 비용

  • 실패한 작업에 쓴 비용

  • 재시도에 쓴 비용

비용 관리는 사후 대시보드만으로 부족하다. 고위험 작업은 실행 전에 남은 예산을 확인하고, 초과하면 차단하거나 저렴한 모델로 라우팅해야 한다3.

6. 사람 승인 대기 시간

Human approval과 guardrails에서 human approval을 다뤘다. 운영에서는 승인 대기 시간이 중요한 병목이 된다.

  • 평균 승인 대기 시간

  • 승인 거절률

  • 승인 만료율

  • 승인자별 처리량

  • 위험 등급별 승인 소요 시간

승인 대기 시간이 길면 에이전트가 느린 것이 아니라 조직 프로세스가 병목일 수 있다.

7. 사용자 만족도와 품질 지표

에이전트는 HTTP 200을 반환해도 실패할 수 있다. 그래서 품질 지표가 필요하다. 운영 환경에서는 전체 트래픽을 사람이 모두 검토할 수 없으므로 샘플링, 사용자 피드백, LLM-as-judge, 주기적 human review를 조합한다. 자동 평가만 믿기보다 사람 평가로 보정하는 것이 안전하다4.

  • thumbs up/down

  • 재질문 비율

  • 사용자가 직접 수정한 비율

  • 근거 문서 일치율

  • 환각 의심률

  • 안전 정책 위반률

  • 최종 작업 성공률

직접 해보는 실습: 비동기 에이전트 런타임 초안 만들기

이번 실습에서는 간단한 에이전트를 프로덕션 구조에 가깝게 바꾼다. 목표는 완벽한 서비스를 만드는 것이 아니라 운영 뼈대를 잡는 것이다.

실습 목표

  • 에이전트를 Docker로 실행한다.

  • 작업 요청을 즉시 task_id로 반환한다.

  • worker가 queue에서 작업을 처리한다.

  • 실행 로그를 구조화해서 저장한다.

  • SSE로 진행 이벤트를 보낸다.

  • 운영 대시보드 초안을 만든다.

1단계: 최소 구조

agent-service/
  app.py              # API 서버
  worker.py           # 비동기 작업자
  agent.py            # 에이전트 로직
  state_store.py      # 상태 저장
  event_store.py      # 진행 이벤트 저장
  Dockerfile
  docker-compose.yml

2단계: 작업 요청 흐름

POST /tasks
  -> task_id 생성
  -> 상태: queued 저장
  -> queue에 job 등록
  -> {task_id} 반환

GET /tasks/{task_id}
  -> 현재 상태와 결과 반환

GET /tasks/{task_id}/events
  -> SSE로 진행 이벤트 스트리밍

3단계: 로그 스키마 정하기

처음부터 로그 형식을 정해두면 나중에 대시보드를 만들기 쉽다.

{
  "trace_id": "tr_123",
  "task_id": "task_456",
  "span_id": "sp_001",
  "step": "tool_call",
  "model": "small-model",
  "tool": "search_policy",
  "status": "success",
  "latency_ms": 842,
  "input_tokens": 1200,
  "output_tokens": 320,
  "cost_estimate": 0.0041,
  "retry_count": 0,
  "created_at": "2026-05-18T10:00:00Z"
}

주의할 점이 있다. 프롬프트와 응답 전문을 그대로 저장하면 개인정보나 기밀이 남을 수 있다. 운영 로그에는 원문, 해시, 마스킹 버전, 접근 권한을 구분해야 한다.

4단계: SSE 이벤트 붙이기

작업자는 단계가 바뀔 때마다 이벤트를 남긴다.

queued -> planning -> tool_calling -> drafting -> approval_required -> completed

프론트엔드는 이 이벤트를 받아 진행 막대나 상태 메시지를 보여준다. 사용자는 "멈춘 서비스"가 아니라 "진행 중인 작업"으로 인식한다.

5단계: 대시보드 초안

대시보드에는 최소한 다음 패널을 둔다.

  • 오늘 요청 수

  • 완료율과 실패율

  • p50/p95 task 완료 시간

  • queue depth

  • 도구별 오류율

  • 모델별 토큰 비용

  • 재시도 상위 도구

  • 승인 대기 중 작업 수

  • dead letter queue 목록

  • 사용자 불만족 피드백 샘플

이 정도만 있어도 운영자는 "무엇이 느린지", "무엇이 비싼지", "어디서 실패하는지"를 볼 수 있다.

흔한 실수와 오류 분석

실수 1. 모든 작업을 동기 HTTP 요청으로 처리한다

처음에는 쉬워 보인다. 하지만 장기 작업, 외부 API 지연, 승인 대기에는 맞지 않는다. 해결책은 task queue와 event stream을 분리하는 것이다.

실수 2. 상태를 프로세스 메모리에 둔다

서버가 재시작되면 작업 상태가 사라진다. 프로덕션에서는 task state와 checkpoint를 외부 저장소에 남겨야 한다.

실수 3. 무조건 재시도한다

재시도는 비용을 늘리고 중복 실행을 만들 수 있다. 읽기 작업은 재시도해도 되지만, 쓰기 작업은 idempotency key와 중복 방지 로직이 필요하다.

실수 4. 비용을 월말 청구서로만 확인한다

에이전트는 루프를 돌며 비용을 빠르게 쓸 수 있다. 요청 경로에서 예산을 확인하고, 작업별·도구별·모델별 한도를 둔다.

실수 5. 로그는 많지만 추적은 안 된다

로그가 많아도 trace_id로 연결되지 않으면 디버깅하기 어렵다. 한 사용자 요청에서 발생한 모든 LLM 호출, 도구 호출, 승인 이벤트를 하나의 trace로 묶어야 한다.

실수 6. 모델 교체로 운영 문제를 해결하려 한다

느린 응답, 중복 실행, 도구 실패, 비용 폭증은 모델 문제가 아닐 때가 많다. 먼저 timeout, retry, queue, state, budget, log를 점검한다.

요약

프로덕션 에이전트는 LLM 호출 코드가 아니라 런타임 시스템이다. API Gateway는 요청과 권한을 관리하고, LLM Router는 모델과 비용을 통제한다. Tool Registry는 도구 계약과 위험도를 관리하고, Workflow Engine은 장기 작업과 승인 대기를 처리한다. State Manager는 작업 상태를 보존하며, Task Queue는 긴 작업을 안정적으로 실행한다. Event Stream은 사용자와 운영자에게 진행 상황을 보여준다.

운영 지표는 가용성, 지연 시간, 단계별 실패율, 재시도, 토큰 비용, 도구 오류율, 승인 대기 시간, 사용자 만족도를 함께 봐야 한다. 에이전트 운영의 핵심은 더 큰 모델을 고르는 것이 아니라 실패를 관찰하고, 비용을 제한하고, 안전하게 재개할 수 있는 구조를 만드는 것이다.

퀴즈

  1. 프로덕션 에이전트에서 HTTP 200만으로 성공 여부를 판단하기 어려운 이유는 무엇인가?

  2. Task Queue가 필요한 상황을 두 가지 들어보라.

  3. Tool Registry에 도구의 위험 등급과 멱등성 여부를 기록해야 하는 이유는 무엇인가?

  4. LLM Router가 단순히 "가장 좋은 모델"을 선택하는 컴포넌트가 아닌 이유는 무엇인가?

  5. 평균 지연 시간보다 p95, p99 지연 시간이 중요한 이유는 무엇인가?

  6. 재시도가 항상 좋은 해결책이 아닌 이유는 무엇인가?

  7. 사람 승인 대기 시간이 길 때 이것이 에이전트 모델의 품질 문제라고 단정하면 안 되는 이유는 무엇인가?

  8. 비용 통제를 사후 대시보드가 아니라 요청 경로에서 해야 하는 이유는 무엇인가?

체크리스트

  • 모든 요청에 request_id, task_id, trace_id를 부여했는가?

  • 긴 작업을 HTTP 요청 안에서 끝까지 처리하지 않는가?

  • task state와 checkpoint를 외부 저장소에 저장하는가?

  • 도구별 timeout, retry, idempotency 정책이 있는가?

  • 모델별, 작업별, 사용자별 비용을 추적하는가?

  • 요청당 비용 한도와 일일 예산 한도가 있는가?

  • queue depth와 dead letter queue를 모니터링하는가?

  • SSE 또는 WebSocket으로 진행 상태를 제공하는가?

  • 승인 대기 작업과 승인 만료 작업을 볼 수 있는가?

  • 품질 평가와 사용자 피드백이 운영 대시보드에 연결되어 있는가?

다음 장 연결

다음 장에서는 이 책의 최종 프로젝트인 승인형 문서 에이전트를 만든다. 이번 장에서 배운 runtime, queue, state, event, log, 비용 통제 구조가 프로젝트의 기반이 된다. 특히 문서 생성 후 바로 외부 발송하지 않고, 사람 승인을 기다리며, 승인 로그와 실행 로그를 남기는 구조를 구현한다. 이제 개별 개념을 넘어 실제로 배포 가능한 작은 에이전트 시스템을 조립할 차례다.

참고

1You don't know what your agent will do until it's in production

2How to Control AI Agent API Costs: Rate Limiting vs Economic Firewalls

3Take Control of Agent Costs

4How to Build an Agent Evaluation Framework for Production AI

책 목록

AI 교육 6권 : 에이전트 설계·배포: 도구를 쓰는 LLM을 운영 가능한 시스템으로 만드는 법

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기