MastraによるAIエージェントの”メモリ”について
こんにちは。AI ShiftでWebフロントエンジニアをしている安井です。今回はMastraのメモリに焦点を当てて解説をしていきます。
はじめに
MastraはTypeScriptでAIエージェントを構築するためのフレームワークです。エージェント、ワークフロー、RAG、評価といった主要機能だけでなく、直感的にデバッグ可能なplayground uiや運用を見据えたOpsの機能なども豊富に備わっています。
また本記事は2025/05時点での内容に基づいています。
コンテキストウィンドウ
メモリは、エージェントが会話の文脈を把握するために重要な情報を整理・保持する仕組みです。これは、すべてのチャットメッセージを圧縮し、言語モデルが任意の時点で見ることができる情報の総量(コンテキストウィンドウ)を効率的に管理します。
Mastraではこのコンテキストは大きく3つに分類されます。
1. メッセージ履歴
MastraでMemoryを使用する方法は、Agent ClassにMemory Classのインスタンスを接続するだけです。会話の履歴を永続化したい場合は、UpstashやPostgresなどのStorageアダプターと接続する必要があり、デフォルトではLibSQLStoreを使用するためサーバープロセスが再起動すると履歴が消えてしまいます。
export const myMemoryAgent = new Agent({
name: "MemoryAgent",
instructions: "...",
model: openai("gpt-4o"),
memory: new Memory(),
});
また、デフォルトでMemoryインスタンスは現在のスレッドから最新40件のメッセージを各新規リクエストに含めます。
2. セマンティックリコール
次にセマンティックリコールです。先ほどのメッセージ履歴はデフォルトで最新40件のメッセージに絞ってリクエストに含めることで、直近の文脈に基づいた応答を可能にしていました。
しかし、デフォルトでは40件を超える過去のメッセージはリクエストに含まれないため、以前の会話内容が参照されず、文脈が途切れてしまうことがあります。
セマンティックリコールは、そうした制約を補うための仕組みです。
https://mastra.ai/image/semantic-recall.png
セマンティックリコールはベクトルベースの検索手法で、過去の会話が直近の履歴に含まれていなくても、エージェントが長期的な文脈を維持できるようにします。
const agent = new Agent({
memory: new Memory({
options: {
semanticRecall: {
topK: 3, // 最も類似した3つのメッセージを取得
messageRange: 2, // 各一致の前後2つのメッセージを含める
},
},
}),
});
設定方法は先ほどのMemory ClassのoptionsにsemanticRecallを追加し、topK(意味的に類似したメッセージを何件取得するか)とmessageRange(各一致に対してどれだけの周囲のコンテキストを含めるか)の値を設定します。
3. ワーキングメモリ
そして最後がワーキングメモリです。
ワーキングメモリは、エージェントがスレッド全体を通じてユーザーに関する重要な情報を保持し、常に利用可能な状態にしておく仕組みです。これはエージェントの「メモ帳」のような役割を果たし、会話中に人が相手の名前や好みを覚えておくことに似ています。
また、ワーキングメモリの挙動は公式ドキュメント内にあるデモ動画を見ていただくと直感的に理解ができます。
ワーキングメモリを使用するにはMemory ClassのoptionでworkingMemoryを有効化し、管理したい内容をtemplateとして設定します。
const memory = new Memory({
options: {
workingMemory: {
enabled: true,
use: "tool-call",
template: `
# User Profile
## Personal Info
- Name:
- Location:
- Timezone:
`,
},
},
});
*注意: workingMemory optionのuse
にはtool-call
とtext-stream
の二つが設定可能です。デフォルトはtext-stream
ですが、今後のbreaking changeで選択肢がtool-call
のみに限定される予定のため、本記事ではtool-call
を前提にして解説します。
ワーキングメモリのtemplate設計
ワーキングメモリに設定するtemplateは以下の内容に気をつける必要があります。
-
短く、焦点を絞ったラベル付け
- 段落や非常に長い見出しは避け、
## Personal Info
のように簡潔にする
- 段落や非常に長い見出しは避け、
-
一貫した大文字小文字の使用
- 大文字小文字の不一致は更新を乱雑にする可能性がある
-
プレースホルダーテキストはシンプルに設定
-
[Date]
などのヒントを使用して、LLMが正しい場所に入力できるようにする
-
これらの内容は要約するとわかりやすく、シンプルにtemplateを設計する必要があるというものです。
それに加えて、更新ルールをinstructionsで言及することも必要です。毎回ワーキングメモリを更新してほしいのか、特定の条件下でのみ更新してほしいのかなどを制御することができます。
ワーキングメモリの内部実装
これまででMastraのメモリには3つのコンテキストウィンドウ(メッセージ履歴、セマンティックリコール、ワーキングメモリ)があり、それぞれの特徴が何であるかを整理しました。
メッセージ履歴は過去コンテキストを最新何件まで使用するかを調整するもので、セマンティックリコールはメッセージ履歴に入りきらない過去の会話から意味的に関連するメッセージを検索し現在のリクエストに組み込むものでした。
これら二つは直感的に理解しやすいかと思います。しかし、ワーキングメモリが内部でどのように実現されているのか不透明な点があると考え、本章ではMastraがどのようにワーキングメモリを実装しているのか見ていきたいと思います。
MastraのMemoryに関する実装はpackages/memoryの中に配置されています。
ツールとしてワーキングメモリの更新を実装する
src/tools/working-memory.ts
の中にupdateWorkingMemoryTool
というツールが実装されていることがわかります。
このツールの役割を整理すると以下の内容で構成されています。
- description(ツールの役割)
- Update the working memory with new information
- 訳)ワーキングメモリを新しい情報で更新する
- parameters(ツールの引数)
- memory
- The Markdown-formatted working memory content to store
- 訳)保存するMarkdown形式のワーキングメモリの内容
- memory
- execute(実行内容)
- 指定されたスレッドIDのメタデータに更新するワーキングメモリの情報を保存
エージェントのツールにupdateWorkingMemoryToolを拡張する
ここで用意されたupdateWorkingMemoryToolですが、ツールが作成されただけではワーキングメモリを更新することはできないため、エージェントがこのツールを使用できるように拡張する必要があります。
updateWorkingMemoryToolはMemory ClassのgetToolsメソッドで設定されており、workingMemory optionがenabledかつtool-call
が設定されている状況で有効になります。
そしてこのMemoryのツールとユーザが独自に定義したツールなどをMergeする形でAgent Classを拡張することでエージェントのツールの選択肢にワーキングメモリの更新が拡張されます。
改めて、なぜワーキングメモリの更新ルールをinstructionsで言及する必要があるのか
先ほどワーキングメモリのtemplate設計の項目で更新ルールをinstructionsで言及することが必要であると解説しました。その理由もワーキングメモリの内部実装を踏まえると理解できます。
ワーキングメモリの更新(updateWorkingMemoryTool)はAgent Classが使用するツールの1つとして拡張されていました。そしてエージェントがどのようにツールを選択するかはユーザからのリクエストとinstructionsによって影響を受けます。
これらを踏まえるとワーキングメモリを使用する際に重要な点として、templateをシンプルに設計するだけでなく、instructionsでその更新タイミングと振る舞いを制御することがいかに重要かがわかると思います。
まとめ
今回はMastraにおけるメモリの特徴として3つのコンテキストウィンドウ(メッセージ履歴、セマンティックリコール、ワーキングメモリ)を紹介しました。
その中でも内部の実装がブラックボックス化していたワーキングメモリに焦点を当てて、実装を解説しその上でどのように扱うべきかを整理しました。
エージェントにおけるメモリの扱いはユーザが期待する振る舞いを実現する上でも重要な要素の1つになります。
最後に
AI Shiftではエンジニアの採用に力を入れています!
少しでも興味を持っていただけましたら、カジュアル面談でお話しませんか?
(オンライン・19時以降の面談も可能です!)
【面談フォームはこちら】
Discussion