0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AI にユーザーを本当に記憶させる:FileMemoryProvider 実装の解析

0
Posted at

多くの AI アプリは記憶を持っているように見えますが、実際には履歴メッセージを繰り返し大規模モデルに渡しているだけです。同じ会話内では、モデルはそれまでのチャット内容を見ることができるため、「ユーザーを覚えている」ように見えます。しかし、新しい Session を作成して履歴メッセージを再投入しなければ、モデルはまるで初めてそのユーザーに会ったかのようになります。

実際の業務では、この種の記憶能力は通常不十分です。採用アシスタントは候補者の技術分野、勤務地、勤務形態を覚えている必要があります。ショッピングアシスタントはユーザーの好みのブランドや予算を覚えている必要があります。企業内アシスタントは、ユーザーが所属するプロジェクト、役職、働き方の習慣を覚えている必要があるかもしれません。これらの情報は、単一のチャット内にだけ存在すればよいのではなく、会話をまたいで長期的に保存できる必要があります。

Microsoft Agent Framework の FileMemoryProvider は、ファイルベースで長期記憶を実現する仕組みです。Agent が価値ある情報をファイルに書き込み、後続の新しい会話でそれらのファイルを再読み込みすることで、本当の永続化された記憶を実現できます。

FileMemoryProvider とは何か

FileMemoryProvider は本質的には AIContextProvider です。Agent にマウントされると、モデルに対して一連のファイル記憶ツールを提供し、記憶ファイルの作成、読み取り、更新、検索、一覧表示、削除を可能にします。

モデルの観点から見ると、これらのツールは通常の Function Calling ツールと本質的に変わりません。求人検索ツールは職種を検索するために使い、天気ツールは天気を問い合わせるために使い、ファイル記憶ツールはユーザーの長期情報を管理するために使います。

したがって、FileMemoryProvider は単にすべてのチャット履歴を自動保存するものではなく、Agent に「メモを取る」能力を与えるものです。いつ記録するか、何を記録するかは、通常システムプロンプトと現在の会話に基づいてモデル自身が判断します。

チャット履歴との違い

チャット履歴は、ユーザーが何を質問し、アシスタントが何を返答したかという完全な対話を保存します。この種の情報は通常、現在の Session 内でのみ使用され、主な役割は文脈の連続性を保つことです。

長期記憶は、要約・抽出されたうえで、将来も価値のある情報を保存します。たとえば、候補者が 5 年の .NET バックエンド開発経験を持ち、リモートワークを希望し、勤務地は上海寄りで、AI アプリケーション分野に関心がある、といった情報です。これらは元のチャット履歴に依存する必要はなく、Session の終了とともに消えるべきでもありません。

チャット履歴は現在の対話の一時的な作業領域、FileMemory は Agent の長期ノートブックだと考えると分かりやすいです。

記憶は最終的にどこに保存されるのか

FileMemoryProvider 自体は具体的なストレージに直接バインドされているわけではなく、AgentFileStore を通じて下層のファイルシステムにアクセスします。あなたの Demo では FileSystemAgentFileStore が使われているため、記憶はそのままローカルディスクに書き込まれます。

var memoryRoot = Path.Combine(AppContext.BaseDirectory, "agent-memory");
var fileStore = new FileSystemAgentFileStore(memoryRoot);

このコードはプログラムディレクトリの下に agent-memory フォルダを作成し、その後 Agent によって生成された記憶ファイルはすべてこのディレクトリに保存されます。

この方法はローカル開発や機能検証に非常に適しています。ファイル内容を直接開いて確認でき、デバッグも直感的です。本番環境では、他の AgentFileStore 実装に置き換えることもできます。たとえば、メモリストレージ、Azure Blob Storage、あるいは社内独自のリモートファイルサービスなどです。

したがって、FileMemory のより正確な表現は「ファイルモデルに基づく記憶」であり、単に「ローカルファイル記憶」ではありません。

WorkingFolder が記憶のスコープを決める

FileMemoryProvider を作成する際には、FileMemoryState を通じて作業ディレクトリを設定する必要があります。

using var fileMemoryProvider = new FileMemoryProvider(
    fileStore,
    _ => new FileMemoryState
    {
        WorkingFolder = workingFolder
    });

あなたの Demo では、作業ディレクトリはユーザー ID ごとに分けられています。

const string UserId = "user00001";
var workingFolder = $"users/{UserId}";

最終的なファイルは、おおむね次のパスに保存されます。

agent-memory/users/user00001

このディレクトリは非常に重要です。どの Session が同じ記憶セットを共有できるかを決めるからです。複数の Session が同じ WorkingFolder を使えば、同じファイル群にアクセスできます。Session が新規作成されたとしても、以前に保存されたユーザー情報は残っています。

毎回 Session を作成するたびに異なるフォルダを生成する場合、記憶は単一の Session 内でしか使えず、会話をまたいだ共有は実現できません。

