본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 29. 00:47

에이전틱 AI(Agentic AI)의 관측 가능성: 실제 LLM 에이전트에 OpenTelemetry를 적용하며 배운 점

요약

에이전틱 AI 시스템의 복잡성을 관리하기 위해 OpenTelemetry를 활용한 관측 가능성(Observability) 확보 방법을 다룹니다. 비결정론적 특성을 가진 LLM 에이전트의 실행 경로와 도구 사용, 가드레일 작동 등을 추적하는 실전 가이드를 제공합니다.

핵심 포인트

  • 비결정론적 특성 대응을 위한 분산 트레이스의 중요성
  • 도구 사용 및 가드레일 결정에 대한 맥락적 분석 필요성
  • OpenTelemetry를 활용한 벤더 중립적 관측 체계 구축
  • 에이전트 생태계 전체를 아우르는 메트릭 기준 수립

단순히 "API가 200을 반환했는가?"를 넘어, 도구(tools), API 호출, MCP 서버, 그리고 모델 상호작용에 대한 가시성을 확보하고자 하는 AI 아키텍트를 위한 실전 가이드입니다.

서론 (Introduction)

전통적인 마이크로서비스(microservices)를 배포한다면, 관측 가능성(observability)은 원칙적으로 해결된 문제입니다. 트레이스(traces)는 요청 경로를 보여주고, 메트릭(metrics)은 지연 시간(latency)과 에러율을 드러내며, 로그(logs)는 서사를 제공합니다. 하지만 에이전틱 AI(Agentic AI)는 이러한 사고 모델을 깨뜨립니다.

동일한 사용자 질문이라도 서로 다른 출력을 생성할 수 있습니다. 단 한 번의 "채팅 턴(chat turn)"이 가드레일(guardrail) 체크, 세션 읽기, 다수의 LLM 호출, 웹 검색, 커스텀 도구 실행, 그리고 후속 추론 루프(reasoning loops)를 트리거할 수 있습니다. 실패는 종종 미묘하게 나타납니다. 도구의 속도가 느려지거나, 컨텍스트 윈도우(context windows)가 급격히 팽창하거나, 가드레일이 너무 자주 작동하거나, 혹은 모델이 명확한 에러를 반환하는 대신 부하 상황에서 성능이 저하되는 식입니다.

최근 저는 OpenTelemetry를 사용하여 LLM 애플리케이션을 관측하는 SigNoz 가이드를 학습하고 OpenTelemetry NBA 에이전트 데모를 처음부터 끝까지 실행해 보았습니다. 이 포스트는 해당 실습을 통해 제가 배운 점과, 관측 가능성이 중심에 있는 모델 호출뿐만 아니라 에이전틱 생태계(agentic ecosystem) 전체를 아울러야 하는 이유에 대한 아키텍트로서의 견해를 담고 있습니다.

왜 에이전틱 AI는 다른 관측 가능성 사고방식을 요구하는가

데모를 직접 실행한 후 SigNoz 기사에서 얻은 세 가지 핵심 아이디어가 머릿속에 남았습니다:

1. 비결정론(Non-determinism)이 기본값이다

동일한 프롬프트(prompt)라도 실행할 때마다 다른 답변을 내놓을 수 있습니다. 이는 회귀 테스트(regression testing)를 더 어렵게 만들며, 단위 테스트(unit tests)만으로는 부족하기 때문에 **분산 트레이스(distributed traces)**를 더욱 가치 있게 만듭니다. 단순히 어떤 텍스트가 돌아왔는지가 아니라, 에이전트가 어떤 경로를 거쳤는지를 확인해야 합니다.

2. "정확함"은 맥락적이다

