Dasis AI Blog
← 목록으로

AI 에이전트 추적이 기존 모니터링과 다른 이유

· DASIS Team · #OpenTelemetry #AI에이전트 #데이터거버넌스

프로덕션에 배포된 AI 에이전트가 잘못된 답변을 내놨을 때, 어디서 문제가 발생했는지 추적할 수 있는가. 기존 APM 도구로는 이 질문에 답하기 어렵다. 에이전트는 단순한 API 호출 체인이 아니라 LLM 추론, 툴 실행, 메모리 조회, 외부 검색이 동적으로 엮이는 구조이기 때문이다.

기존 옵저버빌리티 도구는 HTTP 요청-응답, 레이턴시, 에러율 같은 확정적 지표를 기준으로 설계되었다. 그러나 AI 에이전트의 실패는 레이턴시 스파이크나 500 에러로 드러나지 않는다. "프롬프트에 잘못된 컨텍스트가 전달됐다", "툴이 의도와 다른 순서로 호출됐다", "LLM이 중간 추론 단계에서 잘못된 전제를 채택했다" 같은 의미론적 오류로 나타난다.

이 글은 OpenTelemetry 표준과 Unity Catalog를 조합해 에이전트 추적(tracing)을 프로덕션 수준으로 구축하는 방법을 다룬다. 거버넌스와 운영 안정성을 동시에 요구하는 엔터프라이즈 환경에서 이 조합이 어떤 구조로 작동하는지 설명한다.

전통적 옵저버빌리티가 AI 에이전트에서 실패하는 지점

전통적인 분산 트레이싱은 요청이 마이크로서비스 경계를 넘을 때 span을 생성하고, 이 span들이 하나의 trace로 묶인다. 각 span에는 시작 시각, 종료 시각, 에러 여부가 기록된다. 이 모델은 결정론적(deterministic) 시스템에서 잘 동작한다.

에이전트 시스템은 결정론적이지 않다. 같은 입력을 받아도 에이전트가 어떤 툴을 몇 번 호출할지는 LLM의 추론에 달려 있다. 추적해야 할 데이터도 다르다. 어떤 프롬프트가 LLM에 전달됐는지, LLM이 어떤 reasoning 과정을 거쳤는지, 툴 호출 결과가 다음 추론에 어떻게 반영됐는지, 최종 응답이 어떤 컨텍스트를 바탕으로 생성됐는지 같은 정보가 필요하다.

또한 에이전트는 프레임워크에 따라 실행 환경이 다르다. LangChain, LlamaIndex, AutoGen, OpenAI Assistants, 직접 구현한 에이전트가 동일한 파이프라인에 공존할 수 있다. 각 프레임워크가 자체 로깅 인터페이스를 사용하면, 엔터프라이즈 팀은 파편화된 관측 데이터를 따로따로 관리해야 한다.

OpenTelemetry 기반 에이전트 추적 구조

OpenTelemetry(OTel)는 분산 시스템의 텔레메트리 수집을 표준화하는 CNCF 프로젝트다. 원래는 마이크로서비스 추적을 위해 설계됐지만, span 속성에 임의의 키-값을 추가할 수 있는 유연한 구조 덕분에 AI 에이전트 추적에도 적용 가능하다.

Databricks의 MLflow는 OTel 호환 추적 API를 노출한다. 에이전트의 각 실행 단계를 span으로 기록하고, LLM 입출력, 툴 호출 결과, 토큰 사용량, 레이턴시를 span 속성으로 저장한다. 이 데이터는 Unity Catalog에 테이블로 적재되어 SQL로 쿼리할 수 있다.

핵심 구조는 다음과 같다.

[에이전트 실행]
  └── Root Span: agent_run
        ├── Span: llm_call (프롬프트, 응답, 토큰 수)
        ├── Span: tool_call_1 (툴 이름, 입력, 출력)
        ├── Span: llm_call (중간 추론)
        ├── Span: tool_call_2
        └── Span: llm_call (최종 응답 생성)

각 span은 trace_id로 연결되므로, 특정 사용자 요청이 에이전트 내부에서 어떤 경로로 처리됐는지 전체 흐름을 재구성할 수 있다.

MLflow Tracing API 코드 예시

MLflow의 tracing API는 데코레이터 방식과 컨텍스트 매니저 방식 모두 지원한다. 기존 에이전트 코드에 침습적(invasive) 변경 없이 추적을 추가할 수 있도록 설계되어 있다.

import mlflow
from mlflow.entities import SpanType

# 자동 추적: 지원되는 프레임워크는 한 줄로 활성화
mlflow.langchain.autolog()

# 수동 추적: 커스텀 에이전트에 적용
@mlflow.trace(span_type=SpanType.AGENT)
def run_agent(user_input: str) -> str:
    with mlflow.start_span(name="retrieve_context", span_type=SpanType.RETRIEVER) as span:
        context = retrieve(user_input)
        span.set_attribute("retriever.num_docs", len(context))

    with mlflow.start_span(name="llm_call", span_type=SpanType.LLM) as span:
        span.set_attribute("llm.model", "gpt-4o")
        span.set_attribute("llm.prompt_tokens", count_tokens(context))
        response = call_llm(context, user_input)
        span.set_attribute("llm.completion_tokens", count_tokens(response))

    return response

