Chapter 10

운영 환경 모니터링

  • 10.1 모니터링: 학습의 출발점
  • 10.2 모니터링 스택
  • 10.3 프로젝트에 적합한 스택
  • 10.4 오픈텔레메트리 계측
  • 10.5 시각화와 알림
  • 10.6 모니터링 패턴
  • 10.7 사용자 피드백
  • 10.8 분포 변화
  • 10.9 지표 소유권과 기능 간 거버넌스

모니터링 없이 프로덕션에 에이전트를 올리는 건, 눈 감고 고속도로에 들어서는 것과 같아. 9장까지 에이전트를 설계하고, 평가하고, 배포하는 법을 다뤘는데, 이제 그 다음 단계 — 배포한 놈이 프로덕션에서 실제로 잘 돌아가고 있는지 어떻게 알 수 있냐는 얘기야.

모니터링을 단순한 운영 업무로 보지 말고, 학습의 출발점으로 봐야 해. 에이전트 시스템은 비결정적이니까 — 같은 입력에 다른 출력이 나올 수 있고, 환경이 바뀌면 동작도 바뀌잖아. 이때 모니터링은 "지금 뭐가 잘못됐나"를 찾는 게 아니라 시스템이 현실 세계에서 어떻게 행동하고 있는가를 배우는 도구야.

전통적인 소프트웨어 모니터링이랑 뭐가 다르냐면:

  • 기존 소프트웨어: CPU, 메모리, 에러율, 레이턴시 — 이거면 충분해. 같은 입력에 같은 출력이 나오니까
  • 에이전트 시스템: 위에 더해서 토큰 사용량, 모델 응답 품질, 도구 호출 성공률, 추론 경로, 환각 빈도까지 봐야 해. 비결정적이니까 "정상"의 기준 자체가 유동적이지

이걸 **관찰 가능성(Observability)**이라는 개념으로 확장해야 해. 모니터링이 "미리 정의한 지표를 감시"하는 거라면, 관찰 가능성은 "예상 못 한 문제도 사후적으로 탐색 가능한 상태"를 만드는 거야. 에이전트 시스템에서는 모니터링만으로 부족하고, 관찰 가능성이 필요하다는 게 핵심 논점이지.

에이전트 모니터링에서 봐야 할 세 가지 축:

  • 메트릭(Metrics) — 숫자로 집계되는 것. 토큰 수, 지연시간, 에러율
  • 로그(Logs) — 개별 이벤트 기록. 프롬프트, 응답, 도구 호출 내역
  • 트레이스(Traces) — 요청 하나의 전체 흐름. 에이전트가 어떤 순서로 뭘 했는지

이 세 가지가 합쳐져야 "왜 이 응답이 나왔는지"를 역추적할 수 있어.

도구 얘기로 넘어가면, 다섯 가지 스택을 비교할 수 있는데 각각의 강점이 달라.

그라파나(Grafana) + LGTM 스택 — 그라파나 자체는 시각화 도구인데, 보통 이런 조합으로 써:

  • Prometheus/Mimir — 메트릭 수집 및 저장
  • Loki — 로그 수집. Elasticsearch처럼 전문 인덱싱은 안 하지만, 라벨 기반으로 가볍고 비용 효율적
  • Tempo — 분산 트레이싱
  • Grafana — 이 셋을 한 대시보드에서 시각화

장점은 생태계가 넓고 커스터마이징이 자유롭다는 거야. 단점은 컴포넌트마다 따로 설정해야 해서 초기 셋업이 번거롭다는 거지. 이미 Prometheus + Grafana 쓰는 팀이면 여기에 LLM 메트릭만 추가하면 되니까 자연스러워.

ELK 스택 (Elasticsearch, Logstash, Kibana) — 전통적인 로그 분석의 왕이야. 풀텍스트 검색이 강해서 에이전트 프롬프트/응답을 검색할 때 좋지. 근데 메트릭이랑 트레이싱은 별도 도구가 필요하고, 리소스를 많이 먹는다는 게 단점이야. 로그 중심 분석이 핵심이면 ELK, 전체 관찰 가능성이면 다른 걸 추천해.

어라이즈 피닉스(Arize Phoenix) — LLM/AI 에이전트에 특화된 오픈소스 관찰 가능성 플랫폼이야. OpenTelemetry 기반이고 자체 호스팅 가능하지. 재밌는 건 스팬 종류를 CHAIN, LLM, TOOL, RETRIEVER, EMBEDDING, AGENT, RERANKER, GUARDRAIL, EVALUATOR 이렇게 세분화해놨다는 거야. 에이전트의 추론 체인을 단계별로 뜯어볼 수 있어.

