コンテンツにスキップ

エージェントメモリ

メモリを使うと、今後のサンドボックスエージェントの実行で過去の実行から学んだことを活用できます。これは、メッセージ履歴を保存する SDK の会話用のセッションメモリとは別のものです。メモリは過去の実行から得た教訓をサンドボックスのワークスペース内のファイルにまとめます。そのため、生成されたメモリアーティファクトは保持データとして扱い、ワークスペースに適用しているものと同じ機密性ポリシーと保持ポリシーを適用してください。

メモリは、今後の実行で次の 3 種類のコストを削減できます。

  1. エージェントのコスト:エージェントがワークフローを完了するまでに長い時間がかかった場合でも、次回の実行では探索が少なくて済むはずです。これにより、トークン使用量と完了までの時間を削減できます。
  2. ユーザーのコスト:ユーザーがエージェントを訂正したり、好みを伝えたりした場合、今後の実行でそのフィードバックを記憶しておけます。これにより、人間の介入を減らせます。
  3. コンテキストのコスト:エージェントが以前に完了したタスクをユーザーが発展させたい場合、以前のスレッドを探したり、コンテキストをすべて入力し直したりする必要がなくなります。これにより、タスクの説明を短くできます。

サンドボックスエージェントに機能として memory() を追加します。

メモリの有効化
import {
filesystem,
Manifest,
memory,
SandboxAgent,
shell,
} from '@openai/agents/sandbox';
const manifest = new Manifest({
entries: {
'README.md': {
type: 'file',
content: '# Memory demo\n\nA workspace for follow-up runs.\n',
},
},
});
const agent = new SandboxAgent({
name: 'Memory-enabled reviewer',
model: 'gpt-5.6-sol',
instructions:
'Inspect the workspace, verify important claims, and preserve useful lessons for follow-up runs.',
defaultManifest: manifest,
capabilities: [filesystem(), shell(), memory()],
});

読み取りが有効な場合、memory() には shell() が必要です。これにより、挿入された要約だけでは不十分なときに、エージェントがメモリファイルを読み取ったり検索したりできます。デフォルトで有効になっているメモリのライブ更新を使用する場合は、filesystem() も必要です。これにより、エージェントが古いメモリを見つけた場合や、ユーザーからメモリの更新を求められた場合に、memories/MEMORY.md を更新できます。

デフォルトでは、メモリアーティファクトはサンドボックスのワークスペース内の memories/ に保存されます。後の実行で再利用するには、同じ稼働中のサンドボックスセッションを維持するか、永続化されたセッション状態またはスナップショットから再開することで、設定で指定したメモリディレクトリ全体を保持して再利用してください。新しい空のサンドボックスは、メモリが空の状態で開始されます。

memory() は、メモリの読み取りと生成の両方を有効にします。メモリを読み取る必要はあるものの、新しいメモリを生成すべきではないエージェントには、memory({ generate: false }) を使用してください。たとえば、実行しても有用な情報があまり増えない内部エージェント、サブエージェント、チェッカー、単発のツールエージェントなどが該当します。後で使うメモリを生成する必要はあるものの、ユーザーが既存のメモリの影響を受けずに実行したい場合は、memory({ read: null }) を使用してください。

読み取り専用メモリの設定
import { memory } from '@openai/agents/sandbox';
const readOnlyMemory = memory({
read: { liveUpdate: false },
generate: false,
});

メモリの読み取りでは、情報を段階的に開示します。実行の開始時に、SDK は一般的に役立つヒント、ユーザーの好み、利用可能なメモリをまとめた短い要約(memory_summary.md)を、エージェントの開発者プロンプトに挿入します。これにより、過去の作業が関連するかどうかを判断するのに十分なコンテキストがエージェントに提供されます。

過去の作業が関連しそうな場合、エージェントは現在のタスクのキーワードを使って、設定されたメモリインデックス(memoriesDir 配下の MEMORY.md)を検索します。タスクにさらに詳細な情報が必要な場合にのみ、設定された rollout_summaries/ ディレクトリ配下にある、対応する過去のロールアウトの要約を開きます。

メモリは古くなることがあります。エージェントには、メモリはあくまで参考として扱い、現在の環境を信頼するよう指示されています。デフォルトでは、メモリの読み取りで liveUpdate が有効になっているため、エージェントが古いメモリを見つけた場合、同じ実行中に設定された MEMORY.md を更新できます。実行時のレイテンシーが重要な場合など、メモリを読み取る必要はあるものの、実行中に変更すべきではない場合は、ライブ更新を無効にしてください。

実行が終了すると、サンドボックスのランタイムはその実行セグメントを会話ファイルに追記します。蓄積された会話ファイルは、サンドボックスセッションが閉じられたときに処理されます。これらの会話ファイルには、ユーザー入力、アシスタントやツールのアイテム、中断、最終出力が含まれる場合があるため、機密性の高いワークロードには適切なメモリストアと保持ポリシーを使用してください。