"내일 비가 올까요?"라는 질문에는 한 단어 답변이 적절할 수 있지만, "내 포트폴리오를 재조정해야 할까요?"라는 질문에는 받아들일 수 없는 답변이 될 수 있습니다. 관측 가능성은 가드레일 결정(guardrail decisions), 도구 사용(tool usage), 그리고 **응답 구조(response structure)**를 사용자의 의도 및 주제와 상관관계 분석(correlate)할 수 있도록 도와줍니다.

3. 스택이 빠르게 변화한다

모델 업데이트, 제공업체의 서비스 일시 중단(brownouts), 새로운 API(Responses vs Chat Completions), 그리고 계속 진화하는 OpenTelemetry GenAI 컨벤션(conventions)은 모두 여러분의 통제 하에 있는 동작을 변화시킵니다. 배포나 모델 교체가 상황을 개선했는지 혹은 악화시켰는지 판단하기 위해서는 기준이 되는 메트릭(baseline metrics)이 필요합니다.

OpenTelemetry는 이러한 상황을 포착할 수 있는 벤더 중립적인(vendor-neutral) 방법을 제공합니다. SigNoz(또는 모든 OTLP 호환 백엔드)는 이를 시각화하는 곳입니다. 데모는 이 배관(plumbing)이 작동함을 증명하며, 실제 운영 환경의 에이전틱 시스템(agentic systems)은 모든 통합 지점(integration point)에 걸쳐 해당 배관을 확장할 것을 요구합니다.

내가 구축하고 실행한 것 (What I Built (and Ran))

이 데모는 의도적으로 작게 설계되었습니다. 하나의 에이전트, 하나의 커스텀 도구(custom tool), 하나의 가드레일(guardrail), 그리고 세션 기반 대화(session-backed conversations)를 갖춘 FastAPI 앱입니다. 이러한 절제는 하나의 기능입니다. 이는 제품의 복잡성 속에 신호(signal)를 숨기지 않으면서도 **의미 있는 에이전트 형태의 텔레메트리(agent-shaped telemetry)**를 생성합니다.

구성 요소역할
FastAPIPOST /agent/turn — 요청당 하나의 대화 턴(conversational turn)
...

환경 변수가 설정되면 실행하는 방법은 간단합니다:

cd python/opentelemetry-llm-demo
pip install -r requirements.txt

...

해당 사이트의 지역적 제한으로 인해 SigNoz 무료 체험 계정을 생성할 수 없었습니다. 하지만 이 데모는 OpenTelemetry 벤더를 지원하므로, 15일간의 Grafana Labs 무료 체험 계정을 생성하여 메트릭을 내보내는 데 사용했습니다.

cd python/opentelemetry-llm-demo
pip install -r requirements.txt

...

중요한 세부 사항: requirements.txt에서 **opentelemetry-instrumentation-openai-agents-v2가 수동으로 고정(pinned)**되어 있습니다. opentelemetry-bootstrap은 아직 OpenAI Agents SDK를 발견하지 못합니다. 이것이 2026년 GenAI 관측 가능성(observability)의 실제 모습입니다. 강력하지만 여전히 성숙해가는 단계에 있습니다.

좋은 트레이스(Trace)는 실제로 어떻게 보이는가

몇 차례의 턴(초기 질문, session_id를 포함한 후속 질문, 도구를 트리거하는 통계 질문, 그리고 가드레일에 의해 차단된 주제 외 질문)을 보낸 후, 나는 트레이스 UI에서 "정상(healthy)"과 "차단됨(blocked)"이 어떻게 보이는지 알게 되었습니다.

성공적인 멀티 턴 흐름 (A successful multi-turn flow)

  1. POST /agent/turn — 루트 (root) HTTP span
  2. Session I/O — 대화 조회 및 저장을 위한 GET/POST span
  3. invoke_agent — 에이전트 워크플로 (workflow) 컨테이너
  4. guardrail_checkgen_ai.guardrail.triggered=false와 함께 수행
  5. Model call span — 모델 이름, 토큰 사용량 (token usage), 선택적 메시지 내용 속성 (attributes)
  6. Tool spans — 에이전트가 calculate_win_percentage를 호출하거나 웹 검색을 수행할 때