LangChain, LlamaIndex, OpenAI SDK 등 주요 프레임워크는 autolog() 한 줄로 자동 계측(auto-instrumentation)이 적용된다.

Unity Catalog에 추적 데이터를 저장하는 이유

추적 데이터를 단순히 로그 시스템에 저장하면 분석 가능성이 제한된다. Unity Catalog에 저장하면 다음이 가능해진다.

첫째, SQL 기반 분석이다. 어떤 에이전트 버전에서 평균 툴 호출 횟수가 가장 많은지, 특정 쿼리 유형에서 토큰 비용이 얼마인지를 표준 SQL로 집계할 수 있다.

-- 에이전트 버전별 평균 툴 호출 횟수와 토큰 비용
SELECT
  request_metadata['mlflow.sourceVersion'] AS agent_version,
  AVG(execution_time_ms)                   AS avg_latency_ms,
  AVG(token_count)                         AS avg_tokens,
  COUNT(*)                                 AS total_requests
FROM catalog.schema.agent_traces
WHERE timestamp >= CURRENT_DATE - INTERVAL 7 DAYS
GROUP BY 1
ORDER BY avg_tokens DESC;

둘째, 접근 제어다. Unity Catalog의 테이블 권한 모델이 그대로 적용된다. 개발팀은 자신이 소유한 에이전트의 trace만 조회하고, 보안팀은 전체 trace에 대한 감사 로그를 별도로 가져갈 수 있다.

셋째, 다운스트림 파이프라인 연결이다. 추적 데이터를 Delta 테이블로 보관하면 평가(evaluation) 파이프라인, 파인튜닝 데이터셋 생성, 비용 청구 모델 등과 바로 연결할 수 있다.

프레임워크 독립성이 엔터프라이즈에서 중요한 이유

엔터프라이즈 환경에서는 에이전트 프레임워크를 단일하게 통일하기 어렵다. 팀마다 이미 사용 중인 도구가 다르고, 외부 벤더가 납품한 에이전트가 특정 SDK에 종속되어 있는 경우도 많다.

OTel 표준을 따르면 프레임워크에 관계없이 동일한 trace 포맷으로 수집할 수 있다. LangChain 에이전트, 직접 구현한 Python 에이전트, 외부 벤더가 제공한 에이전트가 모두 같은 Unity Catalog 테이블에 trace를 쌓는다. 운영팀은 대시보드 하나로 전체 에이전트 플릿을 관측할 수 있다.

반면 MLflow 없이 특정 프레임워크의 자체 로깅에만 의존하면, 에이전트를 교체하거나 추가할 때마다 모니터링 파이프라인을 다시 구축해야 한다.

도입 판단 기준과 운영 고려사항

이 구조가 효과적인 조건이 있다. Databricks를 이미 데이터 플랫폼으로 사용 중이고, MLflow를 실험 추적에 활용하고 있다면 추가 인프라 없이 에이전트 tracing을 붙일 수 있다. Unity Catalog 기반 거버넌스를 이미 운용 중이라면 trace 데이터에도 동일한 권한 모델이 자동으로 적용된다.

반면 Databricks 플랫폼을 사용하지 않는 환경이라면 OTel 수집기(collector)와 백엔드(Jaeger, Tempo 등)를 별도로 구성해야 한다. 이 경우 Unity Catalog와의 통합은 없으므로, SQL 분석이나 접근 제어 연동은 직접 구현해야 한다.

운영 관점에서 주의할 점도 있다. Trace 데이터는 LLM 입출력 전체를 포함하므로 저장 비용이 크다. 프로덕션 트래픽이 많은 환경에서는 샘플링 전략이 필요하다. OTel은 헤드 기반(head-based) 샘플링과 테일 기반(tail-based) 샘플링 모두 지원하지만, 에이전트 실패 케이스를 누락 없이 수집하려면 테일 기반 샘플링 설정이 권장된다.

또한 LLM 입출력에 PII(개인 식별 정보)가 포함될 수 있다. Trace 데이터를 Unity Catalog에 저장하기 전에 PII 마스킹 단계를 파이프라인에 포함해야 한다.

에이전트 옵저버빌리티를 도입하기 전 확인할 것

AI 에이전트를 프로덕션에 운영하는 팀이라면 다음 세 가지 질문에 답할 수 있어야 한다. 특정 사용자 요청이 에이전트 내부에서 어떤 경로로 처리됐는지 재현할 수 있는가. 에이전트 버전을 업데이트했을 때 응답 품질이 나빠진 원인을 데이터로 분석할 수 있는가. 에이전트가 처리한 데이터에 대한 접근 권한을 팀별로 분리할 수 있는가.

OTel 기반 추적과 Unity Catalog를 조합하는 구조는 이 세 질문에 대한 기술적 답변이다. 에이전트 프레임워크가 무엇이든 표준 포맷으로 trace를 수집하고, 기존 데이터 거버넌스 체계 안에서 분석하고 관리할 수 있게 해준다.

에이전트 시스템의 실패는 조용하고 느리게 나타난다. 알림이 울리기 전에 추적 체계를 갖추는 것이 프로덕션 운영의 전제 조건이다.


참고