AWS Builder Center

Building Persistent Memory Multi-Agent AI with Amazon Bedrock AgentCore + Mem0

A hands-on guide to wiring Amazon Bedrock (Nova Pro + Titan Embed v2) with Mem0 and FAISS to give multi-agent systems durable, semantically searchable long-term memory and deploy them on AgentCore Runtime.

Building a Memory-Persistent Multi-Agent AI System with Amazon Bedrock AgentCore + Mem0

Author: Sweta Jha | Senior Data Scientist & AI/ML Engineer | AWS Community Builder (AI/ML) Stack: Strands Agents SDK · Amazon Bedrock Nova Pro · AgentCore Runtime · Mem0 · FAISS · FastAPI



TL;DR

Most AI agents forget everything between conversations. In this post I'll show you how to wire Amazon Bedrock AgentCore Memory together with Mem0 to give your multi-agent system persistent, semantically-searchable long-term memory — deployed as a production-ready container on AgentCore Runtime, with zero OpenAI dependency.



Why Agents Need Memory

Imagine hiring a consultant who forgets every project the moment they walk out the door. You'd brief them from scratch every single time. That's exactly what most LLM-based agents do today.
AgentCore Memory + Mem0 solves this by:
  • Persisting every agent interaction to a vector store
  • Semantically retrieving the most relevant past context before each new request
  • Sharing memory across agents — your ResearchAgent's findings are visible to your WriterAgent
  • Surviving session restarts — memory lives in FAISS on disk (or OpenSearch in production)



Architecture Overview

Plain text
┌─────────────────────────────────────────────────────────────────┐
│ User / Client Application │
└────────────────────────────┬────────────────────────────────────┘
│ HTTP POST /invoke
▼
┌─────────────────────────────────────────────────────────────────┐
│ Amazon Bedrock AgentCore Runtime │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ FastAPI / Handler │ │
│ └───────────────────────┬──────────────────────────────────┘ │
│ │ │
│ ┌──────────────▼──────────────┐ │
│ │ Orchestrator Agent │ ◄── Strands SDK │
│ │ (Amazon Nova Pro) │ │
│ └──┬───────────┬──────────────┘ │
│ │ │ │
│ ┌──────────▼──┐ ┌─────▼──────┐ ┌────────────────┐ │
│ │ ResearchAgent│ │WriterAgent │ │ ReviewerAgent │ │
│ │ (Nova Pro) │ │ (Nova Pro) │ │ (Nova Pro) │ │
│ └──────┬──────┘ └──────┬─────┘ └───────┬────────┘ │
│ │ │ │ │
│ └────────────────┴─────────────────┘ │
│ │ │
│ ┌──────▼───────┐ │
│ │ Mem0 Layer │ ◄── AgentCore Memory │
│ │ ┌─────────┐ │ │
│ │ │ FAISS │ │ ◄── Vector Store (local) │
│ │ │ (local) │ │ │
│ │ └─────────┘ │ │
│ │ ┌─────────┐ │ │
│ │ │ SQLite │ │ ◄── History DB │
│ │ └─────────┘ │ │
│ └──────────────┘ │
│ │
│ Embeddings: Amazon Titan Embed v2 (Bedrock) │
│ LLM: Amazon Nova Pro (Bedrock) │
└─────────────────────────────────────────────────────────────────┘
Three specialist agents, one shared memory layer. Every agent reads from and writes to the same Mem0 store, so knowledge compounds over time.



Prerequisites

Requirement
Notes
Python 3.11+
Tested on 3.11 and 3.12
AWS Account
With Bedrock model access enabled
Amazon Nova Pro access
Enable in Bedrock console → Model Access
Amazon Titan Embed v2 access
Same — enable in Model Access
Docker (optional)
For AgentCore Runtime deployment



Project Structure