후속 요청은 session_id를 재사용하며, 트레이스 (trace)를 통해 에이전트가 처음부터 시작하는 대신 이전 컨텍스트 (context)를 가져오는 것을 확인할 수 있습니다. 이러한 컨텍스트의 증가는 세션 동안 입력 토큰 수의 증가로 나타나며, 이는 대시보드에 기록할 가치가 있는 요소입니다.

가드레일 차단 (A guardrail block)

주제에서 벗어난 쿼리 (off-topic queries) 또한 유용한 텔레메트리 (telemetry)를 생성합니다:

  • **gen_ai.guardrail.triggered=true**가 포함된 guardrail_check
  • 비용이 많이 드는 모델/도구 작업이 수행되기 전에 워크플로 (workflow) 중단
  • FastAPI가 span.record_exception(exc)를 통해 span에 예외 (exception) 기록
  • API가 명확한 메시지와 함께 400 응답 반환

이것이 바로 안전 (safety)과 비용 제어를 동시에 수행하는 관측 가능성 (observability)입니다. 전체 에이전트 루프 (agent loop)에 대한 비용을 지불하지 않고도, 주제별로 가드레일이 얼마나 자주 작동하는지 측정할 수 있습니다.

내가 발견한 솔직한 격차 (Honest gaps I noticed)

여러 span이 **unknown**으로 나타났는데, 이는 아직 시맨틱 span 이름 (semantic span names)으로 매핑되지 않은 내부 SDK 경로들입니다. 자식 span (예: guardrail_check)은 여전히 흐름을 설명해 줍니다. Agents SDK를 위한 개방형 준수 노력 (open conformance effort)이 이루어진다면 이 부분이 개선될 것입니다. 아키텍트로서, **오늘은 부분적인 커버리지 (partial coverage)**를 계획하고 **내일은 더 풍부한 컨벤션 (richer conventions)**을 대비하십시오. 가능한 경우 안정적인 속성 (gen_ai.*)을 중심으로 대시보드를 설계하십시오.

전체 에이전틱 생태계 전반의 관측 가능성 (Observability Across the Full Agentic Ecosystem)

NBA 데모는 HTTP → 에이전트 (agent) → 가드레일 (guardrail) → LLM → 도구 (tools) → 세션 스토어 (session store)를 포괄합니다. 실제 운영 환경의 에이전틱 시스템은 더 많은 계층을 추가합니다. 각 계층에는 동일한 처리가 필요합니다: 트레이스 컨텍스트 전파 (trace context propagation), 일관된 span 명명 (consistent span naming), 그리고 **SLO로 집계되는 메트릭 (metrics that roll up to SLOs)**입니다.

Interactions between components in Agentic Ecosystem

LLM 상호작용 (LLM interactions)

모든 모델 호출은 다음 항목을 방출(emit)해야 합니다:

  • 작업 이름(Operation name) 및 제공자 (gen_ai.system, gen_ai.request.model)
  • 입력 / 출력 / 총 토큰 (Input / output / total tokens) (사용 가능한 경우 캐시된 토큰 포함)
  • 지속 시간 (Duration) (gen_ai.client.operation.duration)
  • 종료 사유(Finish reason), 오류 유형(error type), 재시도 횟수(retry count)
  • 선택 사항: 프롬프트/완성 콘텐츠 (운영 환경에서는 OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=0을 통해 비활성화)

데모에서는 API 응답에서도 사용량(usage)을 보여줍니다. 이는 디버깅에 유용하지만, 트렌드 파악을 위한 **진실의 원천(source of truth)은 메트릭(metrics)과 트레이스(traces)**입니다:

