저는 3년째 AI Agent 시스템을 프로덕션 환경에서 운영하는 엔지니어입니다. 이번 글에서는 현재 가장 널리 사용되는 두 가지 도구 호출 패턴인 ReAct(Reasoning + Acting)와 Plan-and-Execute를 실제 비즈니스 사례와 함께 깊이 비교하겠습니다. 특히 이커머스 플랫폼에서의 AI 고객 서비스 구축 경험을 바탕으로, 어떤 상황에서 어떤 패턴이 더 효과적인지 실전 데이터를 통해 분석해 드리겠습니다.
실제 도입 사례: 이커머스 AI 고객 서비스 급증
제 경험상, 연말 대규모 세일 기간 동안 고객 문의가 평소의 15배 이상 급증했던 이커머스 플랫폼에서 AI 고객 서비스 봇을 구축한 적이 있습니다. 초기에는 단순한 규칙 기반 봇로 시작했지만, 상품 검색, 주문 상태 조회, 반품 처리, 추천 시스템까지 연동해야 하는 복잡한 요구사항이 발생했습니다.
이 과정에서 ReAct와 Plan-and-Execute 두 패턴을 모두 시도해 보았고, 각각의 장단점이 명확하게 드러났습니다. 결론부터 말씀드리면, 단순한 조회 작업에는 ReAct가, 복잡한 멀티스텝 워크플로우에는 Plan-and-Execute가 더 적합했습니다.
ReAct 패턴이란?
ReAct(Reasoning + Acting)는 스탭포유니버시티에서 2023년 발표한 프롬프트 기법으로,大型语言模型이 도구를 호출하기 전에 생각의 사슬(Chain of Thought)을 통해 추론 과정을 먼저 진행한 후 행동을 취하는 방식입니다.
ReAct의 핵심 동작 흐름
- Thought: 현재 상황을 분석하고 다음 행동을 계획
- Action: 계획에 따라 도구 호출
- Observation: 도구 호출 결과 확인
- 이 과정을 최종 응답에 도달할 때까지 반복
ReAct 코드 구현 예시
# ReAct 패턴 구현 예시
import requests
from typing import List, Dict, Any
class ReActAgent:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.holysheep.ai/v1"
def think(self, query: str, tools: List[Dict], max_iterations: int = 10):
"""
ReAct 패턴의 핵심: Thought → Action → Observation 반복
"""
messages = [
{"role": "system", "content": self._build_system_prompt(tools)}
]
context = ""
for i in range(max_iterations):
# Step 1: Thought - 추론 과정 생성
user_prompt = f"""질문: {query}
현재까지의 컨텍스트:
{context}
위 정보를 바탕으로 다음 행동을 결정하세요.
"""
messages.append({"role": "user", "content": user_prompt})
response = self._call_model(messages)
messages.append({"role": "assistant", "content": response})
# Step 2: Action 파싱
if "Final Answer:" in response:
return self._extract_final_answer(response)
action = self._parse_action(response)
if not action:
break
# Step 3: Observation - 도구 실행
obs_result = self._execute_tool(action)
context += f"\n행동: {action['name']}\n결과: {obs_result}\n"
return context
def _build_system_prompt(self, tools: List[Dict]) -> str:
return f"""당신은 ReAct 에이전트입니다.
도구를 사용해서 질문에 답하세요.
사용 가능한 도구:
{self._format_tools(tools)}
출력 형식:
Thought: [현재 분석과 다음 행동 계획]
Action: [도구 이름과 파라미터]
Observation: [실행 결과]
최종 답변:
Final Answer: [최종 응답]
"""
HolySheep AI를 통한 ReAct 에이전트 실행
agent = ReActAgent(api_key="YOUR_HOLYSHEEP_API_KEY")
result = agent.think(
query="최근 주문한 블루투스 헤드폰 배송 상황 알려주세요",
tools=[
{"name": "search_order", "description": "주문 검색", "params": ["order_id"]},
{"name": "get_shipping", "description": "배송 추적", "params": ["tracking_number"]}
]
)
print(result)
Plan-and-Execute 패턴이란?
Plan-and-Execute는 먼저 전체 작업의 플랜을 수립한 후, 수립된 플랜에 따라 각 단계를 순차적으로 실행하는 방식입니다. 복잡한 워크플로우에서 특히 효과적이며, 각 단계의 결과를 다음 단계에 전달하는 체인 형태를 가집니다.
Plan-and-Execute의 핵심 동작 흐름
- Plan: 목표 달성 위한 단계별 계획 수립
- Execute: 수립된 계획의 각 단계를 순차 실행
- Feedback: 각 단계 결과 기반 필요시 계획 수정
Plan-and-Execute 코드 구현 예시
# Plan-and-Execute 패턴 구현 예시
import requests
import json
class PlanExecuteAgent:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.holysheep.ai/v1"
def run(self, task: str, available_tools: List[Dict]) -> Dict[str, Any]:
"""
Plan-and-Execute 패턴: Plan → Execute → Feedback 루프
"""
# Phase 1: Planning
plan = self._create_plan(task, available_tools)
print(f"[PLAN] 생성된 플랜: {len(plan['steps'])}단계")
# Phase 2: Execution with feedback loop
results = []
for idx, step in enumerate(plan['steps']):
print(f"[EXECUTE] Step {idx + 1}: {step['description']}")
# 도구 실행
tool_result = self._execute_step(step, results)
results.append({
"step": idx + 1,
"description": step['description'],
"result": tool_result
})
# Phase 3: Feedback - 계획 수정 필요시 반영
if step.get('requires_feedback'):
updated_plan = self._adjust_plan(plan, results)
if updated_plan != plan:
print(f"[FEEDBACK] 플랜 업데이트 감지")
plan = updated_plan
# Phase 4: Final Synthesis
return self._synthesize_results(task, results)
def _create_plan(self, task: str, tools: List[Dict]) -> Dict:
"""플랜 수립 단계"""
planning_prompt = f"""다음 작업을 수행하기 위한 세부 계획을 세우세요.
작업: {task}
사용 가능한 도구: {json.dumps(tools, ensure_ascii=False, indent=2)}
각 단계를 순서대로 나열하고, 각 단계에서 사용할 도구와 기대 결과를 명시하세요.
"""
response = self._call_model([
{"role": "user", "content": planning_prompt}
])
# 플랜 파싱 로직
plan_steps = self._parse_plan(response)
return {
"task": task,
"steps": plan_steps,
"created_with": "claude-sonnet-4-5"
}
def _execute_step(self, step: Dict, previous_results: List) -> Any:
"""개별 단계 실행"""
context = self._build_execution_context(previous_results)
execution_prompt = f"""이전 단계 결과:
{context}
현재 단계: {step['description']}
사용 도구: {step.get('tool