
Mem0 + Kuzu 완전 가이드: AI에게 '기억'을 주면 대화가 달라진다
'저는 SF 영화를 좋아해요'라고 말했는데, 다음 대화에서 스릴러를 추천받은 적 있는가? LLM은 대화가 끝나면 모든 것을 잊는다. Mem0는 대화에서 사용자 취향과 관계를 자동 추출하여 그래프 DB(Kuzu)에 저장하고, 다음 대화에서 개인화된 응답을 제공한다. AI 메모리의 원리부터 실전 구현, 2026년 개인화 AI의 미래까지.

'저는 SF 영화를 좋아해요'라고 말했는데, 다음 대화에서 스릴러를 추천받은 적 있는가? LLM은 대화가 끝나면 모든 것을 잊는다. Mem0는 대화에서 사용자 취향과 관계를 자동 추출하여 그래프 DB(Kuzu)에 저장하고, 다음 대화에서 개인화된 응답을 제공한다. AI 메모리의 원리부터 실전 구현, 2026년 개인화 AI의 미래까지.
당신은 AI 챗봇과 영화에 대해 이야기하고 있다.
당신: "저는 스릴러 영화를 별로 안 좋아해요. SF 영화를 좋아합니다." AI: "알겠습니다! 앞으로 SF 영화를 추천해드리겠습니다."
일주일 뒤, 같은 AI에게 다시 묻는다.
당신: "오늘 밤에 영화 볼 건데, 뭐 추천해줘?" AI: "스릴러 영화는 어떠세요? 몰입감이 좋답니다."
…분명히 싫다고 했는데.

이것이 현재 LLM의 근본적인 한계다. 대화가 끝나면, 모든 것을 잊는다. 컨텍스트 윈도우 안에서는 완벽하게 기억하지만, 세션이 바뀌면 백지 상태로 돌아간다. 마치 금붕어처럼.
"AI가 나의 취향, 습관, 선호도를 기억하게 할 수는 없을까?"
Mem0는 바로 이 문제를 해결하기 위해 탄생한 AI 메모리 레이어다. 그리고 Kuzu는 그 기억을 관계 그래프로 저장하는 임베디드 그래프 데이터베이스다.
이 글에서는 Mem0의 공식 예제 노트북을 기반으로, AI에게 기억을 주는 기술의 원리부터 실전 구현, 그리고 2026년 개인화 AI의 미래까지 종합적으로 다룬다.
📎 이 글은 Mem0 공식 리포지토리의 kuzu-example.ipynb를 기반으로 작성되었다.
LLM은 본질적으로 무상태(stateless) 시스템이다. 각 API 호출은 독립적이며, 이전 호출의 정보를 보존하지 않는다.
| 인간의 대화 | LLM의 대화 | |
|---|---|---|
| 단기 기억 | 현재 대화 내용 기억 | ✅ 컨텍스트 윈도우 내에서 가능 |
| 장기 기억 | 지난주 대화 내용 기억 | ❌ 세션 종료 시 소멸 |
| 선호도 학습 | "이 사람은 매운 걸 좋아해" | ❌ 매번 처음부터 시작 |
| 관계 파악 | "이 사람의 아내 이름은 수진" | ❌ 알려줘도 다음에 잊음 |
이 문제를 해결하기 위한 시도들이 있었다:
1. 대화 이력 전체를 프롬프트에 넣기
# 모든 과거 대화를 프롬프트에 포함
messages = [
previous_conversation_1, # 3일 전 대화
previous_conversation_2, # 어제 대화
current_message # 지금 대화
]
문제: 대화가 쌓이면 토큰 한도를 초과하고, 비용이 급증한다. 100번의 대화 이력을 매번 보내는 것은 비현실적이다.
2. 대화 요약을 저장하기
각 대화를 요약하여 저장하고, 다음 대화에 요약만 포함. 하지만 요약 과정에서 세부 정보가 손실된다. "SF 영화를 좋아한다"는 기억될 수 있지만, "인터스텔라가 인생 영화"라는 디테일은 사라진다.
3. 벡터 DB에 대화를 저장하기 (RAG)
대화 청크를 벡터화하여 저장하고, 유사한 대화를 검색. 하지만 이전 글에서 살펴봤듯이, 벡터 검색은 관계를 추적하지 못한다. "이 사용자가 SF를 좋아한다"는 사실과 "이 사용자가 스릴러를 싫어한다"는 사실이 서로 다른 청크에 있으면 연결되지 않는다.

