사람도 자신이 쓴 글을 바로 교정하면 오타를 많이 놓칩니다. AI 에이전트도 마찬가지입니다. 코드를 만든 것과 동일한 모델이 동일한 컨텍스트로 리뷰하면, 처음에 한 가정을 그대로 유지한 채 '괜찮아 보인다'고 판단하는 경향이 있습니다. 이 문제를 해결하는 것이 메이커-체커(Maker-Checker) 분리입니다.
왜 '같은 모델 두 번 실행'으로는 부족한가
핵심은 독립성(independence)입니다. 메이커와 체커가 같은 대화 맥락을 공유한다면, 체커는 사실상 메이커의 연장선입니다. 진짜 체커는 메이커의 코드는 볼 수 있지만, 메이커가 어떤 가정을 했는지, 어떤 옵션을 고려했는지는 모르는 상태에서 독립적으로 평가해야 합니다.
메이커-체커의 3가지 구현 방식
| 방식 | 설명 | 적합한 상황 |
|---|---|---|
| 같은 세션, 다른 프롬프트 | 이제 비판적 리뷰어 역할로 평가해줘 지시 | 빠른 검토, 저비용 |
| 독립 서브에이전트 | 별도 모델 인스턴스, 독립 컨텍스트로 실행 | 중요한 코드, 문서 |
| 다른 모델로 검증 | A 모델이 만들고 B 모델이 리뷰 | 최고 수준 독립성 필요 |
세 가지 방식 중 실제 생산 환경에서 가장 신뢰할 수 있는 것은 독립 서브에이전트 방식입니다. 서로 다른 대화 기록, 서로 다른 컨텍스트로 각각 실행됩니다. 메이커와 체커 사이에 공유되는 것은 결과물(artifact)뿐이어야 합니다.
어드버서리얼 리뷰(Adversarial Review)
좋은 체커는 '문제가 없나 한번 봐줘'가 아니라, '이 코드의 약점을 찾아라'는 임무를 받아야 합니다. 이를 어드버서리얼 리뷰(adversarial review, 적대적 리뷰)라고 합니다. 체커의 역할은 '좋아 보인다'는 확인이 아니라, '이 부분이 문제다'를 찾아내는 것입니다.
체커 에이전트 시스템 프롬프트 예시
당신은 코드 보안 및 품질 감사 전문가입니다.
아래 코드를 구현한 개발자의 의도는 신경 쓰지 마세요.
오직 결과물 자체만 평가하고, 다음 항목을 반드시 확인하세요:
1. 보안 취약점 (SQL Injection, XSS, 인증 누락)
2. 타입 안전성 위반 (any 사용, 암묵적 변환)
3. 엣지 케이스 미처리 (빈 배열, null, 네트워크 오류)
4. 테스트 가능성 (의존성 주입 없이 테스트하기 어려운 구조)
각 문제를 CRITICAL / HIGH / MEDIUM / LOW로 분류하고,
문제 코드 라인과 구체적인 수정 방법을 함께 제시하세요.
통과 기준: CRITICAL 0개, HIGH 0개.
독립 패스(Independent Pass)로 테스트 분리
메이커-체커를 테스트에도 적용할 수 있습니다. 명세(specification)를 먼저 만들고, 메이커는 그 명세를 보고 구현하고, 체커는 같은 명세를 보고 테스트를 작성합니다. 둘은 서로의 코드를 모릅니다. 테스트가 구현을 통과하면 명세가 올바르게 이해된 것입니다.
에스컬레이션 조건
체커가 CRITICAL 문제를 발견하면 메이커에게 돌려보내는 것으로 끝나지 않을 수 있습니다. N번 이상 같은 문제가 반복되면 사람(human)에게 에스컬레이션해야 합니다. '에이전트 루프가 고칠 수 없는 문제'를 자동으로 감지하고 사람을 호출하는 것도 하네스의 역할입니다.
체커 에이전트를 만들 때는 '칭찬 금지' 지시를 넣으세요. 기본적으로 LLM은 긍정적으로 반응하려는 경향이 있어서, '문제를 찾는 것이 당신의 임무'라고 명시적으로 알려줘야 진짜 비판적 리뷰를 합니다.
체커가 없다고 셀프 리뷰로 대체하는 것은 위험합니다. '이제 비판적 시각으로 다시 봐줘'라는 프롬프트는 완전히 독립된 리뷰가 아닙니다. 중요한 코드에는 반드시 독립된 서브에이전트나 사람의 리뷰를 거치세요.