For AI agents: a documentation index is available at https://www.mongodb.com/docs/llms.txt — markdown versions of all pages are available by appending .md to any URL path.
Docs Menu

Add Long-Term Memory to CrewAI Agents

In this tutorial, you use the crewai-mongodb-memory package to give a CrewAI agent durable long-term memory that persists in MongoDB Atlas. The agent stores user preferences as memory records and recalls them semantically with MongoDB Vector Search, so a brand-new crew in a later session can answer correctly by retrieving learnings from a previous session.

To learn more about the MongoDB CrewAI integration, see Integrate MongoDB with CrewAI.

To complete this tutorial, you must have the following:

  • Python 3.10 or later.

  • One of the following MongoDB cluster types:

  • A Voyage AI API key. To create an API key, see Model API Keys.

  • A large language model (LLM) API key, such as Anthropic or OpenAI, to power the agent's inference.

The crewai-mongodb-memory backend implements CrewAI's StorageBackend protocol. It stores each memory as a record in a MongoDB collection and uses MongoDB Vector Search to retrieve relevant records semantically. The backend uses the following components:

  • MongoDBStorageBackend: Connects to your Atlas cluster, stores memory records, and runs $vectorSearch queries to recall them.

  • MemoryRecord: Represents a single memory, including its text content, a hierarchical scope such as /users/alex/preferences, optional categories, and its vector embedding.

  • embed_text(): Generates 1024-dimensional embeddings with the Voyage AI voyage-4 model for both stored documents and queries.

Because the memory lives in Atlas instead of the crew's in-process context, any crew that connects to the same cluster and scope can recall the stored memories.

{
"_id": "cff7db8d-aa2e-4d82-8234-e4b8f1ccccb6",
"content": "The user always prefers window seats on flights.",
"scope": "/users/alex/preferences",
"categories": [
"preference"
],
"metadata": {},
"importance": 0.5,
"created_at": {
"$date": "2026-07-14T22:06:59.162Z"
},
"last_accessed": {
"$date": "2026-07-14T22:06:59.162Z"
},
"source": null,
"private": false,
"embedding": [
0.03147803992033005,
0.015906454995274544,
-0.007409059442579746,
0.028631621971726418,
...
],
"scope_ancestors": [
"/users",
"/users/alex",
"/users/alex/preferences"
]
}

Complete the following steps to build and run an agent that stores and recalls user preferences:

1
  1. Run the following commands in your terminal to create a new directory named crewai-memory-project and install the required dependencies:

    mkdir crewai-memory-project
    cd crewai-memory-project
    pip install crewai-mongodb-memory crewai "crewai[google-genai]" voyageai python-dotenv
  2. In your project, create a .env file and add the following lines:

    ATLAS_URI="<connection-string>"
    VOYAGE_API_KEY="<voyage-api-key>"
    ANTHROPIC_API_KEY="<anthropic-api-key>"
    MODEL="<anthropic-model>"

    Note

    Replace <connection-string> with the connection string for your Atlas cluster or local Atlas deployment.

    Your connection string should use the following format:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net

    To learn more, see Connect to a Cluster via Client Libraries.

    Your connection string should use the following format:

    mongodb://localhost:<port-number>/?directConnection=true

    To learn more, see Connection Strings.

2

Create a file named main.py in your project and paste the following code:

from __future__ import annotations
import os
import sys
import time
import warnings
from dotenv import load_dotenv
load_dotenv()
warnings.filterwarnings("ignore")
from crewai import Agent, Crew, Task
from crewai.tools import tool
from crewai_mongodb_memory import MemoryRecord, MongoDBStorageBackend, embed_text
from crewai.events import CrewKickoffStartedEvent, CrewKickoffCompletedEvent, AgentExecutionCompletedEvent
from crewai.events import BaseEventListener
DEMO_DB = "crewai_mem_agent_demo"
SCOPE = "/users/alex/preferences"
MODEL = os.environ.get("ANTHROPIC_MODEL", "anthropic/claude-3-5-sonnet-latest")
EMBEDDING_MODEL = os.environ.get("VOYAGE_MODEL", "voyage-4")
# Module-level backend handle so the function tools can reach it.
_BACKEND: MongoDBStorageBackend | None = None
_SESSION_LABEL = ""
# Custom event listener for logging Crew and Agent events.
class EventListener(BaseEventListener):
def __init__(self):
super().__init__()
def setup_listeners(self, crewai_event_bus):
@crewai_event_bus.on(CrewKickoffStartedEvent)
def on_crew_started(source, event):
print(f"Crew '{event.crew_name}' has started execution!")
@crewai_event_bus.on(CrewKickoffCompletedEvent)
def on_crew_completed(source, event):
print(f"Crew '{event.crew_name}' has completed execution!")
print(f"Output: {event.output}")
@crewai_event_bus.on(AgentExecutionCompletedEvent)
def on_agent_execution_completed(source, event):
print(f"Agent '{event.agent.role}' completed task")
print(f"Output: {event.output}")
def banner(title: str) -> None:
print(f"\n{'=' * 70}\n{title}\n{'=' * 70}")
def embed(text: str, input_type: str) -> list[float]:
"""Generate embeddings with an explicit Voyage model."""
try:
return embed_text(text, input_type=input_type, model=EMBEDDING_MODEL)
except TypeError:
# Backward compatibility for older crewai-mongodb-memory versions.
return embed_text(text, input_type=input_type)
@tool("remember_preference")
def remember_preference(fact: str) -> str:
"""Store a durable user preference in MongoDB Atlas long-term memory."""
assert _BACKEND is not None
rec = MemoryRecord(
content=fact,
scope=SCOPE,
categories=["preference"],
embedding=embed(fact, input_type="document"),
)
_BACKEND.save([rec])
return f"Stored preference: {fact}"
@tool("recall_preferences")
def recall_preferences(query: str) -> str:
"""Retrieve relevant user preferences from Atlas via $vectorSearch."""
assert _BACKEND is not None
qv = embed(query, input_type="query")
hits = _BACKEND.search(qv, scope_prefix=SCOPE, limit=3)
if not hits:
return "No relevant preferences found."
for rec, score in hits:
print(f" - [{score:.3f}] {rec.content}")
return "\n".join(f"- {rec.content} (score={score:.3f})" for rec, score in hits)
def build_agent() -> Agent:
return Agent(
role="Personal Concierge",
goal="Help the user with durable long-term memory stored in MongoDB Atlas.",
backstory=(
"""You remember user preferences across sessions. When the user shares
a durable preference, call remember_preference. When a request may
depend on what you know about them, call recall_preferences first
and use the results."""
),
tools=[remember_preference, recall_preferences],
llm=MODEL,
verbose=True,
)
def run_task(description: str, expected_output: str) -> str:
"""Run a single-task crew (a fresh crew each call is a fresh session)."""
agent = build_agent()
task = Task(description=description, expected_output=expected_output, agent=agent)
crew = Crew(agent, [task])
return str(crew.kickoff())
def main() -> None:
global _BACKEND, _SESSION_LABEL
uri = os.environ.get("ATLAS_URI")
# Fast fail if the required environment variables are not set.
if not all([uri, os.environ.get("ANTHROPIC_API_KEY"), os.environ.get("VOYAGE_API_KEY")]):
print("This script needs ATLAS_URI, ANTHROPIC_API_KEY, and VOYAGE_API_KEY.")
sys.exit(1)
print(f"=== CrewAI and MongoDB Atlas long-term memory (model={MODEL}) ===")
_BACKEND = MongoDBStorageBackend(uri, database_name=DEMO_DB)
_BACKEND.delete(scope_prefix=SCOPE) # clean slate for a repeatable run
print("Ensuring Atlas Vector Search index (first build can take ~1 min)...")
if not _BACKEND.ensure_vector_index(wait=True):
print("Vector index did not become queryable in time.")
sys.exit(1)
print("Index queryable.")
# Initialize the event listener for the agent.
listener = EventListener()
# Session 1: the agent learns and stores preferences.
banner("SESSION 1 - agent stores durable preferences in Atlas")
session_1_input = (
"""The user says: 'I'm vegetarian, I avoid dairy, and I always prefer
window seats on flights.' Store each durable preference."""
)
_SESSION_LABEL = "SESSION 1"
print(f" {session_1_input}")
out1 = run_task(
description=session_1_input,
expected_output="A short confirmation of what was stored.",
)
print(f"\nAgent (session 1): {out1}")
# Atlas indexing is asynchronous, so wait until the facts are searchable.
print("\nWaiting for Atlas to index the new memories...")
for _ in range(20):
if _BACKEND.search(embed("food", input_type="query"), scope_prefix=SCOPE, limit=1):
break
time.sleep(2)
print("Memories searchable.")
# Session 2: a brand-new crew with no shared state recalls from Atlas.
banner("SESSION 2 - fresh crew answers via recall_preferences")
session_2_input = (
"""The user is booking a long flight and pre-ordering an in-flight meal.
Recommend a seat and a meal that fit their preferences."""
)
_SESSION_LABEL = "SESSION 2"
print(f" {session_2_input}")
out2 = run_task(
description=session_2_input,
expected_output="A seat and meal recommendation grounded in recalled preferences.",
)
print(f"\nAgent (session 2, brand-new crew): {out2}")
banner("Proof: direct $vectorSearch recall over stored preferences")
hits = _BACKEND.search(
embed("dietary and seating preferences", input_type="query"),
scope_prefix=SCOPE,
limit=5,
)
for rec, score in hits:
print(f" - [{score:.3f}] {rec.content}")
_BACKEND.delete(scope_prefix=SCOPE)
_BACKEND.close()
print("\nDone - CrewAI stored and recalled preferences via MongoDB Vector Search.")
if __name__ == "__main__":
main()

