
SigNoz를 통해 디버깅하는 AI SRE를 구축했습니다 — 가장 어려웠던 점은 AI가 아니었습니다
요약
SigNoz를 활용하여 운영 환경의 장애를 조사하고 근본 원인을 분석하는 자율형 AI SRE 에이전트 'Agent K' 구축 사례를 소개합니다. 에이전트의 추론이 실제 텔레메트리 데이터에 근거하도록 신뢰성을 확보하고, 에이전트 자체를 관찰 가능하게 만드는 과정에 집중합니다.
핵심 포인트
- SigNoz MCP 서버를 통해 에이전트가 트레이스, 로그 등 텔레메트리 데이터를 직접 조회
- 에이전트의 모든 동작을 OpenTelemetry로 기록하여 에이전트 자체의 관찰 가능성 확보
- 단순 추론을 넘어 실제 데이터에 근거한 신뢰할 수 있는 에이전트 구축의 중요성 강조
- 장애 발생 시 Slack 알림, 원인 분석, 복구 제안까지 이어지는 자동화 워크플로우
Agents of SigNoz 해커톤 (WeMakeDevs × SigNoz). 트랙 1: AI & Agent Observability.
Repo: https://github.com/100xRahul/agent-k-signoz · 데모 영상:
저는 운영 환경의 장애(production incidents)를 조사하는 AI 에이전트(AI agent)를 구축하기로 했습니다. 제가 어렵다고 예상했던 부분 — LLM이 트레이스(traces)와 로그(logs)를 바탕으로 추론하게 만드는 것 — 은 알고 보니 쉬운 20%에 불과했습니다. 진짜 어려운 80%는 에이전트가 운영 환경을 지목할 수 있을 만큼 신뢰할 수 있게 만드는 것이었습니다. 즉, 에이전트의 답변이 실제 텔레메트리(telemetry)에 근거하고 있음을 증명하고, 에이전트 자체를 관찰 가능(observable)하게 만드는 것이었습니다. 이 포스트는 저에게 그 사실을 가르쳐준 두 가지 버그와, SigNoz가 어떻게 에이전트의 눈이자 책임 계층(accountability layer)이 되었는지에 관한 이야기입니다.
제가 구축한 것
Agent K는 자율적인 온콜 SRE(on-call SRE)입니다. SigNoz 알람(alert)이 발생하면 → 웹훅(webhook)이 에이전트를 깨우고 → 공식 SigNoz MCP 서버를 통해 조사하며 → 비즈니스 영향 범위(business blast radius)를 포함한 근본 원인 분석(root-cause analysis)을 Slack에 게시합니다 → 그리고 클릭 한 번의 승인을 거쳐 보호된 복구(guarded remediation)를 제안합니다 → 에이전트가 수행하는 모든 단계는 OpenTelemetry를 통해 동일한 SigNoz 인스턴스로 다시 방출됩니다.
이 마지막 구절이 핵심 아이디어입니다: SigNoz가 SigNoz를 관찰하는 에이전트를 관찰합니다.
이것을 단순한 장난감이 아닌 실제적인 것으로 만들기 위해, 저는 OpenTelemetry가 적용된 소규모 데모 숍인 "AstroMart"를 구축했습니다. 이는 Postgres와 Redis를 사용하는 4개의 FastAPI 서비스(gateway → checkout → payment → inventory)로 구성되며, 5가지의 뚜렷한 장애 시그니처(잘못된 배포, DB 풀 고갈, 피처 플래그(feature-flag) 충돌, 비밀 정보 유출, 정상 상태)를 주입하는 카오스 CLI(chaos CLI)를 포함합니다.
SigNoz가 작업을 수행하는 방식
에이전트는 데이터베이스와 직접 통신하지 않습니다. 대신 SigNoz MCP 서버를 통해 모든 것을 읽습니다. 여기에는 14개의 읽기 전용 도구(서비스 목록 조회, 트레이스(traces) 집계, 로그 검색, Query Builder v5 실행, 알림(alert) 이력 가져오기 등)가 포함됩니다. 저의 조사 "플레이북(playbook)"은 기본적으로 모델이 따르는 QB v5 치트 시트(cheat-sheet)와 같습니다.
- 에러율 (Error rate):
service.name = 'checkout'에 대해countIf(has_error=true) / count() * 100실행. - 배포 상관관계 (Deploy correlation): 잘못된 롤아웃(rollout)을 포착하기 위해
service.version별로p99(duration_nano)와countIf(has_error=true)를 그룹화. - 영향 범위 (Blast radius): 실패한 주문 금액을 위한
sumIf(order.total, has_error = true)및 영향을 받은 사용자 수를 위한count_distinct(user.id). - 비밀 정보 유출 (Secret leak): 로그 본문에 대한 정규 표현식(regex) 적용 —
body REGEXP 'AKIA[0-9A-Z]{16}'.
여러분의 시간을 한 시간 정도 아껴줄 만한 구체적인 주의 사항 하나를 말씀드리자면, QB v5에서 hasAll(...)은 **스팬(span) 속성이 아니라 로그 본문 JSON(log-body JSON)**에서 작동한다는 점입니다. 스팬에서 기능 플래그(feature-flag) 충돌을 격리하기 위해 저는 hasAll 대신 feature_flags CONTAINS 'new-checkout' AND feature_flags CONTAINS 'express-pay'를 사용해야 했습니다. 또 다른 하나는, 모든 쿼리를 알림이 발생한 시간대(alert's fire window, 알림 발생 약 15분 전)에 고정해야 한다는 것입니다. 제 첫 번째 버전은 이전에 이미 해결된 사고(incident) 데이터를 가져와서 엉뚱한 배포를 원인으로 확신하며 지목하곤 했습니다.
"그라운딩(grounded)"의 의미를 가르쳐준 버그
이 부분은 문서(docs)만으로는 배울 수 없었던 내용입니다. 저는 두 번째 독립적인 모델인 **감사자 (auditor)**를 추가했습니다. 이 모델의 유일한 임무는 완성된 RCA(근본 원인 분석)를 읽고, 모든 사실적 주장이 에이전트가 실제로 수집한 증거에 의해 뒷받침되는지 확인하는 것입니다. 간단해 보이지만, 이 모델은 제가 작성한 정확한 보고서들을 계속해서 실패 처리했습니다.
첫 번째 실패는 저를 놀라게 했습니다. 제가 작성한 잘못된 배포(bad-deploy) RCA는 다음과 같이 정확하게 기술했습니다: "checkout v1.4.2 배포가 실패 경로를 유발했습니다.". 하지만 감사자는 정확히 그 문장을 **근거 없음 (unsupported)**으로 표시했습니다. 기술적으로는 감사자가 맞았습니다. 그 문장은 원시 도구 출력(raw tool output) 어디에도 나타나지 않았기 때문입니다. 하지만 그 문장은 _RCA의 핵심_입니다. 그것은 상관관계가 있는 증거(배포 마커와 그 직후의 에러 급증)로부터 도출된 **추론 (inference)**이지, grep으로 찾아낼 수 있는 사실이 아닙니다. 저는 감사자에게 "이 특정 숫자가 증거에 없다"(플래그 표시)와 "이것은 인용된 증거가 합리적으로 뒷받침하는 진단적 결론이다"(그것이 본연의 임무) 사이의 차이점을 가르쳐야 했습니다.
두 번째 실패는 더 미묘하고 당혹스러웠습니다. 그 수정 이후에도 감사자는 영향 범위 (blast-radius) 수치, 즉 달러 금액과 사용자 수를 계속해서 플래그로 표시했습니다. 저는 그 수치들이 실제 sumIf/count_distinct 쿼리에서 나온 것이라고 확신했습니다. 실제로 그랬습니다. 문제는 제가 감사자에게 전달하는 증거를 처음 45KB로 잘라내고(truncating) 있었다는 점입니다. 그런데 영향 범위 쿼리는 플레이북(playbook)의 마지막에 실행되므로, 그 결과는 절단 지점(cutoff)을 벗어나 있었습니다. 감사자는 말 그대로 볼 수 없는 숫자를 검증하라는 요구를 받고 있었던 것입니다. 앞부분과 뒷부분을 모두 유지하는 head-and-tail truncation 방식으로 전환하여 이 문제를 해결했습니다.
두 가지 수정 사항 모두 실제 시스템을 운영하며 왜 시스템이 내 의견과 다른지를 읽어봐야만 발견할 수 있는 종류의 것들입니다. 이 수정들을 거친 후, 정확한 RCA는 안정적으로 **그라운딩 (grounded)**된 상태로 반환됩니다. 그리고 그 판정 결과는 보고서의 배지, SigNoz의 agentk.audit.groundedness 메트릭, 그리고 근거가 없는 RCA가 배포될 경우 발생하는 알림으로 게시됩니다.
사소한 주의사항: GPT-5와 temperature
저는 에이전트를 gpt-5-mini에서 실행했습니다. 결정론적 (determinism) 결과를 위해 전체 루프에서 temperature=0을 전송했습니다. 하지만 모든 호출에서 다음과 같은 400 에러가 발생했습니다:
Unsupported value: 'temperature' does not support 0 with this model.
Only the default (1) value is supported.
해결 방법은 temperature를 선택 사항으로 만들고, gpt-5-family 모델의 경우 0을 보내는 대신 단순히 이를 생략 (omit) 하는 것이었습니다. 사소한 문제였지만, SDK의 기본값이 괜찮을 것이라고 가정하는 대신 에러 메시지를 읽기 전까지는 모든 조사가 조용히 실패하고 있었습니다.
단순 데모가 아닌 측정
데모는 에이전트가 한 번 맞출 수 있다는 것을 증명할 뿐입니다. 저는 수치를 원했습니다. 그래서 점수가 매겨지는 벤치마크 (benchmark)를 작성했습니다. 이 벤치마크는 실제 혼란 상황을 유도하고 각 장애 클래스에 대해 알림을 발생시킨 뒤, 에이전트가 실시간 조사를 수행하도록 합니다. 그 후 저장된 판결을 정답 (ground truth) — 올바른 서비스, 올바른 장애 시그니처, 올바른 방어 조치 — 에 대해 결정론적으로 채점하며, 아무런 문제가 없을 때 얼마나 자주 페이지를 보내는지 측정하는 건전한 대조군 (control) 테스트도 병행합니다. 채점 기준이 저장된 사실과 감사관 (auditor)의 판결에 기반하기 때문에, 실행 결과가 환각된 서사 (hallucinated narrative)로 통과될 수는 없습니다.
5개 클래스 실행 결과: 탐지, 위치 파악, 분류에서 100%, 근거성 (groundedness) 100%, 그리고 건전한 대조군에서 **오탐 (false alarms) 0%**를 기록했습니다. 또한 이 벤치마크는 먼저 실패함으로써 제 역할을 다했습니다. 제 체크 로직이 보고서 템플릿의 문자열인 "Regression onset:" 라인과 부분 일치(substring-match)하여 완벽하게 정상적인 판결을 오류로 표시하는 오탐 채점 버그를 이 과정에서 잡아낼 수 있었습니다. 정직한 벤치마크는 심사위원이 찾아내기 전에 당신의 버그를 찾아냅니다.
과거의 나에게 해주고 싶은 말
- 에이전트(Agent)는 쉬운 부분입니다. 진짜 핵심 작업은 그라운딩 (Grounding)과 관측성 (Observability)에 있습니다. 근거를 바탕으로 확인하는 방법이 없다면, 자신 있게 근본 원인 분석 (RCA, Root Cause Analysis)을 작성하는 LLM은 아무런 가치가 없습니다.
- 에이전트를 제약하는 것은 유용성을 떨어뜨리는 것이 아니라 오히려 높여줍니다. 하나의 도구 인터페이스 (MCP
step), 비용 예산, 종료 보장, 그리고 독립적인 감사자 (Auditor) — 이러한 제약 조건들이야말로 출력값을 안전하게 신뢰할 수 있게 만든 핵심 요소였습니다. - 가치 있는 신호는 결합(Join)에서 나옵니다. 클라이언트 측 에러율도, 서버 측 롤업 (Rollup) 데이터도 새로운 것은 아닙니다. 정확한 장애 발생 시간대(Incident window)를 기준으로 이 둘을 결합하는 것이
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기




