jongkwan.dev
개발 · Essay №034

Reflexion: 실패로부터 배우는 에이전트

실패를 언어로 분석하고 메모리에 저장하여 같은 실수를 반복하지 않는 자기 개선 기법

이종관2026년 2월 1일5 min read
Contents

언어적 자기 성찰을 통한 학습

개념

Reflexion은 실패한 시도를 언어로 분석하고 메모리에 저장하여, 다음 시도에서 같은 실수를 반복하지 않도록 하는 기법이다.

동작 구조

  1. 1차 시도 후 실패한다
  2. 반성 -- "왜 실패했는가?"를 언어로 분석한다
  3. 메모리에 교훈 저장 -- 반성 내용을 텍스트로 기록한다
  4. 2차 시도 -- 메모리를 참조하여 같은 실수를 피하고 성공한다

예시

python
# [1차 시도]
def book_hotel(name, dates, room_type):
    reservation = {
        "name": name,
        "dates": dates,
        "room": room_type
    }
    return confirm_booking(reservation)
 
# 결과: RuntimeError - 'dates' must be a list

반성: "dates 변수의 타입 검증이 필요하다. 사용자가 문자열이나 다른 타입을 전달할 수 있다."

메모리에 저장

python
# [2차 시도] - 메모리 참조
def book_hotel(name, dates, room_type):
    # 메모리에서 학습: 타입 검증 필요
    if not isinstance(dates, list):
        raise ValueError("dates must be a list")
 
    reservation = {
        "name": name,
        "dates": dates,
        "room": room_type
    }
    return confirm_booking(reservation)
 
# 결과: 성공!

핵심 특징

특징설명
가중치 변경 없음모델 재학습 불필요
텍스트 기반 메모리효율적이고 해석 가능
누적 학습경험이 쌓일수록 개선

성능

벤치마크기존Reflexion
HumanEval (코딩)48%91%

**HumanEval 48% → 91%**는 약 2배의 성능 향상이다.

단순 재시도와의 차이

  • 단순 재시도: 1차 실패 -- 2차 실패(같은 실수 반복) -- 3차 실패(또 같은 실수). 피드백 없이 반복하므로 개선되지 않다.
  • Reflexion: 1차 실패 후 "타입 검증이 없었다"라고 반성하고, 2차에서 타입 검증을 추가하여 성공한다. 실패 원인을 분석하므로 빠르게 개선된다.

메모리 구조

python
# Reflexion 메모리 예시
memory = [
    {
        "task": "book_hotel 함수 구현",
        "failure": "TypeError: dates must be a list",
        "reflection": "입력 타입 검증이 필요하다",
        "solution": "isinstance() 체크 추가"
    },
    {
        "task": "API 호출 함수",
        "failure": "ConnectionError",
        "reflection": "네트워크 에러 처리가 필요하다",
        "solution": "try-except와 재시도 로직 추가"
    }
]

메모리 활용

새로운 작업: "결제 API 함수 구현"

메모리 검색 -- 관련 경험: "API 호출 함수" - 네트워크 에러 처리 필요

적용 -- 처음부터 try-except와 재시도 로직을 포함하여 1차 시도에서 성공!

Self-Refine과의 차이

ReflexionSelf-Refine
트리거실패 후 반성지속적 개선
실패 신호명확한 실패 필요실패 없이도 개선
메모리장기 메모리에 저장즉시 반영
적용 분야코딩, QA글쓰기, 요약

동작 알고리즘

python
def reflexion_loop(task, max_attempts=3):
    memory = load_memory()
 
    for attempt in range(max_attempts):
        # 메모리 참조하여 시도
        result = execute_with_memory(task, memory)
 
        if result.success:
            return result
 
        # 실패 시 반성
        reflection = reflect_on_failure(
            task=task,
            error=result.error,
            code=result.code
        )
 
        # 메모리에 저장
        memory.append({
            "task": task,
            "failure": result.error,
            "reflection": reflection
        })
 
    return result

적용 시나리오

시나리오적합 여부
코딩 문제 (테스트 있음)매우 적합
명확한 성공/실패 기준적합
팩트 기반 QA적합 (CRITIC과 결합)
창작 글쓰기덜 적합 (Self-Refine 권장)

한계

  1. 명확한 실패 신호 필요: 성공/실패가 불분명한 작업에는 부적합
  2. 메모리 검색 품질: 관련 경험을 찾지 못할 수 있음
  3. 일반화: 비슷한 상황을 인식하지 못할 수 있음

관련 개념

  • Self-Refine: 지속적 개선 (실패 없이도)
  • CRITIC: 외부 도구 검증
  • ReAct: 기반 프레임워크