MINERVA Phase C-6 — 에이전트 생명주기 (등록·버전·활성화·폐기·롤백)

draft → canary → staged → active → deprecated → retired — 6단계 게이트로 변경 위험을 분산하고 인지 부담을 줄인다

C24 하네싱·C25 실행 제어가 운영 중 안전을 다뤘다면, C26은 시간 축의 안전이다. 에이전트가 어떻게 도입되고 활성화되고 폐기되는지의 전체 생명주기 관리. 본 편은 6단계 생명주기, registry 스키마, 버전 관리(semver·prompt·model 분리), canary 배포·롤백 전략, CI/CD 통합, zombie agents 같은 운영 부채 함정을 정리한다. Phase C-6의 클로저로 거버넌스가 시간 축으로 확장된다.

Agent
저자

Kwangmin Kim

공개

2026년 05월 06일

1 왜 생명주기 관리인가

C24 하네싱·C25 실행 제어지금 이 순간의 안전이라면, C26은 시간 축의 안전이다.

시간 축에서 발생하는 문제 생명주기 없이의 결과
새 에이전트 도입 100% 트래픽 즉시 → 회귀 발견 시 영향 큼
기존 에이전트 수정 버전 불명 — 어떤 버전이 어디 사용 중인지 모름
에이전트 사용 중지 코드는 남고 traffic만 0 — zombie 누적
롤백 무엇으로 롤백할지 명확치 않음
같은 prompt가 다른 에이전트들에 복사 한 곳만 수정해 일관성 깨짐

생명주기 관리는 변경의 표준 게이트를 만든다. 모든 에이전트가 같은 단계를 거치고, 모든 단계에 검증이 정해져 있다.

2 6단계 생명주기

draft → canary → staged → active → deprecated → retired
  ↑                                    ↓
  └──────────── (롤백 시 단계 역행) ──┘
단계 트래픽 의미 다음 단계 게이트
draft 0% 개발 중, 사내 PR review 단계 golden eval + A/A 통과
canary 5% 소규모 트래픽 노출, 회귀 점검 7일 모니터링 + SLO 만족
staged 25~50% 통계적으로 유의한 비교 가능 C19 A/B 결과 또는 manual
active 100% 운영 표준 (수정 시 새 draft)
deprecated 100% (sunset 예고) 후속 버전 도입, 폐기 예정 후속 버전 active 검증
retired 0% 코드·route 제거 (없음)

각 단계 전이는 자동 또는 사람 게이트 — C19 거버넌스와 일관.

3 Registry 스키마

# app/registry/agent_record.py
from datetime import datetime
from enum import Enum
from pydantic import BaseModel


class LifecycleStage(str, Enum):
    draft = "draft"
    canary = "canary"
    staged = "staged"
    active = "active"
    deprecated = "deprecated"
    retired = "retired"


class AgentRecord(BaseModel):
    agent_id: str                              # "qna_chatbot"
    version: str                                # semver — "2.3.1"
    prompt_version: str                         # 별도 — "p-1.7"
    model: str                                  # "gpt-4o-2024-08-06"
    reranker_id: str | None = None

    stage: LifecycleStage
    traffic_pct: float

    # 관계
    parent_version: str | None = None           # 이 버전이 어느 버전을 대체
    deprecates: list[str] = []                  # 이 버전이 deprecate시키는 버전들

    # 메타
    owner: str
    created_at: datetime
    activated_at: datetime | None = None
    deprecated_at: datetime | None = None
    retired_at: datetime | None = None
    sunset_date: datetime | None = None         # deprecate 후 retire 예정일

    # 거버넌스
    governance_class: str                       # "auto_ship" | "pending_review" | "governance_review"

    # 검증 산출물 (참조)
    golden_eval_run_id: str | None = None
    aa_test_run_id: str | None = None
    canary_metrics_snapshot_id: str | None = None

이 record가 DB·git registry에 저장. 모든 변경은 PR + audit log.

4 버전 관리 — 3축 분리

같은 에이전트도 세 축이 독립적으로 변한다 — semver만으로는 부족.

agent_version : semver — 코드 변경 (BaseAgent contract·라우팅 로직)
prompt_version : semver — 프롬프트만 변경 (코드 그대로)
model_id      : provider 식별자 — 모델 교체

세 축이 직교라서 조합이 폭발 — registry가 단일 진실:

