In Silico

AIエージェント

AIエージェントの長期記憶の仕組み:mem0とZep(graphiti)比較

2026/9/12 (更新: 2026/10/11)

  • AIエージェントの長期記憶
  • 長期記憶
  • LLM
  • mem0
  • graphiti
  • Zep
  • 有効期間
  • 矛盾
  • valid_at
  • invalid_at
  • 時間軸
  • 取り込み
  • 抽出プロンプト
  • ベクトルストア
  • 埋め込み
  • エッジ
  • エンティティ
  • LOCOMO
  • LongMemEval
  • MemGPT
  • A-Mem
  • LangMem
  • ChatGPT
  • 時間推論
  • データモデル
  • 追加専用
  • 重複
  • 無効化
目次
背景・問い・要点
背景

エージェントに長期記憶を持たせると、すぐに一つの困りごとに当たる。利用者が先週「担当はAです」と言い、今週「Bに交代しました」と言ったとする。記憶が両方を貯めていれば、エージェントは次の会話でどちらを信じるかを決めなければならない。古いほうを消していれば、「いつまでAだったか」には二度と答えられない。矛盾した事実をどう扱うかは、記憶を持たせた瞬間に必ず発生し、避ける方法はない。

この仕事を、記憶に書き込むときに済ませるか、記憶を読むたびにやり直すか。どの実装もどちらかを選んでいるが、機能の一覧に「矛盾を解決する」と書いてあっても、いつ誰が解いているかまでは書いていない。

見るべき場所は一つで、記憶の一件が何であるかというデータモデルである。その形が、矛盾を書き込むときに解けるか、解くなら何を失うかを分けている。一件が自然言語の文なのか、二つのエンティティをつなぐエッジなのか、有効期間の欄を持つのか。

本稿は、記憶の一件を文に取るmem0と、エッジに取るgraphitiという、オープンソースの二つの実装を例に取る。二つは記憶の単位の取り方がはっきり違う。どちらの作り手も設計の考え方を論文とREADMEに書いているので、読者は原典に当たって中身を検算できる。

問い

記憶の一件に何を持たせるかで、矛盾を解く仕事はどこへ行くのか。

要点

記憶の一件が何を持つかが、書き込みで矛盾を解くときに何を失うかを決める。文だけを単位にすると、書き込みで解くには古い文を消すか書き換えるしかなく、古い時点を残すかは書き換えるLLMの判断に任される。消さなければ、読む側が読むたびに矛盾を解く。有効期間の欄を持たせると、消さずに書き込む側で解ける。 どちらが良いかは、「過去の時点で何が真だったか」を問う用途があるかと、今の状態を読む側に毎回解かせてよいかで決まる。

モデル・例示

担当の交代を、三つの記憶の持たせ方で書き込む

※ この節の数値は説明のための仮定で、測定値ではありません。

利用者が9月1日に「担当はAです」と言い、9月15日に「Bに交代しました」と言ったとする。この二つの発言を三つの持たせ方で記憶に書き込み、「今の担当は誰か」と「9月10日の担当は誰か」の二つを問う。

一つ目は、文だけを貯めて何も消さない持たせ方である。記憶には「9月1日、担当はA」と「9月15日、担当はBに交代」の二文が残る。二つの問いに答えるには、読む側が両方の文を引き、文中の日付を比べる。片方を引き損ねると、答えを誤る。

二つ目は、文だけを貯め、矛盾した古い文を書き込みのときに消す持たせ方である。記憶には「9月15日、担当はBに交代」だけが残る。「今の担当」には日付を比べずに答えられるが、「9月10日の担当」にはもう答えられない。古い文を消さずに「9月15日まで担当はA、以後はB」と書き換え、二つの時点を一文に収める道もある。そうするかどうかは、書き込むLLMの判断に任される。

三つ目は、一件に有効期間の欄を持たせる持たせ方である。書き込みのときに、Aの件には「9月1日から9月15日まで」、Bの件には「9月15日から」と欄を埋める。古い件は消えず、二つの問いはどちらも欄を引けば答えが出る。その代わり、書き込むたびに新旧を見比べて欄を埋める仕事が要る。

三つを比べると、次のことが分かる。文だけの記憶で矛盾を書き込みのときに解くと、古い文を消せば過去の時点を問う材料を失い、書き換えれば古い時点が残るかどうかは書き込むLLM次第になる。解かなければ、読むたびに読む側が解き直す。有効期間の欄を持たせると、古い件を残したまま書き込みのときに解けるが、欄を埋める仕事が書き込みに加わる。

二つの実装の立ち位置

