한국어
Week 2: 추론
01. RAG & Memory

01. Planning Agents & Chain of Thought

왜 계획이 중요한가

Week 1에서 배운 ReAct 패턴은 간단한 작업에 잘 작동하지만, 복잡한 문제에는 다른 접근이 필요합니다. 에이전트가 즉흥적으로 단계별로 행동하면:

  • 무한 루프에 빠질 수 있음
  • 전체 목표를 놓칠 수 있음
  • 장기적 결과에 해로운 근시안적 결정을 내릴 수 있음

Planning Agents는 행동하기 전에 완전한 계획을 세워 이 문제를 해결합니다—인간이 행동하기 전에 생각하는 것처럼.

Chain of Thought (CoT) 프롬프팅

계획의 기초는 Chain of Thought—LLM에게 "단계별로 생각하라"고 프롬프팅하는 것입니다.

마법의 문구

"Let's think step by step"만 추가해도 추론 능력이 극적으로 향상됩니다:

# 표준 프롬프팅
prompt_standard = f"질문: {problem}\n답변:"
 
# CoT 프롬프팅
prompt_cot = f"질문: {problem}\n단계별로 생각해봅시다."

CoT가 효과적인 이유

측면표준 프롬프트Chain of Thought
과정바로 답변명시적 추론 단계
정확도복잡한 문제에서 오류 발생높은 정확도
투명성블랙박스추론 과정 가시화
오류 감지식별 어려움추론에서 오류 보임

연구 인사이트: Wei et al. (2022)는 CoT 프롬프팅이 GSM8K 벤치마크에서 수학 문제 정확도를 17.9%에서 78.7%로 향상시킬 수 있음을 보였습니다.

실제 CoT 적용

problem = """
존이 사과 5개를 가지고 있었습니다. 메리에게 2개를 주고 1개를 먹었습니다.
그 후 마이크에게서 3개를 더 받았지만, 집에 오는 길에 1개를 떨어뜨렸습니다.
존은 지금 사과가 몇 개 있을까요?
"""
 
def get_completion(prompt):
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "당신은 도움이 되는 어시스턴트입니다."},
            {"role": "user", "content": prompt}
        ],
        temperature=0
    )
    return response.choices[0].message.content
 
# CoT 적용
response = get_completion(f"{problem}\n단계별로 생각해봅시다.")
# 출력:
# 1. 존은 사과 5개로 시작
# 2. 메리에게 2개 줌: 5 - 2 = 3개
# 3. 1개 먹음: 3 - 1 = 2개
# 4. 마이크에게서 3개 받음: 2 + 3 = 5개
# 5. 1개 떨어뜨림: 5 - 1 = 4개
# 답: 4개

Plan-and-Execute 패턴

CoT를 기반으로, Plan-and-Execute 패턴은 계획과 실행을 분리합니다:

아키텍처 구성요소

플래너 (Planner)

쿼리를 분석하고 순서가 있는 단계들로 구성된 구조화된 계획 생성

실행자 (Executor)

사용 가능한 도구를 사용하여 각 단계 실행

종합자 (Synthesizer)

모든 단계의 결과를 최종 답변으로 결합

플래너 구현

구조화된 출력을 위해 Pydantic 사용:

from pydantic import BaseModel, Field
from typing import List
 
class PlanStep(BaseModel):
    id: int = Field(description="단계 번호 (1부터 시작)")
    description: str = Field(description="이 단계에서 할 일")
    tool: str = Field(description="사용할 도구 (search 또는 calculate)")
    args: str = Field(description="도구에 전달할 인자")
 
class Plan(BaseModel):
    steps: List[PlanStep] = Field(description="순서가 있는 단계 목록")
 
def create_plan(query: str) -> Plan:
    completion = client.beta.chat.completions.parse(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "사용 가능한 도구로 단계별 계획을 생성하세요."},
            {"role": "user", "content": query}
        ],
        response_format=Plan
    )
    return completion.choices[0].message.parsed

실행자 구현

def execute_plan(plan: Plan, tools: dict) -> str:
    results = {}
 
    for step in plan.steps:
        if step.tool in tools:
            result = tools[step.tool](step.args)
            results[step.id] = result
            print(f"Step {step.id}: {result}")
 
    # 최종 답변 종합
    return synthesize_results(results)

Plan-and-Execute vs ReAct

특징ReActPlan-and-Execute
접근 방식생각과 행동 번갈아먼저 계획, 그 다음 실행
유연성높은 적응성미리 정해진 계획 따름
적합한 경우탐색, 대화형 작업다단계 분석, 레시피
약점길을 잃을 수 있음 (근시안적)계획이 잘못되면 경직됨
복구자연스러운 적응명시적 재계획 필요

고급: 재계획 (Replanning)

실행이 실패하면, Replanner가 전략을 조정할 수 있습니다:

def execute_with_replanning(plan: Plan, max_replans: int = 2):
    for attempt in range(max_replans):
        results, failed_step = execute_plan(plan)
 
        if failed_step is None:
            return results  # 성공!
 
        # 실패한 단계부터 재계획
        plan = replan(plan, failed_step, results)
 
    return results  # 최선의 결과

실습 내용

노트북에서 다음을 수행합니다:

CoT 체험

논리 퍼즐에서 표준 프롬프팅 vs. CoT 프롬프팅 비교

플래너 구축

구조화된 계획을 출력하는 Pydantic 기반 플래너 생성

실행 구현

모의 검색 및 계산기 도구로 계획 실행

전체 파이프라인 실행

복잡한 쿼리에 대해 계획과 실행 결합

핵심 요점

  1. CoT가 기초 - "단계별로 생각하기"가 추론 능력을 극적으로 향상
  2. 관심사 분리 - 계획과 실행은 서로 다른 인지적 작업
  3. 구조화된 출력 - 신뢰할 수 있는 계획 형식을 위해 Pydantic/JSON Schema 사용
  4. 계획 복구 - 견고한 에이전트를 위해 재계획 구현

참고 자료 & 추가 학습

학술 논문

다음 단계

계획을 이해했으니, Reflection Agents로 이동하여 에이전트가 자신의 출력을 비평하고 개선하는 방법을 배워보세요!