4 min read

Part 6. 관측성 설계: Trace, Span, 로그 스키마, 회귀 감지

LLM 운영에서 장애 없는 품질 저하를 잡아내려면 trace, 로그, 품질 지표를 하나의 관측 체계로 설계해야 한다.

LLM 시스템에서 "장애"와 "품질 저하"는 같은 사건이 아니다. HTTP 200이 정상적으로 반환되어도 사용자는 "도움이 안 된다"고 느낄 수 있고, 운영자는 인프라 대시보드만 보고 있으면 이 변화를 놓친다. 그래서 LLM 관측성은 전통적인 인프라 모니터링보다 더 넓어야 한다. 추론 단계, 검색 단계, 정책 단계, 도구 실행 단계, 그리고 사용자 반응까지 하나의 흐름으로 묶어야 한다.

문제 제기

실무에서 가장 위험한 상황은 "에러는 없는데 서비스가 나빠지는" 경우다. 다음 패턴이 대표적이다.

  • 모델 응답 성공률은 높지만 사용자 재질문률(follow-up ratio)이 급증한다.
  • 평균 latency는 정상인데 특정 테넌트/도메인만 p95가 악화된다.
  • 비용 절감 라우팅 후 품질이 하락했지만 로그 스키마에 라우팅 정보가 없어 원인 분석이 불가능하다.
  • RAG 검색 품질이 떨어져도 모델 단계 지표만 수집해 회귀를 늦게 인지한다.

실전 예시 A: 사내 검색형 챗봇

배포 후 "답변이 엉뚱하다"는 피드백이 증가했지만, 인프라 지표는 정상으로 보였다. 원인은 retrieval top-k 변경으로 관련 문서 비율이 낮아진 것이었다. 검색 단계 span이 없어서 모델 문제로 오판했다.

실전 예시 B: 고객지원 자동 응답

정책 엔진 룰을 강화한 뒤 응답 거절 비율이 상승했고, 사용자는 다시 질문을 반복했다. 시스템은 200 응답을 반환해 장애로 감지되지 않았다. 결국 CS 티켓이 급증한 뒤에야 문제를 발견했다.

핵심 개념

LLM 관측성은 최소 네 축이 동시에 필요하다.

질문대표 신호실패 시 증상
경로 관측(Path)어디서 느려졌는가trace/span latency병목 구간 미식별
결과 관측(Output)어떤 응답이 나갔는가structured log, policy result원인 재현 불가
품질 관측(Quality)사용자에게 유효했는가resolved rate, follow-up ratio잠복 품질 저하
비용 관측(Cost)이 품질을 얼마에 달성했는가token cost/request비용 급등 탐지 지연

중요한 원칙은 "같은 요청 ID로 모든 신호를 연결"하는 것이다. 이 연결이 없으면 대시보드는 화려해도 의사결정 속도는 느리다.

Mermaid diagram rendering...

실전 패턴

패턴 1: 단계별 Span 표준화

Span 이름과 속성이 팀마다 다르면 분석이 불가능하다. 최소한 요청당 아래 span 집합을 고정하는 것이 좋다.

  • llm.request
  • llm.retrieval
  • llm.inference
  • llm.policy_check
  • llm.tool_execution
  • llm.response_render
import { trace } from "@opentelemetry/api";

const tracer = trace.getTracer("llm-platform");

export async function tracedInference(req: {
  requestId: string;
  tenantId: string;
  promptVersion: string;
  modelRoute: string;
}) {
  return tracer.startActiveSpan("llm.request", async (root) => {
    root.setAttribute("request.id", req.requestId);
    root.setAttribute("tenant.id", req.tenantId);
    root.setAttribute("prompt.version", req.promptVersion);
    root.setAttribute("model.route", req.modelRoute);

    const retrieval = tracer.startSpan("llm.retrieval");
    const docs = await retrieveDocs(req).finally(() => retrieval.end());

    const infer = tracer.startSpan("llm.inference");
    const output = await callModel(req, docs).finally(() => infer.end());

    const policy = tracer.startSpan("llm.policy_check");
    const decision = await evaluatePolicy(output).finally(() => policy.end());

    root.setAttribute("policy.decision", decision.status);
    root.end();

    return decision;
  });
}

운영 포인트:

  • span attribute에 tenant, promptVersion, modelRoute를 반드시 포함한다.
  • 응답 길이/토큰/정책 결정값은 root span에 요약해 검색성을 높인다.
  • PII가 될 수 있는 원문 텍스트는 span에 저장하지 않는다.

패턴 2: 로그 스키마를 "디버그용 문자열"이 아닌 계약으로 관리

LLM 로그는 자유 텍스트로 남기면 활용도가 낮다. 운영 이벤트를 스키마화해 품질/보안/비용 분석에 공통으로 사용해야 한다.