mem0は、Mem0社が開発するオープンソースのエージェント記憶ライブラリで、GitHubのスターは6万件を超える1。graphitiは、商用のエージェント記憶サービスZepを提供する会社が公開するオープンソースのフレームワークで、スターは3万件台2。どちらも設計を説明する論文が2025年にarXivへ投稿されており、mem0の論文は査読会議ECAI 2025に採録され、Zepの論文は査読を経た掲載が確認できていないプレプリントである34。

記憶の持たせ方はこの二つの外にもあり、Mem0の論文は比較の相手に、会話の記録を全部そのまま渡す構成や、記録を切って検索で引く構成を含む六つの種類を並べる3。名前で挙がるのは、MemGPT、A-Mem、LangMem、ChatGPTのメモリ機能などである3。

成績で比べたくなるが、順位は出ない。Mem0の論文は同じLOCOMOでZepも測っているが、測ったのは片方の当事者で、対象も論文の旧構成とZepの商用版だった3。LongMemEvalの数字は両社とも公開しているが、どちらも自社のサービスを自社で測ったもので、設定も違う41。

なぜ今、記憶の単位が問われるのか

記憶を持たせるには、何を一件として貯めるかを先に決めることになる。文とエッジをそれぞれ一件に取った二つの作り手が、何を診断し、何を前提に置いたかを、作り手の言葉で追う。

貯める物の形は違うが、診断は重なる。Mem0の論文は、コンテキストウィンドウが伸びても根本の限界は「先送り」されるだけだとし、実際の会話は話題の連続性をめったに保たないと書く3。Zepの論文は、既存の検索補強が「ほぼ静的なコーパス」を相手にしてきたとし、エージェントには利用者との対話に加えて業務や世界のデータから「絶えず変わり続けるデータ」が要ると書く4。

前提の置き方はそこで分かれる。Mem0の論文は堅牢な記憶を「重要な情報を選んで貯め、関連する概念を統合し、必要なときに関連する細部を取り出す」ものと定め3、現在のREADMEは、更新も削除も無い一回のLLM呼び出しへ改めたとし、「記憶は積み上がり、何も上書きされない」と書く1。Zepの論文はグラフを「損失なく」更新し「事実と関係の時系列を、有効期間も含めて保つ」ことを狙いに置き4、graphitiのREADMEも冒頭で「事実が時間とともにどう変わるかを追跡する」と書く2。一方は何を残すかを選び、他方はいつまで真かを持つ。Mem0の側では、論文は書き込み時に矛盾を解き、今のOSSは記憶を積み上げる形へ改めたうえで、矛盾を解く仕事を読む側に任せている。

mem0のOSSの記憶は一文で、矛盾は読む側が解く

mem0の記憶一件は、「User went to Paris the week of May 15, 2023」のような、それだけで読める短い文である。埋め込みベクトルとともにベクトルストアへ一件ずつ入り、エンティティや関係といった構造は持たない1。

時点の情報は、文の中に書き込まれる。抽出プロンプトは基準日を渡し(OSSの実装では取り込み当日の日付で、会話の日付は渡せない)、「先週」のような相対表現をその日付に解決させる。理由は、「先週」のままでは半年後に役に立たないから、と書いてある1。OSSの実装には、事実が真だった期間を持つ欄が文の外に無いので、それは文の中に置くしかない。

矛盾は、取り込みでは解かれない。現在の実装は追加専用で、矛盾する文も両方残す。抽出プロンプトは矛盾する既存記憶のIDを「リンク」として返させるが、main.pyの取り込みはそのIDを保存せず、文と埋め込みだけを入れる1。プロンプトの方針は「迷ったら抽出せよ。少し冗長な記憶は、欠けた記憶よりはるかに安い」であり、機械的に弾かれるのはハッシュが一致する完全な重複だけである1。言い回しの違う同じ事実を捨てるかどうかは、プロンプトの指示を受けたLLMが判断する1。取り出しの順位も新しさを見ない。点数は意味の類似・語の一致・エンティティの一致の合計で、時間に対応する項は無い1。

つまり、ある事実の古い状態を述べた文と新しい状態を述べた文は両方残り、同時に検索結果へ入りうる。抽出プロンプトは、変化を書くときに新しい記憶へ、何が何に変わったかを収めさせる1。それでも古い状態を述べた文は日付を持たないことがあり、古い文だけを引いた読む側は、今の状態を取り違えうる。矛盾を解く仕事は消えたのではなく、読む側へ移っている。

著者らの論文は、これとは違う設計を書いていた。基本構成では、取り込みのたびに類似の記憶を引き、追加・更新・削除・何もしないの四つからLLMに選ばせ、矛盾した古い文は削除する3。同じ論文がもう一つ書いたグラフ構成は、古い関係を「時間推論を可能にするため、物理的に取り除くのではなく無効と印を付ける」3。現在のオープンソース実装はどちらの更新段も持たない1。矛盾した古い文を正しく消せば矛盾は解けるが、判定を誤れば根拠ごと失われる。追加だけなら根拠は残るが、矛盾も残る。同じ作り手が、後者へ寄せたことになる。

