콘텐츠로 이동

Evaluator-Optimizer: 생성-평가 루프

Self-Refine 챕터에서 살펴봤듯, 동일 모델에게 생성과 비판을 모두 맡기면 아첨적 비판(sycophantic critique) 문제가 생긴다. 자신이 만든 것을 스스로 엄격하게 평가하기 어렵다. 이 문제를 해결하는 더 강력한 접근이 역할 분리다.

Evaluator-Optimizer는 **Generator(생성자)**와 **Evaluator(평가자)**를 별개의 LLM 호출로 분리한다. Evaluator는 Generator의 출력을 채점하고 구체적인 피드백을 제공한다. Generator는 그 피드백을 받아 출력을 개선한다. 이 루프는 Evaluator가 “통과” 판정을 내리거나 최대 이터레이션에 도달할 때까지 반복된다.

┌──────────────────────────────────────────────────────────────────┐
│ Evaluator-Optimizer 루프 │
│ │
│ 태스크 입력 │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Generator │ ──→ 초기 출력 생성 │
│ └──────┬───────┘ │
│ │ 출력 │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Evaluator │ │
│ │ - 평가 기준(루브릭)에 따라 채점 │ │
│ │ - 구체적 개선 피드백 생성 │ │
│ │ - 통과/재시도 판정 │ │
│ └──────────────┬─────────────────────────────────────────┘ │
│ │ │
│ ┌────────────┴─────────────────┐ │
│ │ 통과 │ 재시도 │
│ ▼ ▼ │
│ 최종 출력 ┌──────────────────────┐ │
│ │ Generator (재생성) │ │
│ │ 피드백을 입력으로 포함│ │
│ └──────────┬───────────┘ │
│ │ │
│ ▲────┘ Evaluator로 다시 │
└──────────────────────────────────────────────────────────────────┘
차원 Self-Refine Evaluator-Optimizer
평가 주체 생성한 모델 자신 별도 Evaluator LLM
평가 기준 암묵적 (모델 내부 판단) 명시적 루브릭
독립성 없음 (자기 비판) 있음 (외부 시선)
아첨 편향 높음 낮음 (설계에 따라 제어 가능)
복잡도 낮음 높음 (두 LLM 조율 필요)

Evaluator에게 명시적인 **루브릭(rubric)**을 제공하는 것이 핵심이다. “이 번역은 좋은가?“보다 “다음 기준으로 각각 1~5점 채점하라: 정확도, 자연스러움, 전문 용어 일관성”처럼 구체적일수록 평가 품질이 높아진다.

개념 이해용 의사 코드이며 실제 API와 다를 수 있습니다.

from dataclasses import dataclass
@dataclass
class EvaluationResult:
passed: bool
score: float # 0.0 ~ 1.0
feedback: str
criteria_scores: dict[str, float]
def evaluator_optimizer(
generator_model,
evaluator_model,
task: str,
rubric: str,
pass_threshold: float = 0.85,
max_iterations: int = 4,
) -> str:
"""
Generator가 출력을 생성하고, Evaluator가 채점 및 피드백 제공.
통과 기준 충족까지 반복.
"""
feedback_history = []
output = None
for iteration in range(max_iterations):
# ① 생성 (Generator)
gen_context = task
if feedback_history:
previous_feedback = "\n".join(
f"시도 {i+1} 피드백: {f}" for i, f in enumerate(feedback_history)
)
gen_context = (
f"{task}\n\n이전 시도들의 피드백:\n{previous_feedback}\n\n"
"위 피드백을 반영해 개선된 결과를 생성하라."
)
gen_result = generator_model.generate(
[{"role": "user", "content": gen_context}]
)
output = gen_result.text
# ② 평가 (Evaluator)
eval_prompt = (
f"태스크: {task}\n\n"
f"평가 기준 (루브릭):\n{rubric}\n\n"
f"평가할 출력:\n{output}\n\n"
"각 기준별 점수(0~1)와 종합 점수, 구체적 피드백을 JSON으로 반환:\n"
'{"passed": bool, "score": 0.0~1.0, '
'"feedback": "...", "criteria_scores": {...}}'
)
eval_result = evaluator_model.generate(
[{"role": "user", "content": eval_prompt}],
temperature=0.0, # 평가는 결정론적으로
)
evaluation = parse_evaluation(eval_result.text)
# ③ 통과 판정
if evaluation.score >= pass_threshold:
break
feedback_history.append(evaluation.feedback)
return output

Evaluator-Optimizer의 가장 위험한 실패 모드는 Goodhart’s Law 현상이다. “측정값이 목표가 되면, 좋은 측정값이 아니게 된다.” Generator가 Evaluator의 평가 기준을 최적화하도록 반복 학습되면, Evaluator 점수는 높아지지만 실제 품질은 높아지지 않거나 오히려 낮아지는 현상이 발생한다.

구체적으로는 Evaluator Drift 형태로 나타난다. Generator가 Evaluator를 “속이는” 패턴을 학습하는 것이다. 예를 들어 Evaluator가 “길이”를 품질 지표로 사용하면, Generator는 내용 없이 장황하게 생성하는 법을 익힌다.

┌────────────────────────────────────────────────────────────────┐
│ Evaluator Drift 완화 전략 │
├──────────────────────────┬─────────────────────────────────────┤
│ 전략 │ 설명 │
├──────────────────────────┼─────────────────────────────────────┤
│ 다면 루브릭 │ 단일 점수 대신 다차원 평가 │
│ 레퍼런스 앵커링 │ 기준 답안과 비교 평가 │
│ 인간 샘플 리뷰 │ 무작위 N% 인간이 검토 │
│ 평가 다양화 │ 여러 Evaluator 앙상블 │
│ 이터레이션 수 제한 │ 과도한 최적화 방지 │
└──────────────────────────┴─────────────────────────────────────┘

Evaluator-Optimizer의 Evaluator는 LLM-as-Judge 패턴의 워크플로 적용이다. Zheng et al.(NeurIPS 2023)의 연구에 따르면 GPT-4를 심판으로 사용할 때 인간 선호와 80% 이상 일치한다고 보고했으며, 이는 인간 간 일치율과 비슷한 수준이다. 단, LLM 심판도 위치 편향(첫 번째 답변 선호), 장황함 편향(긴 답변 선호), 자기 강화 편향(자신이 생성한 스타일 선호)을 가진다. 이 편향들을 완화하기 위해 위치 스왑(두 답변 순서를 바꿔 두 번 평가), CoT 평가(점수 전 이유 먼저 작성), 레퍼런스 기반 평가 등이 사용된다.

Evaluator-Optimizer가 가장 빛나는 조건

섹션 제목: “Evaluator-Optimizer가 가장 빛나는 조건”

이 패턴은 세 가지 조건이 동시에 충족될 때 가장 효과적이다. 첫째, 출력 품질을 측정할 수 있는 명확한 기준이 있어야 한다. 둘째, Generator가 반복으로 개선 가능한 태스크여야 한다(수학 증명처럼 전략을 바꿔야 하는 경우는 단순 반복이 도움이 안 된다). 셋째, 레이턴시보다 품질이 중요한 상황이어야 한다. 이 조건을 갖춘 대표 사례로는 기술 문서 작성, 번역 품질 보장, 코드 리뷰 자동화, 콘텐츠 안전성 검증 등이 있다.

퀴즈를 불러오는 중…

참고 자료