# 같은 agent_id에 여러 active 변형이 가능 (실험 중)
records = [
    AgentRecord(agent_id="qna", version="2.3.1", prompt_version="p-1.5", model="gpt-4o", stage="active", traffic_pct=80),
    AgentRecord(agent_id="qna", version="2.3.1", prompt_version="p-1.7", model="gpt-4o", stage="canary", traffic_pct=5),
    AgentRecord(agent_id="qna", version="2.3.1", prompt_version="p-1.5", model="claude-3.5", stage="canary", traffic_pct=5),
]
# 합계 90% — 나머지 10%는 다른 실험 또는 holdout

라우팅은 매번 registry 조회로 동적 — 코드 변경 없이 트래픽 분배 가능.

4.1 변경 분류

변경 종류 게이트 새 단계
프롬프트 미세 조정 (오타·예시 추가) auto_ship canary 5% → 7일 → active
프롬프트 의미 변경 (페르소나 강화) pending_review canary 5% → A/B → staged → active
모델 교체 (gpt-4o → claude-3.5) pending_review canary 5% → A/B → staged → active
BaseAgent 코드 변경 governance_review canary 1% → 단계별 확장
새 도구 등록 governance_review (별도 도구 등록 절차)
새 sub-agent 위임 governance_review 권한 매트릭스 변경 + canary

C19 governance와 같은 분류 — 일관된 운영 멘탈 모델.

5 단계 1 — Registration (Draft)

# scripts/register_agent.py
from app.registry import register


def register_new_agent(spec_path: str):
    spec = load_spec(spec_path)

    # 1. validation — schema·필수 필드
    AgentRecord(**spec)

    # 2. golden eval — C22 골든셋 사전 통과 필수
    golden_result = run_golden_eval(spec)
    assert golden_result.pass_rate >= 0.95, "golden eval 95% 미만"

    # 3. A/A test — 분석 파이프라인 검증
    aa_result = run_aa_test(spec)
    assert 0.04 <= aa_result.false_positive_rate <= 0.06

    # 4. 등록
    record = AgentRecord(
        **spec,
        stage="draft",
        traffic_pct=0,
        golden_eval_run_id=golden_result.id,
        aa_test_run_id=aa_result.id,
    )
    db.agents.insert(record)
    return record

draft 단계는 트래픽 0% — 시스템에 등록되지만 호출되지 않는다. 검증 통과 후 canary로 승격.

6 단계 2 — Canary

# app/registry/promotion.py
def promote_to_canary(record_id: str):
    record = db.agents.get(record_id)
    assert record.stage == "draft"

    # 5% 트래픽 할당 — sticky hash로 일관
    record.stage = "canary"
    record.traffic_pct = 5.0
    record.activated_at = datetime.utcnow()
    db.agents.update(record_id, record)

    # 모니터링 자동 시작
    schedule_canary_monitor(record_id, duration_days=7)

6.1 Canary 모니터링

7일간 자동 점검:

def canary_monitor(record_id: str):
    snapshot = collect_metrics(record_id)
    baseline = collect_baseline_metrics(record_id)

    checks = {
        "p95_latency": snapshot["p95_lat"] <= baseline["p95_lat"] * 1.2,
        "thumbs_up_rate": snapshot["thumbs"] >= baseline["thumbs"] - 0.05,
        "refusal_rate": snapshot["refusal"] <= baseline["refusal"] + 0.05,
        "cost_per_query": snapshot["cost"] <= baseline["cost"] * 1.3,
        "error_rate": snapshot["error"] <= 0.02,
    }

    if all(checks.values()):
        return "ready_for_staged"
    elif any(snapshot["error"] > 0.10, snapshot["thumbs"] < baseline["thumbs"] - 0.20):
        return "rollback"                       # 즉시 draft로 역행 + 알림
    else:
        return "continue_canary"

canary 통과 → staged 승격. 큰 회귀 → 즉시 rollback.

7 단계 3 — Staged

25~50% 트래픽 — A/B 비교가 통계적으로 유의한 표본 확보. C19 실험 파이프라인 풀 사이클 적용.

def promote_to_staged(record_id: str, target_pct: float = 25.0):
    record = db.agents.get(record_id)
    assert record.stage == "canary"

    record.stage = "staged"
    record.traffic_pct = target_pct
    db.agents.update(record_id, record)

    # C19 실험 자동 등록
    register_ab_experiment(
        title=f"{record.agent_id} v{record.version} promotion",
        control=current_active(record.agent_id),
        treatment=record_id,
        duration_days=14,
    )

A/B 결과 → active 승격 또는 rollback.

8 단계 4 — Active

100% 트래픽. 이전 active 버전은 자동 deprecated:

def promote_to_active(record_id: str):
    record = db.agents.get(record_id)
    assert record.stage == "staged"

    # 이전 active 자동 deprecated
    for prev in db.agents.find(agent_id=record.agent_id, stage="active"):
        deprecate(prev.id, sunset_days=30, reason=f"replaced by {record.id}")

    record.stage = "active"
    record.traffic_pct = 100.0
    db.agents.update(record_id, record)

9 단계 5 — Deprecated

코드는 남지만 sunset 예정. sunset_days=30 동안 traffic은 점진 감소:

def deprecate(record_id: str, sunset_days: int, reason: str):
    record = db.agents.get(record_id)
    record.stage = "deprecated"
    record.deprecated_at = datetime.utcnow()
    record.sunset_date = datetime.utcnow() + timedelta(days=sunset_days)
    db.agents.update(record_id, record)

    # 알림 — 의존 시스템에 영향 가능
    notify_dependents(record.agent_id, sunset_days, reason)

기존 in-flight session은 deprecated 버전으로 처리 (사용자 경험 끊김 방지). 신규 session은 새 active로.

10 단계 6 — Retired

sunset 도달 시 자동 retired:

def retire(record_id: str):
    record = db.agents.get(record_id)
    assert record.stage == "deprecated"
    assert datetime.utcnow() > record.sunset_date

    record.stage = "retired"
    record.retired_at = datetime.utcnow()
    record.traffic_pct = 0.0
    db.agents.update(record_id, record)

    # 코드·prompt·route 제거 PR 자동 생성
    create_cleanup_pr(record)

retired는 registry에는 남지만 호출 불가능. 코드 cleanup은 PR로 — 사람 review 통과 시 진짜 삭제.

11 롤백 전략

11.1 자동 롤백 (canary)

# canary 모니터링이 임계 위반 발견 → 즉시
def auto_rollback(record_id: str, reason: str):
    record = db.agents.get(record_id)
    record.stage = "draft"                      # 단계 역행
    record.traffic_pct = 0
    db.agents.update(record_id, record)

    audit("auto_rollback", record_id, reason)
    notify(record.owner, reason)

11.2 사람 롤백 (active 단계 후)

# CLI
python -m scripts.rollback --agent qna --to-version 2.3.0 --reason "regression in finance dept"

내부적으로: - 현재 active 즉시 deprecated (sunset 7일 빠른 sunset) - 지정 버전 active로 승격 - 모든 변경은 audit log

11.3 롤백 가능성 보존

이를 위해 이전 active 버전의 코드·prompt가 보존되어야 한다 — git tag·docker image registry에 영구 보관.

# CI/CD ([07-1편](./07-1-minerva-cicd-github-actions.qmd))
on:
  registry_promote_to_active:
    - tag git: agent_${{record.id}}_v${{record.version}}
    - push docker image with version tag
    - keep last 10 versions

12 CI/CD 통합

# .github/workflows/agent_lifecycle.yml
on:
  pull_request:
    paths:
      - "agents/**"
      - "config/access.yaml"

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: python -m scripts.validate_agent_spec
      - run: python -m scripts.run_golden_eval
      - run: python -m scripts.run_aa_test
      - if: success()
        run: python -m scripts.register_draft

PR merge → draft 자동 등록. 그 후 manual 또는 자동으로 canary 승격.

13 MINERVA 적용

app/registry/
├── agent_record.py          # AgentRecord schema
├── store.py                 # DB·git 동기화
├── promotion.py              # 단계 전이 로직
├── monitor.py                # canary 모니터링
├── rollback.py               # 롤백
└── audit.py                 # 모든 변경 기록

scripts/
├── register_agent.py        # draft 등록 + 사전 검증
├── promote.py                # CLI — canary/staged/active 승격
├── deprecate.py              # CLI — deprecated + sunset 일정
├── rollback.py               # CLI — 사람 롤백
└── retire_due.py             # cron — sunset 도달 자동 retire

config/
├── governance.yaml          # 변경별 게이트 (auto_ship/pending_review/governance_review)
└── lifecycle_slo.yaml       # 단계별 SLO·임계

이 인프라가 C19 실험 파이프라인·C24 하네싱·C25 실행 제어와 자연스럽게 결합: - C19: staged 단계의 A/B - C24: registry 권한 매트릭스 (active 버전만 호출 가능) - C25: Kill Switch가 deprecated를 강제 retire 가능

14 Phase C-6 통합 요약

[C24 하네싱]    "어떤 행동이 허용되는가" — 권한·가드·예산
[C25 실행 제어]  "허용된 행동이 실패할 때" — Timeout·Retry·Breaker·Kill·Bulkhead
[C26 생명주기]   "행동이 시간 축에서 어떻게 도입·폐기되는가" — 6단계 게이트

