AI エージェントは、マルチターン対話やシーケンシャルタスクを実行する際に、ユーザーのプリファレンス、過去の命令、またはコンテキスト情報を保持できないことがよくあります。このような効果的なメモリの欠如は、対話エクスペリエンスを妨げ、タスクの効率を低下させます。PolarSearch メモリコンテナーはこの問題を解決します。これは、PolarDB for PostgreSQL に組み込まれた長期および短期メモリ管理システムです。この機能により、エージェントは会話データを自動的に構造化して永続化します。その後、セマンティック検索を使用して関連するメモリを迅速に取得し、真に継続的で、パーソナライズされた、効率的なサービスを提供します。
PolarSearch メモリコンテナー機能はカナリアリリース中です。アクセスをリクエストするには、チケットを送信してください。
仕組み
PolarSearch メモリコンテナーは、自動化された処理フローを使用して、非構造化会話データを検索可能で利用可能な構造化メモリに変換します。これは、3層ストレージアーキテクチャとインテリジェントなメモリ処理パイプラインに基づいて構築されています。
3層ストレージアーキテクチャ
メモリコンテナーは、階層化された設計を使用して、ライフスパンが異なるメモリのストレージと取得の効率のバランスを取ります。
メモリタイプ | インデックスタイプ | 主な目的 |
短期メモリ (ワーキングメモリ) | 転置インデックス | 未処理の生の短期会話データを保存します。高速な取得のために転置インデックスを使用します。現在の会話のコンテキストを維持します。 |
長期メモリ (長期メモリ) | ベクトルインデックス + 転置インデックス | 大規模言語モデル (LLM) を使用して会話から主要なファクトを抽出し、ベクトルとして保存します。深い知識と経験の取得のために KNN セマンティック検索をサポートします。 |
メモリ履歴 (履歴メモリ) | 転置インデックス | すべてのメモリオペレーション (追加や更新など) を記録し、完全な監査ログを形成します。メモリの進化が追跡可能であることを保証します。 |
メモリ処理フロー
エージェントが新しい入力を受け取ると、メモリコンテナーは一連のアクションをトリガーして、メモリを自動的に取り込み、永続化し、取得します。
メモリの取り込み:
入力と前処理:Elasticsearch プロトコルを使用してエージェントの会話入力を受け取ります。オプションで大規模言語モデル (LLM) を呼び出して、要約の生成、意図の分類、またはタグの抽出を行うことができます。
ルーティングの決定:メモリールーターは入力を分析し、既存のメモリと比較して、メモリを追加 (ADD)、更新 (UPDATE)、または削除 (DELETE) するかどうかを決定します。
メモリの永続化:
短期メモリ:生の会話コンテンツを保存します。
長期メモリ:LLM によって抽出され、埋め込みモデルによってベクトル化された構造化ファクトを保存します。
メモリ履歴:すべての操作をメモリ履歴に書き込み、監査証跡を作成します。
メモリ取得:
入力解析:検索条件を受け入れます。Elasticsearch プロトコルを使用してマルチモーダル検索リクエストを解析します。権限検証モジュールを呼び出して、データアクセス境界を確認します。
ハイブリッドインデックス検索:長期メモリでハイブリッド検索 (ANN ベクトル類似性検索と転置インデックスフィルタリング) を実行します。短期メモリでキーワードマッチングを実行します。メモリのタイムスタンプに基づいて重みを調整します。
結果の統合:リランクモデルを使用して結果の順序を最適化します。タイムスタンプやその他のメタデータを使用して競合を解決します。最も関連性の高いメモリをエージェントに返します。
主な利点
機能ディメンション | 従来のアプローチ | PolarSearch ソリューション |
メモリ使用率 | 既存データの 30% 未満しか保持されず、効果的な活用が妨げられています。 | LLM を使用してファクトを抽出し、セマンティックインデックスと組み合わせることで、有効な情報利用率を 85% 以上に向上させます。 |
検索効率 | キーワードマッチングに依存し、精度は 60% 以下です。 | ハイブリッドベクトルおよび転置インデックス、さらにリランキングを使用します。これにより、95% 以上のセマンティック検索精度を達成します。 |
エンタープライズコンプライアンス | マルチテナント分離と権限コントロールの実装は複雑です。 | ネイティブのマルチテナント分離、ロールベースアクセス制御 (RBAC) による権限コントロール、および操作監査を提供し、企業のセキュリティ要件を満たします。 |
システムのスケーラビリティ | 単一ポイントのストレージ容量はテラバイトレベルが上限です。 | クラウドネイティブ分散ストレージアーキテクチャ上に構築されています。ストレージはペタバイトレベルまで拡張可能です。 |
開発コスト | カスタム開発が必要で、実装に長い時間がかかります。 | すぐに使える API と SDK を提供し、開発を簡素化し、迅速な統合を可能にします。 |
適用範囲
機能ノード:クラスターに PolarSearch 検索ノードを追加します。
アカウント権限:検索ノードの管理者アカウントを作成して、プラグインを有効にし、リソースを作成します。
クイックスタート
このガイドでは、環境設定からメモリの保存と取得までの全プロセスを説明します。
全体のワークフロー:環境の準備 → プラグインの有効化 → モデルの登録 → メモリコンテナーの作成 → メモリの保存と検証。
ステップ 1:アクセス認証情報と環境変数の設定
開始前に、次の情報を準備し、環境変数として設定してください。これにより、後続の curl コマンドが簡素化され、繰り返し編集する必要がなくなります。すべての構成と認証情報を一元化することで、コピーおよび実行が容易になります。
変数名 | 説明 | 値の例 |
| PolarSearch ノードの接続アドレスとポート。 |
|
| PolarSearch ノードの管理者アカウント。 |
|
| Alibaba Cloud Model Studio の API キー。 |
|
操作:ターミナルで以下のコマンドを実行します。サンプル値を実際の値に置き換えてください。
# Set the PolarSearch host and port
# PolarSearch のホストとポートを設定
export POLARSEARCH_HOST_PORT="pc-xxx.polardbsearch.rds.aliyuncs.com:3001"
# Set the PolarSearch administrator password
# PolarSearch の管理者パスワードを設定
export USER_PASSWORD="polarsearch_user:your_password"
# Set your Qwen API key
# Qwen の API キーを設定
export YOUR_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxx"ステップ 2:メモリコンテナープラグインの有効化
次のコマンドを実行して、ご利用の PolarDB クラスターでメモリコンテナー機能を有効にします。
コマンドライン
curl -XPUT "http://${POLARSEARCH_HOST_PORT}/_cluster/settings" \
--user "${USER_PASSWORD}" \
-H 'Content-Type: application/json' \
-d '{
"persistent": {
"plugins.ml_commons.agentic_memory_enabled": true
}
}'ダッシュボード
PUT _cluster/settings
{
"persistent": {
"plugins.ml_commons.agentic_memory_enabled": true
}
}ステップ 3:モデルの登録
ファクト抽出用の LLM とセマンティック処理用の埋め込みモデルを PolarSearch に登録する必要があります。
埋め込みモデルの登録
Alibaba Cloud Model Studio の埋め込みモデルサービスを指すコネクタを作成し、PolarSearch で呼び出し可能なモデルとして登録します。
信頼できるエンドポイントの設定:モデルの API エンドポイントを信頼リストに追加して、PolarSearch がそれを呼び出せるようにします。
コマンドライン
curl -XPUT "http://${POLARSEARCH_HOST_PORT}/_cluster/settings" \ --user "${USER_PASSWORD}" \ -H 'Content-Type: application/json' \ -d '{ "persistent": { "plugins.ml_commons.trusted_connector_endpoints_regex": [ "^https://dashscope.aliyuncs.com/compatible-mode/v1/.*$" ] } }'ダッシュボード
PUT _cluster/settings { "persistent": { "plugins.ml_commons.trusted_connector_endpoints_regex": [ "^https://dashscope.aliyuncs.com/compatible-mode/v1/.*$" ] } }モデル コネクタを作成します:
text-embedding-v4モデルに接続するためのパラメーターを設定します。説明pre_process_functionおよびpost_process_functionパラメーターは、異なるモデルサービス向けにリクエストおよび応答フォーマットを調整します。この例では、組み込みのopenai.embeddingフォーマットコンバーターを使用しています。これは、互換モードでの Alibaba Cloud Model Studio のフォーマットと一致するためです。コマンドライン
curl -XPOST "http://${POLARSEARCH_HOST_PORT}/_plugins/_ml/connectors/_create" \ --user "${USER_PASSWORD}" \ -H 'Content-Type: application/json' \ -d '{ "name": "qwen embedding connector", "description": "The connector to qwen embedding model", "version": 1, "protocol": "http", "parameters": { "model": "text-embedding-v4", "endpoint": "dashscope.aliyuncs.com/compatible-mode" }, "credential": { "api_key": "${YOUR_API_KEY}" }, "actions": [ { "action_type": "predict", "method": "POST", "headers": { "Authorization": "Bearer ${credential.api_key}", "content-type": "application/json" }, "url": "https://${parameters.endpoint}/v1/embeddings", "request_body": "{ \"model\": \"${parameters.model}\", \"input\": ${parameters.input} }", "pre_process_function": "connector.pre_process.openai.embedding", "post_process_function":"connector.post_process.openai.embedding" } ] }'ダッシュボード
重要次のコマンド内の
<YOUR_API_KEY>を、実際の Alibaba Cloud Model Studio の API キー に置き換えてください。POST _plugins/_ml/connectors/_create { "name": "qwen embedding connector", "description": "The connector to qwen embedding model", "version": 1, "protocol": "http", "parameters": { "model": "text-embedding-v4", "endpoint": "dashscope.aliyuncs.com/compatible-mode" }, "credential": { "api_key": "<YOUR_API_KEY>" }, "actions": [ { "action_type": "predict", "method": "POST", "headers": { "Authorization": "Bearer ${credential.api_key}", "content-type": "application/json" }, "url": "https://${parameters.endpoint}/v1/embeddings", "request_body": "{ \"model\": \"${parameters.model}\", \"input\": ${parameters.input} }", "pre_process_function": "connector.pre_process.openai.embedding", "post_process_function":"connector.post_process.openai.embedding" } ] }コマンドが正常に実行された後、システムは
connector_idを返します。このIDは後で使用するために控えてください。{"connector_id": "LBFt6ZsBk04xxx"}モデルの登録:前のステップで作成したコネクタをモデルとして登録します。
コマンドライン
curl -XPOST "http://${POLARSEARCH_HOST_PORT}/_plugins/_ml/models/_register" \ --user "${USER_PASSWORD}" \ -H 'Content-Type: application/json' \ -d '{ "name": "qwen embedding model", "function_name": "remote", "description": "Embedding model for memory", "connector_id": "LBFt6Zsxxx" }'ダッシュボード
POST _plugins/_ml/models/_register { "name": "qwen embedding model", "function_name": "remote", "description": "Embedding model for memory", "connector_id": "LBFt6ZsBk04xxx" }コマンドが正常に実行されると、システムは
model_idを返します。後で使用するためにこのIDを記録してください。# Record the returned model_id # 返された model_id を記録 {"task_id": "LRFx6ZsBk04ixxx","status": "CREATED","model_id": "LhFx6ZsBk04xxx"}モデルのテスト:次のクエリを実行して LLM と直接チャットし、その応答を表示します。
コマンドライン
curl -XPOST "http://${POLARSEARCH_HOST_PORT}/_plugins/_ml/_predict/text_embedding/<model ID from previous step>" \ --user "${USER_PASSWORD}" \ -H 'Content-Type: application/json' \ -d'{ "text_docs":[ "Bob likes swimming. Context: He expressed his interest in swimming."], "return_number": true, "target_response": ["sentence_embedding"] }'ダッシュボード
POST _plugins/_ml/_predict/text_embedding/<model ID from previous step> { "text_docs":[ "Bob likes swimming. Context: He expressed his interest in swimming."], "return_number": true, "target_response": ["sentence_embedding"] }期待される応答:
{ "inference_results": [ { "output": [ { "name": "sentence_embedding", "data_type": "FLOAT32", "shape": [ 1024 ], "data": [ 0.019752666354179382, -0.03468115255236626, 0.05591931194067001, ... ] } ], "status_code": 200 } ] }
テキスト生成モデル (LLM) の登録
Alibaba Cloud Model Studio で、qwen-plus LLM へのコネクタを作成および登録します。
モデルコネクタの作成:
コマンドライン
curl -XPOST "http://${POLARSEARCH_HOST_PORT}/_plugins/_ml/connectors/_create" \ --user "${USER_PASSWORD}" \ -H 'Content-Type: application/json' \ -d '{ "name": "QWen LLM Connector", "description": "The connector to qwen LLM", "version": 1, "protocol": "http", "parameters": { "model": "qwen-plus", "endpoint": "dashscope.aliyuncs.com/compatible-mode" }, "credential": { "api_key": "${YOUR_API_KEY}" }, "actions": [ { "action_type": "predict", "method": "POST", "headers": { "Authorization": "Bearer ${credential.api_key}", "content-type": "application/json" }, "url": "https://${parameters.endpoint}/v1/chat/completions", "request_body": "{ \"model\":\"${parameters.model}\", \"system\": \"${parameters.system_prompt}\", \"messages\": [ { \"role\": \"system\", \"content\": \"${parameters.system_prompt}\" }, { \"role\": \"user\", \"content\": \"${parameters.user_prompt}\" } ], \"response_format\": { \"type\": \"json_object\" } }" } ] }'ダッシュボード
重要<YOUR_API_KEY>を、以下のコマンドで実際の Alibaba Cloud Model Studio の API キー に置き換えます。POST /_plugins/_ml/connectors/_create { "name": "QWen LLM Connector", "description": "The connector to qwen LLM", "version": 1, "protocol": "http", "parameters": { "model": "qwen-plus", "endpoint": "dashscope.aliyuncs.com/compatible-mode" }, "credential": { "api_key": "<YOUR_API_KEY>" }, "actions": [ { "action_type": "predict", "method": "POST", "headers": { "Authorization": "Bearer ${credential.api_key}", "content-type": "application/json" }, "url": "https://${parameters.endpoint}/v1/chat/completions", "request_body": "{ \"model\":\"${parameters.model}\", \"system\": \"${parameters.system_prompt}\", \"messages\": [ { \"role\": \"system\", \"content\": \"${parameters.system_prompt}\" }, { \"role\": \"user\", \"content\": \"${parameters.user_prompt}\" } ], \"response_format\": { \"type\": \"json_object\" } }" } ] }コマンドが正常に実行されると、システムは
connector_idを返します。この ID は後で使用するため、記録しておいてください。{"connector_id": "PRGy6ZsBk04xxx"}モデルの登録:前のステップで作成したコネクタをモデルとして登録します。
コマンドライン
curl -XPOST "http://${POLARSEARCH_HOST_PORT}/_plugins/_ml/models/_register" \ --user "${USER_PASSWORD}" \ -H 'Content-Type: application/json' \ -d '{ "name": "qwen llm model", "function_name": "remote", "description": "LLM model for memory", "connector_id": "PRGy6ZsBk04xxx" }'ダッシュボード
POST _plugins/_ml/models/_register { "name": "qwen llm model", "function_name": "remote", "description": "LLM model for memory", "connector_id": "PRGy6ZsBk04xxx" }コマンドが正常に実行されると、
model_idが返されます。このIDを後で使用するために記録してください。# Record the returned model_id # 返された model_id を記録 {"task_id": "PhGy6ZsBk04xxx","status": "CREATED","model_id": "PxGy6ZsBk04xxx"}モデルのデプロイ:
コマンドライン
curl -XPOST "http://${POLARSEARCH_HOST_PORT}/_plugins/_ml/models/<model ID from previous step>/_deploy" \ --user "${USER_PASSWORD}"ダッシュボード
POST _plugins/_ml/models/<model ID from previous step>/_deployコマンドが正常に実行されると、
statusの値がCOMPLETEDの場合、デプロイメントが成功したことを示します。{"task_id": "NxGI6ZsBk04xxx","task_type": "DEPLOY_MODEL","status": "COMPLETED"}モデルのテスト:次のクエリを実行して LLM と直接チャットし、その応答を表示します。
コマンドライン
curl -XPOST "http://${POLARSEARCH_HOST_PORT}/_plugins/_ml/models/<model ID from previous step>/_predict" \ --user "${USER_PASSWORD}" \ -H 'Content-Type: application/json' \ -d'{ "parameters": { "system_prompt": "<ROLE>You are a USER PREFERENCE EXTRACTOR, not a chat assistant. Your only job is to output JSON facts. Do not answer questions, make suggestions, ask follow-ups, or perform actions.</ROLE>\n\n<SCOPE>\n• Extract preferences only from USER messages. Assistant messages are context only.\n• Explicit: user states a preference (\"I prefer/like/dislike ...\"; \"always/never/usually ...\"; \"set X to Y\"; \"run X when Y\").\n• Implicit: infer only with strong signals: repeated choices (>=2) or clear habitual language. Do not infer from a single one-off.\n</SCOPE>\n\n<EXTRACT>\n• Specific, actionable, likely long-term preferences (likes/dislikes/choices/settings). Ignore non-preferences.\n</EXTRACT>\n\n<STYLE & RULES>\n• One sentence per preference; merge related details; no duplicates; preserve user wording and numbers; avoid relative time; keep each fact < 350 chars.\n• Format: \"Preference sentence. Context: <why/how>. Categories: cat1,cat2\"\n</STYLE & RULES>\n\n<OUTPUT>\nReturn ONLY one minified JSON object exactly as {\"facts\":[\"Preference sentence. Context: <why/how>. Categories: cat1,cat2\"]}. If none, return {\"facts\":[]}. The first character MUST be '{' and the last MUST be '}'. No preambles, explanations, code fences, XML, or other text.\n</OUTPUT>", "user_prompt": "I am Alice, I like travel." } }'ダッシュボード
POST _plugins/_ml/models/<model ID from previous step>/_predict { "parameters": { "system_prompt": "<ROLE>You are a USER PREFERENCE EXTRACTOR, not a chat assistant. Your only job is to output JSON facts. Do not answer questions, make suggestions, ask follow-ups, or perform actions.</ROLE>\n\n<SCOPE>\n• Extract preferences only from USER messages. Assistant messages are context only.\n• Explicit: user states a preference (\"I prefer/like/dislike ...\"; \"always/never/usually ...\"; \"set X to Y\"; \"run X when Y\").\n• Implicit: infer only with strong signals: repeated choices (>=2) or clear habitual language. Do not infer from a single one-off.\n</SCOPE>\n\n<EXTRACT>\n• Specific, actionable, likely long-term preferences (likes/dislikes/choices/settings). Ignore non-preferences.\n</EXTRACT>\n\n<STYLE & RULES>\n• One sentence per preference; merge related details; no duplicates; preserve user wording and numbers; avoid relative time; keep each fact < 350 chars.\n• Format: \"Preference sentence. Context: <why/how>. Categories: cat1,cat2\"\n</STYLE & RULES>\n\n<OUTPUT>\nReturn ONLY one minified JSON object exactly as {\"facts\":[\"Preference sentence. Context: <why/how>. Categories: cat1,cat2\"]}. If none, return {\"facts\":[]}. The first character MUST be '{' and the last MUST be '}'. No preambles, explanations, code fences, XML, or other text.\n</OUTPUT>", "user_prompt": "I am Alice, I like travel." } }期待される応答:
{ "inference_results": [ { "output": [ { "name": "response", "dataAsMap": { "choices": [ { "message": { "role": "assistant", "content": """{"facts":["I like travel. Context: Stated preference. Categories: interest"]}""" }, "finish_reason": "stop", "index": 0, "logprobs": null } ], "object": "chat.completion", "usage": { "prompt_tokens": 325, "completion_tokens": 17, "total_tokens": 342, "prompt_tokens_details": { "cached_tokens": 0 } }, "created": 1769152651, "system_fingerprint": null, "model": "qwen-plus", "id": "chatcmpl-50c6bfc9-xxx-xxx-xxx-1a39cfe080f5" } } ], "status_code": 200 } ] }
ステップ 4:メモリコンテナーの作成
メモリコンテナーインスタンスを作成し、そのモデル、ストレージポリシー、および自動化動作を設定します。名前が
agentic memory testのコンテナーを作成するには、次のコマンドを実行します。コマンドライン
curl -XPOST "http://${POLARSEARCH_HOST_PORT}/_plugins/_ml/memory_containers/_create" \ --user "${USER_PASSWORD}" \ -H 'Content-Type: application/json' \ -d'{ "name": "my agentic memory test", "description": "Store conversations with semantic search and summarization", "configuration": { "embedding_model_type": "TEXT_EMBEDDING", "embedding_model_id": "<embedding model ID from previous step>", "embedding_dimension": 1024, "llm_id": "<LLM model ID from previous step>", "index_prefix": "mem_test", "index_settings": { "short_term_memory_index": { "index": { "number_of_shards": "2", "number_of_replicas": "2" } }, "long_term_memory_index": { "index": { "number_of_shards": "2", "number_of_replicas": "2" } }, "long_term_memory_history_index": { "index": { "number_of_shards": "2", "number_of_replicas": "2" } } }, "strategies": [ { "type": "SEMANTIC", "namespace": ["user_id"], "configuration": { "llm_result_path": "$.choices[0].message.content" } }, { "type": "USER_PREFERENCE", "namespace": ["user_id"], "configuration": { "llm_result_path": "$.choices[0].message.content" } }, { "type": "SUMMARY", "namespace": ["agent_id"], "configuration": { "llm_result_path": "$.choices[0].message.content" } } ], "parameters": { "llm_result_path": "$.choices[0].message.content" } } }'ダッシュボード
POST _plugins/_ml/memory_containers/_create { "name": "my agentic memory test", "description": "Store conversations with semantic search and summarization", "configuration": { "embedding_model_type": "TEXT_EMBEDDING", "embedding_model_id": "<embedding model ID from previous step>", "embedding_dimension": 1024, "llm_id": "<LLM model ID from previous step>", "index_prefix": "mem_test", "index_settings": { "short_term_memory_index": { "index": { "number_of_shards": "2", "number_of_replicas": "2" } }, "long_term_memory_index": { "index": { "number_of_shards": "2", "number_of_replicas": "2" } }, "long_term_memory_history_index": { "index": { "number_of_shards": "2", "number_of_replicas": "2" } } }, "strategies": [ { "type": "SEMANTIC", "namespace": ["user_id"], "configuration": { "llm_result_path": "$.choices[0].message.content" } }, { "type": "USER_PREFERENCE", "namespace": ["user_id"], "configuration": { "llm_result_path": "$.choices[0].message.content" } }, { "type": "SUMMARY", "namespace": ["agent_id"], "configuration": { "llm_result_path": "$.choices[0].message.content" } } ], "parameters": { "llm_result_path": "$.choices[0].message.content" } } }パラメーターの説明
index_prefix: このコンテナーによって作成される内部インデックス(例:短期メモリインデックスおよび長期メモリインデックス)の共通プレフィックス。index_settings: 各種メモリインデックスのシャード数とレプリカ数を設定して、高可用性を確保します。strategies: 自動化ルールを定義します。この例では、SEMANTICストラテジーを定義しており、これはuser_id名前空間内の会話からセマンティクス情報を自動的に抽出します。llm_result_path: JSONPath 構文を使用して、LLM の JSON 応答からコアコンテンツを抽出する方法を指定します。パス$.choices[0].message.contentは、互換モードでの Alibaba Cloud Model Studio の応答構造と一致します。
コマンドが正常に実行されると、システムは
memory_container_idを返します。このIDを今後の使用のために記録してください。# Record the returned model_id # 返された model_id を記録 {"memory_container_id": "QRHF6ZsBk04xxx","status": "created"}メモリコンテナーを作成すると、システムは次のインデックスとパイプラインを作成します:
.plugins-ml-am-mem_test-memory-long-term .plugins-ml-am-mem_test-memory-working .plugins-ml-am-mem_test-memory-history .plugins-ml-am-mem_test-memory-long-term-embedding" : { "description" : "Agentic Memory Text embedding pipeline", "processors" : [ { "text_embedding" : { "model_id" : "QRHF6ZsBk04xxx", "field_map" : { "memory" : "memory_embedding" } } } ] }
ステップ 5:メモリの保存と検証
メモリコンテナーに会話を追加し、それが短期および長期メモリに正しく保存されていることを確認します。
メモリの保存: Bob という名前のユーザーに関する会話を含む POST リクエストをコンテナーに送信します。
"infer": trueパラメーターは、LLM を呼び出してファクトを抽出するように以前に設定したSEMANTICストラテジーをトリガーします。コマンドライン
curl -XPOST "http://${POLARSEARCH_HOST_PORT}/_plugins/_ml/memory_containers/<memory container ID from previous step>/memories" \ --user "${USER_PASSWORD}" \ -H 'Content-Type: application/json' \ -d'{ "messages": [ { "role": "user", "content": [ { "text": "I am Bob, I really like swimming.", "type": "text" } ] }, { "role": "assistant", "content": [ { "text": "Cool, nice. Hope you enjoy your life.", "type": "text" } ] } ], "namespace": { "user_id": "bob" }, "tags": { "topic": "personal info" }, "infer": true, "memory_type": "conversation" }'ダッシュボード
POST _plugins/_ml/memory_containers/<memory_container_id>/memories { "messages": [ { "role": "user", "content": [ { "text": "I am Bob, I really like swimming.", "type": "text" } ] }, { "role": "assistant", "content": [ { "text": "Cool, nice. Hope you enjoy your life.", "type": "text" } ] } ], "namespace": { "user_id": "bob" }, "tags": { "topic": "personal info" }, "infer": true, "memory_type": "conversation" }短期メモリの検証:短期メモリインデックスを直接クエリして、保存された元の会話を表示します。
コマンドライン
curl -XGET "http://${POLARSEARCH_HOST_PORT}/.plugins-ml-am-<index_prefix from previous step>-memory-working/_search?pretty" \ --user "${USER_PASSWORD}" \ダッシュボード
GET .plugins-ml-am-<index_prefix from previous step>-memory-working/_search?pretty期待される出力 (一部):
{ "_source" : { "memory_container_id": "QRHF6ZsBk04xxx", "payload_type" : "conversational", "messages" : [ { "role" : "user", "content": [{ "text": "I am Bob, I really like swimming.","type": "text"}] }, { "role" : "assistant", "content": [{ "text": "Cool, nice. Hope you enjoy your life.","type": "text"}] } ], "namespace" : { "user_id" : "bob" } } }長期記憶の検証: 長期記憶インデックスにクエリを実行して、LLM が「Bob likes swimming」 というコアな事実を正常に抽出し、埋め込みモデルが対応する
memory_embeddingベクターを生成したことを確認します。コマンドライン
curl -XGET "http://${POLARSEARCH_HOST_PORT}/.plugins-ml-am-<index_prefix from previous step>-memory-long-term/_search?pretty" \ --user "${USER_PASSWORD}" \ダッシュボード
GET .plugins-ml-am-<index_prefix from previous step>-memory-long-term/_search?pretty期待される出力 (一部):
{ "_source" : { "created_time": 1769155210918, "memory": "Bob likes swimming.", "memory_container_id": "QRHF6ZsBk04xxx", "tags": { "topic": "personal info" }, "last_updated_time": 1769155210918, "memory_embedding" : [ 0.0195..., -0.0387..., ... ], "namespace" : { "user_id" : "bob" } } }メモリ履歴の表示:
memory-historyインデックスには、2 つの ADD レコードとそのタイムスタンプが含まれています。コマンドライン
curl -XGET "http://${POLARSEARCH_HOST_PORT}/.plugins-ml-am-<index_prefix from previous step>-memory-history/_search?pretty" \ --user "${USER_PASSWORD}" \ダッシュボード
GET .plugins-ml-am-<index_prefix from previous step>-memory-history/_search?pretty期待される出力 (一部):
{ "_source": { "created_time": 1769155211164, "memory_id": "TBHe6ZsBk04xxx", "namespace_size": 1, "namespace": { "user_id": "bob" }, "action": "ADD", "memory_container_id": "QRHF6ZsBk04xxx", "after": { "memory": "Bob likes swimming." }, "tags": { "topic": "personal info" } } }
これで、長期的な取得をサポートする AI エージェントのメモリを正常に保存できました。
ステップ 6:(オプション) メモリの更新
メモリコンテナーは長期メモリを抽出して更新できます。
まず、メモリを保存します:
コマンドライン
curl -XPOST "http://${POLARSEARCH_HOST_PORT}/_plugins/_ml/memory_containers/<memory container ID from previous step>/memories" \ --user "${USER_PASSWORD}" \ -H 'Content-Type: application/json' \ -d'{ "messages": [ { "role": "user", "content": [ { "text": "My name is NameA. I am from AreaA. I currently live in AreaB.", "type": "text" } ] }, { "role": "assistant", "content": [ { "text": "Hello, NameA! Nice to meet you.", "type": "text" } ] } ], "namespace": { "user_id": "NameA" }, "tags": { "topic": "personal info" }, "infer": true, "memory_type": "conversation" }'ダッシュボード
POST _plugins/_ml/memory_containers/<memory_container_id>/memories { "messages": [ { "role": "user", "content": [ { "text": "My name is NameA. I am from AreaA. I currently live in AreaB.", "type": "text" } ] }, { "role": "assistant", "content": [ { "text": "Hello, NameA! Nice to meet you.", "type": "text" } ] } ], "namespace": { "user_id": "NameA" }, "tags": { "topic": "personal info" }, "infer": true, "memory_type": "conversation" }長期メモリインデックスを検索します:
コマンドライン
curl -XGET "http://${POLARSEARCH_HOST_PORT}/.plugins-ml-am-<index_prefix from previous step>-memory-long-term/_search" \ --user "${USER_PASSWORD}" \ -H 'Content-Type: application/json' \ -d'{ "_source": { "excludes": ["memory_embedding"] }, "query": { "match_all": {} } }'ダッシュボード
GET .plugins-ml-am-<index_prefix from previous step>-memory-long-term/_search { "_source": { "excludes": ["memory_embedding"] }, "query": { "match_all": {} } }期待される出力 (一部):
{ "hits": [ { "_source": { "created_time": 1769156096335, "memory": "NameA is from AreaA.", "last_updated_time": 1769156096335, "namespace": { "user_id": "NameA" }, "memory_container_id": "QRHF6ZsBk04xxx", "tags": { "topic": "personal info" } } }, { "_source": { "created_time": 1769156096335, "memory": "NameA currently resides in AreaB.", "last_updated_time": 1769156096335, "namespace": { "user_id": "NameA" }, "memory_container_id": "QRHF6ZsBk04xxx", "tags": { "topic": "personal info" } } } ] }前のメモリと競合する別のメモリを保存します:
コマンドライン
curl -XPOST "http://${POLARSEARCH_HOST_PORT}/_plugins/_ml/memory_containers/<memory container ID from previous step>/memories" \ --user "${USER_PASSWORD}" \ -H 'Content-Type: application/json' \ -d'{ "messages": [ { "role": "user", "content": [ { "text": "My name is NameA. I currently live in AreaC.", "type": "text" } ] }, { "role": "assistant", "content": [ { "text": "Hello, NameA! Nice to meet you.", "type": "text" } ] } ], "namespace": { "user_id": "NameA" }, "tags": { "topic": "personal info" }, "infer": true, "memory_type": "conversation" }'ダッシュボード
POST _plugins/_ml/memory_containers/<memory_container_id>/memories { "messages": [ { "role": "user", "content": [ { "text": "My name is NameA. I currently live in AreaC.", "type": "text" } ] }, { "role": "assistant", "content": [ { "text": "Hello, NameA! Nice to meet you.", "type": "text" } ] } ], "namespace": { "user_id": "NameA" }, "tags": { "topic": "personal info" }, "infer": true, "memory_type": "conversation" }長期メモリインデックスを再度検索して、更新されたコンテンツを表示します (一部):
{ "hits": [ { "_source": { "created_time": 1769156096335, "memory": "NameA resides in AreaC.", "last_updated_time": 1769156493970, "namespace": { "user_id": "NameA" }, "memory_container_id": "QRHF6ZsBk04xxx", "tags": { "topic": "personal info" } } } ] }
ユースケース:旅行記憶エージェントの構築
このセクションでは、メモリコンテナー API を使用して、ユーザーの旅行プリファレンスを記憶し、パーソナライズされた推奨事項を提供する Python エージェントを構築する方法を示します。
事前準備
コードを実行する前に、必要な Python ライブラリをインストールする必要があります。以下の依存関係を requirements.txt ファイルに追加します。
requests
openaipip install -r requirements.txt を実行してインストールします。
コアコードの説明
以下は、メモリコンテナーと対話する主要な関数です:
opensearch_request(): PolarSearch API への HTTP リクエストをラップし、認証とエラーを処理します。add_memory()関数は、メモリ コンテナのmemoriesAPI を呼び出して、新しい会話データを保存します。search_memories():_searchAPI を呼び出して、長期および短期メモリからユーザー クエリに関連する情報を取得します。generate_response_with_memories(): 取得されたメモリをコンテキストとして、ユーザーの現在の質問とともに LLM に送信し、よりパーソナライズされた応答を生成します。
完全なサンプルコード
以下は、安全で論理的に最適化された Python スクリプトです。次のように保存します trip_agent.py し、指示に従って環境変数を設定します。
実行と対話
環境変数の設定:ターミナルで、スクリプトに必要な環境変数を設定します。
スクリプトを実行します:
python trip_agent.py対話例:
API リファレンス
このガイドでは、次の API を使用します。詳細については、公式の OpenSearch ドキュメントをご参照ください:
Create Memory Container API:メモリコンテナーを作成および設定します。
Agentic memory APIs:メモリの作成、読み取り、更新、削除 (CRUD) 操作のための完全な API セット。
課金
PolarSearch メモリコンテナーを使用すると、次のコストが発生します。本番環境でこの機能を使用する前に、これらのコストを注意深く確認してください。
コンピュートノード料金:PolarDB の一部として、PolarSearch ノードにはコンピュートノード料金が発生します。
モデルサービス料金:ファクト抽出やベクトル化のために Alibaba Cloud Model Studio のモデルなどの外部モデルを呼び出すと、API 呼び出し料金が発生します。