Plain text
agentcore-mem0/
├── agents/
│ ├── orchestrator.py # Routes requests, injects memory context
│ ├── research_agent.py # Fetches docs, summarises findings
│ └── writer_reviewer_agents.py # Drafts & reviews content
├── memory/
│ └── mem0_layer.py # Mem0 + Bedrock Titan Embed integration
├── agentcore_handler.py # AgentCore Runtime entry point
├── api_server.py # FastAPI wrapper for local dev
├── Dockerfile # AgentCore Runtime container
├── requirements.txt
└── .env.example



Step 1 — Install Dependencies

Bash
# Clone the repo
git clone https://github.com/sweta-jha/agentcore-mem0-multiagent
cd agentcore-mem0

# Create virtual environment
python -m venv venv && source venv/bin/activate

# Install
pip install -r requirements.txt



Step 2 — Configure Environment

Bash
cp .env.example .env
# Edit .env with your AWS credentials and Bedrock model IDs
Key variables:
Bash
AWS_REGION=us-east-1
BEDROCK_MODEL_ID=amazon.nova-pro-v1:0
BEDROCK_EMBEDDING_MODEL=amazon.titan-embed-text-v2:0
MEM0_USER_ID=your_username



Step 3 — The Memory Layer (Core Innovation)

The heart of this system is  memory/mem0_layer.py . Here's how Mem0 is configured to use Amazon Bedrock entirely — no OpenAI key required:
Python
def build_mem0_config() -> dict:
return {
# LLM: Amazon Bedrock Nova Pro for memory distillation
"llm": {
"provider": "aws_bedrock",
"config": {
"model": "amazon.nova-pro-v1:0",
"aws_region": "us-east-1",
"temperature": 0.1,
"max_tokens": 1500,
},
},
# Embedder: Amazon Titan Embed v2 (1024-dim vectors)
"embedder": {
"provider": "aws_bedrock",
"config": {
"model": "amazon.titan-embed-text-v2:0",
"aws_region": "us-east-1",
"embedding_dims": 1024,
},
},
# Vector Store: FAISS persisted to disk
"vector_store": {
"provider": "faiss",
"config": {
"embedding_model_dims": 1024,
"path": "./memory_store",
},
},
"history_db_path": "./memory_store/mem0_history.db",
}

How Memory Injection Works

Before every agent call, we retrieve semantically relevant past interactions and inject them into the system prompt:
Python
def format_for_prompt(self, query: str, limit: int = 5) -> str:
"""
Retrieve relevant memories and format as a context block
ready to inject into any agent's system prompt.
"""
memories = self.search(query, limit=limit)
if not memories:
return "No relevant past context found."

lines = ["## Relevant Memory Context\n"]
for i, mem in enumerate(memories, 1):
score = mem.get("score", 0)
text = mem.get("memory", "")
agent = mem.get("metadata", {}).get("agent_id", "unknown")
lines.append(f"{i}. [{agent}] (relevance: {score:.2f}) {text}")

return "\n".join(lines)
This means your agent's system prompt becomes:
Plain text
[Standard system prompt]

## Relevant Memory Context
1. [research_agent] (relevance: 0.91) User researched Strands SDK on 2025-06-01...
2. [writer_agent] (relevance: 0.84) Blog draft written on AgentCore Memory topic...
3. [orchestrator] (relevance: 0.79) User asked about Mem0 FAISS integration...
The agent knows what it has done before and builds on it.



Step 4 — The Orchestrator Agent

The Orchestrator reads memory, decides which specialist to call, and writes back:
Python
def run_orchestrator(user_message: str, user_id: str = "default_user") -> str:
memory = get_memory(user_id)

# 1. Retrieve relevant past context
memory_context = memory.format_for_prompt(query=user_message, limit=5)

# 2. Enrich the prompt with memory
enriched_prompt = f"""
[MEMORY CONTEXT]
{memory_context}

[USER REQUEST]
{user_message}
"""

# 3. Run the Strands Agent
agent, _ = build_orchestrator(user_id)
result = agent(enriched_prompt)
response_text = str(result)

