coredot.today
기술 탐색으로 돌아가기
에이전트 기억성장

Graphiti

사실마다 유효기간을 적는 시간 지식 그래프 — 에이전트 기억이 '옛 사실'과 '지금 사실'을 구분하게 한다

직접 해보기 6라이브 실행실측빠른 시작
종류
오픈소스
라이선스
Apache-2.0
언어
Python
사실 확인
2026.10.24
pip install graphiti-core

TRY IT

직접 해보기

OVERVIEW

개요

무엇인가

Graphiti는 Zep이 만든 시간 인식 지식 그래프 엔진입니다. 대화·문서 같은 '에피소드'를 넣으면 언어 모델이 사람·대상(노드)과 그 사이의 사실(간선)을 뽑아 그래프에 쌓습니다. 다른 그래프 RAG와 다른 점은 사실마다 유효기간이 붙는다는 것입니다.

"판교에 산다"는 사실이 있고 두 달 뒤 "서초로 이사했다"는 말이 들어오면, Graphiti는 앞 사실을 지우지 않고 닫습니다(invalid_at). 그래서 "지금 어디 사나"와 "4월에는 어디 살았나"에 모두 답할 수 있습니다.

어떻게 동작하나

1. 에피소드 수집
대화 한 턴이나 문서 한 조각을 넣는다. 언어 모델 호출이 여러 번 일어난다(개체 추출, 중복 정리, 사실 추출, 날짜 판정, 모순 판정, 요약 갱신).
2. 두 개의 시계
사실이 세상에서 참이었던 기간(valid_at·invalid_at)과 시스템이 알게 된·폐기한 시각(created_at·expired_at)을 따로 적는다 — 이중 시간(bitemporal) 모델.
3. 무효화
새 사실이 기존 사실과 충돌하면 "나중에 시작된 사실이 이긴다" 규칙으로 앞 사실을 닫는다.
4. 하이브리드 검색
임베딩 유사도 + BM25 키워드 + 그래프 거리를 합쳐 순위를 매긴다. 질의 시점에 언어 모델 요약을 다시 만들지 않아 검색이 빠르다.

저장소는 Neo4j가 기본이고 FalkorDB·Amazon Neptune도 지원합니다(Kuzu 드라이버는 2026-10 README 기준 폐기 예정). MCP 서버가 함께 들어 있어 Claude·Cursor 같은 에이전트에 바로 붙일 수 있습니다.

빠른 시작

bash
pip install graphiti-core
# Neo4j를 로컬에 띄운다
docker run -d -p 7474:7474 -p 7687:7687 -e NEO4J_AUTH=neo4j/password neo4j:5.26
python
import asyncio
from datetime import datetime, timezone
from graphiti_core import Graphiti
from graphiti_core.nodes import EpisodeType

async def main():
    g = Graphiti("bolt://localhost:7687", "neo4j", "password")
    await g.build_indices_and_constraints()

    await g.add_episode(
        name="상담-0302",
        episode_body="고객: 저 이번에 판교로 이사했어요.",
        source=EpisodeType.message,
        source_description="상담 로그",
        reference_time=datetime(2026, 3, 2, tzinfo=timezone.utc),
    )
    await g.add_episode(
        name="상담-0510",
        episode_body="고객: 회사가 강남으로 옮겨서 서초로 다시 이사했습니다.",
        source=EpisodeType.message,
        source_description="상담 로그",
        reference_time=datetime(2026, 5, 10, tzinfo=timezone.utc),
    )

    for edge in await g.search("고객은 어디에 사나?"):
        print(edge.fact, edge.valid_at, edge.invalid_at)

asyncio.run(main())

기본 설정은 OpenAI 키(OPENAI_API_KEY)를 씁니다. 구조화 출력을 지원하는 모델을 쓰라고 README가 강조합니다 — 작은 모델은 출력 형식이 틀려 수집이 실패하는 일이 잦습니다.

코어닷투데이 실측

graphiti-core 0.30.2에 한국어 상담 로그 240건을 넣고 옛 사실이 제대로 닫히는지 쟀습니다(Neo4j 5.26, 임베딩 bge-m3).

측정기본 설정바꾼 설정
잘못 닫힌 사실 (판정 모델)15~28% (gpt-4.1-nano)0% (gpt-4.1-mini)
바뀐 사실을 못 닫음37~42%모델을 바꿔도 남음
한국어 키워드 검색 적중23.7% (기본 BM25 분석기)58.8% (cjk 분석기)
한국어로 저장된 사실30% 미만 (gpt-4.1-mini)100% (gpt-5.5, 비용 12배)

모순·날짜 판정은 기본으로 작은 모델(small_model)이 맡습니다. 한국어 데이터라면 판정 모델과 전문 검색 분석기부터 바꾸는 것이 가장 효과가 큽니다. 실험 전 과정은 아래 관련 글에 있습니다.

언제 쓰고, 언제 피하나

  • 잘 맞는다: 사용자 정보가 시간에 따라 바뀌는 상담·CRM 에이전트, "그때는 무엇이 참이었나"를 물어야 하는 감사·규정 업무, 여러 출처의 사실을 엮어야 하는 기억.
  • 다른 방법을 먼저 본다: 기억이 짧고 대화가 단순하다면 원문을 파일로 쌓고 검색하는 편이 더 정확했다(코어닷투데이 실측에서 원문 파일 95% 대 그래프 81%). 수집 한 건마다 LLM 호출이 여러 번 들어가 비용·지연이 크다.

한계와 주의

  • 미래형 표현을 거르는 정규식이 영어 전용이다. 한국어 "다음 달에 이사할 거예요"가 현재 사실로 들어갈 수 있다.
  • 무효화 후보를 찾을 때 그룹 전체를 뒤진다(이슈 #1728). 관련 수정 PR은 2026-10 기준 병합되지 않았다.
  • 날짜 하나만 바꿔 넣어도 기억이 바뀐다 — 출처를 확인하지 않는 수집은 기억 오염에 취약하다.
  • Zep 논문은 arXiv 2501.13956이다. 2504.03182는 이름이 비슷한 다른 논문(Cypher↔SQL 동치 검증)이니 혼동하지 않는다.

LIVE

라이브 실행

대화에서 시간 붙은 사실 뽑기

Graphiti·이중 시간 테이블이 다루는 문제를 손으로 해 봅니다. 대화 기록에서 사실을 뽑고, 언제부터 참이었는지와 나중 발언으로 무효가 된 사실을 표시합니다.

콘솔에서 키 발급받기

키는 이 브라우저에서 core.today 게이트웨이로만 전송되고 코어닷투데이 서버를 거치지 않습니다. 실행 비용은 키 주인의 크레딧에서 차감됩니다.

예시 입력
모델에게 보내는 시스템 프롬프트 보기
대화 기록에서 사람·대상에 관한 사실을 추출해 시간 그래프의 간선처럼 만든다.
각 사실: 주어, 관계, 대상, valid_from(언제부터 참인지, 모르면 null), invalidated_by(이 사실을 무효로 만든 나중 사실의 번호, 없으면 null).
나중 발언이 앞의 사실과 충돌하면 앞 사실을 지우지 말고 invalidated_by로 닫는다.
JSON 하나만 출력한다: {"facts": [{"id": 1, "subject": ..., "relation": ..., "object": ..., "valid_from": ..., "invalidated_by": ...}]}

134 / 1,500자 · 모델 gpt-5.6-luna · 출력 최대 700 토큰

DEEP DIVE

더 깊이 읽기