Reflexion: 실패로부터 배우는 에이전트
실패한 시도를 언어로 분석하고 메모리에 저장하여, 다음 시도에서 같은 실수를 반복하지 않습니다
2026년 2월 1일·5 min read·
ai
ai-agent
llm
reflexion
self-reflection
learning
언어적 자기 성찰을 통한 학습
개념
Reflexion은 실패한 시도를 언어로 분석하고 메모리에 저장하여, 다음 시도에서 같은 실수를 반복하지 않도록 하는 기법입니다.
동작 구조
1차 시도 → 실패
↓
반성: "왜 실패했는가?"
↓
메모리에 교훈 저장
↓
2차 시도 (메모리 참조) → 성공
예시
# [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 변수의 타입 검증이 필요하다.
사용자가 문자열이나 다른 타입을 전달할 수 있다."
→ 메모리에 저장
# [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차: 타입 검증 추가 → 성공!
메모리 구조
# 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과의 차이
| Reflexion | Self-Refine | |
|---|---|---|
| 트리거 | 실패 후 반성 | 지속적 개선 |
| 실패 신호 | 명확한 실패 필요 | 실패 없이도 개선 |
| 메모리 | 장기 메모리에 저장 | 즉시 반영 |
| 적용 분야 | 코딩, QA | 글쓰기, 요약 |
동작 알고리즘
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 권장) |
한계
- 명확한 실패 신호 필요: 성공/실패가 불분명한 작업에는 부적합
- 메모리 검색 품질: 관련 경험을 찾지 못할 수 있음
- 일반화: 비슷한 상황을 인식하지 못할 수 있음
관련 개념
- Self-Refine: 지속적 개선 (실패 없이도)
- CRITIC: 외부 도구 검증
- ReAct: 기반 프레임워크