트레이스 뷰에서 "이 에이전트가 도구를 3번 호출했는데 두 번째에서 실패해서 재시도한 흐름"을 시각적으로 볼 수 있다는 게 핵심이지.

시그노즈(SigNoz) — 메트릭, 로그, 트레이스를 단일 플랫폼에서 제공하는 오픈소스 도구야. 백엔드로 ClickHouse를 써서 쿼리가 빠르고, 그라파나 스택 대비 최대 45% 비용 절감을 주장하지. 셋업이 간단한 게 장점이야. 근데 LLM 특화 기능은 Phoenix나 Langfuse에 비해 약해.

랭퓨즈(Langfuse) — LLM 관찰 가능성 분야에서 오픈소스 리더야. GitHub 스타 1만 9천 개 이상, MIT 라이선스. 특징은:

  • 멀티턴 대화 지원 트레이싱
  • 프롬프트 버전 관리 + 플레이그라운드
  • LLM-as-a-judge, 사용자 피드백, 커스텀 메트릭을 통한 평가
  • OpenTelemetry 네이티브 지원

LLM 앱을 처음 모니터링하려는 팀에게 진입장벽이 가장 낮다고 보면 돼.

다섯 개 도구를 늘어놓으면 "그래서 뭘 쓰라고?"가 되니까, 상황별로 정리하면:

이미 그라파나/프로메테우스 쓰는 팀 — 그라파나 스택에 LLM 메트릭 레이어만 추가. Tempo로 트레이싱 확장. 기존 인프라를 활용하는 게 효율적이야.

LLM 앱 시작 단계, 빠르게 관찰 가능성 확보하고 싶은 팀 — Langfuse. 셋업이 빠르고 프롬프트 관리까지 돼. 오픈소스라 비용 부담 없지.

프로덕션에서 에이전트 품질을 깊이 분석해야 하는 팀 — Arize Phoenix. 스팬 종류가 세밀해서 에이전트 추론 경로를 정밀 분석 가능해.

통합 플랫폼을 원하는데 비용이 중요한 팀 — SigNoz. 메트릭+로그+트레이스 올인원. ClickHouse 기반이라 대용량에서도 성능 괜찮아.

로그 검색/분석이 핵심인 팀 — ELK. 풀텍스트 검색이 필요하면 여전히 최고야.

핵심 원칙: 도구 하나에 올인하지 마. 실제로는 Langfuse로 LLM 트레이싱 + Grafana로 인프라 메트릭, 이런 식의 조합이 흔하거든. OpenTelemetry를 계측 표준으로 쓰면 백엔드를 나중에 바꿀 수 있으니까, 수집은 OTel로 통일하고 시각화/분석 도구는 용도에 맞게 선택하는 게 맞지.

실무적으로 가장 중요한 건 OpenTelemetry(OTel) 계측이야. 벤더 중립적인 텔레메트리 수집 표준이거든. 한 번 계측하면 Grafana든 Langfuse든 Arize든 어디로든 데이터를 보낼 수 있어.

한 번 계측, 어디든 전송(instrument once, send anywhere) — 특정 모니터링 벤더에 종속되지 않는 게 핵심 장점이지.

OTel의 GenAI 시맨틱 컨벤션(v1.37 기준)이 2025년에 안정화되면서, LLM 앱 텔레메트리를 표준화된 방식으로 수집할 수 있게 됐어. 주요 속성들:

  • gen_ai.system — 어떤 모델 제공자인지 (openai, anthropic 등)
  • gen_ai.request.model — 사용한 모델명
  • gen_ai.request.temperature — 온도 설정
  • gen_ai.response.finish_reason — 종료 이유 (stop, length 등)
  • gen_ai.usage.input_tokens, gen_ai.usage.output_tokens — 토큰 사용량

에이전트 스팬은 invoke_agent {gen_ai.agent.name} 형태로 기록되고, 하위 스팬으로 LLM 호출, 도구 호출, 검색 등이 트리 구조로 달려.

실제 계측 구조를 보면:

