Generator-Verifier 격차
생성은 쉽고 검증은 어렵다
섹션 제목: “생성은 쉽고 검증은 어렵다”인간 인지의 고전적 비대칭이 있다. 훌륭한 시를 짓는 것은 어렵지만, 누군가의 시가 훌륭한지 아닌지 판단하는 것은 상대적으로 쉽다. 바둑 수를 창의적으로 두는 것은 어렵지만, 그 수가 규칙에 맞는지 확인하는 것은 컴퓨터로도 즉시 가능하다. 이것이 **Generator-Verifier 격차(Generator-Verifier Gap)**다. 생성(generation)의 난이도와 검증(verification)의 난이도가 비대칭적이라는 현상이다.
그런데 LLM 에이전트에서는 이 관계가 뒤집히는 측면이 있다. 생성은 모델이 자연스럽게 잘 하는 일이다. 하지만 자신이 생성한 내용이 올바른지 검증하는 것은 종종 더 어렵다. 특히 모델은 유창하고 그럴듯한 텍스트를 생성하는 데 특화되어 있기 때문에, 틀린 답도 자신 있게(confidently) 내놓는다. 검증 없이 생성만 반복하는 루프는 이 취약점에 무방비로 노출된다.
┌──────────────────────────────────────────────────────────────┐│ Generator-Verifier 격차의 두 방향 │├─────────────────────────────┬────────────────────────────────┤│ 인간 인지 │ LLM 에이전트 │├─────────────────────────────┼────────────────────────────────┤│ 생성 > 검증 (어려운 쪽) │ 생성 ≈ 쉬움 (유창하게 출력) ││ "좋은 시 짓기 > 판단하기" │ "답 생성 > 답 검증" ││ │ ││ → 검증이 상대적으로 쉽다 │ → 검증이 오히려 더 어렵다 ││ (규칙, 기준으로 확인) │ (모델이 틀린 답도 자신감) │└─────────────────────────────┴────────────────────────────────┘검증 스텝이 없는 루프의 실패 패턴
섹션 제목: “검증 스텝이 없는 루프의 실패 패턴”검증 없이 생성만 반복하는 에이전틱 루프는 다음과 같은 실패 패턴을 보인다.
패턴 1: 이른 성공 종료(Premature Success). 모델이 작업을 완료하지 않았음에도 “완료됐다”고 선언하고 루프를 끝낸다. Anthropic의 장기 에이전트 가이드는 이것을 명시적으로 경계한다. 외부 검증자(테스트 러너, 별도 LLM 심판 등) 없이 모델 자신의 선언만 믿으면 이 실패를 잡아낼 수 없다.
패턴 2: 자기 확인 편향(Self-confirmation Bias). 모델에게 “네가 생성한 코드가 맞나요?“라고 물으면, 모델은 자신이 방금 만든 것을 검증하는 데 제대로 비판적이지 못한 경향이 있다. 자신이 생성자이자 검증자가 되는 것은 이해충돌이다.
패턴 3: 그럴듯한 오답의 전파. LLM은 사실적으로 틀렸더라도 유창하게 표현되고 논리적으로 들리는 텍스트를 생성할 수 있다. 검증 없이 이 오답이 다음 스텝의 전제로 쓰이면, 오류가 하류 전체에 전파된다.
검증 스텝을 루프에 삽입하기
섹션 제목: “검증 스텝을 루프에 삽입하기”Generator-Verifier 격차를 해소하는 가장 직접적인 방법은 생성(generator)과 검증(verifier)을 루프 구조 안에서 명시적으로 분리하는 것이다.
# 개념 이해용 의사 코드이며 실제 API와 다를 수 있습니다.
def run_loop_with_verification(task: str, tools: list, max_iters: int = 20): messages = [{"role": "user", "content": task}]
for _ in range(max_iters): # 1단계: 생성 (Generator) response = model.generate(messages, tools=tools)
if response.stop_reason == "end_turn": candidate = response.content
# 2단계: 검증 (Verifier) — 생성자와 분리 verification = verify(candidate, task)
if verification.passed: return {"status": "success", "result": candidate} else: # 검증 실패: 피드백을 컨텍스트에 추가하고 재시도 messages.append({ "role": "user", "content": f"검증 실패: {verification.reason}\n다시 시도하세요." }) continue
# 도구 실행 후 계속 for call in response.tool_calls: result = run_tool(call) messages.append(tool_result(result))
return {"status": "max_iters_exceeded"}여기서 verify() 함수는 다양한 방식으로 구현될 수 있다. 다음 챕터들이 각각 하나의 구현 방법을 다룬다.
| 검증 방법 | 특성 | 챕터 |
|---|---|---|
| 테스트 러너 | 결정론적, 빠름, 코딩 태스크에 적합 | 6-4 |
| LLM-as-Judge | 유연함, 언어 태스크에 적합, 편향 존재 | 6-3 |
| 인간 검토 | 가장 신뢰성 높음, 느리고 비쌈 | 6-5 |
| 규칙 기반 검사 | 빠름, 제한적 적용 범위 | — |
검증 난이도와 생성 난이도의 정렬
섹션 제목: “검증 난이도와 생성 난이도의 정렬”이상적인 루프 설계에서는 검증이 생성보다 명확히 더 쉽거나 더 신뢰할 수 있어야 한다. 코딩 에이전트가 이 원칙의 모범 사례다. 코드를 생성하는 것은 어렵지만, 그 코드가 테스트를 통과하는지 확인하는 것은 결정론적이고 자동화되어 있다. 테스트 통과 여부라는 검증 신호가 생성의 품질을 명확하게 측정한다.
반대로 검증이 생성만큼 어렵거나 더 어려운 태스크에서는 자동화 루프의 한계가 드러난다. 창의적 글쓰기의 품질, 복잡한 전략 결정의 옳고 그름 같은 태스크에서 자동 검증은 불완전할 수밖에 없다. 이 경우에는 인간 검토(6-5)나 LLM-as-Judge의 한계를 인식하면서 사용하는 것이 현실적이다.
검증 없는 루프는 무엇을 만들어 내는가
섹션 제목: “검증 없는 루프는 무엇을 만들어 내는가”검증 스텝이 없는 루프는 기술적으로 “동작”하지만, 그 출력의 품질을 보장할 방법이 없다. 루프가 30회 돌고 end_turn을 반환하면, 그것은 모델이 만족한다는 의미일 뿐 작업이 실제로 올바르게 완료됐다는 의미가 아니다. Generator-Verifier 격차를 인식하는 것이 루프에 검증 단계를 설계하는 출발점이다. 다음 두 챕터에서는 이 격차를 메우는 두 가지 주요 자동 검증 전략 — LLM-as-Judge와 테스트 주도 루프 — 을 구체적으로 다룬다.
참고 자료
- Anthropic — Building Effective AI Agents — 접속 2026-06-30
- Anthropic — Effective harnesses for long-running agents — 접속 2026-06-30
- Zheng et al. — Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena (arXiv:2306.05685) — 접속 2026-06-30