diff --git a/book/300_architecture/311_백엔드_구조_원칙.md b/book/300_architecture/311_백엔드_구조_원칙.md index 1c5d08b..3e22e8c 100644 --- a/book/300_architecture/311_백엔드_구조_원칙.md +++ b/book/300_architecture/311_백엔드_구조_원칙.md @@ -135,6 +135,9 @@ utils - **Slack 서명 검증 경로 원문 보존**: 프록시 경유 웹훅은 원문 body를 유지해야 하며, 서명 검증 경로에서 body 재직렬화를 금지한다. - **원인 직접 수정 우선**: 증상을 감추는 광범위 예외 폴백/임시 우회 코드를 금지한다. 재현 가능한 근본 원인(입력/경로/설정/데이터)을 먼저 수정한다. - **상태코드 의미 보존**: 인증 실패(401/403), 권한 문제(403), 입력 오류(400)는 원래 의미대로 반환하고 500으로 왜곡하지 않는다. +- **폴백 남용 금지**: 폴백은 사용자 보호용 최후 수단으로만 사용한다. 개선 신호를 가리는 무조건 폴백(`catch-all fallback`)을 금지한다. +- **관측 가능한 실패 보장**: 운영/카나리 경로에는 `strict_observe` 모드를 두어 일부 요청은 폴백 없이 실패를 노출하고, 구조화된 오류 로그/메트릭을 반드시 남긴다. +- **로그 없는 폴백 금지**: 폴백이 발생하면 `request_id`, `route`, `template/version`, `fallback_reason`, `upstream_error`를 필수 기록한다. ## 6. DB 접근 규칙 diff --git a/journey/plans/251225_프롬프트_동적관리_계획.md b/journey/plans/251225_프롬프트_동적관리_계획.md index e1cd0fd..2283ca4 100644 --- a/journey/plans/251225_프롬프트_동적관리_계획.md +++ b/journey/plans/251225_프롬프트_동적관리_계획.md @@ -84,6 +84,7 @@ - purpose: 요청 단위 결과 로그 - columns: - `id`, `request_id`, `template_key`, `version_id`, `variant` + - `execution_mode` (`safe_prod`, `strict_observe`) - `user_id`, `robeing_id`, `task_type` - `latency_ms`, `tokens_in`, `tokens_out` - `feedback_signal` (up/down/reask/abandon) @@ -110,7 +111,9 @@ ### 5.2 병합 원칙 - 문자열 덮어쓰기 금지, 섹션 단위 병합(`role`, `constraints`, `output_format`) - 금지 규칙(예: 민감 라벨 직접 노출 금지)은 항상 최종 승자 -- 해석 실패 시 즉시 fallback (최근 stable active 버전) +- 해석 실패 시 처리 규칙: + - `safe_prod`: 즉시 fallback (최근 stable active 버전) + - `strict_observe`: fallback 금지, 오류 노출 + 구조화 로그 기록 --- @@ -161,6 +164,7 @@ - 테스트: - DB 성공 시 DB 프롬프트 사용 - DB 실패 시 하드코딩 fallback + - `strict_observe`에서 DB 실패 시 fallback 없이 오류/로그 노출 검증 ### Phase 3: 병합/개인화/감정 modifier - scope 병합 및 변수 치환 @@ -185,6 +189,7 @@ - 실험 대시보드에서 버전별 지표 확인 가능 - 자동 롤백 시나리오 리허설 1회 이상 통과 - 장애 시 서비스 무중단 fallback 확인 +- `strict_observe` 경로에서 의도적 실패가 로그/메트릭으로 누락 없이 수집되는지 검증 --- @@ -199,7 +204,65 @@ --- -## 10. 체크리스트 (누락 방지) +## 10. 운영 권고안 (초기 4주) + +### 10.1 운영 모드 +- 기본 모드: `자동 제안 + 사람 승인 후 승격` +- 완전 자동 승격은 안정화 4주 후, low-risk 템플릿부터 제한 허용 + +### 10.2 배포/승격 절차 +- 단계 고정: `draft -> candidate -> canary(10%) -> full` +- canary 승격 최소 조건: + - 최소 샘플 수 `n >= 500` + - 최소 관찰 시간 `>= 24h` + - guardrail 위반 0건 + +### 10.3 실시간 가드레일 (권장 임계치) +- `reask_rate`가 control 대비 10%p 이상 악화 시 즉시 중단 +- `negative_feedback_rate`가 control 대비 5%p 이상 악화 시 롤백 +- `fallback_rate`가 15분 윈도우에서 2배 이상 급증 시 롤백 +- 5xx/파싱 실패 연쇄 발생 시 즉시 kill-switch + +### 10.4 DB 운영 권장 +- `prompt_events`는 일 단위 파티셔닝 권장 +- 보관 주기: 원천 이벤트 30~90일, 집계 메트릭 장기 보관 +- 필수 인덱스: + - `(template_key, version_id, created_at)` + - `(experiment_key, status)` + - `(date, template_key, version_id)` on daily metrics +- 권한 분리: + - 편집 권한(템플릿 수정)과 승격 권한(활성화/롤백) 분리 + +### 10.5 관측/알람 +- 대시보드 3축: + - 품질: reask, feedback, task_success + - 성능: latency, tokens + - 안정성: fallback, parse_fail, 5xx +- 알람 윈도우 이중화: + - 15분 단기(즉시 대응) + - 1시간 중기(추세 확인) + +### 10.6 복구/감사 +- 승격마다 `change_reason`, `approver`, `experiment_key` 필수 기록 +- 월 1회 롤백 드릴 수행 및 결과 문서화 + +### 10.7 폴백 규율 (핵심) +- 원칙: 폴백은 사용자 보호용 최후 수단이며, 개선 신호를 가리는 기본 경로가 되어서는 안 된다. +- 이중 운영 모드: + - `safe_prod`: 일반 사용자 트래픽, 제한적 폴백 허용 + - `strict_observe`: 카나리/내부 검증 트래픽, 폴백 금지(오류를 노출해 개선 포인트 확보) +- 필수 로그 스키마(폴백/실패 공통): + - `request_id`, `template_key`, `version_id`, `variant` + - `route`, `fallback_reason`, `upstream_error_code`, `upstream_error_message` + - `latency_ms`, `created_at` +- 운영 규칙: + - `strict_observe` 비율은 최소 5~10% 유지 + - 폴백 비율이 기준치 초과 시 실험 승격 금지 + - 로그 없는 폴백 경로는 배포 금지 + +--- + +## 11. 체크리스트 (누락 방지) ### 설계 - [ ] 실제 하드코딩 인벤토리 목록화 완료 @@ -210,15 +273,20 @@ - [ ] Repository/DDL/Service 동시 반영 - [ ] fallback 경로(코드/DB) 모두 테스트 - [ ] 실험 라우팅 deterministic 보장 +- [ ] `safe_prod` vs `strict_observe` 모드별 실패 처리 테스트 +- [ ] 실패 이벤트의 구조화 로그 스키마(`execution_mode` 포함) 검증 ### 운영 - [ ] 승격/롤백 가드레일 임계값 합의 - [ ] 대시보드/알람 연결 - [ ] 장애 훈련(롤백 drill) 수행 +- [ ] `strict_observe` 트래픽 비율(최소 5~10%) 운영 중인지 확인 +- [ ] 폴백 이벤트 필수 로그 스키마 누락 없는지 점검 +- [ ] 로그 없는 폴백 경로가 없는지 배포 전 검증 --- -## 11. 2회 점검 기록 (2026-03-03) +## 12. 2회 점검 기록 (2026-03-03) ### 1차 점검에서 추가한 누락 항목 - 자동 승격 조건(샘플 수/가드레일) @@ -233,6 +301,200 @@ --- +## 13. 운영 기본값 표 (초기값) + +| 항목 | 기본값 | 비고 | +|---|---:|---| +| canary 비율 | 10% | high-risk 템플릿은 5% | +| 최소 샘플 수 | 500 | 승격 전 필수 | +| 최소 관찰 시간 | 24h | 승격 전 필수 | +| reask_rate 가드레일 | +10%p | control 대비 악화 시 중단 | +| negative_feedback_rate 가드레일 | +5%p | control 대비 악화 시 롤백 | +| fallback_rate 가드레일 | 2x | 15분 윈도우 급증 시 롤백 | +| 오류 가드레일 | 5xx/파싱 실패 연쇄 | 즉시 kill-switch | + +--- + +## 14. DDL/롤백 SQL 예시 + +### 14.1 생성 DDL (요약) +```sql +CREATE TABLE IF NOT EXISTS prompt_templates ( + id BIGSERIAL PRIMARY KEY, + template_key TEXT NOT NULL UNIQUE, + prompt_type TEXT NOT NULL, + scope_level TEXT NOT NULL, + scope_id TEXT, + is_enabled BOOLEAN NOT NULL DEFAULT TRUE, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS prompt_versions ( + id BIGSERIAL PRIMARY KEY, + template_id BIGINT NOT NULL REFERENCES prompt_templates(id), + version INT NOT NULL, + content JSONB NOT NULL, + variables_schema JSONB, + status TEXT NOT NULL, + created_by TEXT, + change_reason TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + UNIQUE(template_id, version) +); + +CREATE TABLE IF NOT EXISTS prompt_experiments ( + id BIGSERIAL PRIMARY KEY, + experiment_key TEXT NOT NULL UNIQUE, + template_key TEXT NOT NULL, + control_version_id BIGINT NOT NULL REFERENCES prompt_versions(id), + treatment_version_id BIGINT NOT NULL REFERENCES prompt_versions(id), + traffic_ratio JSONB NOT NULL, + guardrail_config JSONB NOT NULL, + status TEXT NOT NULL, + started_at TIMESTAMPTZ, + ended_at TIMESTAMPTZ +); + +CREATE TABLE IF NOT EXISTS prompt_events ( + id BIGSERIAL PRIMARY KEY, + request_id TEXT NOT NULL, + template_key TEXT NOT NULL, + version_id BIGINT NOT NULL REFERENCES prompt_versions(id), + variant TEXT NOT NULL, + user_id TEXT, + robeing_id TEXT, + task_type TEXT, + latency_ms INT, + tokens_in INT, + tokens_out INT, + feedback_signal TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS prompt_metrics_daily ( + date DATE NOT NULL, + template_key TEXT NOT NULL, + version_id BIGINT NOT NULL REFERENCES prompt_versions(id), + variant TEXT NOT NULL, + success_rate DOUBLE PRECISION, + reask_rate DOUBLE PRECISION, + fallback_rate DOUBLE PRECISION, + avg_latency_ms DOUBLE PRECISION, + avg_tokens DOUBLE PRECISION, + feedback_score DOUBLE PRECISION, + PRIMARY KEY (date, template_key, version_id, variant) +); + +CREATE INDEX IF NOT EXISTS idx_prompt_events_template_ver_time + ON prompt_events(template_key, version_id, created_at); +CREATE INDEX IF NOT EXISTS idx_prompt_experiments_key_status + ON prompt_experiments(experiment_key, status); +CREATE INDEX IF NOT EXISTS idx_prompt_metrics_daily_lookup + ON prompt_metrics_daily(date, template_key, version_id); +``` + +### 14.2 롤백 SQL (요약) +```sql +-- 1) active 버전 되돌리기(예: status 전환 정책 사용 시) +-- UPDATE prompt_versions SET status='active' WHERE id=:stable_version_id; +-- UPDATE prompt_versions SET status='retired' WHERE id=:bad_version_id; + +-- 2) 실험 즉시 중단 +-- UPDATE prompt_experiments SET status='paused', ended_at=NOW() WHERE experiment_key=:exp_key; + +-- 3) 필요 시 인덱스/테이블 제거 (개발환경 한정) +-- DROP INDEX IF EXISTS idx_prompt_events_template_ver_time; +-- DROP TABLE IF EXISTS prompt_metrics_daily, prompt_events, prompt_experiments, prompt_versions, prompt_templates; +``` + +--- + +## 15. RACI (책임 체계) + +| 역할 | 책임 | +|---|---| +| Author | 프롬프트 초안 작성, 변경 사유 기록 | +| Reviewer | 품질/톤/안전 제약 검토 | +| Approver | canary/full 승격 승인 | +| Operator | 알람 대응, kill-switch, 롤백 실행 | + +운영 원칙: +- 편집 권한과 승격 권한은 분리한다. +- 야간/주말 온콜 Operator를 지정한다. + +--- + +## 16. 운영 캘린더 + +- 일일: + - 15분/1시간 알람 리뷰 + - 전일 대비 품질/성능/안정성 지표 점검 +- 주간: + - 실험 결과 리뷰 + - candidate -> canary -> full 승격 회의 +- 월간: + - 롤백 드릴 1회 + - 가드레일 임계값 재평가 + +--- + +## 17. 변경 이력 템플릿 + +```text +change_id: +template_key: +from_version: +to_version: +experiment_key: +change_reason: +expected_impact: +approver: +applied_at: +rollback_target_version: +post_check_result: +``` + +--- + +## 18. 장애 런북 (요약) + +1. 알람 감지: 가드레일 위반 확인(15분/1시간 동시 확인) +2. 즉시 차단: experiment `paused` + kill-switch 적용 +3. 안정화: stable active 버전 강제 전환 +4. 검증: 핵심 API smoke + 주요 UX 시나리오 3건 확인 +5. 사후 분석: 원인/영향/재발 방지 항목 기록 + +운영 목표: +- 장애 감지 후 15분 내 안정 버전 복귀 + +--- + +## 19. 일정 추정 (체크용) + +### 19.1 빠른 현실 기준 +- 30분: 설계/문서 확정, 작업 분할, 체크리스트 고정 (구현 완료 불가) +- 4~6시간: MVP 골격 구현 + - 스키마/Repository/기본 조회·병합 + - `safe_prod`/`strict_observe` 분기 연결 + - 핵심 단위 테스트 일부 +- 1~2일: 기능 완료 + 테스트 통과 + - LLM 경로 연동(`llm_service`, `gemini_handler`) + - fallback/strict_observe 동작 검증 + - TDD + 핵심 E2E +- 4~5일: 운영 안정화 포함 + - canary(5~10%) 관측 + - 가드레일 임계치 보정 + - 롤백 드릴 수행 + +### 19.2 마일스톤 +- M1 (반나절): DB 스키마 + Repository 초안 +- M2 (1일): 런타임 병합 + 모드 분기 동작 +- M3 (2일): 테스트/검증 완료, canary 시작 준비 +- M4 (4~5일): canary 관측 + 운영 기준 확정 + +--- + ## 참고 문서 - `book/300_architecture/311_백엔드_구조_원칙.md` - `book/300_architecture/312_문서_작성_원칙.md`