こんにちは、YAMALEXの駿です。
昨今、対話型AIの活用が進む中で、ユーザーごとにパーソナライズされた体験を提供することが、より重要になっています。
単なる一問一答ではなく、「ユーザーが誰で、どんな関心や目的を持っているか」を理解したうえで応答できるエージェントが求められています。
本記事では、Strands AgentsとBedrock AgentCoreを組み合わせて、ユーザーとの対話履歴を記憶・活用するパーソナライズ型エージェントの実装と検証を行います。
1. はじめに
まずは、それぞれの構成要素について簡単に紹介します。
1.1. Strands Agentsとは
Strands Agentsは、対話エージェントの振る舞いや会話フローを柔軟に設計・構築できる仕組みです。
複数のツールを組み合わせることで、会話の中で必要な処理(API呼び出し、データ検索、記憶の参照など)を実現できます。
こちらの記事でも紹介しているので、あわせてご一読ください。
1.1.1. Strands Agents Tools
Strands Agentsにおける「ツール」とは、エージェントが利用する外部機能のことです。
本記事では、会話記憶を扱う「Agent Core Memory」ツールを中心に取り上げます。
1.2. Bedrock AgentCoreとは
Bedrock AgentCoreは、エージェントの開発と実行に必要な機能を提供するマネージドサービスです。
以下のような機能を備えており、スムーズなエージェント構築を支援します:
- 実行環境の提供
- 各種ツールとの連携
- 認証・認可機能
- ユーザーごとの記憶管理 など
1.2.1. AgentCore Memory
AgentCoreには「Memory」機能が備わっており、エージェントに短期記憶と長期記憶を持たせることができます。
特に長期記憶は、ユーザーとの会話を通じて得られた事実(ファクト)を記録し、今後の会話に活用することが可能です。
たとえば、「Pythonが得意」「旅行が好き」といったユーザーの好みや特性を記憶しておくことで、次回以降の会話において、より適切な応答や提案ができるようになります。
記憶された内容は常にすべて使われるわけではなく、現在の会話に関連する情報だけが動的に検索され、利用されます。
ChatGPTにもメモリ機能があり、個人の情報や好みを覚えてくれていますが、それと同等の機能を自分で実装することができ、自然なパーソナライズが実現できます。
2. 検証
実際にエージェントを作成し、記憶の保存、検索を行いながら会話できるか、検証します。
短期記憶はStrandsAgentsのConversationManagerで管理できるため、今回は特に長期メモリに注目します。
「ユーザープリファレンス」の戦略を有効にしたメモリーをAgentCoreのコンソールから作成しました。
2.1. 構成図
2.2. 実装
下にエージェントの実装を示します。
その人との会話の記録を取得するために、誰と会話するのか、を引数で受け取れるようにしました。
class MemoryAgent: PROMPT = dedent("""\ ユーザーにパーソナライズされた、ユーザーに寄り添うアシスタントとして振舞ってください。 ユーザーとの過去のやり取りを活用して、ユーザーがやりたいことをくみ取って下さい。 以下に記載した内容は自分の中のみで行ってください。ユーザーに伝えてはいけません。 自然にふるまってください。 - ユーザーの入力は内容を変更することなく、すべて、agent_core_memoryのrecordツールで記録してください。 - 会話をする中でトピックが変化した、新しい話題についての会話が始まったら、 agent_core_memoryのretrieveツールで関連するユーザーの情報を過去のやり取りから取得してください。 以上に記載した内容は自分の中のみで行ってください。ユーザーに伝えてはいけません。 """) def __init__(self, actor_id: str, session_id: str): model = BedrockModel( model_id='us.anthropic.claude-sonnet-4-20250514-v1:0', streaming=True, additional_request_fields={ 'thinking': {'type': 'enabled', 'budget_tokens': 4000}, 'anthropic_beta': ['interleaved-thinking-2025-05-14'], }, region_name='us-west-2', ) provider = AgentCoreMemoryToolProvider( memory_id=MEMORY_ID, actor_id=actor_id, session_id=session_id, namespace=f'/strategies/{STRATEGY_ID}/actors/{actor_id}', region='us-west-2', ) self.agent = Agent( model=model, system_prompt=self.PROMPT, tools=provider.tools, ) async def stream(self, prompt): async for event in self.agent.stream_async(prompt): if text := event.get('event', {}).get('contentBlockDelta', {}).get('delta', {}).get('text', ''): yield text for content in event.get('message', {}).get('content', []): if isinstance(content, dict) and (tool_use := content.get('toolUse', '')): logger.info('## tool use: %s', tool_use)
2.3. 会話してみた
私は普段Python+Angularの構成でアプリケーションを作成しています。
エージェントが作成するアプリケーションもその構成で出してもらえると、自分も理解しやすいですし、そのまま適用まで持っていけます。
今回は、最初にPython+Angularで実装することを明示して、その次に何も伝えずに実装させたときに、Angularを使ってくれるかを検証しました。
もし、明示しなくてもAngularを使ってくれたら、私の好みを理解し、パーソナライズされている感じがして、親切なエージェントだ、と感じることでしょう。
2.3.1. 好みを理解していない場合
Strands Agents Toolsを設定せずMemoryを使わない場合の挙動を確認します。
-
初回は使用するフレームワークを明示して実装してもらう
「Python+AngularでLLMチャットのGUIアプリケーションを作成してください」
要望通り、Python+Angularでアプリケーションを実装してくれました。
LLMチャットアプリケーションを作成します。 Python(FastAPI)をバックエンド、Angularをフロントエンドとして構築していきましょう。 (後略)
-
別スレッドにて、フレームワークを伝えずに実装してもらう
同じエージェントに実装させると、会話履歴からAngularを使うことを推測してしまうかもしれません。
そうならないように、一度、エージェントアプリを停止して、新しいエージェントを初期化してから下記依頼をしてみました。「RAGチャットのGUIアプリケーションを作成して」
前の会話を覚えていないため、前回はAngularでフロントエンドを作ったことは覚えていません。
そのため、私が使いたいAngularではなく、Streamlitを使ったコードを生成してきました。
RAGチャットのGUIアプリケーションを作成します。 Streamlitを使って、ドキュメントアップロード、ベクトル検索、チャット機能を含む完全なアプリケーションを構築します。 (後略)
2.3.2. 好みを理解している場合
次にStrands Agents ToolsのMemoryツールを有効にして、AgentCore Memoryを使うことで、過去の会話を記憶しパーソナライズされたエージェントになっていることを確認します。
-
初回は使用するフレームワークを明示して実装してもらう
「Python+AngularでLLMチャットのGUIアプリケーションを作成してください」
こちらも依頼通り作ってくれました。
Python + AngularでLLMチャットのGUIアプリケーションを作成しますね! フルスタック構成で、実用的なチャットアプリケーションを構築しましょう。 (後略)
-
別スレッドにて、フレームワークを伝えずに実装してもらう
こちらも一度新しいエージェントを作成してから、依頼しました。
「RAGチャットのGUIアプリケーションを作成して」
過去のやり取りを参考にすると、PythonとAngularでLLMチャットアプリケーションに興味をお持ちでしたね! 今回はRAG(Retrieval-Augmented Generation)機能を組み込んだチャットGUIアプリケーションを作成しましょう。 以下に構成をご提案します: ## 技術スタック - **バックエンド**: Python (FastAPI) - **フロントエンド**: Angular - **RAG**: LangChain + Vector Database (Chroma/FAISS) - **LLM**: OpenAI API or Hugging Face (後略)
前にPython+AngularでGUIアプリケーションを使ったことを覚えているので、同構成で作成するか提案、実装をしてくれました。
AgentCore Memoryが想定通りに働き、私の好みに合った回答をできていることを確認できました。
2.4. Memoryの中身を見てみた
AWSコンソールからはMemoryの中身を確認することができないため、AWSCLI を用いて取得します。
これを見ると、「LLMのアプリケーション作成に興味があること」、「Python+Angularでアプリを作成すること」を私の好みとして理解してくれていることが分かります。
$ aws bedrock-agentcore list-memory-records \ --memory-id $memoryId \ --namespace /strategies/memory_preference/actors/sy
{ "memoryRecordSummaries": [ { "memoryRecordId": "mem-cacf3145-324f-4f30-8e83-dade742bc2e0", "content": { "text": "{\"context\":\"LLM(大規模言語モデル)チャットアプリケーションの開発に関心を示している\",\"preference\":\"LLMベースのチャットアプリケーションに興味がある\",\"categories\":[\"人工知能\",\"テクノロジー\",\"アプリケーション開発\"]}" }, "memoryStrategyId": "memory_preference", "namespaces": ["/strategies/memory_preference/actors/sy"] }, { "memoryRecordId": "mem-77a9f50f-8589-4229-874b-2dcac251708f", "content": { "text": "{\"context\":\"ユーザーはPython+AngularでLLMチャットのGUIアプリケーションを作成することを要求しています。\",\"preference\":\"PythonとAngularを用いたアプリケーション開発に興味がある\",\"categories\":[\"プログラミング\",\"ソフトウェア開発\",\"技術\"]}" }, "memoryStrategyId": "memory_preference", "namespaces": ["/strategies/memory_preference/actors/sy"] } ] }
このMemoryをStrands Agentsのエージェントが呼び出すときは、ベクトル検索により一致度が高いものを関連する記憶として取得することができます。
下記は実際に2回目にエージェントを動かしたときに、Strands Agentsが実行したツール利用の内容です。
ベクトル検索のスコアを利用して取得してるのが分かります。
agent.agent.tool.agent_core_memory( action='retrieve', query='RAG チャット GUI アプリケーション 開発 プログラミング', )
{ "memoryRecordSummaries": [ { "content": { "text": "{\"context\":\"ユーザーはPython+AngularでLLMチャットのGUIアプリケーションを作成することを要求しています。\",\"preference\":\"PythonとAngularを用いたアプリケーション開発に興味がある\",\"categories\":[\"プログラミング\",\"ソフトウェア開発\",\"技術\"]}" }, "namespaces": ["/strategies/memory_preference/actors/sy"], "score": 0.49530885 } ] }
3. 応用例
Strands Agents ToolsとAgentCore Memoryを組み合わせることで、会話の文脈を記憶し、ユーザーの好みや目的に合わせてパーソナライズされた対応が可能となります。
ここでは、実際の業務やサービスでの応用シナリオをいくつか紹介します。
-
カスタマーサポート
ユーザーが過去に問い合わせた内容やトラブルの履歴を長期記憶に保持することで、毎回最初から状況を説明する必要がなくなります。
たとえば、エラー対応の際に「前回は〇〇というエラーが出ていましたが、今回は△△のようですね」といった形で、文脈を理解したサポートが実現できます。 -
継続的な学習支援
教育アプリや社内研修のアシスタントとして、学習者の進捗や苦手分野を記録し、それに基づいて出題内容や説明の仕方を調整することが可能です。
ユーザーが「以前はこの問題が苦手だったけど、今回は解けたね」といったフィードバックを得ることで、より継続的な学習を支援できます。 -
パーソナライズされた提案システム
製品推薦やコンテンツ提案を行うアプリケーションにおいて、ユーザーの好みや過去の選択を踏まえた提案が可能になります。
たとえば、旅行プラン提案エージェントで「前回は静かな温泉地を好んでいましたね。今回は似た雰囲気の〇〇を提案します」といった応答が実現できます。
4. まとめ
Strands AgentsとBedrock AgentCoreのMemory機能を組み合わせることで、従来の会話型AIでは難しかった文脈保持や個人の嗜好を踏まえた対応が可能になります。
本記事では、シンプルなチャットアプリを通じてAgentCore Memoryの検証を行いました。
その結果、Memoryツールを活用することで、より自然で継続的なユーザー体験を提供できることが確認できました。
今後は、記憶の精度向上や削除・修正の制御、複数ユーザー対応など、より高度なユースケースへの対応が求められると考えられます。
エージェントに「記憶」を持たせることは、今後のAI活用において大きな鍵となる機能のひとつと言えるでしょう。
Acroquest Technologyでは、キャリア採用を行っています。
- Azure OpenAI/Amazon Bedrock等を使った生成AIソリューションの開発
- ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
- マイクロサービス、DevOps、最新のOSSやクラウドサービスを利用する開発プロジェクト
- 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。