메모리 블록(Memory Blocks)과 수면 시간 계산(Sleep-Time Compute) — Letta
MemGPT는 2024년에 Letta로 이름을 바꾸었습니다. 2026년의 진화는 두 가지 아이디어를 더합니다. 모델이 직접 편집할 수 있는 분리된 기능형 메모리 블록(discrete functional memory blocks), 그리고 기본 에이전트가 유휴 상태일 때 비동기로 메모리를 통합하는 수면 시간 에이전트(sleep-time agent)입니다. 이것이 메모리를 하나의 대화 범위 너머로 확장하는 방식입니다.
유형: Build
언어: Python (stdlib)
선수 학습: Phase 14 · 07 (MemGPT)
소요 시간: 약 75분
학습 목표
- Letta가 사용하는 세 가지 메모리 계층(core, recall, archival)과 각 계층의 역할을 설명합니다.
- 메모리 블록 패턴을 설명합니다. Human 블록, Persona 블록, 사용자 정의 블록을 일급의 타입이 지정된 객체(first-class typed object)로 다룹니다.
- 수면 시간 계산이 무엇인지, 왜 주요 실행 경로(critical path) 밖에 있는지, 왜 기본 에이전트보다 더 강한 모델을 사용할 수 있는지 설명합니다.
- 기본 에이전트가 응답을 처리하고, 수면 시간 에이전트가 턴 사이에 블록을 통합하는 스크립트형 두 에이전트 루프를 구현합니다.
문제
MemGPT(07강)는 가상 메모리 제어 흐름을 해결했습니다. 하지만 프로덕션에서는 세 가지 문제가 나타났습니다.
- 지연 시간(Latency). 모든 메모리 작업이 주요 실행 경로에 놓입니다. 사용자가 기다리는 동안 에이전트가 가지치기, 요약, 정합성 조정을 해야 한다면 꼬리 지연 시간(tail latency)이 폭발합니다.
- 기억 부패(Memory rot). 쓰기가 누적됩니다. 모순된 사실이 그대로 남습니다. 검색은 오래된 내용에 묻혀버립니다.
- 구조 손실(Structure loss). 평평한 archival 저장소만으로는 "Human 블록은 항상 프롬프트 안에 있다. Persona 블록도 항상 프롬프트 안에 있다. Task 블록은 세션마다 교체된다" 같은 구조를 표현할 수 없습니다.
Letta(letta.com)는 2026년의 재작성판입니다. 메모리 블록은 구조를 명시적으로 드러내고, 수면 시간 계산은 통합 작업을 주요 실행 경로 밖으로 옮깁니다.
개념
세 계층
| 계층 | 범위 | 위치 | 작성 주체 |
|---|
| Core | 항상 보임 | 주 프롬프트 안 | 에이전트 도구 호출 + 수면 시간 재작성 |
| Recall | 대화 이력 | 검색 가능 | 자동 턴 로깅 |
| Archival | 임의의 사실 | 벡터 + KV + 그래프 | 에이전트 도구 호출 + 수면 시간 수집 |
Core는 MemGPT의 core 계층에 해당합니다. Recall은 밀려난 꼬리(evicted tail)를 가진 대화 버퍼입니다. Archival은 외부 저장소입니다. 이 분리는 MemGPT의 2계층 구조에서 한 계층이 여러 책임을 떠안던 문제를 정리해 줍니다.
메모리 블록
블록은 core 계층 안에 있는, 타입이 지정된(typed) 지속적이고 편집 가능한 영역입니다. 원래 MemGPT 논문은 두 가지를 정의했습니다.
- Human 블록(Human block) — 사용자에 관한 사실입니다. 이름, 역할, 선호, 목표 등이 들어갑니다.
- Persona 블록(Persona block) — 에이전트의 자기 개념입니다. 정체성, 말투, 제약이 들어갑니다.
Letta는 이를 임의의 사용자 정의 블록으로 일반화합니다. 현재 목표를 담는 Task 블록, 코드베이스 관련 사실을 담는 Project 블록, 절대 어겨서는 안 되는 제약을 담는 Safety 블록을 둘 수 있습니다. 각 블록은 id, label, value, limit(문자 한도), description(모델이 언제 편집해야 하는지 판단하도록 해주는 설명)을 갖습니다.
블록은 다음과 같은 도구 인터페이스를 통해 편집할 수 있습니다.
block_append(label, text)
block_replace(label, old, new)
block_read(label)
block_summarize(label) — 한도에 가까워진 블록을 압축합니다.
수면 시간 계산
2025년 Letta가 더한 아이디어는 두 번째 에이전트를 주요 실행 경로 밖의 백그라운드에서 실행한다는 것입니다. 수면 시간 에이전트는 대화 기록과 코드베이스 맥락을 처리하고, 공유 블록에 learned_context를 기록하며, archival 레코드를 통합하거나 무효화합니다.
그 결과 다음과 같은 특성이 따라옵니다.
- 지연 시간 비용이 없습니다. 기본 응답은 메모리 작업이 끝나기를 기다리지 않습니다.
- 더 강한 모델을 사용할 수 있습니다. 수면 시간 에이전트는 지연 시간 제약을 받지 않기 때문에 더 비싸고 느린 모델을 써도 괜찮습니다.
- 자연스러운 통합 시간대가 생깁니다. 사용자가 기다리지 않는 시점에 중복 제거, 요약, 모순된 사실의 무효화를 수행합니다.
이 형태는 사람이 일하는 방식과 닮아 있습니다. 낮 동안 작업을 하고, 잠을 자며, 장기 기억은 밤사이에 정리됩니다.
Letta V1과 네이티브 추론(Native Reasoning)
Letta V1(letta_v1_agent, 2026)은 send_message/heartbeat와 프롬프트 안의 Thought: 토큰을 폐기하고, 네이티브 추론(native reasoning)을 사용합니다. Responses API(OpenAI)와 확장 사고(extended thinking)를 사용하는 Messages API(Anthropic)는 추론을 별도 채널로 내보내며, 이 추론은 턴 사이를 가로질러 전달됩니다. 프로덕션에서는 제공자 간 암호화되어 전달됩니다. 제어 루프는 여전히 ReAct입니다. 다만 사고 추적(thought trace)이 프롬프트 모양이 아니라 구조적인 형태로 다뤄집니다.
이 패턴이 잘못되는 지점
- 블록 비대화(Block bloat). 무한정
block_append를 호출하면 한도에 금세 도달합니다. 한도를 넘기는 쓰기가 발생하기 전에 블록 요약기(block summarizer)를 연결해 두세요.
- 조용한 표류(Silent drift). 수면 시간 에이전트가 블록을 다시 썼지만 기본 에이전트가 그 변경을 알아차리지 못하는 경우입니다. 블록에 버전을 붙이고 추적(trace)에 변경 내역(diff)을 드러내세요.
- 오염된 통합(Poisoned consolidation). 수면 시간 에이전트가 공격자가 도달할 수 있는 내용을 core로 끌어들이는 경우입니다. 27강에서 다루는 내용은 수면 시간 영역에도 그대로 적용됩니다.
만들어보기
code/main.py는 다음을 구현합니다.
Block — id, label, value, limit, description을 가진 블록 타입입니다.
BlockStore — CRUD 연산과 near_limit(label) 보조 기능을 제공합니다.
- 두 개의 스크립트형 에이전트 —
PrimaryAgent는 턴을 처리하고, SleepTimeAgent는 턴 사이에 통합 작업을 수행합니다.
- 세 턴짜리 대화에서 블록 쓰기를 보여주고, 수면 시간 패스(sleep-time pass)가 블록을 요약하고 오래된 사실을 무효화하는 추적(trace)을 포함합니다.
다음과 같이 실행합니다.
python3 code/main.py
대화 기록(transcript)에는 역할 분리가 그대로 드러납니다. 기본 턴은 빠르게 진행되며 가공되지 않은 원시 쓰기(raw write)를 생성하고, 수면 패스는 그 결과를 압축하고 정리합니다.
사용해보기
- Letta(letta.com) — 참조 구현입니다. 자체 호스팅하거나 관리형 클라우드(managed cloud)를 사용할 수 있습니다.
- Claude Agent SDK 스킬(skills) — 블록 형태의 지식으로 바라볼 수 있습니다. 스킬은 에이전트가 필요할 때 불러오는, 이름과 버전을 갖고 검색 가능한 지시 블록입니다.
- 사용자 정의 구현(Custom builds) — 저장소 백엔드를 직접 통제하고 싶은 팀에 맞는 선택지입니다. 나중에 이관할 수 있도록 Letta API 규약(contract)을 따르세요.
산출물 만들기
outputs/skill-memory-blocks.md는 어떤 런타임에서도 Letta 형태의 블록 시스템과 수면 시간 훅(sleep-time hooks)을 만들어 냅니다. 안전 규칙과 인용 연결(citation wiring)도 함께 포함합니다.
연습문제
- (쉬움)
near_limit이 true를 반환할 때 블록 값을 모델이 생성한 요약으로 교체하는 block_summarize 도구를 추가해 보세요. 요약 호출 횟수와 블록 한도 초과를 동시에 최소화하는 트리거 임계값(threshold)은 어느 정도일까요?
- (중간) archival 위에 수면 시간 중복 제거(dedup)를 구현해 보세요. 두 레코드의 텍스트 토큰 겹침이 90%를 넘으면 하나로 합칩니다. 반드시 수면 패스에서만 수행하고, 주요 실행 경로에서는 절대 실행하지 마세요.
- (중간) 블록 버전을 관리해 보세요. 모든 쓰기마다 이전 값과 변경 내역(diff)을 기록합니다. 운영자가 "왜 에이전트가 X를 잊었는지"를 디버그할 수 있도록
block_history(label)을 노출하세요.
- (어려움) 수면 시간 에이전트를 신뢰할 수 없는 작성자로 취급해 보세요. Persona 또는 Safety 블록을 건드릴 때는 커밋 전에 두 번째 에이전트의 검토(review)를 거치도록 요구합니다.
- (어려움) 예제를 Letta API(
letta_v1_agent)를 사용하도록 옮겨 보세요. 블록 스키마(block schema)에서 무엇이 달라지고, 네이티브 추론은 추적 형태를 어떻게 바꾸나요?
핵심 용어
| 용어 | 흔한 설명 | 실제 의미 |
|---|
| 메모리 블록(Memory block) | "편집 가능한 프롬프트 섹션" | core 메모리 안에 있는, 타입이 지정된 지속적이고 LLM이 편집할 수 있는 영역이다. |
| Human 블록(Human block) | "사용자 메모리" | 사용자에 관한 사실로, core 계층에 고정된다. |
| Persona 블록(Persona block) | "에이전트 정체성" | 자기 개념, 말투, 제약으로 구성되며, core 계층에 고정된다. |
| 수면 시간 계산(Sleep-time compute) | "비동기 메모리 작업" | 두 번째 에이전트가 주요 실행 경로 밖에서 통합 작업을 수행하는 방식이다. |
| Core / Recall / Archival | "계층(Tiers)" | 항상 보임 / 대화 / 외부 저장소로 나뉘는 3계층 메모리 구조이다. |
| 블록 한도(Block limit) | "상한(Cap)" | 블록별 문자 한도이며, 요약을 강제하는 장치이다. |
| 네이티브 추론(Native reasoning) | "사고 채널(Thinking channel)" | 프롬프트 수준의 Thought:가 아니라 제공자 수준에서 별도 채널로 내보내는 추론 출력이다. |
| 학습된 맥락(Learned context) | "수면 출력" | 수면 시간 에이전트가 공유 블록에 기록하는 사실들이다. |
더 읽을거리