당신의 AI 에이전트는 변장한 분산 시스템입니다 — 파산하기 전에 OpenTelemetry와 SigNoz로 계측하세요
요약
AI 에이전트를 단순한 애플리케이션이 아닌 복잡한 분산 시스템으로 정의하며, OpenTelemetry와 SigNoz를 활용한 관측성(Observability)의 중요성을 강조합니다. 에이전트 운영 시 발생하는 비용 폭주, 무한 루프, 품질 저하 등의 문제를 해결하기 위한 계측 전략을 제시합니다.
핵심 포인트
- AI 에이전트는 비결정론적이며 복잡한 분산 시스템의 특성을 가짐
- 전통적인 APM으로는 에이전트의 토큰 비용 및 품질 저하를 포착하기 어려움
- OpenTelemetry와 SigNoz를 통한 표준 기반의 계측 필요성 강조
- 비용 폭주, 무한 도구 호출, 조용한 품질 저하가 주요 실패 모드임
WeMakeDevs x SigNoz가 주관하는 Agents of SigNoz 해커톤을 위한 워밍업 블로그입니다. 코드와 전체 빌드 로그는 제 리포지토리에서 확인하실 수 있습니다: github.com/SairaammBharadwaj/sentinel-signoz.
이 포스트의 나머지 부분 동안 제가 옹호할 주장이 하나 있습니다: 당신이 LLM (Large Language Model)을 루프(loop)로 감싸고 도구(tools)를 부여하는 순간, 당신은 애플리케이션을 만드는 것을 멈추고 분산 시스템 (distributed system)을 운영하기 시작한 것입니다 — 이 시스템은 비결정론적(non-deterministic)이며, 당신이 제어할 수 없는 네트워크 경계를 가로질러 확장(fan out)되고, 그 특권에 대해 토큰당 비용을 청구합니다. 대부분의 팀은 장난감 수준의 CRUD 앱보다도 적은 계측(instrumentation)만으로 이러한 시스템을 프로덕션에서 운영하고 있습니다. 그 격차야말로 새벽 2시의 장애, 의문의 청구서, 그리고 소리 없는 품질 저하가 발생하는 지점입니다.
저는 왜 AI 에이전트가 관측성 (observability)을 요구하는지, 2026년 기준 표준 기반의 방식은 어떠해야 하는지, 그리고 왜 SigNoz와 같은 OpenTelemetry 네이티브 백엔드가 데이터를 보내기에 적합한 곳인지에 대해 구체적인 근거를 제시하고자 합니다.
전통적인 모니터링이 포착할 수 없는 실패 모드 (failure modes)
전통적인 서비스는 경계가 있고 대부분 결정론적인 실행 경로를 가집니다. 기존의 APM (Application Performance Monitoring)은 그곳에서 발생하는 잘못된 것들, 즉 500 에러, 느린 쿼리, 메모리 누수 등을 잡아냅니다. 이제 에이전트가 단일 사용자 요청에 대해 실제로 수행하는 작업을 살펴보십시오:
사용자 쿼리 (user query)
└─ LLM 호출 #1 (planning) → 1,900 tokens
└─ 도구: vector_search(k=8) → 420 ms, 8 chunks
...
이것은 **세 번의 LLM 호출, 네 번의 도구 호출, 세 번의 재시도(retries), 그리고 14 KB의 컨텍스트 주입(context injection)**이 단 하나의 채팅 말풍선 뒤에 숨겨져 있는 상태입니다. 이 각각은 독립적인 실패 표면(failure surface)이며, 흥미로운 실패들은 바로 당신의 HTTP 상태 코드 대시보드가 절대 기록하지 못할 것들입니다:
-
비용 폭주(Cost runaway). 재시도 루프나 지나치게 적극적인 재계획 단계는 예외를 발생시키지 않습니다. 그저 조용히 토큰 지출을 10배로 늘릴 뿐입니다. 비용은 에이전트의 주요 실패 모드이며, 청구서의 각주가 아닙니다. 단 하나의 오작동하는 대화가 천 개의 잘 작동하는 대화보다 더 많은 비용을 초래할 수 있습니다.
-
무한 도구 호출 루프(Unbounded tool-call loops). 에이전트가 도구를 호출하기로 결정하고, 그 결과에 만족하지 못해 다시, 또다시 호출합니다. 예외는 발생하지 않습니다. 지연 시간은 증가하고, 토큰은 소모되며, 유일한 외부 증상은 포기한 사용자입니다.
-
조용한 품질 저하(Silent quality degradation). 이것이 가장 무서운 경우입니다. 시스템은 유창하고 자신감 있지만, 틀린 답변을 담아
200 OK를 반환합니다. 로그나 메트릭에서 아무것도 변하지 않습니다. 지원 티켓이나 이탈 고객으로부터 그 사실을 알게 됩니다. -
컨텍스트 및 검색 오염(Context and retrieval poisoning). 검색 단계가 잘못된 청크를 가져오거나, 도구가 프롬프트에 신뢰할 수 없는 텍스트를 주입합니다. 모델은 충실하게 이를 따릅니다. 외부에서 볼 때 모든 것이 정상으로 보입니다.
-
비재현성(Non-reproducibility). 샘플링 온도와 모델 측의 비결정론성은
-
**트레이스 (Trace)**는 엔드 투 엔드(end to end)의 전체 요청 하나를 의미합니다. 위의 트리 전체가 하나의 트레이스입니다.
-
**스팬 (Span)**은 해당 트리 내의 하나의 노드(LLM 호출, 도구 호출, 검색 등)이며, 시작 시간, 지속 시간, 상태, 그리고 임의의 키/값 **속성 (Attributes)**을 가집니다.
-
**스팬 링크 (Span links) 및 부모/자식 관계 (Parent/child relationships)**는 인과 구조를 재구성합니다. 즉, 어떤 LLM 호출이 어떤 도구 호출을 트리거했는지를 보여줍니다.
-
**메트릭 (Metrics)**은 알람을 설정하는 집계 데이터입니다 (p95 지연 시간, 분당 토큰 수, 시간당 비용 등).
-
**로그 (Logs)**는 트레이스 ID(trace ID)를 통해 스팬과 상관관계(correlate)를 가집니다. 따라서 로그 라인은 이를 생성한 정확한 단계에 고정됩니다.
이것이 AI에 특히 유용하게 쓰이는 이유는 OpenTelemetry GenAI 시맨틱 컨벤션 (semantic conventions) 덕분입니다. 이는 표준화된 gen_ai.* 속성 네임스페이스입니다. 모든 팀이 각자 필드 이름을 만들어내는 대신, 생태계는 다음과 같은 컨벤션으로 수렴되었습니다 (이는 이제 2026년의 사실상 표준(de facto) 기준입니다):
gen_ai.system— 제공자 (openai,anthropic, …)gen_ai.request.model/gen_ai.response.modelgen_ai.usage.input_tokens/gen_ai.usage.output_tokensgen_ai.request.temperature,gen_ai.request.max_tokensgen_ai.response.finish_reasongen_ai.operation.name—chat,tool_execution,embeddings등
표준화된 이름은 단순히 미적인 편의를 위한 것이 아닙니다. 표준화된 이름이 있어야 백엔드에서 LLM 전용 뷰를 렌더링할 수 있고, 여러 제공자에 걸쳐 일반적인 공식으로 비용을 계산할 수 있으며, 계측(instrumentation) 코드를 다시 작성하지 않고도 도구를 교체할 수 있습니다. 벤더 중립성 (Vendor-neutrality)이 핵심입니다. 여러분의 데이터는 구조적으로 이식 가능(portable)합니다.
다음은 하나의 모델 호출을 수동으로 계측(manual instrumentation)하는 예시입니다. 실제 에이전트에서는 자동 계측(auto-instrumentation, OpenLLMetry, OpenInference 또는 LangChain/LangGraph를 위한 프레임워크 훅)에 의존하겠지만, 직접 코드로 보는 것이 모델의 구조를 구체적으로 이해하는 데 도움이 됩니다:
from opentelemetry import trace
from opentelemetry.trace import SpanKind, Status, StatusCode
...
도구 호출(tool calls)을 활성 스팬(active span) 아래의 자식 스팬(child spans)으로 중첩하면, 모든 노드에 토큰과 비용이 결합된 전체 인과 관계 트리(causal tree)를 얻을 수 있습니다. 이제 당신의 블랙박스(black box)에서는 구조화되고 쿼리가 가능한 텔레메트리(telemetry)가 흘러나옵니다.
백엔드가 OpenTelemetry-native여야 하는 이유: SigNoz
OTel은 데이터를 방출하지만, 그 데이터를 저장하고, 쿼리하고, 시각화하며, 알림(alert)을 보낼 장소는 여전히 필요합니다. 여기서 중요한 아키텍처 결정은 네이티브(native)인가 아니면 적응형(adapted)인가입니다.
많은 관측성(observability) 벤더들은 독자적인 데이터 모델에 OTLP 엔드포인트를 덧붙이는 방식을 사용합니다. 즉, 당신은 OTel을 보내지만 그들은 이를 변환하며, 그 과정에서 임피던스 불일치(impedance mismatch)(속성 누락, 손실이 발생하는 변환, 트레이스(traces)를 고려하여 설계되지 않은 UI 등)를 떠안게 됩니다. SigNoz는 OpenTelemetry-native입니다. OTLP가 주요 수집 경로이며, 스팬(spans)/메트릭(metrics)/로그(logs)는 gen_ai.* 데이터와 정확히 일치하는 고카디널리티(high-cardinality) 속성에 최적화된 컬럼형 저장소(ClickHouse)에 저장됩니다. 또한 트레이스, 메트릭, 로그는 사후에 짜 맞추는 것이 아니라 설계 단계부터 서로 연관(correlated)되어 있습니다. 이는 오픈 소스이며, Docker 또는 Kubernetes를 통해 셀프 호스팅이 가능하고, 관리형 클라우드 옵션도 제공합니다.
에이전트의 경우, 이러한 아키텍처는 직접적인 이점으로 돌아옵니다:
- 고카디널리티(High-cardinality) 속성이 일급 객체(first-class)로 취급됩니다. 태그 기반 시스템에 페널티를 주는 카디널리티 문제 없이
gen_ai.request.model, 사용자, 도구, 종료 사유(finish reason)별로 데이터를 슬라이싱할 수 있습니다. - **Trace → metric → log 상관관계(correlation)**를 통해
2026년에 SigNoz는 **MCP 서버**를 출시했습니다 (공지, 소스). MCP (Model Context Protocol)는 LLM에 도구 인터페이스(tool surface)를 노출하는 개방형 표준입니다. 여기서 이는 AI 어시스턴트가 자연어로 여러분의 관측 가능성 (observability) 데이터를 쿼리할 수 있음을 의미합니다: "지난 한 시간 동안 가장 느렸던 트레이스(trace)를 보여줘", "오늘 토큰 비용이 가장 높았던 모델 호출은 무엇인가?", 심지어 _"결제 서비스(checkout service)를 위한 장애 대시보드(incident dashboard)를 구축해줘"_와 같은 요청이 가능해집니다.
이것이 시사하는 바를 깊이 생각해보십시오. 전통적인 루프는 사람 → 대시보드 → 눈으로 확인 → 가설 수립입니다. MCP로 쿼리 가능한 백엔드가 있다면, _에이전트(agent)_가 이 루프를 주도할 수 있습니다. LLM이 문제가 되는 트레이스(trace)를 가져오고, 스팬 속성(span attributes)을 읽고, 로그를 상관관계(correlate) 분석하며, 프로그래밍 방식으로 대시보드를 구축할 수 있습니다. 관측 가능성 (observability)은 단순히 확인하러 가는 장소가 아니라, 여러분의 자동화 도구가 추론할 수 있는 API가 됩니다. SigNoz는 이미 자신의 MCP 서버를 쿼리하는 LangChain 에이전트를 데모로 선보였으며, 이를 통해 "관찰 대상인 AI"에서 "관찰하는 AI"로의 루프를 완성했습니다.
해커톤에 가져갈 나의 논지: 루프를 완성하라
오늘날 관측 가능성 (observability)은 탐지(detection) 단계에서 멈춥니다. 알림(alert)을 받으면, 사람이 진단하고 수정합니다. 하지만 이제 진단을 자동화하기 위한 모든 요소가 존재합니다. SigNoz의 표준화된 gen_ai.* 텔레메트리(telemetry), 그리고 에이전트가 이를 읽을 수 있게 해주는 MCP 서버가 그것입니다. 그렇다면 왜 알림 단계에서 멈춰야 합니까?
제가 프로토타입으로 만들고 있는 아키텍처 — Sentinel이라 부르겠습니다 — 는 전체 루프를 실행합니다:
- 대상 에이전트를 OTel GenAI 컨벤션(conventions)으로 계측 (Instrument) 합니다 → 텔레메트리(telemetry) 데이터가 SigNoz로 전송됩니다.
- 전통적인 모니터링이 놓치는 에이전트 특유의 실패 유형을 탐지 (Detect) 합니다 — 비용 폭주(cost runaways), 도구 호출 루프(tool-call loops), 지연 시간 급증(latency cliffs), 그리고 평가 점수를 스팬 속성(span-attributes)으로 활용한 조용한 품질 저하 (silent quality regressions) 등입니다.
- MCP를 통해 SigNoz에 쿼리를 날리고, 문제가 되는 스팬(span)을 격리하며, 인과 관계(causal chain)를 재구성하는 조사 에이전트를 파견하여 진단 (Diagnose) 합니다.
- 조치 (Act) 합니다 — 인시던트 대시보드를 자동 생성하고, 정확히 실패한 스팬에 고정된 평이한 영어 형태의 근본 원인(root-cause) 보고서를 발행하며, 해결책(예: 폭주하는 루프에 대한 서킷 브레이커 적용)을 적용하거나 권장합니다.
다른 AI를 감시하며, 단순히 무엇이 고장 났는지만 알려주는 것이 아니라 왜 고장 났는지 알려주고 이를 해결하기 위해 움직이는 AI. 이것이 제가 심사위원들에게 보여주고 싶은 데모입니다.
에이전트를 출시하고 있다면, 여기서부터 시작하세요
해커톤을 핑계 삼을 필요도 없고, 모든 것을 한꺼번에 해결하려(boil the ocean) 할 필요도 없습니다. 가장 레버리지가 높은 순서는 다음과 같습니다:
- 에이전트에 OpenTelemetry를 추가하세요. GenAI 시맨틱 컨벤션(semantic conventions)을 사용하십시오. 먼저 자동 계측(auto-instrument)을 수행한 다음, 중요한 스팬(도구 호출, 검색 등)을 수동 계측(hand-instrument)하세요.
- 비용과 토큰을 스팬 속성(span attributes)으로 첨부하고,
cost_usd필드를 도출하여 지출이 일차적이고 경고 가능한 신호(signal)가 되도록 하세요. - OTLP를 SigNoz로 연결하세요. Docker로 시작하여 몇 가지 명령만 입력하면 됩니다. 그리고 실제 엔드 투 엔드(end-to-end) 대화 트레이스(trace)를 딱 하나만 읽어보세요.
- 답변 스팬에 평가 점수(eval score)를 첨부하여, 단순한 에러뿐만 아니라 품질 _변동 (drift)_에 대해서도 경고를 받을 수 있도록 하세요.
블랙박스의 가장 무서운 속성은 그것이 실패한다는 점이 아닙니다. 그것이 조용히 실패한다는 점입니다. 그래서 텔레메트리가 아닌 사용자나 청구서를 통해 그 사실을 알게 되는 것이죠.
박스를 계측하세요. 그런 다음 그 내부를 파헤치십시오.
SigNoz 에이전트 해커톤 (2026년 7월 20일–26일)을 위해 제작되었습니다. 계측된 에이전트 (instrumented agent), 주입된 장애 시나리오 (injected failure scenarios), 그리고 탐지 → 진단 → 조치 (detect → diagnose → act) 탐지기가 포함된 코드는 GitHub에서 확인하실 수 있습니다: github.com/SairaammBharadwaj/sentinel-signoz. SigNoz Slack 커뮤니티에 오셔서 함께 기술적인 이야기를 나누어 보세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기