Fragments of verbose memory

冗長な記憶の断片 - Web技術のメモをほぼ毎日更新

Mar 10, 2026 - 日記

Graphitiとリアルタイム知識グラフ: 何を解決し、どこで効くのか

graphiti-real-time-knowledge-graph-what-it-solves cover image

Graphiti を見ていて面白かったのは、「知識グラフを使う」こと自体より、「更新し続けるデータをどう扱うか」を正面から設計している点でした。

RAG(Retrieval-Augmented Generation: 検索拡張生成)系のツールはかなり増えましたが、多くは静的な文書集合を前提にしています。そこにユーザーとの会話、状態が変わる業務データ、あとから訂正される事実が入ってくると、だんだん「検索はできるが、今どうなっているかが曖昧」という状態になりがちです。

本記事では、Graphitiがその問題をどう解こうとしているのかを整理します。あわせて、普通のベクトルRAG(embedding: テキストを数値ベクトルに変換して近い文書を探す方式)と何が違うのか、実際に試す最小コードも含めて見ていきます。

まず結論: Graphitiが解こうとしているのは「更新される知識」の扱いです

Graphitiはgetzep が公開している、AIエージェント向けのリアルタイム知識グラフ基盤です。公式READMEでは、単なるKnowledge Graphではなく、時間を持った知識グラフとして位置付けられています。

ここで言う知識グラフ(Knowledge Graph: エンティティと関係をグラフ構造で表すデータモデル)は、たとえば「Kendra が Adidas shoes を好き」という事実を、ノード(entity: 実体)とエッジ(edge: 関係)で表します。Graphitiが面白いのは、その関係があとで変わることを前提にしている点です。

普通のRAGでつらくなりやすいのは、次のようなケースです。

  • ユーザーの好みが会話中に変わる
  • チケットの状態や担当者が更新される
  • 一度正しかった事実が、あとで訂正される
  • 「今の状態」と「先週の状態」の両方を知りたい

静的文書の検索ならベクトルRAGで十分なことも多いです。しかし、状態遷移や履歴照会が必要になると、文書断片の近傍検索だけでは厳しくなります。

GraphitiはGraphRAGの言い換えではない

最近はGraphRAG (グラフ構造を使うRAGの総称)という言葉も広く使われています。ただ、Graphitiは「文書をグラフ化して要約検索を賢くする」方向より、「更新され続ける事実をグラフとして保守する」方向にかなり寄っています。

ざっくり整理すると、違いはこのあたりです。

観点一般的な静的RAG/GraphRAGGraphiti
主戦場文書集合の検索・要約動的データの継続更新
更新モデルバッチ再構築が中心エピソード単位の増分更新
履歴の扱い弱いことが多い時点指定の問い合わせを重視
矛盾の扱い要約や再埋め込みに依存関係の無効化を明示的に扱う
向いている用途FAQ、社内文書検索、要約agent memory、状態追跡、時系列知識

個人的には、Graphitiを「高機能なRAG検索器」として見るより、「エージェント向けの状態付きメモリ基盤」として見る方がしっくりきます。

いちばん効いているのは bi-temporal です

Graphitiの差別化としてよく出てくるのが、bi-temporal data model(2つの時間軸を持つデータモデル)です。これはざっくり言うと、次の2つを分けて持つ考え方です。

  • event time: その出来事が実際に起きた時刻
  • ingestion time: その出来事をシステムが取り込んだ時刻

この2つを分けると、単なる「最新情報の検索」ではなく、次のような問いに答えやすくなります。

  • 2日前の時点では、担当者は誰だったか
  • 後から訂正されたが、当時は何が正しいと見なされていたか
  • ある判断をした時点で、エージェントは何を知っていたか

この視点は、監査ログやワークフロー自動化だけでなく、長期記憶を持つAI エージェントでも地味に重要です。会話履歴を全部突っ込むだけでは、「昔そう言っていた」と「今そうである」が混ざりやすいからです。

どういうときに普通のRAGより嬉しいのか

Graphitiが効きやすいユースケースを、実務寄りに言い換えるとこうなります。

1. エージェントがユーザーや世界の状態を追い続けるとき

たとえばサポートエージェントなら、ユーザーの所属、利用中プラン、直近の障害、過去のやり取りが時間とともに変わります。

このとき必要なのは、「似た文書を取る」ことより「今の関係を取り違えない」ことです。Graphitiは、会話や構造化データをエピソード(episode: 1回の出来事や入力単位)として積み、ノード間の関係を更新していく設計なので、この用途と相性が良いです。

2. 履歴照会が要件に入るとき

「現在の契約担当者は誰か」だけでなく、「3月1日時点の契約担当者は誰だったか」を聞かれるシステムでは、要約済みメモだけだと弱いです。

Graphitiは時間を明示的に持つので、あとから説明責任が必要なユースケースで価値が出ます。

3. テキスト以外の業務データも混ぜたいとき

Graphitiは会話ログだけでなく、構造化JSONもエピソードとして取り込めます。つまり、「Slackの会話」と「CRMの顧客属性」と「チケット状態」を同じ記憶空間に寄せる方向が取りやすいです。

