ReWOO: 모든 도구 호출을 사전에 계획하고, 모델은 단 두 번만 호출하기
요약
ReWOO는 멀티홉 질문 해결 시 발생하는 과도한 LLM 호출 비용을 줄이기 위해 제안된 추론 프레임워크입니다. 모델이 도구의 실행 결과를 기다리지 않고 전체 계획을 먼저 수립한 뒤, 코드 기반의 Worker가 실행을 담당하여 호출 횟수를 최소화합니다.
핵심 포인트
- ReAct 방식의 반복적인 모델 호출 및 컨텍스트 전송 비용 문제 해결
- Planner, Worker, Solver의 세 단계로 에이전트 역할 분리
- 변수 할당 방식을 통해 관찰(Observation) 없이도 전체 추론 계획 수립 가능
- 단계 수와 상관없이 모델 호출을 단 2회로 최적화
에이전트에게 멀티홉(multi-hop) 질문을 던지면 일반적인 답변은 ReAct 방식입니다: 생각하고, 행동하고, 결과를 확인하고, 다시 생각하고, 다시 행동하는 방식이죠. 이 방식은 작동하지만, 숨겨진 비용이 있습니다. 모든 "생각(think)" 단계는 모델에 대한 전체 호출이며, 매 호출마다 점점 길어지는 전체 대화 기록(transcript)을 다시 전송해야 합니다. 3단계(three-hop) 질문은 4번의 모델 호출 비용이 들고, 10단계 질문은 11번의 호출 비용이 듭니다. ReWOO — Reasoning WithOut Observation (관찰 없는 추론) — 는 더 날카로운 질문을 던집니다: 만약 모델이 추론하는 동안 도구 결과(tool results)를 전혀 볼 필요가 없다면 어떨까요? 그렇다면 전체 과정을 한 번에 계획하고, 그 계획을 일반 코드에 전달한 뒤, 맨 마지막에 답변을 작성하기 위해서만 다시 돌아오면 됩니다. 몇 단계의 홉(hop)이든 상관없이 단 두 번의 모델 호출이면 충분합니다.
예시
진정한 멀티홉(multi-hop) 질문을 예로 들어보겠습니다: "2018년 월드컵에서 우승한 국가의 수도 인구는 얼마인가요?" 이 질문은 한 번의 조회로 답할 수 없습니다. 우승국(프랑스), 그 국가의 수도(파리), 그리고 그 도시의 인구(210만 명)를 차례로 알아내야 합니다. 마지막 결과에 의존하는 세 번의 도구 홉(tool hops)이 필요합니다.
ReAct는 마치 자신과 대화하듯 진행합니다:
- 생각 1 (모델 호출): "2018년 월드컵 우승자를 알아내야 합니다." → 검색 → 프랑스
- 생각 2 (모델 호출): "이제 프랑스의 수도를 알아내야 합니다." → 검색 → 파리
- 생각 3 (모델 호출): "이제 파리의 인구를 알아내야 합니다." → 인구 → 210만
- 최종 (모델 호출): "정답은 210만 명입니다."
네 번의 LLM 호출이 발생하며, 각 호출마다 이전의 모든 내용을 다시 읽어야 합니다. 모델이 전체 과정의 루프(loop) 안에 계속 머물러 있는 것입니다.
ReWOO: 계획, 실행, 해결
ReWOO는 에이전트를 세 가지 역할로 나누며, 그중 두 가지만 모델을 사용합니다.
1. Planner (LLM 호출 1회). 모델에게 질문과 도구 목록을 주고, 전체 계획을 변수 할당(variable assignments) 형태로 사전에 요청합니다:
Plan: 우승자 찾기
#E1 = Search[2018 World Cup winner]
Plan: 그 국가의 수도 찾기
...
모델이 이를 작성하는 동안 단 하나의 도구 결과(tool result)도 보지 않았다는 점에 주목하세요. 모델은 우승국이 프랑스라는 사실을 모릅니다. 모델은 단지 "#E1이 무엇으로 밝혀지든 그 국가의 수도"라고 말하기만 하면 됩니다. 이것이 바로 "관찰 없이 (without observation)" 부분입니다. 즉, 추론(reasoning)이 어떠한 관찰(observation)이 존재하기 전에 발생합니다. 의존성(dependencies)은 이러한 #E1, #E2 토큰을 통해 선언됩니다.
2. Worker (LLM 호출 0회). 이제 이것은 단순한 코드입니다. 단계들을 순서대로 수행합니다. 각 도구 호출(tool call) 전에, 지금까지 수집된 결과로 토큰을 치환하고, 도구를 실행하며, 결과를 저장합니다:
const evidence = {};
for (const s of steps) {
let input = s.input;
...
#E1이 "France"로 해결되면, #E2의 입력은 Search[capital of France] → "Paris"가 되고, #E3은 Population[Paris] → "2.1 million"이 됩니다. 관찰 결과(observations)는 수집되지만, 실행 중간에 모델로 다시 전송되지는 않습니다. 이 전체 루프 동안 모델은 호출되지 않습니다.
3. Solver (LLM 호출 1회). 증거(evidence)가 채워진 계획(plan)을 모델에 전달하고 최종 답변을 요청합니다. 그것으로 끝입니다 — 이것이 두 번째 호출입니다.
이것이 더 저렴한 이유
홉(hops)의 수 k에 따른 호출 횟수를 계산해 보겠습니다:
const reactCalls = k + 1; // k번의 사고(thoughts) + 1번의 최종 답변
const rewooCalls = 2; // 항상 계획(plan) + 해결(solve)
3홉의 경우: ReAct 4회, ReWOO 2회. 10홉의 경우: ReAct 11회, ReWOO 2회. 30홉의 경우: ReAct 31회, ReWOO 2회. ReWOO의 모델 호출 횟수는 **상수(constant)**입니다 — 체인의 길이에 따라 증가하지 않습니다. 또한 단순히 호출 횟수만의 문제가 아닙니다. ReAct는 매 호출마다 전체 기록(transcript)을 다시 전송하므로 토큰 사용량도 복리로 증가합니다. 호출 횟수가 적고 기록을 반복하지 않는다는 점 덕분에, ReWOO 논문은 멀티 홉(multi-hop) 벤치마크에서 유사한 정확도를 유지하면서도 대폭적인 토큰 절감 효과를 보고하고 있습니다. 왕복(round-trips) 횟수가 적다는 것은 네트워크 시간이 주로 지배적이라는 점에서 지연 시간(latency) 또한 낮음을 의미합니다.
주의할 점 (The catch)
계획 단계에서의 맹목성(Planning blind)은 ReWOO가 저렴한 이유인 동시에, 바로 그 점이 문제를 일으킬 수 있는 지점입니다. Planner는 도구의 결과(tool result)를 결코 확인하지 않기 때문에, 예상치 못한 상황이 발생했을 때 경로를 변경할 수 없습니다. 예를 들어, 검색 결과가 없거나, 엔티티(entity)가 모호하거나, 단계에서 오류가 발생하거나, 혹은 누구도 예상하지 못한 분기(branch)가 실제 정답을 위해 필요할 때 말입니다. 반면, 각 관찰(observation)을 확인하는 ReAct는 다시 생각하고 방향을 전환(pivot)할 수 있습니다. 따라서 이 두 기술은 하나의 스펙트럼 상에 놓여 있습니다. ReWOO는 효율성을 위해 적응성(adaptability)을 맞바꾼 것입니다.
경로가 예측 가능하고 다단계(multi-hop)인 경우 — 즉, 고정된 조회(lookups), 알려진 파이프라인, 혹은 어떤 소스를 참조해야 할지 이미 알고 있는 RAG 검색(retrievals) 등의 상황에서는 ReWOO를 선택하세요. 경로가 불확실하고 발견된 내용에 따라 대응해야 하는 경우에는 ReAct를 선택하세요. 좋은 절충안은 하이브리드 방식입니다. ReWOO처럼 계획을 세우되, Worker가 예상치 못한 상황에 직면할 때마다 새로운 Planner 호출을 실행하여 재계획(re-plan)하는 것입니다. 이렇게 하면 일반적인 경로에서는 두 번의 호출로 절약 효과를 유지하면서, 드문 예외 상황에서는 적응성을 확보할 수 있습니다.
대화형 버전을 직접 실행해 보세요. 두 에이전트를 나란히 실행하고, 단계(hops)를 추가함에 따라 LLM 호출 카운터가 어떻게 벌어지는지 관찰할 수 있습니다: https://dev48v.infy.uk/prompt/day23-rewoo.html
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기