본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 10. 21:01

에이전트 시리즈 (18): 비용 및 성능 최적화 — 더 저렴하고 더 빠르게

요약

AI 에이전트 운영 시 발생하는 비용과 지연 시간을 최적화하기 위한 전략을 다룹니다. 시스템 프롬프트 최적화, 프롬프트 캐싱, 그리고 모델 라우팅을 통해 토큰 사용량과 불필요한 에이전트 루프를 줄이는 구체적인 방법을 제시합니다.

핵심 포인트

  • 시스템 프롬프트 최적화는 지연 시간보다 토큰 비용 절감에 효과적임
  • 대규모 컨텍스트 사용 시 프롬프트 캐싱(Prompt Caching) 활용 권장
  • 모델 라우팅을 통해 단순 쿼리에 대한 에이전트 오버헤드 방지 가능
  • 지연 시간 측정 시 통계적 유의성을 위해 충분한 샘플 확보 필요

에이전트의 비용은 어디로 가는가?

에이전트 호출 1회당 비용 내역:

입력 토큰 (Input tokens):
  시스템 프롬프트 (System prompt)         고정 — 매 호출마다 비용 발생
  도구 스키마 (Tool schemas)          고정 — 등록된 도구당 항목 1개
...

모든 최적화는 두 가지 범주 중 하나에 속합니다: 토큰 수(token count) 감소 또는 대기 시간(wait time) 감소. 각 전략이 실제로 무엇을 제공하는지 정량화하기 위한 네 가지 실험을 진행합니다.

데모 1: 토큰 비용 분석 — 시스템 프롬프트 다듬기

시스템 프롬프트 (System prompt)는 매 호출마다 모델로 전송됩니다. 이는 가장 간과하기 쉬운 고정 비용입니다.

두 가지 버전을 비교합니다:

MINIMAL_PROMPT = "You are a helpful assistant."
# → 6 토큰

...

토큰 수 (Token counts):

  Minimal  (  6 tokens): 'You are a helpful assistant.'
  Verbose  (107 tokens): 'You are an extremely helpful...'
  호출당 추가 토큰: 101 tokens

101 토큰은 작게 들릴 수도 있습니다. GPT-4o 입력 가격($2.50 / 1M tokens) 기준으로는:

  • 일일 1만 회 호출 → 일일 $0.25 추가 비용
  • 일일 100만 회 호출 → 일일 $25, 월 $750 추가 비용

지연 시간(Latency) 측정 (동일 쿼리에 대해 2회 실행):

  Agent       Run 1    Run 2     Avg   Answer
  Minimal     6.90s    3.39s   5.15s  The current weather in Beijing is 25°C...
  Verbose     3.10s    4.21s   3.66s  The current weather in Beijing is 25°C...

Verbose 버전이 Minimal 버전보다 평균적으로 낮은 지연 시간을 기록했습니다 — 이는 직관에 어긋나는 결과입니다.

설명: 2개의 샘플은 LLM 지연 시간을 측정하기에 턱없이 부족합니다. API 응답 시간은 서버 부하에 따라 ±50% 이상 차이가 날 수 있습니다. 안정적인 패턴을 확인하려면 최소 10~20개의 샘플과 중앙값(median)이 필요합니다. 여기서 나타난 차이는 순전한 노이즈(noise)입니다.

시스템 프롬프트 다듬기는 지연 시간이 아닌 토큰 비용을 절감합니다. 지연 시간 최적화에는 다른 도구가 필요합니다.

프롬프트 캐싱 (Prompt Caching) (심화): Claude 및 OpenAI API는 명시적인 프롬프트 캐싱을 지원합니다. Claude의 경우:

response = client.messages.create(
    model="claude-sonnet-4-6",
    system=[{
...

10K개 이상의 토큰을 포함하는 시스템 프롬프트(RAG 결과, 도구 문서, 배경 지식 등)를 사용하는 시스템의 경우, 프롬프트 캐싱 (Prompt Caching)은 활용 가능한 가장 강력한 최적화 방법입니다.

데모 2: 모델 라우팅 (Model Routing) — 단순 쿼리에 대한 에이전트 오버헤드 건너뛰기

핵심 아이디어: 저렴한 분류 (Classification) 호출을 한 번 수행하여 쿼리가 실제로 에이전트를 필요로 하는지 결정합니다. 도구가 필요하지 않은 쿼리는 직접 답변을 받아, 다회차 ReAct 루프를 건너뜁니다.

ROUTING_SYSTEM = """사용자 쿼리를 분류하세요. 오직 한 단어로만 답변하세요:
- "direct": 일반 지식으로 답변 가능한 경우 (실시간 데이터 불필요)
- "agent": 도구 호출이 필요한 경우 (날씨, 제품 가격, 계산 등)"""
...

5개의 테스트 쿼리:

  쿼리                                              경로(Route)  총 소요시간    도구(Tools)
  프랑스의 수도는 어디인가요?                        direct       2194ms       []
  머신러닝을 한 문장으로 설명해주세요.                 direct       2011ms       []
...

분류 정확도: 5/5. 하지만 수치를 살펴보십시오:

  • direct 쿼리: 총 ~2000ms — 여기에는 라우팅 호출(~1초)과 직접적인 LLM 답변(~1초)이 포함됩니다.
  • agent 쿼리: 총 4000–6000ms — 라우팅 호출(~1초)과 전체 에이전트 실행(~3–5초)이 포함됩니다.

라우팅의 숨겨진 비용: 모든 라우팅 결정은 추가적인 LLM 호출을 발생시킵니다. 반드시 에이전트를 거쳐야 하는 쿼리의 경우, 라우팅은 이득 없이 약 1초의 오버헤드만 추가합니다.

라우팅의 투자 대비 효과 (ROI)는 워크로드 내 "도구가 필요 없는 쿼리"의 비율에 달려 있습니다:

만약 쿼리의 40% 이상이 도구를 필요로 하지 않는다면:
  라우팅 절감액: (direct_query_count × agent_overhead)
  라우팅 비용: (all_queries × routing_call_cost)
...

라우팅 레이어를 배포하기 전에 실제 워크로드 분포를 측정하십시오.

데모 3: 병렬 도구 호출 (Parallel Tool Calls) — 3.0배 속도 향상

두 개 이상의 도구 호출이 서로 독립적이라면, 이를 순차적으로 실행할 이유가 없습니다.

async def fetch_weather_async(city: str) -> str:
    await asyncio.sleep(0.1)   # 100ms 시뮬레이션된 I/O 지연 시간
    ...
...

3개 도시 × 100ms 지연 시간, 각 3회 실행:

순차 실행 (Sequential) 평균: 300.4ms (예상치 ~300ms) ✓
병렬 실행 (Parallel) 평균: 101.4ms (예상치 ~100ms) ✓
속도 향상 (Speedup) : 3.0x (66% 더 빠름)

이론이 예측하는 바와 정확히 일치합니다. N개의 독립적인 도구 호출 (tool calls)을 병렬로 수행하면, 지연 시간 (latency)은 N×t에서 t로 감소합니다.

LangGraph는 이를 기본적으로 처리합니다. LLM이 단일 응답 턴 (response turn)에서 여러 개의 tool_calls를 생성하면, create_react_agent는 이를 자동으로 병렬 실행합니다. 별도의 asyncio 상용구 코드 (boilerplate)가 필요하지 않습니다 — 단순히 도구 함수를 async def로 선언하기만 하면 됩니다:

@lc_tool
async def get_weather(city: str) -> str:     # ← async 선언
    """도시의 현재 날씨를 가져옵니다."""
...

전제 조건: LLM이 여러 도구 호출이 독립적임을 인식하고, 이를 한 번의 턴에 함께 생성해야 합니다. 성능이 낮은 모델은 여전히 도구들을 하나씩 순차적으로 호출할 수 있습니다.

데모 4: 도구 결과 캐싱 (Tool Result Cache) — 0ms vs 100ms

적용 시점: 짧은 시간 내에 동일한 인자 (arguments)로 동일한 도구가 여러 번 호출될 때 (예: 사용자가 동일한 도시의 날씨를 두 번 묻거나, 다단계 에이전트가 추론 과정의 서로 다른 시점에서 동일한 데이터가 필요할 때).

_cache: dict[str, tuple[str, float]] = {}
CACHE_TTL_S = 60.0

...

6회 호출, 3개의 고유 도시:

  도시 (City)   상태 (Status)   시간 (Time)   비고 (Note)
  Beijing      MISS            100.2ms       1st call
  Shanghai     MISS            100.2ms       1st call
...

TTL 가이드라인:

데이터 유형TTL이유
날씨 (Weather)5–15분변화가 느림; 사용자는 실시간 정밀도가 필요하지 않음
...

부수 효과 (side effects)가 있는 도구는 절대 캐싱하지 마세요 (파일 쓰기, 이메일 전송, 데이터베이스 변경 등). 동일한 파라미터로 동일한 호출을 재실행하면 중복된 부수 효과가 발생하게 됩니다.

설계 체크리스트

토큰 최적화 (Token optimization)

  • 시스템 프롬프트 (system prompt) 토큰 수를 계산하세요; 모든 문장에 대해 의문을 던지세요 ("이 문장이 정말로 필요한가?")
  • 정적 참조 문서 (제품 매뉴얼, API 문서 등)를 RAG 검색 (RAG retrieval)으로 이동시키세요 — 필요할 때만 주입하세요
  • 대화 기록 (conversation history)을 최근 10~20회 대화로 제한하세요; 삭제된 내용은 요약하세요
  • 대량의 호출 + 큰 시스템 프롬프트가 발생하는 경우 → Claude/OpenAI의 프롬프트 캐싱 (Prompt Caching) ROI를 평가하세요

모델 라우팅 (Model routing)

  • 라우터 (router)를 구축하기 전에 도구 (tools)가 필요 없는 쿼리의 비율을 측정하세요
  • 라우팅 분류기 (Routing classifier) 프롬프트는 일반적인 '직접 응답/에이전트 분리'가 아니라, 실제 의도 경계 (intent boundary)를 반영해야 합니다
  • 라우팅 오버헤드 (추가적인 LLM 호출 1회)를 에이전트 오버헤드 절감 효과와 비교하여 측정하세요

병렬 도구 호출 (Parallel tool calls)

  • 도구 함수를 async def로 선언하세요; LangGraph는 독립적인 호출을 자동으로 병렬화합니다
  • "반드시 순차적이어야 하는" 도구 (A의 출력이 B의 입력으로 들어가는 경우)와 진정으로 독립적인 도구를 식별하세요
  • 멀티 프로바이더 (Multi-provider) 시나리오: 서로 다른 서비스로의 병렬 호출 → 총 지연 시간 (total latency) = 개별 지연 시간의 합이 아닌, 개별 지연 시간 중 최댓값(max)

도구 결과 캐싱 (Tool result caching)

  • 멱등성 (idempotent) 도구 (동일한 입력 → 동일한 출력)를 우선시하세요
  • 데이터 신선도 (data freshness) 요구 사항에 따라 도구별로 TTL (Time To Live)을 설정하세요; 모든 것에 하나의 TTL을 사용하지 마세요
  • 쓰기/부수 효과 (write/side-effect)가 있는 도구는 절대 캐싱하지 마세요
  • 프로덕션 환경: 멀티 인스턴스 간 캐시 공유를 위해 인메모리 딕셔너리 (in-memory dict) 대신 Redis를 사용하세요

요약 (Summary)

다섯 가지 핵심 요점:

  1. 토큰 비용 (Token cost)은 가장 통제 가능한 비용입니다: 시스템 프롬프트 (system prompt), 도구 스키마 (tool schemas), 대화 기록 (conversation history) — 이들은 각각 모델이나 아키텍처를 변경하지 않고도 측정 및 감소가 가능합니다.
  2. 지연 시간 (Latency) 측정에는 충분한 샘플이 필요합니다: 2회 실행 결과는 오해를 불러일으킬 수 있습니다 (여기서는 verbose 모드가 "더 빨랐음"); 10개 이상의 샘플과 중앙값 (median values)을 사용하여 안정화하세요.
  3. 모델 라우팅 (Model routing)에는 숨겨진 오버헤드가 있습니다: 라우팅은 쿼리당 하나의 LLM 호출을 추가합니다; 이는 쿼리의 40% 이상이 도구를 필요로 하지 않을 때만 이득이 됩니다.
  4. 병렬 도구 호출 (Parallel tool calls)은 가장 깔끔한 최적화 방법입니다: N개의 독립적인 호출 → 지연 시간이 N×t에서 t로 단축됩니다; LangGraph는 비동기 도구 함수 (async tool functions)를 통해 이를 기본적으로 지원합니다.
  5. 캐시 ROI (Cache ROI)는 적중률 (hit rate)에 달려 있습니다: 적중률이 30% 미만이면 캐싱의 복잡성이 이점보다 커집니다; 캐시 구현 자체보다 TTL (Time To Live) 설계가 더 중요합니다.

다음 예고: Harness Engineering — Complete System — 5가지 요소의 소개에서 확장하여, 액션 스페이스 레지스트리 (action space registry), 권한 예산 시스템 (permission budget system), 그리고 완전한 위협 모델 (threat model)을 포함하는 전체 8계층 프레임워크를 다룹니다.

참고 문헌 (References)

실제 기업급 워크플로우에서 검증된 AI 에이전트와 기술의 큐레이션 마켓플레이스인 PrimeSkills를 확인해 보세요. 군더더기 없이 실제로 작동하는 것들만 제공합니다.

홈페이지에서 더 유용한 지식과 흥미로운 제품들을 찾아보세요.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0