세 편이 직교하면서 결합 — C24 권한 매트릭스의 변경이 C26 staged 게이트를 거치고, C25 Kill Switch가 C26 deprecated/retired를 강제할 수 있다.

15 자주 발생하는 함정

15.1 Zombie Agents

retired 단계로 안 가고 deprecated 상태로 영원히 — 코드·route·DB row가 누적. 시간 흐를수록 운영 부채.

해법: - sunset_date 도달 시 자동 retire job - 분기마다 deprecated > 90일 보고서 - registry audit이 cleanup PR 자동 생성

15.2 Rollback Chain Hell

v2.3 → v2.4 (regression) → rollback to v2.3 → 그 사이 prompt v2.3.5만 hot-fix → 다시 v2.4로 forward 시 v2.3.5 변경분 누락.

해법: - 모든 hot-fix는 새 prompt_version (2.3.5) - forward 시 명시적 cherry-pick - registry에 ancestor relation 추적

15.3 Version Drift

코드 v2.4·prompt v1.7·model gpt-4o-mini가 active. 어느 날 model이 deprecated 됨 → 자동 fallback이 모델만 바꾸지만 코드·prompt는 그대로 → 회귀.

해법: - model 변경도 registry promote 절차 강제 - model deprecated alert가 dependent agent owner에게 page - 매월 외부 의존 추적 (provider 공식 lifecycle)

15.4 Canary Bias

canary 5%가 활성 사용자·VIP·R&D 부서로 sticky 할당 → baseline과 다른 사용자 mix → 비교 의미 없음.

해법: - canary 할당은 stratified sampling — 세그먼트 비율 baseline과 일치 - holdout 5% baseline 동시 추적 - 회귀 점검은 같은 세그먼트끼리만 비교

15.5 Ignored Sunset

deprecated 알림이 너무 많아 owner가 무시 → sunset 도달해도 후속 버전 활성화 안 됨 → forced retire 시 traffic 0% 사용자 영향.

해법: - sunset 7일 전 escalation (manager에게도) - Owner 부재 시 governance team이 자동 인수 - 30일 후 자동 forced retire는 알림 더 strict

15.6 Multi-Active Confusion

같은 agent_id에 여러 active version이 동시 (실험 중) — 운영 dashboard·로그·메트릭에서 어느 게 어느 건지 혼란.

해법: - 모든 메트릭에 version·prompt_version·model을 label - dashboard는 version별 분리 시각화 - “primary active” 표시 — staged·canary가 아닌 100% 그것

15.7 Registry as Single Point of Failure

registry DB down → 라우팅 결정 못 함 → 시스템 전체 down.

해법: - registry는 read-heavy → cache (Redis) + 5분 TTL - 라우팅은 cache 우선, registry는 비동기 갱신 - registry down 시 last-known config로 운영 (degraded mode)

16 정리

영역 핵심
6단계 draft·canary·staged·active·deprecated·retired
전이 게이트 단계별 자동 검증 + governance 분류
버전 3축 code·prompt·model 독립 관리
Canary 5% + 7일 모니터링 + 자동 rollback
Active 이전 버전 자동 deprecated, sunset 30일
롤백 canary 자동 + active 사람 결정 + 영구 git tag·image
CI/CD PR merge → 자동 검증 → draft 등록
함정 zombie·rollback chain·version drift·canary bias·ignored sunset·multi-active·registry SPOF

17 응용 분야

시나리오 활용
새 모델 도입 draft → canary 5% → A/B → staged → active
프롬프트 hot-fix auto_ship → canary 5% → 7일 → active (빠른 cycle)
회귀 발견 즉시 대응 C25 Kill Switch + C26 rollback to last active
이전 active 버전 재현 git tag로 정확한 코드·prompt·model 복원
실험 종료 후 정리 losing arm을 자동 deprecated → retired
외부 모델 deprecation 대응 provider alert → 후속 모델 canary 시작

18 관련 주제

선행 학습 (선수 — Phase C-6 전체)

Cross-reference

18-LangGraph 시리즈 cross-reference

  • #14 스킬 설계와 생성 — 스킬 생명주기는 본 편 패턴 응용 (Phase C-7 C30에서 확장)

후속 (Phase C-7 진입)

  • C27~C30 스킬 생태계 — 본 편 생명주기 패턴을 스킬 단위로 확장
  • C31~C33 지식 기반 관리 — 문서·인덱스의 생명주기 (같은 6단계 멘탈 모델)

Subscribe

Enjoy this blog? Get notified of new posts by email: