본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 08. 04:57

Self-Critique Loops for Agents: Where the 3rd Iteration Stops Helping

요약

AI 에이전트의 자기 비평 루프(self-critique loop)는 초기 반복에서 큰 개선을 가져오지만, 그 효과는 급격히 감소합니다. 1~2회 반복은 유용하지만, 3회 이후부터는 모델이 이전 출력을 방어하거나 미묘한 오류를 추가하는 등 회귀 현상이 나타나기 쉽습니다. 따라서 실질적인 가이드라인으로 1~2회의 비평 반복을 권장하며, 루프를 무한히 돌리는 것은 비용만 증가시킬 뿐입니다. 또한, 에이전트의 성능 향상을 극대화하려면 출력을 생성하는 '행위자(actor)'와 이를 평가하는 '비평가(critic)' 역할을 동일 모델 호출로 처리하지 않고 분리해야 합니다.

핵심 포인트

  • 자기 비평 루프는 초기 1~2회 반복에서 가장 큰 이득을 얻는다.
  • 3회 이상의 반복은 효과가 급격히 감소하며, 오히려 회귀 현상이나 방어적 수정이 발생할 수 있다.
  • 실용적인 가이드라인으로 최대 2회의 비평 반복을 사용하는 것이 좋다.
  • 최상의 성능을 위해 '행위자(actor)'와 '비평가(critic)' 역할을 분리하여 별도의 모델 호출로 처리해야 한다.
  • 분리는 비평가가 행위자의 추론 체인에 오염되지 않고 객관적으로 오류를 찾게 돕는다.

책: AI Agents Pocket Guide: Patterns for Building Autonomous Systems with LLMs 저자: me (2-book series) — Complete Guide to Go Programming + Hexagonal Architecture in Go
프로젝트: Hermes IDE | GitHub — Claude Code 및 기타 AI 코딩 도구와 함께 개발자를 위한 IDE
저자: xgabriel.com | GitHub

지난 스프링에 에이전트에 자기 비평 루프 (self-critique loop) 를 연결했습니다. 1 번 반복은 명백한 실수를 정리합니다. 2 번 반복은 더 미묘한 실수를 잡습니다. 3 번 반복으로 에이전트는 장식을 제거하는 문장을 다시 쓰며 평가 점수는 거의 움직이지 않습니다. 4 번 반복으로 점수가 두 점을 하락하기 시작하며, 모델이 이전 잘못된 선택을 방어하기 시작하고 수정 대상이 아닌 주변에 편집하기 때문입니다.

팀들이 실제 평가 데이터 앞에 반성 루프 (reflection loops) 를 배치할 때 수렴하는 형태입니다. 자기 정제 (self-refine) 와 반성 (reflexion) 에 대한 첫 번째 논문들은 제목을 올바르게 잡았습니다: 모델에게 자신의 출력을 비판하게 하면 도움이 됩니다.

대부분의 프로덕션 팀이 놓친 부분은 곡선이 오목하고 짧으며, 작은 수의 패스 후 루프는 토큰, 지연 시간, 정확성을 비용으로 만듭니다.

반복 곡선이 실제로 어떻게 보이는지

패턴은 단일 숫자가 아닙니다. 작업, 모델, 그리고 비평가가 지문 (ground truth) 에 접근할 수 있는지 또는 행위자의 이전 출력만 볼 수 있는지에 따라 다릅니다.

발표된 작업 (Self-Refine 논문, Reflexion 논문, Anthropic 의 효과적인 에이전트 구축에 대한 글) 을 통해 형태는 계획하기 위해 충분히 일관적입니다. 0 번 반복은 기준 초안입니다. 1 번 반복은 첫 번째 비판 및 수정 패스입니다. 0 에서 1 로의 상승은 루프에서 볼 수 있는 가장 큰 이득입니다.

실제적으로, 팀들이 공개한 평가에서 이 상승은 도메인 특화 벤치마크에서 약 5~15 점 범위에서 멈추며, 정확한 수는 작업과 모델에 따라 크게 달라집니다 — 이를 관측 사례로 취급하고 보장하지 마세요. 2 번 반복은 더 작은 그러나 실용적인 버프를 추가하며, 보통 1 번 반복의 델타의 분수입니다.

