MemGPT - 無限のコンテキストのための自己編集メモリを備えたLLM
(github.com/cpacker)- Lettaは、時間とともに学習し自己改善できる高度なメモリベースのAIを構築するためのプロジェクト
- 利用方法は、ローカル端末でエージェントを実行するLetta Codeと、アプリケーションにエージェントを統合するLetta APIに分かれる
- CLIは**Node.js 18+**を必要とし、
npm install -g @letta-ai/letta-codeでインストールした後、lettaを実行してローカルコンピューター上でメモリを持つエージェントを動かす - Letta Codeエージェントは、コーディングやコンピューター上で実行できる作業を支援し、skillsとsubagentsをサポートする。また、高度なメモリと継続学習のための事前構築済みskills/subagentsをバンドルしている
- Lettaはモデル非依存で、READMEでは最高性能のためにOpus 4.5とGPT-5.2を推奨し、順位の参考資料としてmodel leaderboardにリンクしている
- Letta APIは、状態を持つエージェントをアプリケーションに統合するためのもので、フル機能のagents APIとPythonおよびTypeScript SDKを提供する
- TypeScript/Node.jsパッケージ:
@letta-ai/letta-client - Pythonパッケージ:
letta-client - 例は、
LETTA_API_KEYとLetta API keyを使ってエージェントを作成し、メッセージを送信する流れ
- TypeScript/Node.jsパッケージ:
- Lettaおよび関連するLettaサービスの利用は、privacy policyとterms of serviceに同意することが条件
1件のコメント
Hacker News のコメント
MemGPT の作者です。実装に関する質問があれば答えます
実際に試してみたい場合は、MemGPT Discord サーバーの Discord ボット(https://discord.gg/9GEQrxmVyE)で、メモリ編集が動作する様子を見られます。ボットと会話すると、MemGPT がユーザーと自分自身についてのプロフィールを更新するためにメモリを修正していく過程が見えます
すべてオープンソースなので、https://github.com/cpacker/MemGPT のコードでローカル実行も可能です。リポジトリには、LlamaIndex API ドキュメントについて MemGPT と会話するドキュメント中心の例もあります
なぜすべてを単一のコンテキストウィンドウ内で処理するのか気になります。数か月前に似たものを実験したときは、前処理/後処理段階で複数のエージェントに並列化していました
たとえば、メインのコンテキストウィンドウはメモリが生成または検索されることを知らず、後処理器が会話から自動的にメモリを作って保存し、会話全体もベクトルデータベースに保存していました。前処理器は会話に合わせて関連メモリとコンテキストを自動注入し、さらには履歴を書き換えて、メインのコンテキストウィンドウから見るとそのメモリが最初から存在していたかのように見せていました
こうすると、メインのコンテキストウィンドウで不要なシステムプロンプトなどに使うスペースをかなり節約できました
暗黙的方式では、「メイン LLM」、チャットで言えば「会話スレッド」は、バックグラウンドのメモリ管理を知りません。この管理は「メモリ LLM」、ルールベースのスクリプト、小さなニューラルネットワークなどが担えます
明示的方式が MemGPT に当たり、1つの LLM がすべてを処理します。複数セッション/長距離チャットに関する既存研究は、通常は別途メモリ生成プロセスを置く暗黙的方式で、消費者向けチャットボットのメモリストアもほとんどは暗黙的である可能性が高いです
明示的メモリ管理には複雑な指示追従が必要なので、現在公開されている LLM の大半では難しいと見ています。オープンモデルのファインチューニングなどで解決する方法を検討中です
トレードオフはおっしゃる通りです。暗黙的方式では、メモリ管理の指示を LLM の事前プロンプトにすべて入れなくて済みます。MemGPT のシステムメッセージ全体は約1000トークンです。一方で明示的メモリ管理は、LLM が適切に動作すればシステム全体がはるかに単純になり、並列スレッドで複数の LLM モデルを管理するオーバーヘッドがなくなります
LLM と自然言語処理は、構造化データに対するより実現可能なインターフェースになり得ると考えています。特定のビジネス文脈でデータが生成されると、データを抽出し、埋め込みを作成し、ベクトルデータベースを構築します
後処理では、メインモデルが応答した後、後処理器が会話をもとにメモリを自動生成して保存します。重要なコンテキストを保存しつつ、この作業負荷をメインモデルに負わせません。リクエストの一部として関連するビジネスロジックも実行し、その後システムにフィードバックします
前処理では、新しい入力をメインモデルに送る前に保存済みメモリを確認し、関連コンテキストを注入し、ロジックも実行します。前処理器がメインモデルに以前の会話についての「復習」を提供し、より一貫性があり情報量の多い応答の準備をさせるわけです
制限事項に書かれていた内容について、Llama 2 70B の派生モデルが関数呼び出し向けにファインチューニングされていても、誤った関数呼び出しを作ったり、提供されたスキーマ外の関数を幻覚したりするなら、文法ベースのサンプリングを使えます
少なくとも関数呼び出しが構文上正しいことは保証できます
[0] https://github.com/ggerganov/llama.cpp/tree/master/grammars
たとえば、関数呼び出しデータでファインチューニングされた大きなモデル(https://huggingface.co/jondurbin/airoboros-l2-70b-2.1#agentf...)も、概ねパース可能な JSON は出力しましたが、引数や関数名が間違っていました
データを書き込もうとするときに、事前プロンプトで明示された正しい
working_context.append呼び出しの代わりに、まったく指定されていないpersonal_diary.add呼び出しを出力する、といった具合ですタイトルだけを見て、LLM のニューラルネットワークメモリ、つまりコンテキストではなく重みレベルのメモリを会話中に変えるメモリ編集手法、たとえば ROME [1] のようなアプローチかと思いました
実際には素晴らしい RAG の取り組みだと分かってよかったです。近いうちに自分のバージョンの MemEditGPT を作るつもりです
[1] https://arxiv.org/abs/2202.05262
ご理解の通り、MemGPT は ROME のように LLM の重みを編集するものではありません。MemGPT で言う「メモリ」は重みレベルではなく、テキスト/トークンレベルです
核心となる考え方は、LLM に対して、コンテキスト内に保持される作業メモリのスクラッチパッドを編集し、関数を通じて外部コンテキストを読み書きする能力を与えることです。重要な細部は、有限のコンテキスト制限に対処するため、読み込みが常にページ単位、つまりチャンク単位で行われる点です
MemGPT は単一のユーザー入力から関数を連鎖させ、複数回繰り返して読み書きできます。そのため README の LlamaIndex API ドキュメント例のように、大きなドキュメントデータベースを検索し、複数の出典から情報を集めて回答を返すことができます
しばらくの間、ChatGPTのWeb版(chat.openai.com、APIではなく)が会話内でこのように動作しているのではないかと疑っていた。非常に長いチャット履歴でも、すべてを突然忘れるというより、徐々に品質が落ちていく感じがあった。
もちろん、自分が思っていたよりも文脈内に手がかりが多いのかもしれない。
いずれにせよ、こうしたアイデアは今後すべてのチャットボットの基本機能になる可能性が高いと思う。
損失はあり、重要な情報はいずれ失われるが、比較的なだらかに性能が低下する可能性がある。MemGPTでは、すべての明示的なメモリ管理の上に、暗黙的な再帰的要約も使っている。
少しでも興味深い作業をしたなら、出力はプロンプトに強く偏る。以前の出力/履歴という単一のサンプルしかないため、滑らかな確率分布の代わりに一部の情報を失い、複数の入力が同じ出力にマッピングされることもあるので、さらに一部の情報を失う。
しかし現実のプロンプトは、望む結果を得るために思いつく最も簡単で短い表現であることが多い。だからLLMがそのプロンプトを推定すれば、欠落した文脈に対する解釈はそれなりに当たっている可能性が高い。つまり、消えたように見える多くの情報がLLMの出力内に保持され、古い文脈が押し出されても、一度に失う情報量はそれほど大きくない。
損失のあるメモリを実装する些細な手法はたくさんある。たとえばsentence transformersが使うように、トークンを平均プーリングする方法がある。多くの文脈をプロンプトへ圧縮するのに、この方式がなぜあまり使われないのかはよく分からない。実質的に中期メモリの役割を果たす。
名前は思い出せないが、命令を不安定に実行する難解プログラミング言語がすでにある。慎重にプログラムを設計すれば、命令シーケンスを99%、99.9%といった信頼度で実行されるようにできる。
20年後、同じアプローチがインフラ分野で「カオスエンジニアリング」という名前で、皮肉ではなく普及した。
更新:MemGPT上に実装したDiscord常駐チャットボットをたった今公開した。ここで試せる:https://discord.gg/9GEQrxmVyE
GitHubのコードで、チャットボットデモと、APIドキュメントについてMemGPTに質問できるドキュメントQ&Aボットのデモもローカルで実行できる。
LLMの最大の限界は文脈ウィンドウだと思う。優れた推論能力も、実際のユースケースでは文脈ウィンドウの制限に頻繁にぶつかる。
再帰的要約は、あふれる文脈ウィンドウを扱う単純な方法だが、本質的に損失があり、最終的にはシステムメモリに大きな穴を作る、という説明には同意する。
ただしMemGPTも同じことをしており、同じ問題がある。すべてを再帰的に要約する代わりに、履歴を選択的に検索してリクエストごとに生成する点だけが少し違う。アイデアは素晴らしい。
しかし懐疑的だ。このアプローチは、既存の文脈が低エントロピーで要約可能な文脈であり、クエリが履歴の一部だけに依存する、という仮定に根本的に依存している。
チャットや「巨大な文書集合から質問に答える」といった場合には当てはまるかもしれない。だがコード生成のように、文脈が特定のAPI定義のような捨てられない情報で詰まっていて、多くのAPI定義のように広い文脈が必要な場合には、どちらの仮定も誤っている。
構造と実装は興味深く、デモも素晴らしいが、要約関連の論文がこのアプローチの根本的な限界を認めない点は残念だ。
言う通り、MemGPTの会話キューは既存研究や多くのチャットボット実装と同じく再帰的要約で管理される。しかし再帰的要約とは無関係な、読み書き可能な「固定」領域のLLMメモリもあり、論文ではこれを「作業文脈」と呼んでいる。
したがってMemGPTは、自動生成された再帰的要約と、MemGPTが能動的に最新状態に保つ作業文脈の両方にアクセスできる。
この2つは、関数呼び出しで会話キューに取り込むMemGPTの外部文脈とも別物だ。すべての例で、外部文脈の読み取りは圧縮されず、要約なしでページ単位で行われる。
キュー要約がトリガーされるとMemGPTはシステム通知を受けるので、会話キュー内の特定の詳細を保持する必要があるなら、削除または要約される前に作業文脈へ書き込める。
対話型エージェントの例では、作業文脈がユーザーとエージェントに関する重要な事実を保存し、一貫した会話を維持するために使われる。作業文脈は常にLLMから見えるので、別途検索する必要はない。
ドキュメントQ&Aでは、作業文脈が現在のタスク/質問とその進捗を追跡するために使える。複雑なクエリでは、以前の検索や以前のページリクエストといった詳細をMemGPTが追い続けるのに役立つ。