기억과 망각
에이전트의 기억 모듈을 단기·장기 기억과 읽기·쓰기 기준으로 정리하고, 장기 실행에서 생기는 컨텍스트 관성과 주기적으로 잊는 방법을 실습한다.
- LLM은 호출 사이에 아무것도 기억하지 않음. 에이전트의 "기억"은 다음 호출의 컨텍스트에 무엇을 다시 넣을지 정하는 장치.
- 기억이 없으면 결정을 잊고, 너무 많으면 오래된 가설에 끌려감. 언제 잊을지도 설계 대상.
- 코딩 도구의 메모리: 메모리와 AGENTS.md.
기억 모듈
| 구분 | 구현 | 장점 | 단점 |
|---|---|---|---|
| 단기 기억(short-term memory) | 프롬프트에 직접 씀(대화 이력, 작업 메모) | 간단, 최근 일을 바로 반영 | 컨텍스트 창의 한계 |
| 장기 기억(long-term memory) | 외부에 저장(파일, 벡터 DB, DB) | 오래·많이 보관 | 찾아서 불러와야 함 |
- 장기 기억은 컨텍스트 엔지니어링의 외부 저장. 형식은 자연어, 임베딩(벡터 검색), DB, 할 일 목록 등. 출처: Wang 외(2023), A Survey on LLM based Autonomous Agents.
- 읽기(무엇을 꺼낼까): Generative Agents는 세 점수를 0-1로 정규화해 더한 값으로 기억을 고름. 출처: Park 외(2023), Generative Agents.
- 최신성(recency): 지난 시간에 따라 지수적으로 감소(감소율 0.995)
- 중요성(importance): 기억을 만들 때 LLM이 1-10으로 매김
- 관련성(relevance): 기억과 질의의 임베딩 코사인 유사도
- 쓰기(무엇을 남길까): 중복·충돌을 막기 위해 오래된 것 지우기(FIFO), 비슷한 기억 합치기. 무엇을 지울지가 곧 망각의 설계.
장기 실행에서 생기는 실패: 컨텍스트 관성
- 컨텍스트 관성(context inertia): 쌓인 가설·하위 목표에 집중해 그만둬야 할 때도 계속하는 현상. 매몰 비용과 비슷. 출처: Breunig(2026), Context Inertia.
- 대응은 공통적으로 환경(파일·결과물)은 남기고 대화 컨텍스트는 주기적으로 버리기.
| 방법 | 남기는 것 | 버리는 것 | 결과 |
|---|---|---|---|
| Memento(Anthropic) | 코드·환경, 짧은 메모 | 대화 이력(1.5시간마다) | 잘못된 가설에 몇 시간씩 고착되는 실패 완화 |
| Fork-and-Flush(Cai 외) | 작업 공간 | 여러 갈래로 나눈 뒤 대화 이력 | 같은 예산에서 단일 실행보다 66.0% 높은 점수 |
| 망각(Tan 외) | 가장 좋은 후보 | 세션과 후보 이력 | 병렬 에이전트보다 최대 15% 개선 |
출처: Anthropic(2026), AI models may be capable of self-replicating without access to a datacenter 부록; Cai 외(2026), Fork-and-Flush; Tan 외(2026), Scaling Discovery Requires Forgetting.
실습: 진행 메모로 이어 가기
- 작업: 마인드몰 고객 안내서의 절마다 FAQ 한 개씩 작성.
- 세션 1: 1-2절 작성, 중간에 형식 규칙을 정함 → 진행 메모를 파일에 저장하고 이력 삭제.
- 세션 2: 이력 없이 메모 파일만 읽고 다음 절 작성.
- 실습 자료 다운로드: mindmall_guide.py. 현재 폴더에 업로드.
!pip install -q openai
from pathlib import Path
from openai import OpenAI
from mindmall_guide import guide
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=Path("openrouter-key.txt").read_text().strip(), # 키 파일에서 읽기
)
model = "openai/gpt-4.1-mini"
system = {"role": "system", "content": "마인드몰 고객 안내서로 FAQ를 만드는 작성자.\n\n[안내서]\n" + guide}
def chat(messages):
return client.chat.completions.create(model=model, messages=messages).choices[0].message.content
세션 1: 대화를 이어 가며 작업
session1 = [system]
for request in ["1절(회원 등급)로 FAQ 하나를 써 주세요. 형식: Q: ... / A: ...",
"앞으로 답(A)은 두 문장 이내로, 끝에 근거 절을 [2절]처럼 붙여 주세요. 2절(적립금)로 써 주세요."]:
session1.append({"role": "user", "content": request})
session1.append({"role": "assistant", "content": chat(session1)})
print(session1[-1]["content"], "\n")
실행 결과
Q: 최근 6개월 동안 구매 금액이 35만 원인데, 저의 회원 등급은 무엇인가요?
A: 최근 6개월 동안 구매 금액이 30만 원 이상 100만 원 미만이므로 실버 회원 등급에 해당합니다. 실버 회원은 매월 무료 배송 쿠폰 2장을 받으실 수 있습니다.
Q: 적립금은 언제 지급되며, 얼마부터 사용할 수 있나요?
A: 적립금은 상품 배송 완료 후 7일 뒤에 지급되며, 1,000원 이상일 때부터 사용할 수 있습니다. [2절]
진행 메모 쓰고 대화 비우기
note = chat(session1 + [{"role": "user", "content": "대화 이력은 사라지고 이 메모만 남습니다. "
"이어받을 사람을 위해 목표, 지켜야 할 규칙, 완료한 것, 다음 할 일만 짧게 쓰세요."}])
Path("progress.md").write_text(note)
session1 = None # 대화 이력 삭제
print(note)
실행 결과
목표: 마인드몰 고객 안내서로 FAQ 작성
지켜야 할 규칙: 답변 두 문장 이내, 근거 절 표시
완료한 것: 1절, 2절 FAQ 작성
다음 할 일: 다른 절 FAQ 작성 및 보완
- 위 실행의 메모에는 대화 중간에 정한 규칙(두 문장 이내, 근거 절 표시)이 들어감.
- 빠진 것도 있음: "절마다 FAQ 하나", "Q: ... / A: ..." 형식,
[2절]이라는 정확한 표기. 실행마다 메모 내용은 달라질 수 있음.
세션 2: 메모만으로 이어 가기
session2 = [system, {"role": "user", "content": "[진행 메모]\n" + Path("progress.md").read_text()
+ "\n\n'다음 할 일'에서 다음 절 하나만 쓰세요."}]
print(chat(session2))
실행 결과
## 3. 배송 FAQ
Q: 오후 2시 이후에 주문했는데 언제 출고되나요?
A: 다음 영업일에 출고됩니다. (3절 배송)
Q: 배송비는 얼마인가요?
A: 기본 배송비는 3,000원이며, 5만 원 이상 주문 시 무료입니다. (3절 배송)
Q: 제주도에 주문하면 배송비가 어떻게 되나요?
A: 추가 배송비 3,000원이 붙으며, 결제 금액과 관계없이 부과됩니다. (3절 배송)
Q: 출고 후 3일이 지났는데 상품이 도착하지 않으면 어떻게 하나요?
A: 고객센터로 문의하시면 됩니다. (3절 배송)
- 위 실행의 세션 2는 1-2절을 반복하지 않고 3절(배송)로 넘어갔고, 두 문장 이내 규칙도 지킴.
- 하지만 메모에서 빠진 부분은 흔들림: FAQ를 하나가 아니라 넷 썼고, 근거 표기도
[3절]이 아닌(3절 배송). 메모의 품질이 다음 세션의 품질을 정함. 정확한 예시를 메모에 넣으라고 요청하면 개선 가능. - 남긴 것은 안내서(환경)와 메모 파일뿐. Memento와 같은 구조. 하네스는 이를 일정 단계마다 자동으로 반복(에이전트에 하네스 달기).
장기 기억의 충돌과 전략적 망각
- Breunig가 6개월 돌린 개인 에이전트는 스킬에 서로 충돌하는 해결책이 쌓임. 이를 정리하는 전략적 망각(strategic forgetting) 은 아직 풀리지 않은 과제.
- 실천: 메모에 날짜와 출처 남기기, 바뀐 결정은 덮어쓰기, 프로젝트별로 기억 분리, 주기적으로 정리.
퀴즈
단기 기억을 프롬프트에 직접 쓰는 방식의 단점은?
퀴즈를 풀려면 대화형 기능을 불러와야 합니다.