1 왜 닫힌 루프인가
C20~C22가 만든 가시성을 사람이 매주 회의에서 검토하고 처치를 결정하는 패턴은 운영 규모가 커지면 깨진다.
| 사람 검토 패턴의 한계 | 결과 |
|---|---|
| 회의에서 “약한 의도 3개” 토론 → 다음주 PR | 처치 cycle 1~2주 |
| 약점이 100개씩 발견되면 우선순위 결정 부담 | 일부만 처리 → 누적 부채 |
| 처치 후 효과 측정을 누락 (PR merge 후 잊힘) | 학습 누적 안 됨 |
| 같은 약점에 다른 처치를 반복 | 회귀 모르고 재시도 |
자동 루프의 가치 — 발견·처치·검증·학습이 한 흐름으로 묶임. 사람은 거버넌스 결정에만 개입.
[C20 로깅]
↓
[C21 의도·토픽] [C22 품질 평가]
↓ ↓
└─────┬────────────┘
↓
[C23 약점 탐지] → 가설 생성
↓
[처치 후보] → 거버넌스 게이트 → C19 실험 파이프라인
↓
[모니터링] → 효과 검증 → 카탈로그 누적
↓
(루프 반복)
2 피드백의 4가지 타깃
| 타깃 | 처치 예시 | 처치 비용 | 위험 |
|---|---|---|---|
| 프롬프트 | system prompt 보강·few-shot 추가·rubric 수정 | 낮음 (config 변경) | 회귀 (다른 의도 영향) |
| 지식 | 새 문서 인덱싱·청킹 재조정·메타데이터 보강 | 중간 (인덱싱 시간) | drift (오래된 정보 잔존) |
| 라우팅 | Bandit 가중 조정·새 arm 도입·세그먼트 분기 | 중간 (실험 1~2주) | 작은 세그먼트 손실 |
| 운영 정책 | refusal 임계 조정·HITL trigger 변경·scope 확장 | 높음 (보안·정책 영향) | 권한 누출·정책 위반 |
타깃별로 거버넌스 게이트 분리 — 프롬프트 변경은 빠르게, 정책 변경은 신중하게.
3 단계 1 — 약점 탐지
C21·C22의 출력을 매일 집계.
# app/feedback/detect.py
def detect_weak_cells(window_days: int = 7) -> list[dict]:
df = clickhouse.query(f"""
SELECT
query_intent_class as intent,
query_topic_cluster as topic,
segment['department'] as dept,
count() as n,
avg(quality_fused_score) as score,
avg(thumbs_up) as thumbs,
sum(is_refusal) / count() as refusal_rate
FROM feature_table
WHERE timestamp >= now() - INTERVAL {window_days} DAY
GROUP BY intent, topic, dept
HAVING n >= 100
""")
weak = df[
(df.score < df.score.quantile(0.2))
| (df.refusal_rate > 0.3)
| (df.thumbs < df.thumbs.median() - 2 * df.thumbs.std())
]
return weak.to_dict("records")탐지 기준: - 상대 약함 — 같은 의도×세그먼트 내 하위 20% - 절대 약함 — refusal rate > 30%, thumbs < threshold - 추세 악화 — 7일 평균 vs 28일 평균 비교 (drift)
def trend_decay(intent: str, window: int = 7, baseline: int = 28) -> float:
recent = avg_score(intent, days=window)
base = avg_score(intent, days=baseline)
return (recent - base) / base # 음수면 악화각 약점에 priority score 부여:
def priority(cell: dict) -> float:
return (
cell["n"] / 1000 # 영향 사용자 수
+ (1 - cell["score"]) * 2 # 품질 격차
+ cell["refusal_rate"] * 3 # refusal 가중
)상위 10~20개를 매일 처치 후보로 큐잉.
4 단계 2 — 가설 자동 생성
각 약점에 대해 LLM이 처치 가설을 작성.
HYPOTHESIS_PROMPT = """
약점 셀:
- 의도: {intent}
- 토픽: {topic}
- 부서: {dept}
- 표본 수: {n}
- 품질 점수: {score:.2f} (median {median:.2f})
- refusal rate: {refusal_rate:.2f}
샘플 query·response·feedback (10개):
{samples}
이 약점의 가능한 원인을 3가지 가설로 작성. 각 가설마다:
1. 원인 (왜 약함)
2. 처치 (프롬프트·지식·라우팅·정책 중 어디)
3. 측정 메트릭 (개선이 보일 신호)
JSON 형식으로 답변.
"""
def generate_hypotheses(cell: dict) -> list[dict]:
samples = sample_queries_in_cell(cell, n=10)
prompt = HYPOTHESIS_PROMPT.format(**cell, samples=format_samples(samples))
raw = llm_call(prompt)
return json.loads(raw)LLM은 여러 가설을 내고 — 사람·자동 게이트가 우선순위 선택. 단일 가설로 좁히지 않음 (LLM의 hallucination 위험 분산).
4.1 가설 검증 — 휴리스틱
LLM 가설을 그대로 신뢰하지 않고 데이터로 1차 점검:
def validate_hypothesis(hyp: dict, cell: dict) -> bool:
if hyp["target"] == "knowledge":
# 가설: "관련 문서가 부족"
# 점검: retrieval citation count 평균이 다른 셀 대비 낮은가?
cell_citations = avg_citation_count(cell)
global_citations = avg_citation_count_all()
return cell_citations < global_citations * 0.6
if hyp["target"] == "prompt":
# 가설: "프롬프트가 부서 컨텍스트 부족"
# 점검: 같은 의도 다른 부서는 점수 좋은가?
same_intent_other = avg_score_by_intent_excl_dept(cell)
return same_intent_other > cell["score"] * 1.2
...검증 통과 가설만 다음 단계로.
5 단계 3 — 처치 등록 (C19 통합)
검증된 가설을 C19 실험 spec으로 자동 변환:
# app/feedback/treatment.py
def register_treatment(hyp: dict, cell: dict) -> str:
if hyp["target"] == "prompt":
spec = {
"id": gen_exp_id(),
"title": f"프롬프트 보강 — {cell['intent']}/{cell['dept']}",
"hypothesis": hyp["text"],
"audience": {"segment": f"{cell['dept']}_{cell['intent']}"},
"metrics": {
"primary": "thumbs_up_rate",
"guardrail": ["p95_latency_ms", "refusal_rate"],
},
"arms": {
"control": {"prompt_version": current_prompt_version()},
"treatment": {"prompt_version": hyp["proposed_prompt_version"]},
},
"allocation": {"type": "bandit", "bandit_algo": "thompson", "holdout_fraction": 0.05},
"duration": {"min_days": 7, "max_days": 21},
"design": {"alpha": 0.05, "power": 0.8, "mde": 0.03},
"governance": "auto_ship", # 프롬프트는 저위험
}
elif hyp["target"] == "knowledge":
# 지식 처치는 재인덱싱이라 spec 다름
spec = build_knowledge_treatment_spec(...)
elif hyp["target"] == "routing":
spec = build_routing_treatment_spec(...)
elif hyp["target"] == "policy":
spec = build_policy_treatment_spec(...)
spec["governance"] = "governance_review" # 정책은 사람 검토 필수
return c19_register(spec) # C19 단계 3에 등록타깃별 거버넌스가 자동 분류 — auto_ship (프롬프트), pending_review (지식·라우팅), governance_review (정책).
6 단계 4 — 모니터링과 효과 검증
C19 단계 6 모니터링 + C19 단계 7 분석을 그대로 활용. 추가:
# app/feedback/track.py
def track_treatment_effect(exp_id: str, cell: dict):
"""처치가 약점 셀의 점수를 실제로 올렸는지."""
pre = pre_treatment_score(cell, days=14) # 처치 전 14일
post = post_treatment_score(cell, exp_id) # 처치 후
return {
"exp_id": exp_id,
"cell": cell,
"pre_score": pre,
"post_score": post,
"lift": post - pre,
"lift_pct": (post - pre) / pre,
}전체 셀이 아니라 그 약점 셀만 측정 — 다른 셀에 spillover가 있는지 별도 점검 (guardrail).
7 단계 5 — 학습 카탈로그
처치-효과 결과가 카탈로그에 누적.
# catalog/treatments/2026Q2/exp_2026Q2_037.yaml
id: exp_2026Q2_037
detected_at: 2026-04-15
cell:
intent: troubleshoot
topic: oom_errors
dept: rnd
pre_score: 0.42
hypothesis:
text: "OOM 관련 프롬프트가 hardware 컨텍스트가 부족 — GPU·batch size 명시 부족"
target: prompt
treatment:
arm: prompt_v3.7_oom_specific
diff: |
+ GPU 메모리·batch size 정보를 우선 묻고, 없으면 일반 답변
result:
decision: ship
post_score: 0.61
lift: +0.19
duration_days: 12
learning:
- "RnD 부서 OOM 질문은 hardware context 우선 질문이 효과적"
- "다른 troubleshoot 토픽에도 적용 검토 가치 있음"다음에 비슷한 약점 발견 시 — 카탈로그 검색이 첫 단계:
def search_similar_treatments(cell: dict) -> list[dict]:
"""과거 비슷한 셀에 어떤 처치가 효과적이었나."""
return [
c for c in load_catalog()
if similar_cell(c["cell"], cell)
and c["result"]["decision"] == "ship"
and c["result"]["lift"] > 0.05
]이 검색이 LLM 가설 생성보다 우선 — 검증된 패턴이 있으면 그대로 적용.
8 거버넌스 — 자동·반자동·사람
# config/feedback_governance.yaml
auto_ship:
- prompt_microcopy
- fewshot_example
- rubric_threshold_minor
pending_review:
- prompt_major_rewrite
- knowledge_reindex
- bandit_weight_change
- new_routing_arm
governance_review:
- scope_expand
- hitl_threshold_change
- refusal_policy_change
- external_facing_change자동 ship 카테고리도 dry-run 단계 거침: 1. 처치 spec 작성 2. golden set (C22)으로 사전 회귀 확인 3. 통과 시 5% 트래픽으로 explore 시작 4. 7일 후 자동 분석 → ship 또는 reject
매주 운영팀이 자동 처치 통계만 review (개별 처치 결정은 안 함).
9 자주 발생하는 함정
9.1 Overcorrection
약한 의도에 강한 처치 → 다른 의도 점수 하락. Whack-a-mole 패턴.
해법: - guardrail에 다른 의도들의 평균 점수 포함 - 회귀 발견 시 자동 롤백
9.2 Confounding
약점 발견과 동시에 외부 요인 변화 (모델 업그레이드·플랫폼 장애·신규 사용자 진입). 처치 효과가 외부 요인 효과와 혼재.
해법: - C19 holdout 5%가 baseline 추적 — holdout이 같이 개선되면 외부 요인 가능성 - 처치 시작 시점에 외부 변경 로그 기록 (correlation)
9.3 Gaming the Detector
엔지니어가 약점 탐지 룰을 알면 — 의도적으로 약점 score를 높여 알림 회피. 또는 quality_fused_score만 최적화 (실제 사용자 만족 X).
해법: - 탐지 룰은 다양한 신호를 OR 결합 (단일 메트릭 회피) - 분기마다 사람 골든셋·user 만족도 별도 monitoring
9.4 Catalog Stale
카탈로그가 1년 전 처치 — 코드·모델·사용자가 모두 변함. 옛 처치를 재적용해도 효과 없음.
해법: - 카탈로그 entry에 expiration (90일) - 재적용 시 reduced confidence - 정기 audit — expired 처치를 active 카탈로그에서 제거
9.5 Feedback Loop의 Feedback Loop
처치 효과 측정 → fused_score 변화 → C22 모델 재학습 → 새 quality 정의 → 약점 탐지 변화 — 무한 self-reinforcing.
해법: - C22의 fused_score 모델은 사람 골든셋이 anchor - 처치 결과로 fused_score 모델을 재학습하지 않음 - 사용자 explicit (thumbs_up) 변화만 신뢰 (raw 신호)
9.6 Privacy Echo
사용자 A의 약점 데이터 → 처치 → 사용자 B에 적용 (개인화 카탈로그 갱신) → A의 행동 패턴 노출 위험.
해법: C18 개인화와 같은 원칙 — 세그먼트 수준 학습, k-anonymity, 작은 세그먼트는 학습 제외.
10 MINERVA 적용
app/feedback/
├── detect.py # 약점 탐지 (cron 매일)
├── hypothesis.py # LLM 가설 생성
├── validate.py # 휴리스틱 검증
├── treatment.py # C19 spec 생성
├── track.py # 처치 효과 측정
├── catalog.py # 학습 누적·검색
└── governance.py # 자동 분기 룰
scripts/
├── feedback_daily.py # 탐지·가설·등록 (자동)
├── feedback_review.py # 매주 사람 review용 보고서
└── catalog_audit.py # 분기 expired 정리
catalog/
├── treatments/ # 처치 카탈로그
│ ├── 2026Q1/
│ ├── 2026Q2/
│ └── _patterns.yaml # 재사용 패턴
└── learnings/ # 누적 인사이트
C19 실험 파이프라인·C22 응답 품질·C20 대화 로깅 모두를 호출 — Phase C-5의 자연스러운 클로저.
11 Phase C-5 전체 통합 요약
[C20] 대화 로깅 ─── raw·structured·feature 3계층
│
↓
[C21] 의도·토픽 ─── intent/topic 라벨로 데이터 구조화
│
↓
[C22] 품질 평가 ─── 4계층 신호 융합 → fused_score
│
↓
[C23] 피드백 루프 ─── 약점 탐지·가설·처치·학습 (이 글)
│
↓
다시 [C20] 로깅으로
각 편이 다음 편의 입력. C23이 닫힌 루프를 만들어 운영이 시간이 갈수록 좋아지는 시스템을 가능하게 한다.
12 정리
| 영역 | 핵심 |
|---|---|
| 4가지 타깃 | 프롬프트 (저위험)·지식 (중위험)·라우팅 (중위험)·정책 (고위험) |
| 약점 탐지 | 상대·절대·추세 3가지 룰 OR 결합, priority score 큐잉 |
| 가설 생성 | LLM 다중 가설 → 휴리스틱 검증 → 카탈로그 우선 검색 |
| 처치 등록 | C19 spec 자동 변환, 타깃별 거버넌스 자동 분류 |
| 모니터링 | C19 단계 6·7 활용 + 약점 셀 specific 측정 |
| 카탈로그 | 처치-효과 누적, expiration·audit·재사용 검색 |
| 거버넌스 | auto_ship·pending_review·governance_review 룰 기반 |
| 함정 | overcorrection·confounding·gaming·feedback loop의 feedback loop·privacy echo |
13 응용 분야
| 시나리오 | 활용 |
|---|---|
| 약한 의도 자동 발견·처치 | 단계 1·2·3·4 풀 사이클 |
| 새 use case 등장 시 빠른 보강 | C21 신규 토픽 → 가설 생성 |
| 모델 업그레이드 후 회귀 catch | 추세 악화 탐지 + 즉시 알림 |
| 운영 학습 누적 | 분기 카탈로그 audit + pattern 추출 |
| 실험 우선순위 결정 | priority score로 처치 큐 정렬 |
| 사람 회의 시간 절감 | 자동 ship 90% + 사람 게이트 10% |
14 관련 주제
선행 학습 (선수 — Phase C-5 전체)
- C20 대화 로깅 설계 — 데이터 토대
- C21 의도·토픽 — 약점 cell 차원 정의
- C22 응답 품질 평가 — 약점 신호 fused_score
Cross-reference (Phase C-4와의 연동)
- C19 실험 파이프라인 — 처치 등록·실행 인프라
- C16 Bandit — 라우팅 처치 직접 적용
- C18 개인화 — 프롬프트 처치 카탈로그 갱신
18-LangGraph 시리즈 cross-reference
- #22 시스템 프롬프트 평가 — 처치 효과 측정 이론적 배경
후속 (Phase C-6 진입)
- C24 하네싱 아키텍처 — 자동 처치가 만든 변경을 안전하게 수용하는 supervisor 설계
- C25 실행 제어 — 처치 실패 시 자동 롤백 (Circuit Breaker·Kill Switch)
- C26 에이전트 생명주기 — 처치 결과로 활성화·폐기 결정