逆に、単にPDFやMarkdownを検索したいだけなら、ここまで重い仕組みは要らないと思います。

最小コードで触る

以下の例は、Neo4j をバックエンドにして、会話から事実を取り込み、検索する最小構成です。前提として、Python 3.10以上、Neo4j、OPENAI_API_KEY が必要です。quickstart README には Python 3.9+ とありますが、リポジトリREADMEでは 3.10+ が要件なので、ここでは 3.10+ 前提で進めます。Graphitiは構造化出力(Structured Output: モデル出力をJSONスキーマに合わせる仕組み)に強いモデルの方が安定しやすいので、その点にも注意してください。

まずはパッケージを入れます。ローカル確認だけなら、Neo4jはDocker Compose や Neo4j Desktop でも十分です。

1
pip install graphiti-core

次のコードは、Graphitiに2つのエピソードを追加し、ユーザーの好みを検索する例です。quickstartと同じく EpisodeType を使い、search() の返り値もそのまま反復する形に寄せています。やっていることは単純で、自然文からノードと関係を抽出し、あとから検索できるようにしています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import asyncio
from datetime import datetime, timezone

from graphiti_core import Graphiti
from graphiti_core.nodes import EpisodeType


async def main() -> None:
    graphiti = Graphiti(
        "bolt://localhost:7687",
        "neo4j",
        "password",
    )

    await graphiti.build_indices_and_constraints()

    await graphiti.add_episode(
        name="user-preference-1",
        episode_body="Aki likes Adidas shoes.",
        source=EpisodeType.text,
        reference_time=datetime.now(timezone.utc),
    )

    await graphiti.add_episode(
        name="user-preference-2",
        episode_body="Aki now prefers New Balance for running shoes.",
        source=EpisodeType.text,
        reference_time=datetime.now(timezone.utc),
    )

    results = await graphiti.search("What shoes does Aki prefer now?")
    for result in results:
        print(result.fact)

    await graphiti.close()


if __name__ == "__main__":
    asyncio.run(main())

確認ポイントは2つです。

  • エピソード追加後に、Neo4j側へノードと関係が作られること
  • 検索結果に、最新の好みを表す関係が返ること

実際には埋め込みモデル、再ランキング(reranking: 検索結果を再評価して並べ替える処理)、DBバックエンドを調整できます。READMEでは Neo4j のほか、FalkorDB、Kuzu、Amazon Neptune もサポートされています。

使ってみる前に知っておきたいトレードオフ

ここはかなり大事です。Graphitiは面白いですが、誰にでもそのまま勧めやすいわけではありません。

良いところ

  • 動的データを前提にした設計が明確
  • 履歴を含めた問い合わせに強い
  • ハイブリッド検索(semantic + keyword + graph traversal)を最初から想定している
  • Model Context Protocol (MCP)サーバ実装もあり、エージェント統合の絵が描きやすい

しんどいところ

  • ベクトルDBだけのRAGより構成が重い
  • グラフDB運用の知識が要る
  • 取り込み時にLLMを使うので、速度やコストはゼロではない
  • Structured Output に弱いモデルだと ingestion failure が起きやすい

READMEでも SEMAPHORE_LIMIT による並列度調整や、429 rate limit への注意が書かれています。つまり、Graphitiは「賢い検索ライブラリ」でもありますが、同時に「LLM付き ingestion pipeline」でもあります。

このため、記事検索や社内ナレッジ検索だけなら、まずは普通のRAG 基盤から始める方が素直です。一方で、ユーザー状態や関係性が更新され続けるAIアプリなら、最初からGraphiti型の設計を考えた方が後で楽になる可能性があります。

自分ならどう使い分けるか

現時点の感想としては、次のように切り分けるのが現実的です。

  • 普通のRAGで十分: 文書検索、FAQ、更新頻度が低い社内ナレッジ
  • Graphitiを検討したい: agent memory、状態遷移の追跡、履歴照会、複数データ源の統合
  • いきなり本番投入は慎重に: グラフスキーマ、更新頻度、取り込みコストの見積もりが未整理な段階

Graphitiの価値は、「グラフだから賢い」ではなく、「変わる世界を変わるまま持てる」ことにあります。この違いが必要なプロダクトなら、かなり面白い選択肢です。

まとめ

Graphitiは、リアルタイム知識グラフという言葉の見た目より、実際には「更新される知識をどう壊さず持つか」という設計に価値があるツールだと思います。

特に、長期記憶を持つLLM アプリやAIエージェントでは、「似た文を探す」だけでなく、「今どうなっていて、以前はどうだったか」を区別できることが効きます。Graphitiはそのための基盤として、かなり筋が良いです。

次に試すなら、まずはNeo4jで最小構成を立てて、1つの会話ログか業務イベントをエピソードとして流し込んでみるのがおすすめです。そこから「履歴照会が本当に必要か」「普通のRAGとの差分は何か」を確認すると、導入判断がしやすくなります。

参考リンク