マルチユーザーシステムでは、通常、ユーザーごとに独立したディレクトリを設定する必要があります。そうしないと、異なるユーザーの記憶が混ざってしまう可能性があります。実際のプロジェクトでは、さらにアプリケーション ID やテナント ID を加えることもできます。たとえば次のようになります。

applications/{applicationId}/tenants/{tenantId}/users/{userId}

これにより、より明確なデータ分離境界を構築できます。

Agent はどのように記憶を読み取るのか

記憶ファイルが増えてくると、毎回すべてのファイル内容を完全にモデルのコンテキストへ入れるのは適切ではありません。そうすると Token を無駄にするだけでなく、どの情報が現在の問題に本当に関連しているのかをモデルが判断しづらくなります。

FileMemoryProvider の考え方は、まず記憶ファイルのインデックスや説明を Agent に提供することです。モデルは現在の質問に基づいて、どのファイルが役に立ちそうかを判断し、その後、読み取りツールを呼び出して具体的な内容を取得します。

たとえば、ユーザーが 3 つの異なる職種のうちどれが自分に適しているかを尋ねた場合、Agent はまず既存の記憶を確認し、候補者が 5 年経験の .NET バックエンドエンジニアであり、上海での勤務を希望し、リモートワークを好み、AI アプリケーション分野に関心があることを把握できます。その後、モデルはこれらの好みをもとに職種を照合し、順位付けできます。

Demo に登場する 3 つの職種のうち、北京での出社勤務の Java エンジニアは、技術スタック、勤務地、勤務形態のいずれも候補者の希望に合いません。上海でのハイブリッド勤務の .NET エンジニアは、技術スタックと勤務地の条件は満たしますが、リモートワークや AI 分野への関心は完全には満たしません。一方、上海でリモート勤務の .NET AI アプリケーションエンジニアは、技術分野、勤務形態、勤務地、キャリア志向のすべてに合致するため、最も推奨に適しています。

この過程は、採用コンサルタントが候補者のプロフィールを参照するのによく似ています。コンサルタントは、毎回候補者のすべての求職条件を聞き直す必要はなく、職種を照合する際に、以前保存した好みを確認してから、的を絞った提案を行います。

大きなファイルについては、FileMemoryProvider は説明ファイルと組み合わせて使うこともできます。メインファイルには完全な内容を保存し、説明ファイルには短い要約だけを保存します。モデルはまず要約を見てファイルが関連するかどうかを判断し、その後で本文を読むかどうかを決めるため、不要なコンテキスト消費を減らせます。

Demo は何を検証したのか

あなたの Demo が主に検証しているのは、FileMemoryProvider の最も重要な能力です。つまり、ある Session で記憶を書き込み、別の完全に新しい Session でそれを読み続けることです。

プログラムはまずローカルファイルストレージを作成し、ユーザー UID1 に固定の作業ディレクトリを設定します。その後、FileMemoryProvider を Agent の AIContextProviders に追加します。

AIContextProviders = [fileMemoryProvider]

この手順が完了すると、採用コンサルタントはファイル記憶ツールを利用できるようになり、対話の中で候補者の求職傾向を自分で読み書きできるようになります。

最初の会話で、候補者は Agent に次のように伝えます。

「私は 5 年経験の .NET バックエンドエンジニアです。リモートワークに対応し、勤務地は上海で、AI アプリケーション分野を重視する職種を探しています。私の求職傾向を覚えておいてください。」

この一文には、長期的に有効な情報がいくつか含まれています。候補者は 5 年の .NET バックエンド開発経験を持ち、上海での勤務を希望し、リモートワークを好み、AI アプリケーション分野に関心があります。これらの好みは今後の職種推薦に継続的に影響するため、長期記憶として保存するのに適しています。

最初の会話が終わった後、プログラムはユーザーディレクトリ下のファイルを列挙します。

foreach (var file in Directory.EnumerateFiles(
    Path.Combine(memoryRoot, workingFolder)))
{
    Console.WriteLine(Path.GetFileName(file));
}

この手順により、Agent が本当にファイル書き込みツールを呼び出したかどうかを視覚的に確認できます。ディレクトリ内に新しいファイルが現れれば、「覚えた」というのがモデルの口先だけの応答ではなく、すでに永続化データとして形成されていることが分かります。

次に、プログラムはまったく新しい Session を作成します。

AgentSession secondSession = await agent.CreateSessionAsync();

この Session には、最初の会話のチャット履歴は含まれていません。その後、ユーザーは Agent に 3 つの職種を提示し、以前の求職傾向を踏まえて推薦するよう依頼します。

「現在、3 つの職種があります。北京での出社勤務の Java エンジニア、上海でのハイブリッド勤務の .NET エンジニア、そして上海でリモート勤務の .NET AI アプリケーションエンジニアです。私の求職傾向を踏まえて最も適した職種を推薦し、その理由も説明してください。」

もし長期記憶がなければ、Agent は現在のメッセージに列挙された求人情報だけをもとに単純比較するしかなく、候補者の技術背景、勤務地の希望、勤務形態の好みを知ることはできません。

