읽기 전용 리뷰어 에이전트(Read-Only Reviewer Agents)는 메인 에이전트가 놓치는 것을 잡아냅니다
요약
메인 에이전트의 완료 편향을 극복하기 위해 수정 권한이 없는 '읽기 전용 리뷰어 에이전트'를 도입하는 구조적 해결책을 제시합니다. 리뷰어 에이전트는 작업 완료에 대한 압박 없이 스펙 드리프트나 누락된 케이스를 더 날카롭게 검증할 수 있습니다.
핵심 포인트
- 메인 에이전트는 자신의 출력을 검증할 때 확인 편향(confirmation bias)을 가짐
- 프롬프팅보다 도구 범위(tool scope)를 제한하는 것이 더 강력한 구조적 해결책임
- 읽기 전용 에이전트는 수정 의무가 없어 스펙 준수 여부를 더 객관적으로 판단함
- 리뷰어 에이전트는 스펙 드리프트, 누락된 케이스, 테스트 결합 문제를 효과적으로 포착함
메인 에이전트(Main agent)는 코드를 작성합니다. 리뷰어 에이전트(Reviewer agent)는 그것을 읽습니다. 리뷰어는 아무것도 수정할 수 없습니다.
그 제약 사항 — 수정 권한이 없다는 것 — 이 핵심입니다. 이것은 안전 조치가 아닙니다. 이것이 리뷰어를 신뢰할 수 있게 만드는 요소입니다.
"그냥 통과시키는 것(waving through)"의 모습
저는 저의 에이전트 기반(agentic) 작업에서 한 가지 패턴을 발견했습니다. 메인 에이전트가 기능을 완료하고, 테스트를 통과하면, 저는 그것을 완료로 표시합니다. 나중에 저는 잘못된 것을 발견합니다 — 처리되지 않은 null 케이스, 사양(spec)과 일치하지 않는 에러 메시지, 테스트는 통과하지만 약간 다른 컨텍스트에서는 실패하는 동작 등입니다. 코드에서 분명히 보였던 것들입니다. 제가 잡아냈어야 했던 것들입니다.
메인 에이전트는 코드를 작성했고 코드를 검증했습니다. 자신의 출력을 읽을 때쯤이면, 에이전트는 이미 해당 기능을 완료된 것으로 정신적 모델링(mentally modeled)을 마친 상태입니다. 에이전트는 모든 것이 올바르다는 가정하에 읽으며 확인(confirmation)을 찾습니다. 에이전트가 직접 작성한 테스트를 통과하도록 코드를 작성했기 때문에, 결국 확인을 찾아내게 됩니다.
이것은 지능(intelligence)의 문제가 아니라 검증(verification)의 문제입니다. 동일한 문제가 인간의 코드 리뷰에서도 나타납니다. 작성자는 자신의 실수를 잡아내기에 가장 적합하지 않은 사람입니다. 부주의해서가 아니라, 작업에 너무 밀착되어 있기 때문입니다.
도구 범위(tool scope)가 올바른 레버인 이유
프롬프팅(prompting)으로 이 문제를 해결하려고 시도할 수 있습니다. 메인 에이전트에게 "완료하기 전에 비판적으로 검토하라"고 말하는 것입니다. 저도 시도해 보았습니다. 약간의 도움이 됩니다. 에이전트는 그냥 넘어갔을 법한 몇 가지 문제들을 드러냅니다. 하지만 이는 에이전트 자신의 완료 편향(completion-bias)에 맞서 싸우는 것이며, 이는 약한 힘입니다.
도구의 범위를 다르게 설정하는 것은 단순한 권유(nudge)가 아니라 구조적인 해결책(structural fix)입니다.
문자 그대로 어떤 쓰기(write)나 수정(edit) 도구도 호출할 수 없는 리뷰어 에이전트는 코드와 다른 관계를 맺습니다. 에이전트는 작업을 끝내려고 노력하지 않습니다. 끝내야 할 작업 자체가 없습니다. 에이전트는 차이점(diff)을 읽고, 사양(spec)을 읽고, 테스트 결과(test results)를 읽습니다. 그것이 에이전트가 할 수 있는 전부입니다. 에이전트의 역할은 수정하는 것이 아니라, 무언가를 알아차리는 것입니다.
수정할 수 있는 옵션을 제거하면, 알아차리는 능력이 더 날카로워집니다.
리뷰어가 실제로 잡아내는 것들
실제로 리뷰어는 몇 가지 범주의 사항들을 찾아냅니다:
스펙 드리프트 (Spec drift). 메인 에이전트가 구현 과정에서 스펙(spec)에서 벗어난 사소한 판단을 내린 경우입니다. 완전히 틀린 것은 아니며 합리적인 결정일 수 있지만, 스펙에 명시된 내용은 아닙니다. 리뷰어는 스펙을 열어둔 상태로 구현에 이해관계가 없기 때문에 이를 찾아냅니다. 메인 에이전트는 구현이 "맞는 것처럼 느껴지기" 때문에 이러한 편차를 인지하지 못했을 수도 있습니다.
누락된 케이스 (Missing cases). 메인 에이전트는 해피 패스 (happy path)와 명백한 에러 케이스를 처리했습니다. 리뷰어는 다음과 같이 질문합니다: "만약 이 입력값이 비어 있다면 어떻게 될까? 이 호출이 실패한다면 어떻게 될까?" 이러한 사항들은 읽기를 통해 찾아낼 수 있으며, 단지 작성할 때와는 다른 주의 모드 (mode of attention)가 필요할 뿐입니다.
테스트-구현 결합 (Test-implementation coupling). 때때로 테스트가 통과하는 이유는 구현과 테스트가 동일한 사각지대를 가진 채 함께 작성되었기 때문입니다. 리뷰어는 둘 다 읽어보고, 테스트가 실제로 동작(behavior)을 커버하는지, 아니면 단순히 코드(code)를 커버하는지 질문합니다. 이 둘은 서로 다른 것입니다.
용어 불일치 (Terminology mismatch). 에러 메시지, 변수 이름, 스펙이나 기존 코드베이스 컨벤션 (conventions)과 일치하지 않는 API 응답 필드 등이 이에 해당합니다. 사소한 부분입니다. 로직에 집중할 때는 놓치기 쉽지만, 읽기에만 집중할 때는 잡아내기 쉽습니다.
설정 방법
메커니즘은 간단합니다. 두 개의 에이전트 호출을 병렬이 아닌 순차적으로 실행합니다. 메인 에이전트가 작업을 수행합니다. 작업이 완료되면, 디프 (diff)와 스펙을 리뷰어라고 명시된 시스템 프롬프트와 함께 두 번째 에이전트에게 전달하며, 이 에이전트에는 읽기 전용 (read-only) 파일 접근 권한을 설정합니다.
특히 Claude Code에서는 에이전트 수준에서 도구 권한 (tool permissions)의 범위를 지정할 수 있습니다. 리뷰어에게는 Read, Grep, Glob 권한을 부여합니다. Edit, Write, Bash 권한은 주지 않습니다. 리뷰어는 원하더라도 문자 그대로 아무것도 변경할 수 없습니다.
리뷰어의 출력은 발견 사항 (findings)의 목록입니다. 그러면 메인 에이전트가 해당 발견 사항들을 전달받아 이를 해결합니다. 필요하다면 한 번 더 검토를 거치거나 리뷰어의 확인을 한 번 더 수행할 수 있습니다.
가치가 없는 경우
짧은 스크립트, 일회성 코드, 어차피 다시 작성할 것들 — 이러한 경우에는 오버헤드(overhead)를 감수할 가치가 없습니다. 리뷰어는 지연 시간(latency)과 비용을 추가합니다. 하지만 프로덕션(production)에 배포될 모든 것, 사양(spec)을 준수해야 하는 모든 것, 또는 다른 사람에게 전달할 모든 것에는 가치가 있습니다.
리뷰어가 실질적인 가치를 더하는 또 다른 경우는 사양(spec)이 핵심적인 역할을 할 때입니다. 만약 당신이 정밀한 수락 기준(acceptance criteria)을 작성했고, 구현 사항이 단순히 "테스트가 통과했는지"가 아니라 "기준을 실제로 충족했는지"를 알고 싶다면, 리뷰어는 그러한 비교를 수행하는 데 탁월합니다.
더 깊은 관점
문제는 메인 에이전트(main agent)가 실수를 한다는 것이 아닙니다. 에이전트와 리뷰어가 컨텍스트(context), 상태(state), 그리고 결과에 대한 이해관계(stake)를 공유한다면, 이들은 동일한 엔티티(entity)라는 점이 문제입니다.
관심사(concerns)를 분리하십시오. 각 에이전트에게 그 역할에 정확히 필요한 도구만을 제공하고, 그 이상은 주지 마십시오. 리뷰어는 읽는 것이 업무이므로 글을 쓸 필요가 없습니다. 오직 읽기만 할 수 있을 때, 리뷰어는 더 잘 읽습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기