{
  "usage": {
    "input_tokens": 123,
...

도구 사용 (Tool usage)

도구는 에이전트가 신뢰할 수 있게 되거나, 혹은 비용이 많이 들게 되는 지점입니다.

각 도구에 다음을 적용(instrument)하세요:

  • 스팬 이름 (Span name): 예: tool.calculate_win_percentage 또는 tool.web_search
  • 인자(Arguments) (정제됨), 결과 크기, 성공/실패 여부
  • 지연 시간(Latency) 및 타임아웃(timeout) 이벤트
  • 에이전트 스팬으로 연결되는 부모 링크 (Parent link)

**도구 지연 시간(tool latency) 대 모델 지연 시간(model latency)**을 비교하십시오. 많은 에이전트에서 느린 외부 API가 p95를 지배하는 반면, LLM은 단독으로는 괜찮아 보일 수 있습니다.

API 호출 (REST, GraphQL, 내부 서비스)

데모의 웹 검색은 모든 외부 의존성(external dependency)을 대신하는 예시입니다. 이를 마이크로서비스 호출처럼 취급하십시오:

  • 아웃바운드 헤더(outbound headers)에 트레이스 컨텍스트(trace context) 전파
  • 상태 코드(status codes), 페이로드 크기(payload sizes), 재시도 동작 기록
  • 의존성 맵(dependency maps)을 위해 의존성 이름별로 태그 지정

MCP 서버 호출

Model Context Protocol (MCP) 서버는 에이전트가 데이터베이스, 리포지토리(repos), 티켓팅 시스템 및 내부 API에 접근하는 표준 방식이 되어가고 있습니다. 이들은 일급 스팬(first-class spans)을 가질 자격이 있습니다:

신호 (Signal)중요한 이유
mcp.server.name, mcp.tool.name어떤 통합(integration)이 실패했거나 느려졌는지 확인
...

API에서 에이전트를 거쳐 MCP 클라이언트 호출에 이르기까지 동일한 트레이스 ID (trace ID)를 전파하십시오. 그렇지 않으면 "에이전트가 느렸다"는 현상을 세분화하여 분석하는 것이 불가능합니다.

가드레일 (Guardrails) 및 정책 계층

데모의 키워드 가드레일은 단순하지만, 프로덕션 시스템에서는 분류기 (classifiers), 개인정보(PII) 탐지기, 예산 집행기 (budget enforcers)를 사용합니다. 다음 사항을 추적하십시오:

  • 가드레일 이름별 트리거율 (Trigger rate)
  • 가드레일 평가에 소요된 시간
  • 차단 (Block) vs 경고 (Warn) vs 편집 (Redact) 결과

가드레일 차단 사례를 절약된 토큰 (saved tokens) 및 **방지된 도구 호출 (avoided tool calls)**과 상관 분석하여 경영진에게 복잡성을 정당화하십시오.

세션 (Sessions) 및 메모리

OpenAIConversationsSession은 컨텍스트 (context)를 명시적으로 만듭니다. 모든 메모리 계층 (벡터 스토어 (vector store), Redis, 커스텀 DB)에 대해 다음을 관찰하십시오:

  • 턴(turn)당 읽기/쓰기 지연 시간 (latency)
  • 컨텍스트 크기 증가 (토큰 또는 바이트)
  • 검색된 청크 (chunks)에 대한 캐시 히트율 (cache hit rate)

통제되지 않는 컨텍스트 확장은 긴 대화에서 **지연 시간 및 비용 급증 (latency and cost spikes)**을 일으키는 주요 원인입니다.

모든 AI 아키텍트가 추적해야 할 지표 (Metrics)

트레이스 (Traces)는 _하나_의 요청을 설명합니다. 지표 (Metrics)는 시스템이 대규모 환경에서 건강한 상태인지를 알려줍니다. 아래는 실무적인 카탈로그입니다. 일부는 현재 GenAI 인스트루멘테이션 (instrumentation)에 의해 자동으로 내보내지며, 나머지는 직접 도출하거나 커스텀 인스트루멘테이션을 추가해야 합니다.

지연 시간 (Latency) 및 스트리밍

지표 (Metric)정의중요한 이유
첫 번째 토큰 도달 시간 (Time to First Token, TTFT)요청 시작 → 첫 번째 스트리밍 토큰사용자가 체감하는 응답성; 급증은 종종 큐잉 (queueing) 또는 콜드 스타트 (cold starts)를 나타냄
...

토큰 및 비용

지표 (Metric)정의중요한 이유
gen_ai.client.token.usage (입력 / 출력 / 총합)작업당 토큰 수비용 및 컨텍스트 압박의 직접적인 동인
...

신뢰성 및 품질 대리 지표 (Reliability and quality proxies)

지표 (Metric)정의 (Definition)중요성 (Why it matters)
Span kind별 에러율 (Error rate by span kind)LLM vs 도구 (tool) vs MCP vs HTTP실패가 집중되는 지점을 타겟팅하여 수정
...

에이전트 특화 운영 지표 (Agent-specific operational metrics)

지표 (Metric)정의 (Definition)중요성 (Why it matters)
턴당 도구 호출 수 (Tool calls per turn)도구별 횟수 계산비용 및 지연 시간 (latency) 승수
...

권장 대시보드 (Suggested dashboards)

  1. 비용 및 사용량 (Cost & usage) — 모델, 주제, 테넌트(tenant)별 토큰 및 예상 지출
  2. 지연 시간 (Latency) — p50/p95 TTFT (첫 토큰 생성 시간), 턴 지연 시간 (turn latency), 도구 지연 시간 (tool latency)
  3. 신뢰성 (Reliability) — 에러율, 가드레일 차단 (guardrail blocks), 도구 실패
  4. 에이전트 행동 (Agent behavior) — 도구/MCP 호출 혼합 비율, 루프 깊이 (loop depth), 세션 길이

SigNoz의 OpenAI Python SDK 대시보드 템플릿은 합리적인 시작점입니다. 다만 에이전트 SDK (Agents SDK), MCP, 그리고 커스텀 도구(custom tools)를 위해 이를 확장해야 할 것입니다.

GenAI 시맨틱 컨벤션 (GenAI Semantic Conventions): 내가 체득한 것

OpenTelemetry는 진화 중인 GenAI 시맨틱 컨벤션 (GenAI semantic conventions)에 따라 gen_ai.* 속성(attributes)을 사용합니다. 이를 **'변화하는 계약 (contract in motion)'**으로 취급하십시오:

  • gen_ai.agent.name — 어떤 에이전트가 실행되었는지
  • gen_ai.input.messages / gen_ai.output.messages — 디버깅에는 강력하지만, 운영 환경에서는 개인정보(PII) 유출 위험이 있음
  • gen_ai.guardrail.triggered — 정책 적용 결과
  • gen_ai.client.token.usage — 표준화된 토큰 지표
  • gen_ai.client.operation.duration — 표준화된 지연 시간 (latency) 지표

콘텐츠 캡처 (Content capture): 세션 기반 대화의 경우, gen_ai.input.messages에는 최신 사용자 메시지뿐만 아니라 **이전 턴 (prior turns)**이 포함될 수 있습니다. 운영 환경에서는 캡처를 비활성화하십시오:

export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=0

계측 (Instrumentation) 선택: 일반적인 OpenAI Python SDK 계측은 Responses API보다 뒤처져 있었습니다. 본 데모에서는 **OpenAI Agents SDK + opentelemetry-instrumentation-openai-agents-v2**를 사용합니다. 실제 실행되는 코드 경로와 일치하는 계측 도구를 선택하십시오. 그렇지 않으면 눈을 감고 운전하는 것과 같습니다.

운영 환경 설계로 가져갈 교훈들

AI 자동 생성 콘텐츠

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

원문 바로가기
0

댓글

0