한국어
Week 2: 추론
02. LangGraph

02. Reflection Agents

왜 리플렉션(Reflection)이 중요한가

인간이 실수를 하면 "왜 틀렸지?"라고 생각하고 같은 실수를 반복하지 않으려 합니다. 하지만 기본 LLM은 상태가 없어서(stateless) 이전 시도를 기억하지 못하고 종종 같은 잘못된 답을 내놓습니다.

Reflection Agents는 자신의 작업을 비평하고 그 비평을 사용해 개선합니다. 작가가 초안을 쓰고 계속 수정하는 과정과 같습니다.

Generator-Reflector 패턴

가장 간단한 리플렉션 패턴은 역할을 둘로 나눕니다:

역할책임
Generator초기 출력 생성 또는 피드백 기반 수정
Reflector출력을 비평하고 개선 제안 제공

Generator 구현

def generator(topic: str, previous_draft: str = None, critique: str = None) -> str:
    """
    초안을 생성하거나 비평을 기반으로 수정합니다.
    """
    if previous_draft and critique:
        prompt = f"""주제: {topic}
이전 초안:
{previous_draft}
 
비평/피드백:
{critique}
 
위의 비평을 반영하여 초안을 다시 작성하세요.
"""
    else:
        prompt = f"주제: {topic}\n주제에 대한 짧은 에세이 초안을 작성하세요."
 
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}]
    )
    return response.choices[0].message.content

Reflector 구현

def reflector(draft: str) -> str:
    """
    초안을 읽고 건설적인 비평을 제공합니다.
    """
    prompt = f"""다음 초안을 읽고 건설적인 비평을 제공하세요.
논리, 명확성, 스타일을 평가하세요. 개선이 필요한 영역을 최대 3개까지 지적하세요.
칭찬보다는 수정이 필요한 부분에 집중하세요.
 
초안:
{draft}
"""
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}]
    )
    return response.choices[0].message.content

Reflexion 루프

Generator와 Reflector를 반복 루프로 결합:

루프 실행

# Step 1: 첫 번째 초안
print("✍️ 초안 V1 작성 중...")
draft_v1 = generator(topic)
 
# Step 2: 리플렉션
print("🤔 성찰 중...")
critique_v1 = reflector(draft_v1)
 
# Step 3: 개선
print("✍️ 초안 V2 작성 (개선)...")
draft_v2 = generator(topic, previous_draft=draft_v1, critique=critique_v1)

예시: 에세이 개선

주제: "AI가 인간의 창의성을 대체할 수 있는가?"

초안 V1:

"AI가 인간의 창의성을 대체할 수 있는지에 대한 질문은 복잡합니다..."

비평 V1:

  1. 논증 구조 명확화 필요
  2. 구체적인 예시 추가 필요
  3. 문체 흐름 개선 필요

초안 V2 (리플렉션 후):

"AI는 창의적 산출물을 생성할 수 있지만, 인간 창의성의 감정적, 맥락적 기반을 완전히 복제할 수 없습니다. 머신러닝과 같은 기술은 패턴을 분석하지만, 이는 감정과 문화에 뿌리를 둔 인간의 창의적 경험과 다릅니다..."

핵심 인사이트: 각 리플렉션 사이클은 Reflector가 식별한 특정 약점을 해결하여 측정 가능하게 더 나은 출력을 생성합니다.

자동화된 Reflexion Agent

중지 조건이 충족될 때까지 루프 자동화:

class ReflexionAgent:
    def __init__(self, max_iterations: int = 3):
        self.max_iterations = max_iterations
 
    def run(self, topic: str):
        current_draft = generator(topic)
        print(f"📝 초기 초안:\n{current_draft}\n")
 
        for i in range(self.max_iterations):
            print(f"--- 반복 {i+1} ---")
 
            # 1. 비평
            critique = reflector(current_draft)
            print(f"🔍 비평:\n{critique}\n")
 
            # 2. 중지 조건 확인
            if "개선 필요 없음" in critique.lower():
                print("✨ Reflector가 만족합니다. 중지.")
                break
 
            # 3. 개선
            current_draft = generator(
                topic,
                previous_draft=current_draft,
                critique=critique
            )
            print(f"✍️ 개선된 초안:\n{current_draft}\n")
 
        return current_draft

자가 디버깅 코드 에이전트

리플렉션은 코딩 작업에 특히 강력합니다:

구현

def code_generator(prompt: str, error_msg: str = None, previous_code: str = None) -> str:
    if error_msg:
        full_prompt = f"""다음 코드에서 에러가 발생했습니다.
코드:
{previous_code}
 
에러:
{error_msg}
 
코드를 수정하세요. 코드만 반환하세요.
"""
    else:
        full_prompt = f"다음을 수행하는 Python 코드를 작성하세요: {prompt}. 코드만 반환하세요."
 
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": full_prompt}]
    )
    return clean_code(response.choices[0].message.content)
 
def execute_code(code: str):
    """실행하고 (성공 여부, 출력/에러) 반환"""
    try:
        exec_globals = {}
        exec(code, exec_globals)
        return True, "성공"
    except Exception as e:
        return False, str(e)
 
# 자가 수정 루프
code = code_generator(problem)
success, output = execute_code(code)
 
if not success:
    print("⚠️ 에러 감지! 자가 수정 중...")
    fixed_code = code_generator(problem, error_msg=output, previous_code=code)

고급 중지 조건

고정된 반복 대신 점수 기반 피드백 사용:

def scored_reflector(draft: str) -> tuple[str, int]:
    """(비평, 1-5 점수) 반환"""
    prompt = f"""초안을 1-5점으로 평가하고 비평을 제공하세요.
형식: 점수: X\n비평: ...
 
초안:
{draft}
"""
    response = client.chat.completions.create(...)
    # 응답에서 점수와 비평 파싱
    return critique, score
 
# 루프에서:
critique, score = scored_reflector(current_draft)
if score >= 4:
    print("✅ 품질 임계값 도달!")
    break

리플렉션 vs 다른 패턴

패턴접근 방식적합한 경우
ReAct번갈아 추론대화형 탐색
Plan-Execute먼저 계획, 그 다음 행동다단계 워크플로우
Reflection생성, 비평, 개선품질 향상
Debate여러 에이전트가 논쟁논쟁적 주제 처리

실습 내용

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

Generator & Reflector 구축

에세이 작성을 위한 두 역할 패턴 구현

Reflexion 루프 실행

여러 반복을 통해 에세이가 개선되는 것 관찰

자가 디버깅 에이전트 생성

자체 오류를 수정하는 코드 에이전트 구축

중지 조건 실험

점수 기반 루프 종료 구현

핵심 요점

  1. 자기 비평이 품질을 향상 - LLM은 자신의 출력을 효과적으로 비평할 수 있음
  2. 관심사 분리 - Generator와 Reflector 역할은 구분되어야 함
  3. 반복이 일회성보다 나음 - 여러 개선 사이클이 일관되게 결과를 향상
  4. 중지 조건이 중요 - 반복 횟수만이 아니라 점수나 품질 임계값 사용

참고 자료 & 추가 학습

학술 논문

관련 개념

다음 단계

리플렉션을 이해했으니, Structured Reasoning으로 이동하여 고급 분해와 Tree of Thoughts를 배워보세요!