Mem0(메모제로, 구 EmbedChain)는 AI 에이전트를 위한 메모리 레이어 오픈소스 프레임워크다. GitHub 스타 25,000개 이상을 달성하며 AI 메모리 분야에서 가장 활발한 프로젝트 중 하나로 자리잡았다.
핵심 아이디어: 대화에서 중요한 사실(fact)과 관계(relation)를 자동으로 추출하여 저장하고, 다음 대화에서 관련 기억을 검색하여 LLM에 제공한다.
| 시점 | 사건 |
|---|---|
| 2023 | EmbedChain으로 시작 — RAG 파이프라인 자동화 도구 |
| 2024 초 | Mem0로 리브랜딩 — AI 메모리 레이어로 방향 전환 |
| 2024 중 | 그래프 메모리(Graph Memory) 기능 추가 — 관계형 기억 지원 |
| 2024 | 투자 유치, 커뮤니티 급성장 |
| 2025~현재 | Kuzu, Neo4j 등 다양한 그래프 DB 백엔드 지원 |
Mem0가 다른 메모리 솔루션과 근본적으로 다른 점은 두 가지 형태의 기억을 동시에 관리한다는 것이다.

대화 내용을 임베딩 벡터로 변환하여 저장한다. "사용자가 영화에 대해 이야기했다"는 의미적 맥락을 포착한다. 나중에 비슷한 주제의 질문이 들어오면, 유사도 검색으로 관련 기억을 꺼낸다.
대화에서 엔티티 간의 관계를 추출하여 그래프로 저장한다:
이 두 가지를 합치면: 벡터 메모리가 "어떤 맥락의 대화였는지"를 기억하고, 그래프 메모리가 "구체적으로 어떤 관계가 있는지"를 기억한다. 마치 인간이 감각적 기억(분위기, 맥락)과 명시적 기억(사실, 관계)을 동시에 가지는 것과 같다.
이전 글에서도 언급했듯, Kuzu는 워털루 대학교 Semih Salihoglu 교수 연구실에서 만든 임베디드 그래프 데이터베이스다. SQLite가 관계형 DB의 임베디드 버전이라면, Kuzu는 그래프 DB의 SQLite다.
Mem0 + Kuzu 조합의 핵심 이점:
pip install "mem0ai[graph]" 한 줄이면 Kuzu가 함께 설치된다. Neo4j처럼 별도 서버를 띄울 필요가 없다."db": ":memory:"로 설정하면 메모리에서 실행된다. 프로토타이핑에 최적. 디스크 경로를 주면 영구 저장도 가능하다.config = {
"embedder": {
"provider": "openai",
"config": {
"model": "text-embedding-3-large",
"embedding_dims": 1536
},
},
"graph_store": {
"provider": "kuzu",
"config": {
"db": ":memory:", # 인메모리 모드
# "db": "./kuzu_data" # 디스크 영구 저장
},
},
}
embedder는 벡터 메모리를 위한 임베딩 모델, graph_store는 그래프 메모리를 위한 그래프 DB를 설정한다. 이 두 줄의 설정이 Mem0의 이중 기억 시스템을 정의한다.