3 번 반복이 곡선이 평평해지는 곳입니다. 4 번 반복에서 일부 실행에서 회귀가 시작됩니다 (이는 저자의 프로덕션 루프에 대한 관찰이며, 발표된 통계가 아닙니다).

회귀의 메커니즘은 특이하지 않습니다. 모델이 텍스트를 생성한 후 한 번의 비판 패스를 통해 그것을 방어하면, 그 텍스트는 컨텍스트에 있습니다. 모델은 이를 약속된 작업으로 처리합니다.

두 번째 자기 비평은 이전 비평과 이전 수정을 보며 이미 올바른 것을 만지거나, 미묘함을 제거하거나, 주의 깊은 헤지를 문장으로 채우기 시작합니다.

코드 작업은 더 "방어적"인 버전으로 다시 쓰여져서 미세한 오프-바이-오 (off-by-one) 를 도입하며, 작성 작업은 원래 주장에 많은 정의를 쌓아주어 주장이 사라집니다.

따라서 실용적인 규칙은: 1 또는 2 번 비평 반복을 배정하고, 3 번을 최대치로 취급하며, 에이전트가 "실제로, 반성하면 더 개선할 수 있습니다"라고 말하기 때문에 루프를 무한히 실행하지 마세요.

행위자 (actor) 와 비평가 (critic) 는 동일한 호출이어야 하지 않습니다

앵커링 문제의 가장 깔끔한 해결책은 구조적입니다. 텍스트를 생성하고 비판하는 데 동일한 모델 호출을 사용하지 마세요. 두 개의 다른 프롬프트 (이상적으로 두 개의 다른 대화 컨텍스트) 를 사용하세요 — 출력을 생성하는 행위자, 그리고 그것을 판단하는 비평가입니다.

분리는 두 가지 이유로 중요합니다. 첫째, 비평가는 행위자의 추론 체인을 보지 않으며, 최종 출력만 보므로, 그렇지 않으면 합리화할 수 있는 결함을 볼 수 없습니다.

mmit to. Second, the critic's prompt can be aggressive about looking for errors without contaminating the actor's instruction with negative framing. A minimal version looks like this in Python with the Anthropic SDK: import anthropic client = anthropic . Anthropic () MODEL = " claude-sonnet-4-5 " # check console for current id def actor ( task : str , prior_output : str | None , critique : str | None ) -> str : if prior_output is None : prompt = task else : prompt = ( f " Task: { task } \n\n " f " Your previous answer: \n { prior_output } \n\n " f " Critic feedback: \n { critique } \n\n " " Revise the answer. Address every concrete " " issue. Do not change parts the critic did " " not flag. " ) msg = client . messages . create ( model = MODEL , max_tokens = 2048 , messages = [{ " role " : " user " , " content " : prompt }], ) return msg . content [ 0 ]. text def critic ( task : str , candidate : str ) -> dict : prompt = ( f " Task: { task } \n\n " f " Candidate answer: \n { candidate } \n\n " " List concrete defects only. For each, give the " " exact text to change and why. If there are no " " concrete defects, reply with the literal token " " NO_DEFECTS and nothing else. " ) msg = client . messages . create ( model = MODEL , max_tokens = 1024 , messages = [{ " role " : " user " , " content " : prompt }], ) text = msg . content [ 0 ]. text . strip () return { " verdict " : " ok " if text == " NO_DEFECTS " else " fix " , " feedback " : text , } Two details in the prompts pull a lot of weight. The actor is told not to change parts the critic did not flag , which stops the rewrite-everything drift. The critic is told to use a literal NO_DEFECTS token when satisfied, which gives you a deterministic halt signal rather than free-form approval language to parse. You can run the critic with a smaller, cheaper model (Haiku, gpt-4o-mini, a fine-tuned Llama) without much loss as long as the 코디의 작업이 충분히 제한된다면. Pattern matching against a rubric is cheaper than generating a full answer. The bounded loop with halting heuristics The loop itself is short. Three counters, two halt conditions, one explicit budget: def critique_loop ( task : str , max_iters : int = 3 ): output = actor ( task , prior_output = None , critique = None ) history = [ output ] for i in range ( max_iters ): verdict = critic ( task , output ) if verdict [ " verdict " ] == " ok " : return { " output " : output , " iters " : i , " halt " : " critic_ok " } revised = actor ( task , prior_output = output , critique = verdict [ " feedback " ], ) if revised . strip () == output . strip (): return { " output " : output , " iters " : i + 1 , " halt " : " no_progress " } if len ( history ) >= 2 and revised in history : return { " output " : output , " iters " : i + 1 , " halt " : " loop_detected " } history . append ( revised ) output = revised return { " output " : output , " iters " : max_iters , " halt " : " budget_exhausted " } Three halt heuristics earn their place here. critic_ok is the obvious one: the critic emitted the agreed token. no_progress catches the case where the actor's revised output is byte-identical to the prior one, which happens more often than you would expect once the model has run out of useful edits. loop_detected catches the rare case where the actor oscillates between two outputs, agreeing with each round of critique by reverting to a prior version. Without that check, your loop will burn the full budget alternating between two near-identical answer