[Agent Span] "고객 문의 처리"
  ├── [LLM Span] claude-3.5-sonnet 호출 (토큰: 입력 1,200 / 출력 450)
  ├── [Tool Span] 주문 조회 API 호출 (200ms)
  ├── [LLM Span] claude-3.5-sonnet 재호출 (토큰: 입력 2,100 / 출력 800)
  └── [Tool Span] 환불 처리 API 호출 (350ms)

중요한 건 프롬프트/응답 내용을 스팬 속성 대신 이벤트로 기록하라는 거야. LLM 워킹 그룹이 권장하는 방식인데, 프롬프트/응답이 보통 크기가 크니까 스팬 속성에 넣으면 백엔드 시스템에 부담이 되거든. 이벤트로 분리하면 필요할 때만 조회할 수 있지.

OTel Collector도 있는데, 텔레메트리를 수집해서 가공하고 여러 백엔드로 라우팅하는 중간 레이어야. 예를 들어 트레이스는 Tempo로, 메트릭은 Prometheus로, LLM 특화 데이터는 Langfuse로 보내는 식이지. Collector의 프로세서(processor) 단계에서 거버넌스 정책도 적용할 수 있어 — PII 마스킹이나 샘플링 비율 조절 같은 거야.

데이터를 모아놓기만 하면 소용없어. 봐야 되고, 문제가 생기면 알려줘야 하지.

에이전트 대시보드의 핵심 패널:

  • 요청 볼륨 & 지연시간 — 시간대별 요청 수와 p50/p95/p99 레이턴시. 갑자기 느려지면 뭔가 문제
  • 토큰 소비 — 모델별, 에이전트별 토큰 사용량 추이. 비용 폭발 감지
  • 도구 호출 성공/실패율 — 외부 API가 죽으면 에이전트도 죽으니까 이걸 실시간으로 봐야 해
  • 에러 분류 — 모델 에러, 도구 에러, 타임아웃, 가드레일 차단 등을 분류해서 표시
  • 품질 스코어 추이 — LLM-as-a-judge나 사용자 평점의 이동 평균

알림은 크게 두 종류로 나눠:

긴급 알림(Alert) — 즉시 대응 필요. 에러율 급등, 전체 다운, 비용 이상 급증. PagerDuty나 Slack으로 바로 알림.

경고(Warning) — 당장 문제는 아닌데 추세가 안 좋은 것. 품질 스코어가 서서히 하락, 특정 도구 호출 실패율이 조금씩 증가. 이건 대시보드에 표시하고 일간/주간 리뷰에서 확인하면 돼.

안티패턴으로 주의할 건 **알림 피로(Alert Fatigue)**야. 뭐든 알림으로 만들면 결국 다 무시하게 되거든. 정말 즉시 대응해야 하는 것만 알림으로, 나머지는 대시보드에서 추세로 보는 게 맞아.

여기가 10장의 꽃이야. 에이전트 운영에서 쓸 수 있는 네 가지 핵심 패턴이 있어.

섀도 모드(Shadow Mode) — 새 에이전트 버전을 배포할 때, 실제 트래픽을 복제해서 새 버전에도 보내지만 사용자에게는 기존 버전의 결과만 반환하는 방식이야. 새 버전의 응답은 기록만 하고 실제 서비스에는 반영 안 하지.

이게 에이전트에서 특히 유용한 이유 — 합성 테스트(synthetic test)로는 프로덕션의 다양성을 재현할 수 없기 때문이야. 실제 사용자 질문은 테스트 데이터보다 훨씬 예측 불가능하거든.

섀도 모드에서 보는 것:

  • 새 버전의 응답 품질이 기존 대비 나아졌나 떨어졌나
  • 레이턴시 차이
  • 에러율 차이
  • 비용(토큰) 차이

단, 도구 호출이 부작용(side effect)을 일으키는 경우 주의해야 해. 섀도 에이전트가 실제로 주문을 취소하면 안 되니까 — 도구 호출은 목(mock) 처리하거나 읽기 전용만 허용해야 하지.

카나리 배포(Canary Deployment) — 새 버전을 전체가 아니라 트래픽의 일부(예: 5%)에만 먼저 적용하고, 메트릭을 비교한 뒤 점진적으로 비율을 늘려가는 방식이야.

섀도 모드와 차이는 — 카나리는 실제 사용자에게 결과를 반환한다는 거야. 그래서 더 현실적인 피드백을 얻지만, 문제가 있으면 실제 사용자가 영향을 받지.

