
AI 기능을 갑자기 100% 공개하고 계신가요? 운영 사고를 줄이는 「0→1 공개 게이트」 5단계
요약
AI 모델이나 에이전트 업데이트 시 발생할 수 있는 운영 사고를 방지하기 위한 '0→1 공개 게이트' 5단계 전략을 소개합니다. Shadow, Offline eval, Canary, Human gate, Rollback 단계를 통해 사용자 영향을 최소화하며 단계적으로 배포하는 설계 방법을 다룹니다.
핵심 포인트
- Shadow 모드를 통해 사용자에게 영향을 주지 않고 백그라운드에서 후보 모델을 관측할 수 있습니다.
- Offline eval 단계에서는 대표 케이스 집합을 활용해 품질, 안전, 성능, 비용을 측정해야 합니다.
- AI는 차이 분류와 리포트 작성을 맡고, 최종 승인과 책임 결정은 사람이 담당해야 합니다.
- 후보 버전은 부작용을 방지하기 위해 읽기 전용(Read-only)으로 제한하는 것이 안전합니다.
업데이트 날짜: 2026-07-21
새로운 모델, 새로운 프롬프트 (Prompt), 새로운 AI 에이전트 (Agent). 테스트 환경에서는 괜찮았으니까, 그대로 모든 사용자에게 공개한다.
이거, 조금 무섭지 않나요?
일반적인 소프트웨어라면 동일한 입력에 대해 대개 동일한 결과가 반환됩니다. 하지만 AI 기능은 문장으로서 자연스럽더라도 의미가 어긋나거나, 안전 규칙을 벗어나거나, 비용만 치솟기도 합니다. 그래서 결론은 심플합니다. 100% 공개하기 전에, 사용자 영향이 0%인 관측부터 시작하는 것입니다.
이 글에서는 이것을 「0→1 공개 게이트 (0→1 Release Gate)」라고 부릅니다. 사용자 영향 0%의 관측부터 시작하여, 증거가 모일 때마다 책임 범위를 단계적으로 넓혀가는 릴리스 (Release) 설계입니다.
- Shadow: 현행 버전을 반환하면서 후보 버전을 백그라운드에서 실행
- Offline eval: 저장된 대표 케이스로 품질과 안전을 측정
- Canary: 아주 일부에게만 후보 버전을 반환
- Human gate: 확대를 할지 사람이 승인
- Rollback: 중단 조건을 초과하면 현행 버전으로 복구
중요한 것은 AI에게 모든 것을 결정하게 하지 않는 것입니다. AI에게는 차이의 분류, 이상 후보 추출, 리포트 초안 작성을 맡깁니다. 사람은 허용 손실, 합격 라인, 공개 범위, 중단을 결정합니다. 이것은 책임의 설계입니다.
첫 번째 성공은, 후보 버전을 사용자에게 반환하지 않고 현행 버전과의 차이 로그를 한 줄 얻는 것입니다.
from dataclasses import asdict, dataclass
import json
import time
...
사용자에게 반환되는 것은 primary.text 뿐입니다. 후보 버전은 관측 전용입니다. 이것이 Shadow입니다. 다만, 백그라운드에서 실행한다고 해서 안전해지는 것은 아닙니다. 기밀 정보를 후보 모델로 보내도 되는지, 부작용이 있는 도구를 호출하지 않는지는 사람이 미리 결정합니다.
후보 버전은 read-only (읽기 전용) 로 한정해 주세요. 메일 전송, 결제, 삭제, 공개, 배포와 같이 부작용을 가진 도구는 연결하지 않습니다. 어떻게든 외부 입력을 사용해야 한다면, 개인 정보를 마스킹하고 후보 모델로 전송해도 되는 데이터인지 미리 확인합니다. Shadow는 「사용자에게 보이지 않는다」는 뜻이지, 「데이터가 외부로 나가지 않는다」는 의미는 아닙니다.
Shadow는 실제 입력 분포를 관측할 수 있는 반면, 아직 오지 않은 중요한 케이스를 기다려야 합니다. 그래서 과거의 실패나 경계값을 익명화한 대표 케이스 집합을 저장하여 후보 버전으로 매번 통과시킵니다. 이것이 offline eval입니다.
예를 들어 「반품 기한」, 「예외 상품 취급」, 「근거를 찾을 수 없는 질문」, 「개인 정보가 포함된 질문」을 각각 몇 건씩 준비합니다. 합격 조건은 단순한 문장 일치가 아니라, 업무 규칙 위반이 없을 것, 근거가 없을 때 단정 짓지 않을 것, 개인 정보를 출력하지 않는 것입니다. AI에게 케이스 안을 늘려달라고 하는 것은 편리하지만, 무엇을 실패라고 부를지는 사람이 결정합니다.
위의 exact_match는 데모에는 편리하지만, 의미 품질의 합격 여부에는 사용할 수 없습니다. 「30일 이내」와 「구매일로부터 30일」은 문자열은 다르지만 의미는 가깝습니다. 반면, 매끄러운 문장이더라도 반품 기한을 90일이라고 답한다면 업무상으로는 오답입니다.
따라서 최소한 4가지를 별도로 측정합니다.
- 품질: 대표 케이스에 대한 정답률, 근거와의 정합성, 업무 규칙 위반
- 안전: 개인 정보, 금지 조작, 프롬프트 인젝션 (Prompt Injection)에 대한 내성
- 성능: p50/p95 레이턴시 (Latency), 타임아웃 비율
- 비용: 1 요청당 토큰량이나 추론 비용
OpenTelemetry에서는 메트릭스 (Metrics)를 실행 시점에 포착하는 측정값, 트레이스 (Trace)를 하나의 요청이 통과하는 경로로 취급합니다. 비교 로그에 ai.version이나 release.stage와 같은 저카디널리티 (Low Cardinality) 속성을 붙이면 현행 버전과 후보 버전을 집계하기 쉬워집니다. 가공되지 않은 사용자 ID나 프롬프트 전문을 속성에 넣는 것은 피해야 합니다. 개인 정보 문제뿐만 아니라, 속성 조합이 계속 늘어나 집계 비용이 팽창하기 때문입니다.
공개한 뒤에 「어디까지 나빠지면 멈출까」라고 상담하면, 멈추는 판단은 대개 늦어집니다. 미리 기계가 읽을 수 있는 형태로 떨어뜨려 놓습니다.
{
"quality": {"min_pass_rate": 0.95},
"safety": {"max_critical_violations": 0},
...
}
이 숫자는 권장값이 아니라 예시입니다. 의료, 결제, 사내 FAQ에서는 손실의 형태가 다르므로 사람이 결정합니다. AI에게 「타당한 숫자를 결정해 줘」라고 부탁하는 것이 아니라, AI에게는 과거 로그를 요약하게 하고, 사람이 수용 가능한 손실로부터 역산하는 것이 안전합니다.
위의 임계값은 설명을 위한 더미(Dummy)입니다. 그대로 운영 환경에 채택하지 말고, 자신의 대표 사례와 허용 가능한 손실로부터 결정하십시오.
Shadow 모드에서는 사용자 영향이 0%입니다. 다음으로, 후보 버전을 일부 사용자에게 반환하는 Canary(카나리) 단계로 진행합니다. 예를 들어 1% → 5% → 25%와 같이 단계적으로 설정할 수 있지만, 이는 예시일 뿐 만능 수치는 아닙니다. 트래픽이 적다면 1%로는 아무것도 알 수 없으며, 결제와 같은 고위험 처리에서는 단 1건의 실패만으로도 치명적입니다.
각 단계에서 던져야 할 질문은 단 세 가지뿐입니다.
- 누구에게 보이는가
- 무엇을 측정할 것인가
- 누가 중단시킬 것인가
비율보다 중요한 것은 확대 조건과 정지 조건이 사전에 정의되어 있다는 점입니다.
GitHub Actions의 environment(환경)에는 required reviewers(필수 검토자)와 같은 보호 규칙(Protection rules)이 있습니다. 후보 버전의 평가 리포트를 artifact(아티팩트)로 저장하고, 운영 확대 작업을 environment 승인 대기 상태로 둘 수 있습니다.
name: ai-release-gate
on:
workflow_dispatch:
...
production-ai 측에서 required reviewers를 설정하면, 평가를 통과한 후에도 인간의 확인 과정을 거칠 수 있습니다. 참고로 이용 가능한 보호 규칙은 플랜이나 공개/비공개 리포지토리(Repository)에 따라 조건이 다르므로 공식 문서를 확인하십시오. 이 YAML은 구성 예시이며, 실제 환경에서의 동작은 확인되지 않았습니다.
되돌릴 방법이 없는 상태는 Canary가 아닙니다. 그것은 단순한 소규모 운영 실험일 뿐입니다.
Kubernetes의 Deployment(디플로이먼트)는 rolling update(롤링 업데이트), rollout status(롤아웃 상태), rollout undo(롤아웃 되돌리기) 기능을 제공합니다. AI 기능에서도 모델명이나 프롬프트 버전을 환경 변수, 설정 스토어, feature flag(피처 플래그)로 전환할 수 있도록 해두면, 애플리케이션 전체를 재구현하지 않고도 되돌릴 수 있습니다.
kubectl rollout status deployment/ai-api
kubectl rollout undo deployment/ai-api
kubectl rollout status deployment/ai-api
롤백(Rollback) 후에도 끝이 아닙니다. 어떤 정지 조건을 초과했는지, 영향받은 건수, 후보 버전의 식별자, 복구 시각을 남겨야 합니다. 이것이 다음 공개를 더 빠르게 만듭니다.
현행 버전과 후보 버전의 출력 차분을 표현 차이, 사실 차이, 업무 규칙 차이, 안전 차이로 분류해 주세요.
근거가 부족한 경우에는 '불명'으로 처리하고, 합격 여부는 결정하지 마세요.
사람이 우선적으로 리뷰해야 할 순서와 이유를 JSON으로 반환해 주세요.
이 AI 기능의 정지 조건 안을 품질, 안전, 성능, 비용의 4개 축으로 리뷰해 주세요.
부족한 관측값과 오탐(False positive)이 발생하기 쉬운 조건을 나열해 주세요.
임계값은 결정하지 말고, 판단에 필요한 과거 데이터만 제안해 주세요.
첨부된 평가 결과로부터 계속, 중단, 추가 관측의 3가지 안을 만들어 주세요.
각 안에는 근거, 미관측 요소, 최악의 상황 시 영향, 되돌리는 방법을 포함해 주세요.
최종 결정자가 30초 안에 비교할 수 있도록 표로 작성해 주세요.
저위험의 사내 문서 보조 작업이고, 출력을 사람이 매번 확인하며 부작용도 없다면, offline eval(오프라인 평가)과 수동 rollback(롤백)만으로도 충분할 수 있습니다. 비교 대상이 없는 완전한 신규 기능이라면 Shadow 모드조차 사용할 수 없습니다. 트래픽이 극도로 적으면 Canary의 통계도 안정되지 않습니다.
판단 기준은 실패했을 때 "누구에게, 얼마나, 되돌릴 수 있는 형태로 영향을 주는가"입니다. 영향이 작고 가역적(Reversible)이라면 간소화하십시오. 외부 전송, 결제, 삭제, 공개, 개인정보가 얽혀 있다면 단계를 늘리십시오. 메커니즘은 많을수록 좋은 것이 아니라, 실패의 무게와 균형을 이루는 것이 중요합니다.
- 현행 함수와 후보 함수를
shadow_call로 감싸기 - 사용자에게 반환되는 값이 현행 버전뿐인지 확인하기
- 더미 입력을 1건 흘려보내 비교 로그를 1행 얻기
- 품질, 안전, 성능, 비용으로부터 정지 조건을 단 하나만 작성하기
우선 후보 버전을 아무에게도 보여주지 않고, 차분이 보이는 상태로 만드십시오. 그것만으로도 "기도하며 일괄 공개"에서 "증거를 보고 단계적 공개"로 바뀝니다.
- Kubernetes: Update a Deployment Without Downtime
- GitHub Docs: Deployments and environments
- OpenTelemetry: Metrics
- OpenTelemetry: Traces
※ Python의 shadow_call은 2026-07-21에 실행 및 구문 확인을 완료했습니다. GitHub Actions와 Kubernetes 예시는 공식 사양과 대조하였으나, 개별 환경에서의 동작은 확인되지 않았습니다.
생성형 AI (Generative AI) 활용 엔지니어이자 세 아이의 아빠. AI × 개발의 실천적 지식을 매일 발신하고 있습니다 → X
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기