s. max_iters=3 는 거의 모든 작업에서 비판 루프를 연결할 때의 프로덕션 기본값입니다. 특정 작업에서 실제 4 번 반복에 대한 이득이 평가에서 보인다면만 이를 높여야 하며, 각 리뷰마다 해당 증거를 요구해야 합니다. 비판자는 그 자체로 아닌 다른 것에 근거해야 합니다. 순수 자기 비판 — 모델 A 가 모델 A 에게 "이것이 좋나요"라고 묻는 것 — 은 알려진 한계가 있습니다. 모델은 자신이 지식을 갖추지 못한 결함을 발견하지 못하며, 자신의 학습 데이터 편향과 일치하는 결함도 발견하지 못합니다. 이득은 비판자가 액터가 접근하지 못하는 외부에 접근할 때 발생합니다. 프로덕션에서 작동하는 세 가지 옵션: 도구 기반 비판 (Tool-grounded critique). 액터의 출력을 LLM 비판자가 되기 전에 결정적인 검사를 통해 실행합니다. 코드: 실행하세요. SQL: 설명하세요. JSON 출력: 스키마에 대해 유효성을 검사하세요. 수학: 계산하세요. 비판자 프롬프트에는 이제 후보 출력과 도구 결과가 포함되며, 모델은 판단을 근거로 할 수 있는 구체적인 것을 갖게 됩니다. 검색 기반 비판 (Retrieval-grounded critique). 액터가 요약하거나 인용해야 한다고 생각된 원본 문서를 가져와서 후보와 함께 비판자에게 전달합니다. 비판자의 역할은 "원본에 의해 지지되지 않는 후보의 주장 찾기"가 되며, 이는 "이것이 좋나요"보다 훨씬 작고 관리 가능한 작업입니다. 비교 판정자 비판 (Comparison-judge critique). 액터에서 두 개의 후보를 생성하고 (다른 시드, 다른 온도, 또는 다른 서브 프롬프트로), 비판자가 더 나은 것을 선택하거나 병합하도록 합니다. 이는 비판자의 역할을 열린 판단이 아닌 비교에 제한하며, 출판된 비교들 (LLM-as-a-judge MT-Bench 논문 참조) 에서 쌍대 판정은 단일 출력을 격리하여 점수하는 것과 동일한 모델을 요청하는 것보다 인간 선호도를 더 신뢰ably 추적합니다. 가능한 곳에서 이를 결합하세요. 비판자가 액터가 사용한 API 의 문서와 실패한 테스트 출력 모두를 볼 수 있는 코드 생성 루프는 각각 단독으로보다 더 많은 결함을 잡습니다. 비용 수학 (Cost math) 자기 비판 루프는 N 번의 비판과 수정 반복에 대해 1 + 2N 개의 호출로 하나의 모델 호출을 변환합니다 (각 반복마다 한 번의 비판자 호출, 한 번의 액터 호출). 세 번째 반복에서는 하나에서 일곱으로 호출이 됩니다. 토큰 비용은 컨텍스트 길이에 따라 증가하며, 이는 각 수정마다 증가합니다. 이전 출력과 이전 비판은 새로운 프롬프트의 일부이기 때문입니다. 세 번째 반복에 도달하면 액터의 수정 세 번째 프롬프트는 원래보다 5 배 크기가 될 수 있습니다. 작업이 원래 2k 입력 토큰을 사용한다면, 세 번째 수정에서 액터는 약 8k 에서 10k 입력 토큰을 처리합니다. 가상의 워크로드에 대한 대략적인 계산 (공공 목록 가격에 있는 Sonnet 클래스 모델당 약 2k 입력과 500 출력 토큰을 가정): 원래 호출당 약 $0.01 이었던 작업에서 세 번째 반복의 비판 루프는 $0.05 에서 $0.08 사이의 비용으로 끝납니다. 공공 모델 가격은 자주 변경되므로, 결정을 내리기 전에 현재 비율에 대해 수학을 다시 실행하세요. 이것이 가치 있는지는 평가 델타에 달려 있습니다. 높은 스테이크 작업 (배포되는 코드, 계약 조항, 의학 요약) 에서는 수학이 잘 작동합니다. 사용자가 3 점 평가 증가를 느끼지 못하는 채팅 응답에서는 그렇지 않습니다. 비용을 줄이는 두 가지 방법: 더 저렴한 비판자 모델. 비판을 위해 Haiku 클래스를 사용하고, 액터는 전체 크기 모델을 사용합니다. 비판자의 역할은 규칙에 대한 비교와 패턴 매칭이며, 액터의 추론 깊이를 필요로 하지 않습니다. 조건부 루프 (Conditional loop). 모든 출력에 대해 한 번씩 비판자를 실행하지만, 오직