추천하는 롤아웃 기준:

  • 에러율이 기존 버전 대비 X% 이상 증가하면 자동 롤백
  • 품질 스코어가 임계치 이하면 자동 롤백
  • 레이턴시가 p99 기준으로 Y초 초과하면 경고

실무에서는 섀도 -> 카나리 -> 전체 배포의 3단계를 거치는 게 가장 안전해.

회귀 트레이스(Regression Trace Collection) — 프로덕션에서 품질이 떨어진 케이스를 자동으로 수집해서 평가 데이터셋에 추가하는 패턴이야. 사용자가 부정적 피드백을 주거나, LLM-as-a-judge 점수가 낮은 트레이스를 골든 데이터셋에 넣어서 다음 변경 시 회귀 테스트로 활용하지.

이게 순환을 만들어:

  1. 프로덕션에서 문제 케이스 발견
  2. 자동으로 평가 데이터셋에 추가
  3. 다음 버전에서 이 케이스들을 통과하는지 검증
  4. 배포 후 다시 1번으로

프로덕션이 가장 좋은 테스트 데이터 생성기라는 말이 딱 맞아.

자가 치유(Self-Healing) — 에이전트가 스스로 모니터링하고, 실패를 감지하면 자동으로 복구 조치를 취하는 패턴이야. 예를 들어:

  • 특정 도구 API가 타임아웃 -> 자동으로 폴백 도구로 전환
  • 토큰 사용량이 급증 -> 자동으로 더 작은 모델로 다운그레이드
  • 에러율 급등 -> 자동으로 이전 안정 버전으로 롤백
  • 특정 유형의 요청에서 반복 실패 -> 해당 요청을 인간 에스컬레이션으로 라우팅

주의할 점은 자가 치유의 범위를 명확히 정해야 한다는 거야. 자가 치유 에이전트가 잘못된 판단으로 정상 트래픽을 차단하면 오히려 장애가 되거든. 자가 치유는 잘 알려진 실패 모드에만 적용하고, 알 수 없는 실패는 인간에게 에스컬레이션하라는 게 핵심이야.

사용자 피드백은 가장 귀중한 관찰 가능성 신호인데, 가장 수집하기 어려운 신호이기도 해.

수집 방법은 크게 세 가지야:

명시적 피드백 — 좋아요/싫어요 버튼, 별점, 텍스트 코멘트. 정보량은 많지만 응답률이 극히 낮아. 보통 1~5%만 피드백을 남기거든.

암시적 피드백 — 사용자 행동에서 추론하는 거야. 에이전트 응답을 복사했다 -> 유용했을 가능성 높음. 응답 후 바로 같은 질문을 다시 했다 -> 불만족. 대화를 중간에 이탈했다 -> 관련성 부족.

구조화된 피드백 — 특정 차원에 대해 평가를 요청하는 거지. "이 답변이 정확했나요?", "빠진 정보가 있나요?", "도구 사용이 적절했나요?" 같은 질문. 정보량이 많지만 사용자 부담도 커.

추천하는 방식: 기본은 암시적 피드백으로 넓게 깔고, 핵심 흐름에만 간단한 명시적 피드백(좋아요/싫어요)을 넣어. 구조화된 피드백은 내부 테스터나 베타 사용자한테만 요청하고.

수집한 피드백은 트레이스에 연결해야 의미가 있어. "싫어요"를 눌렀을 때 그 세션의 전체 트레이스 — 어떤 프롬프트가 갔고, 모델이 뭘 반환했고, 도구를 어떻게 호출했는지 — 를 함께 볼 수 있어야 원인을 알 수 있으니까.

**분포 변화(Distribution Shift)**는 ML 모니터링에서 온 개념인데, 에이전트에서는 더 복잡해져. 프로덕션에서 들어오는 입력의 분포가 개발/테스트 때와 달라지는 현상이야. 크게 두 종류가 있지:

데이터 드리프트(Data Drift) — 입력 자체가 바뀌는 거야. 고객 서비스 에이전트를 만들었는데, 갑자기 새 제품이 출시되면서 전에 없던 유형의 질문이 들어오는 경우. 에이전트는 이런 질문에 대해 학습한 적이 없으니까 성능이 떨어지지.

컨셉 드리프트(Concept Drift) — 입력은 비슷한데 "정답"이 바뀌는 거야. 회사 정책이 바뀌면 같은 질문에 대한 올바른 답변이 달라지는데, 에이전트는 이전 정책으로 답변하는 경우지.