{
  "event": "llm.response.completed",
  "timestamp": "2026-03-03T03:42:10.221Z",
  "request_id": "req_1701",
  "tenant_id": "tenant_a",
  "prompt_version": "assist-v7.1.0",
  "model_route": "small->large_fallback",
  "retrieval_top_k": 8,
  "retrieval_hit_ratio": 0.62,
  "input_tokens": 3480,
  "output_tokens": 512,
  "latency_ms": 1320,
  "policy_decision": "allow",
  "resolved": false,
  "user_follow_up_within_120s": true
}
# 회귀 감지: 최근 30분 follow-up 비율이 7일 베이스라인 대비 20%↑면 경보
./ops/alerts/regression-guard.sh \
  --metric user_follow_up_within_120s_ratio \
  --window 30m \
  --baseline 7d \
  --threshold +20% \
  --group-by tenant_id,model_route

운영 포인트:

  • resolved, follow_up, policy_decision은 제품/플랫폼 공통 KPI로 합의한다.
  • 로그 스키마 버전(schema_version)을 명시해 파서 깨짐을 방지한다.
  • 경보는 전체 평균보다 group-by tenant/model_route/prompt_version 단위가 효과적이다.

패턴 3: "품질 회귀" 전용 SLO 정의

가용성 SLO만 있으면 품질 저하를 놓친다. LLM에는 품질 SLO가 별도로 필요하다.

예시 품질 SLO:

  • resolved_rate >= 78%
  • follow_up_ratio <= 18%
  • policy_false_refusal_rate <= 3%
  • retrieval_hit_ratio >= 0.55

운영 포인트:

  • 품질 SLO 위반 시 배포 파이프라인 승격을 자동 중지한다.
  • 품질 SLO는 주간 단위로 도메인별(결제, 환불, 배송) 분리 검토한다.
  • 정확도/안전성 충돌 구간은 human-review 샘플링 비율을 임시 상향한다.

실패 사례/안티패턴

장애 시나리오: "에러 0%, 불만 급증"

상황:

  • 월요일 오전 배포 후 인프라 오류율은 0.3%로 정상 범위였다.
  • 그러나 user_follow_up_within_120s_ratio가 14%에서 29%로 상승했다.
  • 로그에는 model_route 필드가 누락되어 원인 분리가 어려웠다.

탐지 절차:

  1. CS 티켓 증가와 품질 지표 상승을 교차 확인
  2. trace 샘플에서 llm.retrieval 지연 증가, retrieval_hit_ratio 하락 확인
  3. 최근 배포 변경사항에서 retrieval top-k 축소 및 index refresh 간격 증가 식별

완화 절차:

  1. retrieval 설정을 이전 값으로 롤백
  2. 품질 저하 테넌트에 대해 임시로 큰 모델 라우팅 비율 상향
  3. follow-up 다발 질문을 human-review 큐로 우회

회복 절차:

  1. 로그 스키마에 model_route, retrieval_hit_ratio 필수화
  2. 품질 경보를 배포 경보와 통합
  3. "에러율 정상 + 품질 악화" 복합 시나리오를 장애 훈련(runbook) 항목에 추가

대표 안티패턴

  • 인프라 지표(5xx, CPU)만 보고 LLM 품질을 판단
  • 요청 ID 없이 로그/trace/품질 이벤트를 분리 저장
  • span에 민감정보를 과도하게 기록해 보안 위험 증대
  • 대시보드는 많지만 롤백 트리거 기준이 없는 운영

체크리스트

  • 요청 단위 공통 키(request_id, tenant_id, prompt_version)가 trace/log/metric에 일관되게 포함되는가?
  • llm.retrieval, llm.inference, llm.policy_check span이 표준화되어 있는가?
  • 품질 지표(resolved_rate, follow_up_ratio)가 인프라 지표와 함께 운영되는가?
  • 로그 스키마 버전 관리와 파서 호환 정책이 존재하는가?
  • 회귀 감지 경보가 tenant/model_route/prompt_version 단위로 동작하는가?
  • 품질 SLO 위반 시 배포 승격 중지 또는 자동 롤백이 가능한가?
  • 관측 데이터에 PII 최소화/마스킹 정책이 적용되는가?

요약

LLM 관측성의 목표는 "보여주기"가 아니라 "빠른 원인 규명과 제어"다. trace, 로그, 품질 이벤트를 같은 요청 축으로 묶고, 회귀 감지와 배포 제어까지 연결해야 운영이 안정된다. 장애가 없는데도 품질이 무너질 수 있다는 전제를 시스템에 반영하는 것이 핵심이다.

다음 편 예고

다음 편에서는 Context Engineering을 다룬다. RAG, memory, 최신성(freshness), 멀티테넌시를 어떻게 설계해야 컨텍스트 품질이 유지되는지 설명한다. 특히 "모델은 같은데 답이 갑자기 틀리기 시작한" 상황을 retrieval 품질과 데이터 수명주기 관점으로 분석한다.


이전 편: Part 5. 보안 설계: Prompt Injection, Data Leak, Policy Guard

다음 편: Part 7. Context Engineering: RAG, Memory, 최신성, 멀티테넌시

댓글