作り手は、本稿が読んだOSSの実装には無い時間推論の機能もブログで説明している。文を単位にしたまま、書き込み時に別の処理が各記憶へ時間の欄を付け、同じ事実の新しい状態が来ると古い記憶の終了時点を自動で埋め、何も削除しないという5。単位は文のままでも、有効期間の欄を足せば、矛盾を解く仕事は書き込み側へ移る。

graphitiの記憶はエッジで、矛盾は書き込むときに欄へ解かれる

graphitiの記憶一件は二つのエンティティをつなぐエッジで、事実の文と、Zepの論文が数える四つの時刻を持つ。valid_at(事実が真になった時点)、invalid_at(真でなくなった時点)、created_at(システムが記録した時点)、expired_at(システムが無効にした時点)である2。Zepの論文はこれを二本の時間軸と呼ぶ。世界で事実が真だった期間と、システムがそれを真だと思っていた期間を、別々に持つ4。だから、過去のある時点でシステムが何を真と記録していたか、という問いが立つ。

矛盾は取り込みで解かれる。新しい事実が来ると、似たエッジを検索で集め、LLMが一回の呼び出しで「重複」と「矛盾」に振り分ける。次に日付の比較が向きを決める。矛盾に挙がったエッジのうち、新しいエッジより前から真だったものだけを無効にし、そのinvalid_atへ新しいエッジのvalid_atを書き込む2。LLMが新旧を取り違えても、日付が正しければ向きは壊れない。

代償は二つある。一つは取り込みが重いことで、エンティティの同定も矛盾の判定も、名前や文の一致で決まらないものはLLM呼び出しへ回り、日付の解決は「軽い」LLM呼び出しで行う42。もう一つは日付への依存で、新旧どちらかのvalid_atが空なら比較が成り立たず、無効化は起きない。時間を欄に持つ設計は、欄を埋める仕事を必ず抱える。

ただし、解かれた矛盾は読む側からも見える。既定の検索は無効になったエッジも返し、各事実にvalid_atとinvalid_atを添えたうえで、「invalid_atがPresentなら有効」という規則をLLMへのコンテキスト文字列に書く2。読む側の判断が消えるのではなく、判断に使える欄が渡される。

「過去の時点で何が真だったか」を問う用途なら、時間を欄に持つ設計は欄を引くだけで答えを出す。文の集合でも文中の日付を読めば推定はできるが、mem0のOSSのように取り出しの順位が時間を見なければ、取りこぼしうる。その用途が無くても、消さずに積む文の集合では、今の状態を問う質問のたびに、読む側が新旧の文を引き当てて日付を比べる。


出典5件
  1. mem0ai/mem0(GitHub、mainを2026年9月取得). https://github.com/mem0ai/mem0 — READMEは更新も削除も無い一回の抽出を掲げ成績は管理版のものと断り、ソースは抽出時の日付解決(OSSでは取り込み当日)、保存されない矛盾リンク、時間の項が無い順位式を示す。スターは6万件超。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11

  2. getzep/graphiti(GitHub、mainを2026年9月取得). https://github.com/getzep/graphiti — Zepの論文が数えるエッジの四つの時刻、LLMが重複と矛盾に振り分けたあと日付の比較で古いエッジのinvalid_atを埋める処理、無効になったエッジも有効期間つきで返す既定の検索を示す。スターは3万件台。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  3. 「Mem0: Building Production-Ready AI Agents with Scalable Long-Term Memory」ECAI 2025. https://arxiv.org/abs/2504.19413 https://doi.org/10.3233/faia251160 — 書き込み時に追加・更新・削除・何もしないを選ぶ基本構成と、古い関係を無効と印すグラフ構成、六種類の比較相手を述べる。成績は自社測定。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8

  4. 「Zep: A Temporal Knowledge Graph Architecture for Agent Memory」arXiv:2501.13956(Zep所属の著者のプレプリント). https://arxiv.org/abs/2501.13956 — 有効期間つきで事実を損失なく更新するグラフと二本の時間軸を述べる。成績はZepのサービスの自社測定。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  5. Taranjeet Singh「Introducing Temporal Reasoning in Mem0」Mem0のブログ, 2026年5月12日. https://mem0.ai/blog/introducing-temporal-reasoning-in-mem0 — 抽出後の別処理が各記憶に時間の欄を付け、新しい状態が来ると古い記憶の終了時点を埋めて何も消さないと作り手が説明する。本稿はこの機能のコードを読んでいない。 ↩

この記事はAIを使用して執筆されました。内容には誤りが含まれる可能性があります。事実や数字の出典は脚注から確かめられます。