This script does the following:

  • Connects to your Atlas cluster with MongoDBStorageBackend and ensures a MongoDB Vector Search index exists on the memory collection.

  • Defines two tools, remember_preference and recall_preferences, that the agent calls to store and retrieve memories.

  • Defines a CrewAI agent that uses the memory tools, then runs one crew that stores the user's preferences.

  • Runs a second, brand-new crew that recalls the stored preferences from Atlas and grounds its recommendation in them.

3

Run the following command to execute the script:

python main.py
======================================================================
SESSION 1 - agent stores durable preferences in Atlas
======================================================================
The user says: 'I'm vegetarian, I avoid dairy, and I always prefer
window seats on flights.' Store each durable preference.
Crew 'crew' has started execution!
╭────────────────────────────── 🤖 Agent Started ──────────────────────────────╮
│ │
│ Agent: Personal Concierge │
│ │
│ Task: The user says: 'I'm vegetarian, I avoid dairy, and I always prefer │
│ window seats on flights.' Store each durable preference. │
│ │
╰──────────────────────────────────────────────────────────────────────────────╯
Tool remember_preference executed with result: Stored preference: The user is vegetarian....
Tool remember_preference executed with result: Stored preference: The user avoids dairy....
Tool remember_preference executed with result: Stored preference: The user always prefers window seats on flights....
[Finalize] todos_count=0, todos_with_results=0
╭─────────────────────────── ✅ Agent Final Answer ────────────────────────────╮
│ │
│ Agent: Personal Concierge │
│ │
│ Final Answer: │
│ Stored: │
│ - The user is vegetarian. │
│ - The user avoids dairy. │
│ - The user always prefers window seats on flights. │
│ │
╰──────────────────────────────────────────────────────────────────────────────╯
Agent 'Personal Concierge' completed task
Output: Stored:
- The user is vegetarian.
- The user avoids dairy.
- The user always prefers window seats on flights.
Crew 'crew' has completed execution!
Output: Stored:
- The user is vegetarian.
- The user avoids dairy.
- The user always prefers window seats on flights.
Agent (session 1): Stored:
- The user is vegetarian.
- The user avoids dairy.
- The user always prefers window seats on flights.
Waiting for Atlas to index the new memories...
Memories searchable.
======================================================================
SESSION 2 - fresh crew answers via recall_preferences
======================================================================
The user is booking a long flight and pre-ordering an in-flight meal.
Recommend a seat and a meal that fit their preferences.
Crew 'crew' has started execution!
╭────────────────────────────── 🤖 Agent Started ──────────────────────────────╮
│ │
│ Agent: Personal Concierge │
│ │
│ Task: The user is booking a long flight and pre-ordering an in-flight │
│ meal. │
│ Recommend a seat and a meal that fit their preferences. │
│ │
╰──────────────────────────────────────────────────────────────────────────────╯
- [0.794] The user always prefers window seats on flights.
- [0.748] The user is vegetarian.
- [0.739] The user avoids dairy.
Tool recall_preferences executed with result: - The user always prefers window seats on flights. (score=0.794)
- The user is vegetarian. (score=0.748)
- The user avoids dairy. (score=0.739)...
[Finalize] todos_count=0, todos_with_results=0
╭─────────────────────────── ✅ Agent Final Answer ────────────────────────────╮
│ │
│ Agent: Personal Concierge │
│ │
│ Final Answer: │
│ I recommend booking a **window seat** for the long flight, since you │
│ prefer window seats. │
│ │
│ For your in-flight meal, choose a **vegetarian dairy-free meal**. If the │
│ airline offers specific meal codes, look for something like **VGML / vegan │
│ meal**, since that will typically meet both preferences: vegetarian and no │
│ dairy. │
│ │
╰──────────────────────────────────────────────────────────────────────────────╯
Agent 'Personal Concierge' completed task
Output: I recommend booking a **window seat** for the long flight, since you prefer window seats.
For your in-flight meal, choose a **vegetarian dairy-free meal**. If the airline offers specific meal codes, look for something like **VGML / vegan meal**, since that will typically meet both preferences: vegetarian and no dairy.
Crew 'crew' has completed execution!
Output: I recommend booking a **window seat** for the long flight, since you prefer window seats.
For your in-flight meal, choose a **vegetarian dairy-free meal**. If the airline offers specific meal codes, look for something like **VGML / vegan meal**, since that will typically meet both preferences: vegetarian and no dairy.
Agent (session 2, brand-new crew): I recommend booking a **window seat** for the long flight, since you prefer window seats.
For your in-flight meal, choose a **vegetarian dairy-free meal**. If the airline offers specific meal codes, look for something like **VGML / vegan meal**, since that will typically meet both preferences: vegetarian and no dairy.
======================================================================
Proof: direct $vectorSearch recall over stored preferences
======================================================================
- [0.770] The user always prefers window seats on flights.
- [0.768] The user is vegetarian.
- [0.754] The user avoids dairy.
Done - CrewAI stored and recalled preferences via MongoDB Vector Search.

Note

Your output might differ, as LLM responses and vector search scores can vary between runs.