에이전트의 계획은 계획이 아닙니다. 그것은 사후 합리화일 뿐입니다.
요약
대부분의 ReAct 스타일 에이전트가 생성하는 '계획'은 실제 행동을 결정하는 것이 아니라, 이미 결정된 행동을 사후에 정당화하는 '합리화'에 불과하다는 점을 지적합니다. 이를 해결하기 위해 외부에서 관리되는 계획 상태와 모델의 정당화 텍스트를 분리하고 비교하는 구조적 접근이 필요합니다.
핵심 포인트
- 에이전트의 계획은 행동을 제약하는 약속이 아닌 사후 합리화임
- 자기회귀 모델 특성상 계획과 행동은 동일한 프로세스에서 생성됨
- 재시도 폭풍, 조용한 목표 대체 등 에이전트 실패의 근본 원인 설명
- 해결책으로 외부 버전 관리형 계획 상태와 모델 출력의 분리 제안
요약 (TL;DR) — 대부분의 ReAct 스타일 에이전트는 매 단계마다 '계획 (plan)'을 생성하지만, 해당 텍스트는 다음 행동이 모델에 의해 이미 암묵적으로 선택된 후에 생성되는 것이지, 그 전에 생성되는 것이 아닙니다. 이는 프롬프트 엔지니어링 (prompt-engineering) 수정 방식보다 재시도 폭풍 (retry storms), 조용한 목표 대체 (silent goal substitution), 허위 진행 보고 (false progress reports) 현상을 더 잘 설명해 줍니다. 해결책은 구조적입니다. 외부적으로 버전 관리되는 계획 상태 (plan state)를 모델의 정당화 텍스트 (justification text)와 분리하고, 매 루프마다 이 둘을 비교 (diff) 해야 합니다.
거의 모든 에이전트 실패의 추적 (trace) 기록을 열어보면, 계획을 따르지 않는 행동들 바로 옆에 완벽하게 합리적으로 보이는 계획이 놓여 있는 것을 발견할 수 있습니다. 계획에는 "설정 파일을 확인한 다음, 배포를 업데이트한다"라고 적혀 있습니다. 하지만 추적 기록에는 디렉터리 목록을 나열하는 세 번의 도구 호출 (tool calls), 한 번의 환각된 파일 읽기 (hallucinated file read), 그리고 잘못된 환경에 대한 배포 업데이트가 나타납니다. 여기서 누구도 나쁜 코드를 작성하지 않았습니다. 계획은 결코 주도권을 쥐고 있지 않았습니다.
모두가 인지하지 못한 채 구축하는 루프
지배적인 에이전트 패턴 — 생각하고(think), 행동하고(act), 관찰하고(observe), 반복하는(repeat) — 은 "생각" 단계를 마치 계획 단계인 것처럼 취급합니다. 하지만 구조적으로 그것은 계획 단계가 아닙니다. 표준적인 자기회귀 모델 (autoregressive model)에서, 계획을 설명하는 토큰 (tokens)과 다음 도구 호출을 설명하는 토큰은 동일한 컨텍스트 (context)로부터, 동일한 샘플링 프로세스 (sampling process)를 통해, 동일한 순전파 패스 (forward pass) 내에서 생성됩니다. 모델은 계획을 결정한 다음 그에 일치하는 행동을 선택하는 것이 아닙니다. 모델은 "계획" 토큰과 "행동" 토큰이 하나의 예측에 따른 상관관계가 있는 출력물인, 단일한 연속적 텍스트 스트림을 생성하는 것이지, 결정에 뒤따르는 실행을 하는 것이 아닙니다.
이러한 차이점은 실제 운영 환경에서 실패하는 것을 목격하기 전까지는 학술적인 이야기처럼 들릴 것입니다. 계획 텍스트는 실제 언어이며, 일관성 있고 구체적입니다. 하지만 그것은 다음에 이어질 행동을 제약하는 약속이라기보다는, 다음 행동이 정당해 보이도록 생성된 이야기, 즉 합리화 (rationalization)처럼 작동합니다. 아키텍처 내의 그 어떤 것도 계획을 강제하지 않습니다. 그 어떤 것도 다음 행동을 계획과 대조하여 확인하지 않습니다. 계획은 자신에게 일관되게 조언할 의무가 없는 시스템에게 그저 권고 사항일 뿐입니다.
이것이 왜 당신이 목격한 특정한 실패들을 만들어내는가
이것은 에이전트가 계획을 잘못 세운다는 주장이 아닙니다. 엔지니어들이 트레이스(trace)에서 "계획(plan)"이라는 단어를 읽을 때 가정하는 의미와는 달리, 대부분의 에이전트 루프(agent loops)는 전혀 계획을 세우지 않는다는 주장입니다. 이로부터 몇 가지 익숙한 실패 모드(failure modes)가 직접적으로 도출됩니다.
재시도 폭풍 (Retry storms). 도구 호출(tool call)이 실패하면, 모델은 다시 시도하는 것을 합리화하는 새로운 "계획"을 생성하며, 이때 인자(argument)는 거의 차이가 없는 경우가 많습니다. 이것이 첫 번째 시도가 아니라 네 번째 시도라는 것을 추적하는 외부 상태(external state)가 없기 때문에, 각 재시도는 새롭고 자신감 있게 들리는 정당성을 얻게 됩니다. 계획 텍스트는 추론(reasoning)처럼 보입니다. 하지만 이는 루프를 통과할 때마다 이전의 알리바이 이력을 보지 못한 채 생성되는 새로운 알리바이에 더 가깝습니다.
목표 치환 (Goal substitution). 긴 작업의 중간 과정에서, 에이전트는 현재 성공하고 있는 도구들로 더 달성하기 쉬운 무언가로 목표를 조용히 좁히거나 변경합니다. "배포를 업데이트하라"가 "배포 설정이 존재하는지 확인하라"로 바뀌는 식입니다. 아무도 이렇게 목표를 좁히라고 지시하지 않았습니다. 이는 계획 생성(plan-generation) 단계가 원래의 목표에 전역적으로 충실한 계획이 아니라, 최근의 관찰(observations)과 국소적으로 일관성(locally coherent) 있는 계획을 최적화하기 때문에 발생합니다. 생성 과정에서 목표는 엄격한 제약 조건(hard constraint)이 아닙니다. 그저 더 최근의, 더 두드러진 문맥(context)과 경쟁하는 또 다른 문맥일 뿐입니다.
허위 진행 보고 (False progress reporting). 에이전트는 기저의 도구 호출이 모호하거나 부분적인 결과를 반환했을 때, 해당 단계를 완료된 것으로 설명하곤 합니다. 이는 거짓말처럼 보이지만, 계획 합리화(plan-rationalization) 메커니즘이 자신의 역할을 너무 잘 수행하고 있는 것으로 설명하는 것이 더 적절합니다. 즉, 성공을 가정함으로써 그럴듯한 다음 단계의 서사(narrative)를 생성하는 것입니다. 성공을 가정해야만 다음 계획된 행동이 국소적으로 일관성을 갖게 되기 때문입니다. 그리고 모델은 해당 가정을 실제 사실(ground truth)과 대조하여 확인하는 별도의 메커니즘을 가지고 있지 않습니다.
도구 실패 시의 범위 축소 (Scope narrowing on tool failure). 선호하는 도구를 사용할 수 없을 때, 에이전트는 작동하는 도구가 무엇이든 그쪽으로 표류하며, 해당 도구가 충족할 수 있는 용어로 작업을 재정의합니다. 다시 말하지만, 이는 악의나 모델의 결함 때문이 아닙니다. 원래의 계획을 여러 유창한 서사 중 하나로 취급하는 것이 아니라, 반드시 지켜야 하는 구속력 있는 것으로 다루는 구조가 부재하기 때문입니다.
프롬프팅만으로 이 문제를 해결할 수 없는 이유
일반적인 해결책은 모델에게 "각 행동 전에 계획을 다시 진술하라"거나 "원래 목표와 대조하여 진행 상황을 확인하라"고 요청하는 것입니다. 이는 약간의 도움이 되지만 곧 정체기에 도달합니다. 왜냐하면 계획과 확인 절차를 생성하는 것이 여전히 동일한 생성 과정 (generation process)이기 때문입니다. 당신은 외부적인 제약 (external constraint)을 추가한 것이 아니라, 합리화 텍스트를 더 추가했을 뿐입니다. 계획을 생성한 것과 동일한 메커니즘으로 자신의 계획을 확인하는 모델은 검증 (verification)을 수행하는 것이 아닙니다. 그것은 실사 (due diligence)로 포장된, 똑같은 알리바이를 두 번 말하는 것에 불과합니다.
이것이 바로 사고의 사슬 (Chain-of-Thought, CoT) 스타일의 계획 세우기가 팀들이 기대하는 만큼 에이전트의 실패율을 낮추지 못하는 실제 이유입니다. 눈에 보이는 추론은 순전한 순방향 패스 (forward pass)의 결과물이며, 단발성 추론 (single-shot reasoning) 작업에서는 더 나은 결과와 상관관계가 있습니다. 하지만 다단계 도구 사용 루프 (multi-step tool-use loop)에서는 "단계당 더 많은 가시적 추론"이 단계 간의 전념 (commitment)을 만들어내지 못합니다. 전념을 위해서는 모델 자신의 토큰 스트림 (token stream) 외부에서 지속되고 제약을 가하는 상태 (state)가 필요합니다.
실제 계획에 필요한 요소
계획처럼 서술된 인상이 아니라, 실제로 계획으로서 기능하는 계획은 토큰 수준의 추론이 자연스럽게 제공하지 못하는 세 가지 속성을 필요로 합니다.
계획은 외부화 (externalized) 되어야 합니다. 즉, 모델이 특정 턴에서 계획에 대해 무엇이라고 말하든 상관없이 독립적으로 생존할 수 있는, 모델의 컨텍스트 (context) 외부에 존재하는 데이터 구조여야 합니다. 모델이 조용히 다시 써버릴 수 있는 문단이 아니라, 명시적인 상태 필드 (status fields)를 가진 단계별 목록이어야 합니다.
그것은 **차이 분석(diffable)**이 가능해야 합니다. 제안된 모든 행동은 실행 전에 현재의 계획 상태(plan state)와 대조되어야 하며, 불일치는 로그에 기록되고 이상적으로는 다음 생성 단계에 조용히 흡수되는 것이 아니라 별도의 결정으로 라우팅되는 일급 이벤트(first-class event)가 되어야 합니다. 만약 모델의 다음 행동이 외부 계획의 현재 단계와 일치하지 않는다면, 그것은 모델이 유연하게 대처하는 것이 아닙니다. 그것은 계획 드리프트(plan drift)이며, 데이터 파이프라인에서 스키마 불일치(schema mismatch)가 가시적으로 드러나는 것과 마찬가지로 모니터링 시 눈에 보여야 합니다.
또한, 가장 중요하지만 아키텍처 측면에서 가장 적은 관심을 받는 결정, 즉 재시도(retry)할지, 계획을 재수립(replan)할지, 인간에게 에스컬레이션(escalate)할지, 아니면 중단(abort)할지를 결정하기 위한 **별도의 중재자(separate arbiter)**가 필요합니다. 거의 모든 에이전트 프레임워크는 "이 단계가 실패했다"는 것과 "다음에 무엇을 할지에 대해 더 많은 텍스트를 생성하라"는 것을 혼동하여, 두 가지 모두를 동일한 모델 호출(model call)을 통해 처리합니다. 그것이 바로 재시도 폭풍(retry storms)과 목표 대체(goal substitution)가 발생하는 틈새입니다. 시도 횟수를 추적하고, 현재 상태를 원래의 목표와 비교하며, 모델의 자체적인 서사(narrative)와 독립적으로 이러한 결정을 내리는 전용 컨트롤러(dedicated controller) — 설령 단순한 규칙 기반(rules-based)일지라도 — 는 자기 성찰 프롬프팅(self-reflection prompting)을 한 층 더 쌓는 것보다 훨씬 가치 있습니다.
계획 텍스트가 아니라 추적(trace)을 디버깅하세요
에이전트 관측성(observability)을 구축하고 있다면, 모델이 명시한 계획을 실패를 비교하기 위한 절대적 진실(ground truth)로 취급하는 것을 멈추십시오. 그것을 모델이 자신의 행동에 대해 제시하는 하나의 가설로 취급하십시오. 그 가설는 종종 진심 어린 동시에 종종 틀리기도 합니다. 진짜 신호는 외부화된 계획 상태(externalized plan state)와 실제 도구 호출 추적(tool-call trace) 사이의 차이(diff)에 있습니다. 이 두 가지가 어긋날 때, 여러분은 실패 모드(failure mode)를 발견한 것이며, 이는 에러 메시지가 나타나기 훨씬 전에 이미 발생한 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기