감지 방법:

  • 임베딩 기반 모니터링 — 입력 프롬프트의 임베딩 분포를 기준선과 비교. 클러스터가 이동하거나 새로운 클러스터가 생기면 분포가 바뀐 거야. 코사인 유사도나 통계적 거리 측정(KL divergence, Jensen-Shannon divergence)을 사용
  • 성능 메트릭 추세 — 품질 스코어, 사용자 만족도 등이 서서히 하락하는 추세를 감지
  • LLM-as-a-judge로 드리프트 분류 — 드리프트가 감지되면 LLM에게 "새 입력과 기존 입력이 어떻게 다른지"를 분류하게 해서, "새 주제 등장", "사용자 의도 변화", "언어 스타일 변화" 같은 카테고리로 정리

핵심 조언: 분포 변화를 완전히 막을 수는 없어. 빠르게 감지하고 빠르게 대응하는 게 전략이야. 감지 -> 분석 -> 지식 베이스 업데이트 또는 프롬프트 수정 -> 재평가의 루프를 만들어야 하지.

주간 단위로 드리프트 리포트를 생성해서 팀이 검토하는 것도 추천해. 기술적 자동화만으로는 부족하고, 도메인 전문가가 "이 변화가 실제로 문제인지"를 판단해야 하니까.

마지막은 기술 얘기가 아니라 조직 얘기야. 모니터링을 누가 책임질 것이냐.

에이전트 시스템은 여러 팀이 관여하잖아. ML 팀은 모델을, 백엔드 팀은 인프라를, 프로덕트 팀은 사용자 경험을 보지. 근데 "에이전트 응답 품질이 떨어졌다"는 알림이 오면 누가 대응해야 하나? 모델 문제일 수도, 도구 API 문제일 수도, 프롬프트 문제일 수도, 심지어 사용자 입력 분포가 바뀐 것일 수도 있거든.

지표 소유권(Metric Ownership) 프레임워크로 이 문제를 해결할 수 있어:

  • 인프라 지표 — 레이턴시, 가용성, 리소스 사용량 -> SRE/인프라 팀이 소유
  • 모델 지표 — 토큰 효율, 환각율, 추론 품질 -> ML/AI 팀이 소유
  • 비즈니스 지표 — 사용자 만족도, 태스크 완료율, 비용 대비 효과 -> 프로덕트 팀이 소유
  • 교차 지표 — 여러 팀에 걸치는 것 (예: 에이전트 응답 품질은 모델 + 도구 + 프롬프트가 다 관여) -> 명시적으로 주 담당자를 지정

**기능 간 거버넌스(Cross-functional Governance)**는 이 소유권이 실제로 작동하게 하는 프로세스야:

  • 주간 에이전트 헬스 리뷰 — ML, 백엔드, 프로덕트 팀이 함께 대시보드를 보면서 주요 지표 추세 확인
  • 인시던트 대응 절차 — 알림이 왔을 때 누가 먼저 보고, 어떤 기준으로 에스컬레이션하는지 정의
  • 변경 영향 분석 — 모델 업데이트, 프롬프트 변경, 도구 추가 등을 할 때 영향받는 지표와 담당 팀을 사전에 식별

OTel Collector의 프로세서 단계에서 거버넌스 정책을 적용할 수 있다는 것도 여기서 연결돼. 예를 들어 PII 마스킹 정책, 데이터 보존 기간, 접근 권한 등을 텔레메트리 파이프라인 레벨에서 일괄 적용하면, 각 팀이 알아서 준수하는 것보다 훨씬 안정적이지.


정리

10장에서 기억할 거 네 가지:

  1. 모니터링은 운영이 아니라 학습이야. 에이전트가 프로덕션에서 어떻게 행동하는지 배우는 도구로 봐야 해
  2. OTel로 한 번 계측하고, 백엔드는 나중에 선택해. 벤더 종속 피하는 게 장기적으로 맞지. Langfuse, Phoenix, Grafana — 용도에 맞게 조합하면 돼
  3. 섀도 -> 카나리 -> 전체 배포가 가장 안전한 롤아웃 패턴이야. 프로덕션 트래픽은 합성 테스트보다 훨씬 다양하거든
  4. 지표에 주인이 있어야 해. 누가 어떤 알림에 대응하는지 명확하지 않으면, 아무도 대응하지 않아