# 4. Persist this interaction to Mem0
memory.add(
content=f"User asked: {user_message[:200]} | Response: {response_text[:300]}",
agent_id="orchestrator",
)

return response_text
The read-enrich-run-write cycle is the key pattern. Every agent follows it.



Step 5 — Specialist Agents with Tools

ResearchAgent Tools (Strands SDK  @tool  decorator)

Python
from strands import Agent, tool

@tool
def search_aws_docs(service_name: str, topic: str) -> str:
"""
Search AWS documentation for a given service and topic.
In production: replace with Bedrock Knowledge Base retrieval.
"""
# Swap this body for real RAG / KB retrieval
return f"Documentation results for {service_name} → {topic} ..."

@tool
def extract_keywords(text: str) -> list[str]:
"""Extract AWS service names from text."""
aws_services = ["AgentCore", "Bedrock", "Lambda", "DynamoDB", "Mem0", ...]
return [s for s in aws_services if s.lower() in text.lower()]

WriterAgent Tools

Python
@tool
def generate_section_outline(topic: str, num_sections: int = 6) -> str:
"""Generate a structured blog post outline."""
sections = [
"Introduction & Motivation",
"Architecture Overview",
"Prerequisites & Setup",
"Step-by-Step Implementation",
"Code Deep Dive",
"Deployment on AgentCore Runtime",
]
return "\n".join(f"{i+1}. {s}" for i, s in enumerate(sections[:num_sections]))



Step 6 — AgentCore Runtime Handler

AgentCore Runtime calls your  handler()  function for every request:
Python
def handler(event: dict, context=None) -> dict:
user_message, user_id, task_type = parse_event(event)
memory = AgentMemoryLayer(user_id=user_id)

# Route to the right agent based on sessionAttributes.taskType
if task_type == "research":
response = run_research(user_message, memory)
elif task_type == "write":
response = run_writer(user_message, memory)
elif task_type == "review":
response = run_reviewer(user_message, memory)
else:
response = run_orchestrator(user_message, user_id=user_id)

return {
"statusCode": 200,
"body": json.dumps({
"response": response,
"metadata": {
"user_id": user_id,
"task_type": task_type,
"memory_backend": "Mem0 + FAISS + Bedrock Titan Embed",
},
}),
}
The event envelope from AgentCore looks like this:
JSON
{
"inputText": "Research AgentCore Memory and write me a blog outline.",
"sessionId": "session-abc-123",
"sessionAttributes": {
"userId": "sweta_jha",
"taskType": "orchestrate"
}
}



Step 7 — Local Testing

Bash
# Option A: Run handler directly
python agentcore_handler.py

# Option B: Run FastAPI server
uvicorn api_server:app --reload --port 8080
Test with curl:
Bash
# Full orchestration
curl -X POST http://localhost:8080/invoke \
-H "Content-Type: application/json" \
-d '{
"message": "What is AgentCore Memory and how does Mem0 integrate?",
"user_id": "sweta_jha",
"task_type": "orchestrate"
}'

# Research only
curl -X POST http://localhost:8080/invoke \
-d '{"message": "Strands SDK key features", "task_type": "research"}'

# View all stored memories
curl http://localhost:8080/memory/sweta_jha

# Semantic memory search
curl "http://localhost:8080/memory/sweta_jha/search?q=AgentCore&limit=3"



Step 8 — Deploy to AgentCore Runtime

Build and Push Container

Bash
# Build
docker build -t agentcore-mem0-agent .

# Tag for ECR
aws ecr get-login-password --region us-east-1 \
| docker login --username AWS --password-stdin \
123456789.dkr.ecr.us-east-1.amazonaws.com

docker tag agentcore-mem0-agent:latest \
123456789.dkr.ecr.us-east-1.amazonaws.com/agentcore-mem0-agent:latest

docker push 123456789.dkr.ecr.us-east-1.amazonaws.com/agentcore-mem0-agent:latest

Create AgentCore Agent