비판자가 구체적인 결함을 반환하면 수정 브랜치로 이동합니다. 많은 출력물이 첫 번째 비판자 검사를 통해 NO_DEFECTS 를 반환하며, 특히 비판자 rubric 을 작업에 맞게 튜닝한 후에는 더 그렇습니다. 이 경우 한 번의 추가 호출만 지불하므로 7 회가 아닙니다.

월요일에 무엇을 해야 하는지
이미 비판 루프가 실행 중이라면 가장 빠르게 수익을 창출하는 변경 사항:

  • 반복 횟수를 3 회 (또는 그 이하) 로 제한하고 NO_DEFECTS 정지 토큰과 진행 없음 검사를 추가하여, 할 일이 없을 때 즉시 루프를 종료하도록 합니다.
  • 액터와 비판자를 별도의 프롬프트와 별도의 호출로 분리하여, 비판자가 액터의 추론 체인을 볼 수 없도록 합니다.
  • 마지막 100 회 실행 중 최대 반복 횟수에 도달한 실행을 확인하고, 평가에서 3 번째 반복이 2 번째 반복보다 더 좋은지 확인합니다. 그렇지 않다면 (보통은 그렇지 않습니다), 한계를 2 회로 낮춥니다.
  • 아직 루프가 없으며 추가할 계획이라면 1 회 반복부터 시작합니다. 평가를 통해 상승을 측정합니다. 2 회 반복만 데이터가 이를 지원할 때 추가합니다.
  • 기본 기대치는 3 회 및 그 이상의 반복이 컴퓨테이션의 낭비임을 의미하며, 2 회 이상인 경우 각 반복에 대한 증거를 요구해야 합니다.
  • 곡선의 형태는 모델 결함이 아닙니다. 정보 이론입니다: 외부 지향 없이 비판은 액터와 비판자가 이미 알고 있는 것에 의해 제한됩니다. 쉬운 오류를 한 두 번의 통과에서 제거한 후, 다음 통과에서는 더 이상 찾을 것이 없습니다. 거기서 정지하세요. 추가 반복은 희망이지 신호가 아닙니다.

이것이 유용하다면 AI 에이전트 포켓 가이드: LLM 을 사용하여 자율 시스템을 구축하는 패턴 이 동일한 각도에서 루프 패턴을 다룹니다: 제한된 반복, 정지 heuristics, 액터/비판자 분리, 도구 기반 판단. 이는 비판 루프가 더 큰 에이전트의 한 단계일 때 필요한 주변 요소 (메모리, 서브 에이전트 디스패치, 부분 실패 복구) 와 함께 이를 연결합니다.

자기 비판은 잘못 연결하기 쉬운 루프 중 하나이며, 실제 예산과 실제 정지 규칙을 부여한 후 수익을 창출하기 쉬운 루프 중 하나입니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
2

댓글

0