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 recorddraft 단계는 트래픽 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)
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에 영구 보관.
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_draftPR 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 전체)
- C24 하네싱 아키텍처 — 권한 매트릭스가 active 버전 한정
- C25 실행 제어 — Kill Switch가 deprecated 강제
Cross-reference
- C19 실험 파이프라인 — staged 단계의 A/B 운영
- C22 응답 품질 — golden eval이 draft → canary 게이트
- 07-1 CI/CD GitHub Actions — registry 자동 등록·promote
- 11-0 환경변수 운영 — registry config·secret 분리
- 11-1 Reproducible Build — 이전 버전 영구 보관 인프라
18-LangGraph 시리즈 cross-reference
- #14 스킬 설계와 생성 — 스킬 생명주기는 본 편 패턴 응용 (Phase C-7 C30에서 확장)
후속 (Phase C-7 진입)
- C27~C30 스킬 생태계 — 본 편 생명주기 패턴을 스킬 단위로 확장
- C31~C33 지식 기반 관리 — 문서·인덱스의 생명주기 (같은 6단계 멘탈 모델)