노트북의 데모를 단계별로 살펴보자.
사용자와 AI 사이의 대화를 Mem0에 저장한다:
from mem0 import Memory
memory = Memory.from_config(config_dict=config)
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller movie? They can be quite engaging."},
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
results = memory.add(messages, user_id="myuser", metadata={"category": "movie_recommendations"})
memory.add()를 호출하면, Mem0는 내부적으로 LLM을 사용하여 대화에서 두 가지를 동시에 추출한다:
results(임베딩)와 relations(그래프 엣지) 모두 포함결과를 출력하는 헬퍼 함수:
def print_added_memories(results):
print("::: Saved the following memories:")
print(" embeddings:")
for r in results['results']:
print(" ", r)
print(" relations:")
for k, v in results['relations'].items():
print(" ", k)
for e in v:
print(" ", e)
출력 예시:
핵심: 개발자가 어떤 정보를 추출할지 정의하지 않았다. Mem0가 LLM을 사용하여 대화에서 중요한 사실과 관계를 자동으로 판단하고 추출한 것이다.
저장된 기억 중에서 관련 있는 것을 검색한다:
results = memory.search("what does the user love?", user_id="myuser")
for result in results["results"]:
print(result["memory"], result["score"])
"사용자가 무엇을 좋아하나요?"라는 질문에, Mem0는 벡터 유사도와 그래프 관계를 모두 활용하여 "Loves sci-fi movies"를 높은 점수로 반환한다.
score는 유사도 점수다. 점수가 낮을수록 더 관련성이 높다 (거리 기반).
이제 핵심 — 이 기억을 활용하여 개인화된 대화를 하는 챗봇을 만든다:
def chat_with_memories(message: str, user_id: str = "myuser") -> str:
# 1. 관련 기억 검색
relevant_memories = memory.search(query=message, user_id=user_id, limit=3)
memories_str = "\n".join(
f"- {entry['memory']}" for entry in relevant_memories["results"]
)
# 2. 기억을 시스템 프롬프트에 포함
system_prompt = f"""You are a helpful AI. Answer the question based on query and memories.
User Memories:
{memories_str}"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": message}
]
# 3. LLM으로 응답 생성
response = openai_client.chat.completions.create(
model="gpt-4.1-nano-2025-04-14",
messages=messages
)
assistant_response = response.choices[0].message.content
# 4. 새 대화도 기억에 추가
messages.append({"role": "assistant", "content": assistant_response})
results = memory.add(messages, user_id=user_id)
return assistant_response
이 코드의 흐름을 시각화하면:
핵심 패턴: 검색(Retrieve) → 증강(Augment) → 생성(Generate) → 저장(Store). RAG에 저장(Store) 단계가 추가된 것이다. 대화할수록 기억이 축적되며, 시간이 지날수록 AI는 사용자를 더 잘 이해하게 된다.

memory.add()가 호출되면 내부에서 일어나는 일:
text-embedding-3-large 모델로 벡터화하여 벡터 DB에 저장 (1,536차원).memory.search()가 호출되면:
이 하이브리드 검색이 Mem0의 핵심 강점이다. 벡터 검색은 의미적으로 관련된 기억을, 그래프 검색은 구조적으로 연결된 기억을 가져온다. 둘을 합치면 단일 방식보다 훨씬 정확한 기억 검색이 가능하다.
# 각 사용자의 기억은 완전히 분리
memory.add(messages, user_id="alice") # Alice의 기억
memory.add(messages, user_id="bob") # Bob의 기억
# 검색도 사용자별로 격리
memory.search("영화 추천", user_id="alice") # Alice의 기억에서만 검색
user_id를 통해 사용자별 기억이 완전히 격리된다. 이것은 멀티테넌트 환경에서 필수적이다 — Alice의 취향이 Bob의 검색 결과에 나타나서는 안 된다.
벡터 메모리만으로 충분한 경우도 있다. 하지만 관계가 중요한 순간에는 그래프 메모리가 빛난다.
| 시나리오 | 벡터 메모리만 | 벡터 + 그래프 메모리 |
|---|---|---|
| "사용자가 좋아하는 장르는?" | ✅ 유사도로 찾을 수 있음 | ✅ 관계로 정확히 찾음 |
| "사용자가 싫어하는 것은?" | ⚠️ "좋아한다" 기억과 혼동 가능 | ✅ "싫어한다" 관계를 명확히 구분 |
| "사용자 A와 B의 공통 취향은?" | ❌ 두 사용자 기억을 교차 검색 어려움 | ✅ 그래프에서 공통 노드 탐색 |
| "이 사용자의 아내 이름은?" | ⚠️ 맥락 따라 불안정 | ✅ (사용자) → [배우자] → (수진) |
| "인터스텔라를 좋아하는 사용자는 누구?" | ⚠️ 모든 사용자 기억 전수 검색 | ✅ (인터스텔라) ← [좋아한다] 역방향 탐색 |
특히 부정(negation)의 처리에서 차이가 크다:

가장 직접적인 적용. 사용자의 선호도, 습관, 일정을 기억하여:
학생의 학습 이력과 약점을 기억:
여러 AI 에이전트가 하나의 Mem0 인스턴스를 공유 메모리로 사용:
영화 에이전트가 알아낸 "이 사용자는 SF를 좋아한다"는 정보가, 음식 추천 에이전트에서 "SF 영화관 근처 맛집"을 추천하는 데 활용될 수 있다.
| Mem0 | MemGPT/Letta | Zep | Cognee | |||||
|---|---|---|---|---|---|---|---|---|
| 핵심 메타포 | 메모리 레이어 | OS 가상 메모리 | 대화 기억 서버 | 인지 엔진 | ||||
| 메모리 형태 | 벡터 + 그래프 | 컨텍스트 계층 | 시간적 기억 | 지식 그래프 | ||||
| 입력 소스 | 대화 메시지 | 대화 메시지 | 대화 메시지 | 문서, 텍스트 | ||||
| 그래프 지원 | ✅ Kuzu, Neo4j | ❌ | ⚠️ 내부적 | ✅ Kuzu, Neo4j | ||||
| 사용자별 격리 | ✅ user_id | ✅ agent별 | ✅ user/session | ⚠️ dataset별 | ||||
| 시간 인식 | ⚠️ 제한적 | ❌ | ✅ 강력 | ❌ | ||||
| 설치 난이도 | 낮음 | 중간 | 중간 (서버) | 낮음 | ||||
| 최적 사용처 | 대화형 개인화 AI | 장기 에이전트 | 시간 순서 중요한 대화 | 문서 지식 구조화 |
pip install "mem0ai[graph]"
이 한 줄로 Mem0, Kuzu, 그리고 필요한 모든 의존성이 설치된다.
import os
from mem0 import Memory
os.environ["OPENAI_API_KEY"] = "your-api-key"
# 설정: 임베딩(OpenAI) + 그래프(Kuzu 인메모리)
config = {
"embedder": {
"provider": "openai",
"config": {"model": "text-embedding-3-large", "embedding_dims": 1536},
},
"graph_store": {
"provider": "kuzu",
"config": {"db": ":memory:"},
},
}
memory = Memory.from_config(config_dict=config)
# 1. 기억 저장
memory.add(
[{"role": "user", "content": "나는 SF 영화를 좋아하고 스릴러는 싫어해"}],
user_id="user_1"
)
# 2. 기억 검색
results = memory.search("영화 추천해줘", user_id="user_1")
for r in results["results"]:
print(r["memory"], r["score"])
# 3. 개인화된 대화
from openai import OpenAI
client = OpenAI()
memories = "\n".join(f"- {r['memory']}" for r in results["results"])
response = client.chat.completions.create(
model="gpt-4.1-nano-2025-04-14",
messages=[
{"role": "system", "content": f"사용자 기억:\n{memories}"},
{"role": "user", "content": "오늘 밤 영화 추천해줘"}
]
)
print(response.choices[0].message.content)
프로토타입에서 프로덕션으로 전환할 때는 Kuzu의 인메모리 모드 대신 디스크 경로를 지정하거나, Neo4j로 교체하면 된다:
# 디스크 영구 저장
config["graph_store"]["config"]["db"] = "./production_memory"
# 또는 Neo4j로 전환
config["graph_store"] = {
"provider": "neo4j",
"config": {
"url": "bolt://localhost:7687",
"username": "neo4j",
"password": "password"
}
}
2026년, AI의 가장 큰 변화는 개인화다. 모든 사용자에게 같은 응답을 하는 범용 AI에서, 각 사용자를 기억하고 이해하는 개인 AI로의 전환.
AI가 사용자를 기억한다는 것은 개인정보 보호의 문제이기도 하다. Mem0 + Kuzu의 조합이 특히 주목받는 이유 중 하나:
user_id로 기억이 완전히 분리된다클라우드 기반 메모리와 달리, Kuzu를 사용하면 기억이 사용자의 디바이스에서 벗어나지 않는 구조를 만들 수 있다. 이것은 GDPR이나 개인정보보호법 관점에서 큰 장점이다.
2026년 AI 에이전트 시대에, 메모리는 에이전트의 핵심 인프라가 된다:
Mem0는 이러한 에이전트 메모리를 위한 표준적인 인프라 레이어로 자리잡아가고 있다.
"분명히 말했는데, 왜 또 물어보는 거야?" — 이 불만은 AI 사용자의 가장 흔한 불편함이다. Mem0 + Kuzu는 이 문제에 대한 가장 실용적인 답을 제공한다.
기억하지 못하는 AI는 도구에 불과하다. 기억하는 AI는 파트너가 된다.