When AI agents engage in multi-turn conversations or execute sequential tasks, they often fail to retain user preferences, past instructions, or contextual information. This lack of effective memory disrupts the interaction experience and reduces task efficiency. The PolarSearch Memory Container solves this problem. It is a long-term and short-term memory management system built into PolarDB for PostgreSQL. With this feature, agents automatically structure and persist conversation data. Later, they retrieve relevant memories quickly using semantic search—delivering truly continuous, personalized, and efficient service.
The PolarSearch Memory Container feature is in canary release. To request access, submit a ticket.
How it works
The PolarSearch Memory Container uses an automated processing flow to convert unstructured conversation data into searchable and usable structured memory. It is built on a three-tier storage architecture and an intelligent memory processing pipeline.
Three-tier storage architecture
The Memory Container uses a layered design to balance storage and retrieval efficiency for memories with different lifespans.
Memory type | Index type | Primary purpose |
Short-term memory (Working Memory) | Inverted index | Stores raw, unprocessed short-term conversation data. Uses inverted indexing for fast retrieval. Maintains context for the current conversation. |
Long-term memory (Long-Term Memory) | Vector index + inverted index | Uses a large language model (LLM) to extract key facts from conversations, then stores them as vectors. Supports KNN semantic search for deep knowledge and experience retrieval. |
Memory history (Memory History) | Inverted index | Records every memory operation (such as add or update), forming a complete audit log. Ensures memory evolution is traceable. |
Memory processing flow
When an agent receives new input, the Memory Container triggers a series of actions to automatically ingest, persist, and retrieve memory.
Memory ingestion:
Input and preprocessing: Receives agent conversation input using the Elasticsearch protocol. You can optionally call a large language model (LLM) to generate summaries, classify intent, or extract tags.
Routing decision: The Memory Router analyzes the input and compares it with existing memory to decide whether to add (ADD), update (UPDATE), or delete (DELETE) a memory.
Memory persistence:
Short-term memory: Stores raw conversation content.
Long-term memory: Stores structured facts that are extracted by the LLM and vectorized by an embedding model.
Memory history: Writes all operations to the memory history to create an audit trail.
Memory retrieval:
Input parsing: Accepts search criteria. Parses multimodal search requests using the Elasticsearch protocol. Calls the permission validation module to confirm data access boundaries.
Hybrid index search: Performs a hybrid search (ANN vector similarity search and inverted index filtering) in long-term memory. Performs keyword matching in short-term memory. Adjusts weights based on memory timestamps.
Result integration: Uses a rerank model to optimize the result ordering. Resolves conflicts using timestamps and other metadata. Returns the most relevant memory to the agent.
Key benefits
Capability dimension | Traditional approach | PolarSearch solution |
Memory utilization | Less than 30% of the historical data is retained, which hinders its effective use. | Extracts facts using an LLM and combines them with semantic indexing to increase effective information utilization to over 85%. |
Search efficiency | Relies on keyword matching, with an accuracy of 60% or less. | Uses hybrid vector and inverted indexing, plus reranking. This achieves a semantic search accuracy of over 95%. |
Enterprise compliance | Multi-tenant isolation and permission control are complex to implement. | Provides native multi-tenant isolation, role-based access control (RBAC) permission control, and operation audit to meet enterprise security requirements. |
System scalability | Single-point storage capacity is capped at the terabyte level. | Built on a cloud-native distributed storage architecture. Storage can scale to the petabyte level. |
Development cost | Requires custom development and has a long implementation time. | Provides out-of-the-box APIs and SDKs to simplify development and enable rapid integration. |
Scope
Feature node: Add a PolarSearch search node to your cluster.
Account permissions: Create a search node administrator account to enable plugins and create resources.
Getting Started
This guide walks you through the entire process, from environment setup to storing and retrieving a memory.
Overall workflow: Prepare environment → Enable plugin → Register models → Create memory container → Store and verify memory.
Step 1: Configure access credentials and environment variables
Before you start, prepare the following information and set it as environment variables. This simplifies subsequent curl commands and avoids repeated edits. Centralizing all configurations and credentials makes them easy to copy and execute.
Variable name | Description | Example value |
| The connection address and port of the PolarSearch node. |
|
| The administrator account for the PolarSearch node. |
|
| Your API key for Alibaba Cloud Model Studio. |
|
Action: Run the following commands in your terminal. Replace the example values with your actual values.
# Set the PolarSearch host and port
export POLARSEARCH_HOST_PORT="pc-xxx.polardbsearch.rds.aliyuncs.com:3001"
# Set the PolarSearch administrator password
export USER_PASSWORD="polarsearch_user:your_password"
# Set your Qwen API key
export YOUR_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxx"Step 2: Enable the Memory Container plugin
Run the following command to enable the Memory Container feature in your PolarDB cluster.
Command line
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
}
}'Dashboard
PUT _cluster/settings
{
"persistent": {
"plugins.ml_commons.agentic_memory_enabled": true
}
}Step 3: Register models
You must register an LLM for fact extraction and an embedding model for semantic processing with PolarSearch.
Register an embedding model
Create a connector that points to the embedding model service in Alibaba Cloud Model Studio and register it as a callable model in PolarSearch.
Set a trusted endpoint: Add your model’s API endpoint to the trusted list so that PolarSearch can call it.
Command line
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/.*$" ] } }'Dashboard
PUT _cluster/settings { "persistent": { "plugins.ml_commons.trusted_connector_endpoints_regex": [ "^https://dashscope.aliyuncs.com/compatible-mode/v1/.*$" ] } }Create a model connector: Configure parameters to connect to the
text-embedding-v4model.NoteThe
pre_process_functionandpost_process_functionparameters adapt request and response formats for different model services. In this example, the built-inopenai.embeddingformat converter is used because it matches the format of Alibaba Cloud Model Studio in compatible mode.Command line
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" } ] }'Dashboard
ImportantReplace
<YOUR_API_KEY>in the following command with your actual API key for Alibaba Cloud Model Studio.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" } ] }After the command is successfully run, the system returns a
connector_id. Record this ID for later use.{"connector_id": "LBFt6ZsBk04xxx"}Register the model: Register the connector created in the previous step as a model.
Command line
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" }'Dashboard
POST _plugins/_ml/models/_register { "name": "qwen embedding model", "function_name": "remote", "description": "Embedding model for memory", "connector_id": "LBFt6ZsBk04xxx" }After the command is successfully run, the system returns a
model_id. Record this ID for later use.# Record the returned model_id {"task_id": "LRFx6ZsBk04ixxx","status": "CREATED","model_id": "LhFx6ZsBk04xxx"}Test the model: Run the following query to chat directly with the LLM and view its response.
Command line
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"] }'Dashboard
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"] }Expected response:
{ "inference_results": [ { "output": [ { "name": "sentence_embedding", "data_type": "FLOAT32", "shape": [ 1024 ], "data": [ 0.019752666354179382, -0.03468115255236626, 0.05591931194067001, ... ] } ], "status_code": 200 } ] }
Register a text generation model (LLM)
Create and register a connector to the qwen-plus LLM in Alibaba Cloud Model Studio.
Create a model connector:
Command line
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\" } }" } ] }'Dashboard
ImportantReplace
<YOUR_API_KEY>in the following command with your actual API key for Alibaba Cloud Model Studio.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\" } }" } ] }After the command is successfully run, the system returns a
connector_id. Record this ID for later use.{"connector_id": "PRGy6ZsBk04xxx"}Register the model: Register the connector created in the previous step as a model.
Command line
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" }'Dashboard
POST _plugins/_ml/models/_register { "name": "qwen llm model", "function_name": "remote", "description": "LLM model for memory", "connector_id": "PRGy6ZsBk04xxx" }After the command is successfully run, the system returns a
model_id. Record this ID for later use.# Record the returned model_id {"task_id": "PhGy6ZsBk04xxx","status": "CREATED","model_id": "PxGy6ZsBk04xxx"}Deploy the model:
Command line
curl -XPOST "http://${POLARSEARCH_HOST_PORT}/_plugins/_ml/models/<model ID from previous step>/_deploy" \ --user "${USER_PASSWORD}"Dashboard
POST _plugins/_ml/models/<model ID from previous step>/_deployAfter the command is successfully run, a
statusofCOMPLETEDindicates that the deployment was successful.{"task_id": "NxGI6ZsBk04xxx","task_type": "DEPLOY_MODEL","status": "COMPLETED"}Test the model: Run the following query to chat directly with the LLM and view its response.
Command line
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." } }'Dashboard
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." } }Expected response:
{ "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 } ] }
Step 4: Create a memory container
Create a memory container instance and configure its models, storage policies, and automation behavior. Run the following command to create a container named
agentic memory test.Command line
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" } } }'Dashboard
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" } } }Parameter description
index_prefix: A common prefix for the internal indexes that are created by this container, such as short-term and long-term memory indexes.index_settings: Configures the shard and replica counts for different memory indexes to ensure high availability.strategies: Defines automation rules. This example defines aSEMANTICstrategy that automatically extracts semantic facts from conversations within theuser_idnamespace.llm_result_path: Uses JSONPath syntax to specify how to extract the core content from the LLM’s JSON response. The path$.choices[0].message.contentmatches the response structure of Alibaba Cloud Model Studio in compatible mode.
After the command is successfully run, the system returns a
memory_container_id. Record this ID for later use.# Record the returned model_id {"memory_container_id": "QRHF6ZsBk04xxx","status": "created"}After creating the memory container, the system creates the following indexes and pipelines:
.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" } } } ] }
Step 5: Store and verify memory
Add a conversation to the memory container and verify that it is correctly stored in both short-term and long-term memory.
Store memory: Send a POST request with a conversation about a user named Bob to the container. The
"infer": trueparameter triggers theSEMANTICstrategy that you configured earlier to call the LLM and extract facts.Command line
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" }'Dashboard
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" }Verify short-term memory: Query the short-term memory index directly to view the saved original conversation.
Command line
curl -XGET "http://${POLARSEARCH_HOST_PORT}/.plugins-ml-am-<index_prefix from previous step>-memory-working/_search?pretty" \ --user "${USER_PASSWORD}" \Dashboard
GET .plugins-ml-am-<index_prefix from previous step>-memory-working/_search?prettyExpected output (partial):
{ "_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" } } }Verify long-term memory: Query the long-term memory index to confirm that the LLM successfully extracted the core fact “Bob likes swimming” and that the embedding model generated the corresponding
memory_embeddingvector.Command line
curl -XGET "http://${POLARSEARCH_HOST_PORT}/.plugins-ml-am-<index_prefix from previous step>-memory-long-term/_search?pretty" \ --user "${USER_PASSWORD}" \Dashboard
GET .plugins-ml-am-<index_prefix from previous step>-memory-long-term/_search?prettyExpected output (partial):
{ "_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" } } }View memory history: The
memory-historyindex contains two ADD records and their timestamps.Command line
curl -XGET "http://${POLARSEARCH_HOST_PORT}/.plugins-ml-am-<index_prefix from previous step>-memory-history/_search?pretty" \ --user "${USER_PASSWORD}" \Dashboard
GET .plugins-ml-am-<index_prefix from previous step>-memory-history/_search?prettyExpected output (partial):
{ "_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" } } }
You have now successfully stored a memory for your AI agent that supports long-term retrieval.
Step 6: (Optional) Update memory
The Memory Container can extract and update long-term memory.
First, store a memory:
Command line
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" }'Dashboard
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" }Search the long-term memory index:
Command line
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": {} } }'Dashboard
GET .plugins-ml-am-<index_prefix from previous step>-memory-long-term/_search { "_source": { "excludes": ["memory_embedding"] }, "query": { "match_all": {} } }Expected output (partial):
{ "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" } } } ] }Store another memory that conflicts with the previous one:
Command line
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" }'Dashboard
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" }Search the long-term memory index again to view the updated content (partial):
{ "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" } } } ] }
Use case: Build a travel memory agent
This section shows how to use the Memory Container API to build a Python agent that remembers user travel preferences and provides personalized recommendations.
Preparations
Before you run the code, you must install the required Python libraries. Add the following dependencies to your requirements.txt file.
requests
openaiRun pip install -r requirements.txt to install them.
Core code explanation
The following are the key functions that interact with the Memory Container:
opensearch_request(): Wraps HTTP requests to the PolarSearch API and handles authentication and errors.add_memory(): Calls the Memory Container’smemoriesAPI to store new conversation data.search_memories(): Calls the_searchAPI to retrieve information that is relevant to a user query from long-term and short-term memory.generate_response_with_memories(): Sends the retrieved memories as context, along with the user’s current question, to the LLM to generate a more personalized reply.
Complete example code
The following is a secure and logically optimized Python script. Save it as trip_agent.py and set the environment variables as instructed.
Run and interact
Set environment variables: In your terminal, set the required environment variables for the script.
Run the script:
python trip_agent.pyInteraction example:
API reference
This guide uses the following APIs. For more information, see the official OpenSearch documentation:
Create Memory Container API: Creates and configures a memory container.
Agentic memory APIs: A full set of APIs for memory create, read, update, and delete (CRUD) operations.
Billing
Using the PolarSearch Memory Container incurs the following costs. Review these costs carefully before you use the feature in a production environment.
Compute node fees: As a part of PolarDB, PolarSearch nodes incur compute node fees.
Model service fees: Calling external models, such as models from Alibaba Cloud Model Studio, for fact extraction and vectorization incurs API call fees.