もし Agent が自発的に「上海でリモート勤務の .NET AI アプリケーションエンジニア」を推薦し、その職種が .NET 技術分野、上海の勤務地、リモートワーク、AI 分野への関心に同時に合致していると明確に説明できれば、最初の会話の情報が Session をまたいで正常に保持されたことになります。

これこそが、この Demo 全体で検証したい結果です。つまり、記憶はもはやチャット履歴に依存せず、ユーザーディレクトリに永続化されているということです。

FileMemoryProvider はすべての情報を自動保存するのか

答えは否です。

FileMemoryProvider はファイル操作能力を Agent に提供するだけで、すべての発話を無条件に保存するわけではありません。どの内容を長期記憶として残す価値があるかは、依然としてモデルが判断する必要があります。

たとえば、「5 年の .NET バックエンド開発経験があり、上海のリモート職を探している」は通常、長期的価値があります。一方で、「今日の午後 2 時なら面接できます」は一回限りの情報であり、長期保存には適さないかもしれません。

すべての内容を保存してしまうと、記憶ファイルは急速に肥大化し、大量の期限切れ情報や無関係な情報が混入します。採用シーンでは個人情報も多いため、明確な制限がなければ、モデルが誤って連絡先、身分証番号、詳細住所などをファイルに書き込んでしまい、プライバシーやセキュリティのリスクが生じます。

そのため、本番環境では、プロンプトによって記憶の基準を明確にし、長期的に有効な技術背景、職種方向、勤務地の好み、勤務形態のみを保存し、一時的な予定、機微な身元情報、後続価値のない内容は保存しないようにすべきです。

特に重要な情報については、モデルの判断に完全に頼るのではなく、業務コード側で書き込みを直接制御することもできます。

FileMemory はどのようなシーンに適しているか

FileMemoryProvider は、ユーザーの好み、プロジェクト背景、よく使うルール、学習進捗、仕事の習慣など、自然言語形式の長期情報を保存するのに適しています。

採用アシスタントは候補者の技術スタック、経験年数、希望勤務地、勤務形態、キャリア方向を覚えることができます。旅行アシスタントは食事制限、宿泊予算、ペット同伴旅行の要件を覚えることができます。ショッピングアシスタントはブランドの好み、サイズ、価格帯を覚えることができます。開発アシスタントはプロジェクトの技術スタック、コード規約、ディレクトリ構成を覚えることができます。

その利点は、実装が簡単で、内容が直感的で、デバッグしやすいことです。開発者はファイルを直接確認して、Agent が何を保存したかを把握でき、誤った記憶を手動で修正または削除することもできます。

本番環境でのセキュリティ上の課題

ローカルファイルストレージは Demo に適していますが、本番環境ではデータ分離、権限制御、暗号化、削除メカニズムも考慮する必要があります。

ユーザー ID をそのままパス連結に使うべきではありません。そうしないと、パストラバーサルなどのセキュリティ問題が発生する可能性があります。異なる候補者のファイルディレクトリは厳密に分離しなければならず、機微な情報も権限なしに自動保存されてはなりません。

採用シーンでは、特に個人情報保護を重視する必要があります。システムは、身分証番号、電話番号、メールアドレス、自宅住所などの機微情報の保存を明確に禁止し、すでに保存された記憶に対しては閲覧、更新、削除の機能を提供すべきです。

これらのファイルは Agent の補助データであるだけでなく、候補者の個人データでもあるからです。優れた記憶システムとは、保存量が多いほど良いものではなく、職種マッチングに本当に役立つ情報だけを保存し、なおかつユーザーが常に制御権を持てるものであるべきです。

まとめ

FileMemoryProvider は、AIContextProvider を通じてファイル記憶ツールを Agent に提供し、さらに AgentFileStore 抽象を通じて下層ストレージを扱います。FileMemoryState.WorkingFolder は、記憶をどのディレクトリに保存するか、そしてどの Session がその記憶を共有できるかを決定します。

あなたの Demo では固定のユーザーディレクトリを使用し、最初の会話で候補者の .NET 技術背景、上海の勤務地、リモートワーク、AI アプリケーション志向を保存し、その後、履歴メッセージを含まない新しい Session を作成して、Agent がそれらの情報を再読み込みし、職種推薦に利用できるかを検証しています。

2 回目の回答で「上海でリモート勤務の .NET AI アプリケーションエンジニア」を推薦し、それが候補者の技術スタック、勤務地、勤務形態、キャリア方向に同時に合致していると説明できれば、FileMemory が真の Session 間永続化を実現したことになります。

その実装は複雑ではありませんが、Agent アプリケーションにおける非常に重要な問題、つまり AI に現在のチャットだけを覚えさせるのではなく、利用を重ねるごとに候補者をより深く理解し、より一致度の高い職種提案を行えるようにする、という課題を解決しています。

(Translated by GPT)

元のリンク:https://mp.weixin.qq.com/s/rhX0w7ChSa1Tt0Ue902ziQ?token=1307544074&lang=zh_CN&wt.mc_id=MVP_325642

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?