AI 에이전트에게 세 가지 유형의 메모리가 필요한 이유 (그리고 내가 이 모든 것을 구축한 방법)
요약
단일 벡터 데이터베이스에 의존하는 기존 에이전트 메모리의 한계를 지적하며, 인간의 뇌 구조를 모방한 세 가지 유형의 메모리 시스템 구축 방법을 제안합니다. 의미론적, 일화적, 절차적 기억을 분리하여 에이전트의 성능과 정확도를 높이는 설계 방식을 다룹니다.
핵심 포인트
- 기존 벡터 DB 방식은 사실, 경험, 기술의 망각을 구분하지 못함
- 의미론적, 일화적, 절차적 기억의 세 가지 분리된 시스템 필요
- Cognee를 활용한 지식 그래프 기반의 메모리 관리 구현
- 스키마 정보, 과거 성공 사례, 수행 절차를 각각 별도로 관리
오늘날 대부분의 "에이전트 메모리 (agent memory)"는 세 가지 역할을 수행하는 하나의 요소, 즉 벡터 데이터베이스 (vector database)입니다. 과거의 데이터를 임베딩 (embedding)하고, 가장 가까운 이웃 (nearest neighbor)을 검색하여, 프롬프트 (prompt)에 붙여넣는 방식입니다. 이 방식은 작동할 때도 있지만, 작동하지 않을 때가 있습니다. 그리고 작동하지 않을 때, 에이전트가 사실을 잊은 것인지, 경험을 잊은 것인지, 아니면 기술을 배우지 못한 것인지 구분할 수 없습니다.
인간의 뇌는 이렇게 작동하지 않습니다. 뇌는 세 가지 별개의 시스템을 유지합니다. 저는 이와 동일하게 작동하는 에이전트를 구축했으며, 이를 통해 얻을 수 있는 이점을 측정했습니다.
문제점
저는 언어 모델 (language model)에 한 번도 본 적 없는 데이터베이스 (Northwind)를 제공하고 SQL을 작성하도록 요청했습니다. 아무런 도움 없이 냉정하게 평가했을 때, 강력한 모델이라도 약 4분의 1 정도의 확률로만 정답을 맞혔습니다. 이는 모델이 SQL을 작성할 수 없어서가 아니라, 스키마 (schema)를 알지 못하고, 지난번에 무엇이 효과적이었는지 기억하지 못하며, 주어진 형태의 질문에 어떻게 접근해야 하는지에 대한 감각이 없기 때문입니다. 이것들은 세 가지 서로 다른 종류의 "모름"이며, 단일 벡터 저장소 (vector store)는 이를 하나로 취급합니다.
뇌의 비유
인지 과학 (cognitive science)은 장기 기억 (long-term memory)을 세 가지 종류로 나눕니다:
- **의미론적 기억 (Semantic memory)**은 사물의 의미입니다. 프랑스의 수도.
Orders.CustomerID가Customers에 대한 외래 키 (foreign key)라는 사실. - **일화적 기억 (Episodic memory)**은 당신에게 일어난 일입니다. 지난 화요일에 실행하여 실제로 정확한 수치를 반환했던 쿼리 (query).
- **절차적 기억 (Procedural memory)**은 무언가를 수행하는 방법입니다. 자전거 타기. 조인 (join)에 대한 집계 (aggregate)를 수행할 때 카운트 (count)하기 전에 필터링 (filter)을 해야 한다는 사실.
당신은 가장 유사한 과거의 자전거 타기 경험을 찾는다고 해서 "자전거를 타는 방법"을 인출 (retrieve)하지 않습니다. 절차적 기억은 다른 메커니즘입니다. 이것이 프로젝트 전체를 구축하는 데 바탕이 된 통찰입니다.
두 가지를 위한 Cognee
Cognee는 저에게 remember (기억하기), recall (회상하기), forget (잊기), improve (개선하기)라는 네 가지 동사를 가진 지식 그래프 (knowledge graph)를 제공합니다. 저는 처음 두 가지 유형의 메모리에 이를 사용합니다.
의미론적 (Semantic): 벤치마크 (benchmark)가 실행되기 전에, Northwind 스키마를 한 번 로드합니다. 테이블 (tables), 컬럼 (columns), 외래 키 (foreign keys). 스키마는 절대 변하지 않기 때문에 결코 잊히지 않습니다.
에피소드적 메모리 (Episodic): 에이전트가 정답을 맞힐 때마다, 저는 질문-SQL 쌍을 하나의 에피소드 (episode)로 저장하며, 질문 유형을 인코딩하는 데이터셋 이름으로 태그를 지정합니다. 나중에 recall (회상) 과정에서 현재 질문과 일치하는 에피소드들을 불러옵니다.
어렵게 얻은 세부 사항 하나는 다음과 같습니다: Cognee의 그래프 추출 (graph extraction) 과정은 데이터 주입 (ingestion) 중에 컬럼 (column) 이름을 snake_case로 정규화하는데, 이는 PascalCase로 구성된 Northwind 스키마를 조용히 오염시킵니다. 해결책은 제가 입력한 원본 스키마 텍스트를 그대로 유지하고 이를 직접 주입하며, 그래프는 오직 에피소드 검색 (episode retrieval) 용도로만 사용하는 것이었습니다. 이 포스트에서 실용적인 팁을 하나 얻어 가신다면, 바로 이것입니다.
세 번째를 위한 Synapse
절차적 메모리 (Procedural memory)에는 다른 엔진이 필요했기에, 저는 Synapse-DB를 사용했습니다. 모든 질문은 문구가 아닌 유형 (의도 및 관련 테이블)에 따라 해시 (hash)되어 버킷 (bucket)에 할당됩니다. 각 시도마다 성공 점수와 함께 사고 (thought)를 기록합니다: 정답이면 1.0, 오답이면 0.0입니다. Synapse는 헤브식 (Hebbian-style) 방식으로 승자를 강화하고 패자를 감쇠 (decay) 시킵니다.
벡터 저장소 (vector store)가 제공할 수 없는 '유형별 메모리'는 해당 버킷이 에피소드를 키 (key)로 관리하는 방식에 있습니다. 성공적인 쿼리는 해당 유형의 해시 아래에 저장되며, recall은 단순히 문구가 가장 유사한 이웃을 찾는 것이 아니라 _동일한 유형_의 과거 쿼리들을 반환합니다. 이를 통해 에이전트는 수백 번의 시도에 걸쳐, 단일 유사 답변이 아닌 특정 _유형_의 문제에 어떻게 접근해야 하는지에 대한 감각을 축적합니다.
데모를 구축하며 발견한 솔직한 주의 사항이 하나 있습니다: 제가 사용한 Synapse 빌드에서는 best-next 조회 시 전역적 현저성 (global salience) 신호를 반환하며, 상태 해시 (state hash)에 따른 필터링을 수행하지 않습니다 (보지 못한 해시도 빈번하게 사용된 해시와 동일한 결과를 반환함). 따라서 유형별 차별화는 해시 키 기반의 에피소드적 회상 (episodic recall)에 의해 수행되며, Synapse는 전역적인 강화 및 감쇠 (reinforcement-and-decay) 신호의 역할을 합니다. 이 신호가 아래의 forget (망각) 단계를 구동하는 실질적인 동력입니다. 저는 제가 측정한 사실보다 더 깔끔한 이야기를 지어내어 팔기보다는, 각 메모리 유형이 정확히 어디에서 제 역할을 수행하는지 말씀드리고 싶습니다.
forget()에 대한 통찰
다른 어떤 접근 방식도 갖지 못한 요소가 바로 이것입니다. 훈련 초기 단계에서 에이전트는 때때로 운 좋게 질문에 정답을 맞히고, 오해의 소지가 있는 에피소드 (episode)를 저장하곤 합니다. 그 잘못된 기억은 이후 유사한 모든 질문에 대한 회상 (recall) 과정을 오염시킵니다.
저는 Synapse가 무엇을 잊을지 결정하도록 맡겼습니다. 실행 중간 체크포인트 (checkpoint)에서, Synapse가 세 번 이상 실패한 것을 목격한 질문 버킷 (question bucket)은 forget을 통해 Cognee로부터 초기 에피소드들을 가지치기 (prune) 합니다. 이러한 절차적 신호 (procedural signal)가 에피소드 저장소 (episodic store)를 정화합니다. 에이전트는 인간의 개입 (human in the loop) 없이 스스로 치유합니다. 이것이 바로 cron job 대신 원칙적인 아키텍처 (architecture)에 의해 구동되는 Cognee의 네 가지 동사 (verbs) 전부입니다.
벤치마크 수치
저는 동일한 모델인 claude-haiku-4-5를 사용하여 50개의 훈련 질문과 10개의 홀드아웃 (hold-out) 질문에 대해 두 에이전트를 실행했습니다.
- 메모리가 없는 바닐라 (Vanilla): 26%.
- 메모리 에이전트: 58%.
- 차이: +32 퍼센트 포인트 (percentage points), 총 API 비용은 £0.465였습니다.
실행 비용을 예산 내로 유지하기 위해 Sonnet 대신 Haiku를 사용했습니다. Haiku는 더 약한 베이스 모델 (base model)이기에 절대적인 수치는 겸손한 편입니다. 하지만 모델이 약하든 강하든, 두 에이전트 모두 동일한 모델을 실행했으므로, 이 차이는 오직 메모리 레이어 (memory layer) 때문이며 다른 요인은 없습니다.
저는 솔직한 버전을 공개합니다. 실행 도중 네트워크 오류 (network blip)로 중단되기 전까지 10개 에포크 (epoch) 중 8개를 완료했습니다. 학습은 70%대까지 올라가는 대신 에포크 3부터 58%에서 정체 (plateau)되었습니다. 가장 어려운 JOIN 질문들이 첫 번째 패스 (pass)에서 실패하여 학습할 에피소드가 생성되지 않았기 때문입니다. 홀드아웃 (hold-out) 수치는 평이했습니다. 하지만 이 모든 것이 핵심 결론을 바꾸지는 못합니다. 오직 메모리 레이어만이 동일한 모델을 26%에서 58%로 끌어올렸습니다.
다음 단계
영향력이 큰 순서대로 세 가지 수정 사항을 제안합니다. 첫째, 정체기를 깨뜨릴 수 있도록 어려운 버킷들에 소수의 정답 에피소드를 시드 (seed) 합니다. 둘째, 패킷 손실 (dropped packet)로 인해 밤새 진행한 실행이 무산되지 않도록 API 호출 주위에 재시도 (retry) 로직을 추가합니다. 셋째, Synapse 상태를 실행 간에 지속 (persist) 하여 절차적 메모리 (procedural memory)가 에포크 단위가 아닌 주 단위로 복리 효과를 내도록 합니다. 아키텍처가 핵심 기여점입니다. 수치는 그것이 작동함을 증명합니다. 다음 수치는 그것이 어디까지 갈 수 있는지를 보여줄 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기