メモリの生成には 2 つのフェーズがあります。

  1. フェーズ 1:会話の抽出。メモリ生成モデルが、蓄積された会話ファイルを 1 つ処理し、会話の要約を生成します。システム、開発者、推論のコンテンツは省略されます。会話が長すぎる場合は、冒頭と末尾を保持しながら、コンテキストウィンドウに収まるように切り詰められます。また、元となるメモリの抽出結果も生成します。これは、フェーズ 2 で統合できる、会話から得た簡潔なメモです。
  2. フェーズ 2:レイアウトの統合。統合エージェントが 1 つのメモリレイアウトの元のメモリを読み取り、さらに根拠が必要な場合は会話の要約を開き、パターンを抽出して MEMORY.md と memory_summary.md にまとめます。

デフォルトのワークスペースのレイアウトは次のとおりです。

workspace/
├── sessions/
│ └── <rollout-id>.jsonl
└── memories/
├── memory_summary.md
├── MEMORY.md
├── raw_memories.md
├── raw_memories/
└── rollout_summaries/

memory({ generate: ... }) でメモリの生成を設定できます。

メモリ生成の設定
import { memory } from '@openai/agents/sandbox';
const memoryCapability = memory({
generate: {
maxRawMemoriesForConsolidation: 128,
phaseOneModel: 'gpt-5.4-mini',
phaseTwoModel: 'gpt-5.4',
extraPrompt:
'Prioritize workflow corrections, verification commands, and user preferences.',
},
});

extraPrompt を使用して、ユースケースで最も重要な情報をメモリ生成モデルに伝えてください。たとえば、GTM エージェントなら顧客や企業の詳細情報です。

最近の元のメモリの数が maxRawMemoriesForConsolidation を超えた場合、フェーズ 2 は最新の会話から得たメモリのみを保持し、古いものを削除します。新しさは、会話が最後に更新された時刻に基づきます。この忘却の仕組みにより、メモリに最新の環境を反映しやすくなります。

マルチターンのサンドボックスチャットでは、通常の SDK の Session と、同じ稼働中のサンドボックスセッションを組み合わせて使用します。

1 つの SDK セッションと 1 つのサンドボックスセッションの使用
import { MemorySession, run } from '@openai/agents';
import {
filesystem,
Manifest,
memory,
SandboxAgent,
shell,
} from '@openai/agents/sandbox';
import { UnixLocalSandboxClient } from '@openai/agents/sandbox/local';
const manifest = new Manifest();
const agent = new SandboxAgent({
name: 'Memory-enabled reviewer',
model: 'gpt-5.6-sol',
instructions: 'Inspect the workspace before answering.',
capabilities: [filesystem(), shell(), memory()],
});
const conversation = new MemorySession({ sessionId: 'workspace-review' });
const sandbox = await new UnixLocalSandboxClient().create({ manifest });
try {
await run(agent, 'Analyze data/leads.csv.', {
session: conversation,
sandbox: { session: sandbox },
});
await run(agent, 'Write a follow-up recommendation.', {
session: conversation,
sandbox: { session: sandbox },
});
} finally {
await sandbox.close?.();
}

どちらの実行も同じ SDK の会話セッションを渡しており、同じセッション ID を共有するため、1 つのメモリ用の会話ファイルに追記されます。これは、稼働中のワークスペースを識別するサンドボックスの ID とは異なります。サンドボックスの ID は、メモリの会話 ID としては使用されません。フェーズ 1 は、サンドボックスセッションが閉じられたときに蓄積された会話を参照するため、分離された 2 つのターンではなく、やり取り全体からメモリを抽出できます。

複数の run(...) 呼び出しを 1 つのメモリ用の会話にまとめたい場合は、それらの呼び出しで共通の固定識別子を渡してください。メモリが実行を会話に関連付ける際、識別子は次の順序で決定されます。

  1. run(...) に conversationId を渡した場合は、その値
  2. SDK の Session を渡した場合は、SDK の session の ID
  3. 上記のいずれもない場合は、groupId
  4. 固定識別子がない場合は、実行ごとに生成される ID

レイアウトによるエージェントごとのメモリの分離

Section titled “レイアウトによるエージェントごとのメモリの分離”

メモリの分離は、エージェント名ではなく MemoryLayoutConfig に基づきます。同じレイアウトと同じメモリの会話 ID を持つエージェントは、1 つのメモリ用の会話と 1 つの統合されたメモリを共有します。異なるレイアウトを持つエージェントは、同じサンドボックスのワークスペースを共有していても、ロールアウトファイル、元のメモリ、MEMORY.md、memory_summary.md をそれぞれ別に保持します。

複数のエージェントが 1 つのサンドボックスを共有していても、メモリは共有すべきではない場合は、別々のレイアウトを使用してください。

別々のメモリレイアウトの使用
import { memory } from '@openai/agents/sandbox';
const engineeringMemory = memory({
layout: {
memoriesDir: 'memories/engineering',
sessionsDir: 'sessions/engineering',
},
});
const financeMemory = memory({
layout: {
memoriesDir: 'memories/finance',
sessionsDir: 'sessions/finance',
},
});

これにより、あるドメインの分析が別のドメインのメモリに統合されることを防ぎ、その逆も防げます。