Bash
aws bedrock-agent create-agent \
--agent-name "mem0-multiagent" \
--description "Multi-agent system with Mem0 persistent memory" \
--foundation-model "amazon.nova-pro-v1:0" \
--agent-resource-role-arn "arn:aws:iam::123456789:role/AmazonBedrockAgentRole" \
--region us-east-1

Deploy to AgentCore Runtime

Bash
# AgentCore Runtime (GA - check latest CLI syntax in AWS docs)
aws bedrock-agentcore create-agent-runtime \
--agent-runtime-name "mem0-multiagent-runtime" \
--container-configuration '{
"imageUri": "123456789.dkr.ecr.us-east-1.amazonaws.com/agentcore-mem0-agent:latest",
"port": 8080
}' \
--region us-east-1
AgentCore Runtime handles:
  • Auto-scaling based on request volume
  • Health checks via your  /health  endpoint
  • OAuth 2.0 authentication
  • Session management across requests
  • CloudWatch metrics and logging out of the box



The Memory Lifecycle in Action

Here's what happens across three separate sessions with the same user:
Plain text
Session 1 (Day 1)
User: "Research Strands SDK"
→ ResearchAgent runs, stores findings in Mem0
→ Memory: "Researched Strands SDK: ReAct loop, tool decorators, Bedrock integration"

Session 2 (Day 2)
User: "Write a blog post"
→ Orchestrator retrieves Session 1 memory (relevance: 0.89)
→ WriterAgent gets: "## Memory Context: User researched Strands SDK yesterday..."
→ Blog draft references Strands SDK correctly without re-researching
→ Memory: "Wrote blog post on Strands SDK + AgentCore"

Session 3 (Day 3)
User: "Review the draft"
→ ReviewerAgent retrieves Sessions 1 & 2 memories
→ Knows the topic, knows the draft exists, provides targeted review
→ Memory: "Review complete: draft approved with minor edits"
Each agent builds on what came before. This is the power of shared persistent memory.



Production Considerations

Concern
Local Dev
Production
Vector Store
FAISS on disk
Amazon OpenSearch Serverless
History DB
SQLite
Amazon RDS (PostgreSQL)
Memory Scope
Per-user files
DynamoDB + S3
Auth
None
AgentCore OAuth 2.0
Scaling
Single instance
AgentCore Runtime auto-scale
Monitoring
Stdout logs
CloudWatch + X-Ray

Swap FAISS for OpenSearch (Production)

Python
"vector_store": {
"provider": "opensearch",
"config": {
"host": "your-opensearch-endpoint.us-east-1.aoss.amazonaws.com",
"port": 443,
"index_name": "mem0-agent-memory",
"embedding_model_dims": 1024,
"use_ssl": True,
},
}



Key Takeaways

  1. AgentCore Memory + Mem0 = persistent agent intelligence. Agents remember past interactions semantically, not just as raw chat history.
  1. 100% AWS-native stack. Amazon Bedrock Nova Pro for LLM inference, Amazon Titan Embed v2 for embeddings — no OpenAI dependency.
  1. Strands SDK  @tool  decorator makes it trivially easy to extend any agent with custom capabilities.
  1. Shared memory across agents means your ResearchAgent's findings flow automatically into your WriterAgent's context — no manual data passing needed.
  1. AgentCore Runtime handles all the infrastructure concerns (scaling, auth, health checks) so you ship agent logic, not DevOps boilerplate.



What's Next?

  • Add Bedrock Knowledge Bases as a RAG source inside  search_aws_docs  for real-time AWS documentation retrieval
  • Swap FAISS for Amazon OpenSearch Serverless for production-scale vector search
  • Add AgentCore Gateway to expose your multi-agent system as a managed API endpoint
  • Integrate Amazon Bedrock Guardrails for content filtering and PII redaction
  • Add a PlannerAgent that decomposes complex multi-step tasks before routing to specialists



Repository

All code from this post is available at:  github.com/sweta-jha/agentcore-mem0-multiagent 
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article