왜 메모리 아키텍처가 당신의 모델보다 더 중요한가
Source: Dev.to
대부분의 에이전트 실패는 모델 실패가 아니라 메모리 실패입니다.
- 잘못된 인코딩
- 잡음이 섞인 저장소
- 혼란스러운 검색
- 정렬되지 않은 가지치기
에이전트가 작년 정책을 자신 있게 불러오거나, 컨텍스트 윈도우가 쓰레기로 가득 차서 환각을 일으키는 모습을 본 적이 있다면, 이는 야생에서 발생하는 메모리 드리프트를 목격한 것입니다. 이 글에서는 메모리 아키텍처를 일급 엔지니어링 객체로 만들기 위한 구조적 모델과 코드 패턴을 제공합니다.
두 루프
Inner Loop = 런타임 동작
Outer Loop = 아키텍처 진화
대부분의 프레임워크는 내부 루프만 구현합니다. 그래서 드리프트가 조용히 누적됩니다.
class Agent:
def inner_loop(self, task):
encoded = self.memory.encode(task)
self.memory.store(encoded)
context = self.memory.retrieve(task)
output = self.model.run(task, context)
self.memory.manage(task, output)
return output
def outer_loop(self, logs):
diagnostics = analyze(logs)
self.memory.redesign(diagnostics)
내부 루프는 학습합니다. 외부 루프는 재설계합니다. 두 가지가 모두 없으면, 학습 방법을 절대 업그레이드하지 않는 학생을 배포하는 겁니다.
네 개의 방
모든 메모리 시스템은 네 가지 구성 요소를 가지고 있습니다. 문제가 발생하면 에이전트가 아니라 방을 디버깅하세요.
class Memory:
def encode(self, item):
return embed(item) # embedding model, chunking, feature extraction
def store(self, vector):
vector_db.insert(vector) # vector DB, KV store, graph
def retrieve(self, query):
return vector_db.search(query, top_k=5) # similarity search, reranking
def manage(self, task, output):
prune_stale()
reindex()
decay()
| 방 | 드리프트 패턴 | 증상 |
|---|---|---|
| 인코드 | 임베딩이 대비를 잃음 | 모든 것이 비슷하게 보임 |
| 저장 | DB가 물건을 쌓아두는 다락방이 됨 | 부피 증가, 느린 쿼리 |
| 검색 | Top‑k가 오래되었거나 관련 없는 항목을 반환 | 잘못된 컨텍스트, 환각 |
| 관리 | 프루닝이 잘못된 것을 제거 | 지식 손실, 불안정한 동작 |
드리프트 감지기
def detect_drift(memory):
return {
"encoding_variance": variance(memory.embedding_stats),
"storage_growth": memory.db.size(),
"retrieval_accuracy": memory.metrics.retrieval_precision(),
"pruning_errors": memory.metrics.prune_misses()
}
검색 정확도가 떨어지고 저장 용량이 급증하면, 고전적인 슬롭 영역에 진입한 것입니다.
거버넌스 툴킷
거버넌스는 규정 준수가 아닙니다. 유지보수입니다.
# === APPRENTICE LOOP (Weekly) ===
# Surface friction from runtime behavior
def apprentice_loop(agent, tasks):
return [(task, agent.inner_loop(task)) for task in tasks]
# === ARCHITECT LOOP (Monthly) ===
# Redesign the structure that produced the friction
def architect_loop(agent, logs):
agent.memory.redesign(analyze(logs))
# === FOUR ROOMS AUDIT (On Drift) ===
# Diagnose which room failed
def audit(memory):
return {
"encode": memory.encode_stats(),
"store": memory.db.health(),
"retrieve": memory.metrics.retrieval_precision(),
"manage": memory.metrics.prune_misses()
}
# === DRIFT WATCH (Continuous) ===
# Catch slop early
def drift_watch(memory):
if memory.db.size() > MAX_SIZE:
warn("Storage overgrowth")
if memory.metrics.retrieval_precision() < THRESHOLD:
warn("Retrieval drift")
if memory.embedding_stats.variance < MIN_VARIANCE:
warn("Encoding drift")
# === ARCHITECTURE LEDGER (Versioning) ===
# Track how memory evolves
def log_change(change):
with open("architecture_ledger.jsonl", "a") as f:
f.write(json.dumps(change) + "\n")
메모리 아키텍처에 버전을 지정하지 않으면, 스키마 변경 한 번으로 혼돈에 빠질 수 있습니다.
핵심
에이전트가 점점 더 자율적으로 될수록, 메모리 시스템이 실제 엔진이 된다—모델도, 프롬프트도, RAG 파이프라인도 아니다.
아키텍처는 행동이다.
- 예측 가능한 에이전트는 예측 가능한 메모리를 필요로 한다.
- 예측 가능한 메모리는 거버넌스를 필요로 한다.
- 거버넌스는 두 개의 루프와 네 개의 방을 필요로 한다.
이 게시물 뒤의 개념적 프레임워크는 Substack의 The Two Loops를 참고하세요.