Multi-Agent Memory
Share memory context across agents in multi-agent workflows
Multi-Agent Memory gives all agents in a workflow access to shared memory, so knowledge discovered by one agent is available to others.
from praisonaiagents import Agent, Task, PraisonAIAgents, MultiAgentMemoryConfig
researcher = Agent(name="Researcher", instructions="Research topics and share findings.")
writer = Agent(name="Writer", instructions="Write based on shared research.")
tasks = [
Task(description="Research climate change impacts on agriculture", agent=researcher),
Task(description="Write a policy brief based on the research", agent=writer),
]
workflow = PraisonAIAgents(
agents=[researcher, writer],
tasks=tasks,
memory=MultiAgentMemoryConfig(user_id="project_climate", config={"provider": "rag"}),
)
workflow.start()The user runs a multi-agent workflow; all agents read and write shared memory under one user id.
Quick Start
- Simple Usage
python from praisonaiagents import Agent, Task, PraisonAIAgents, MultiAgentMemoryConfig agent1 = Agent(name="Gatherer", instructions="Gather and remember information.") agent2 = Agent(name="Synthesizer", instructions="Synthesize remembered information.") tasks = [ Task(description="Gather key facts about solar energy", agent=agent1), Task(description="Create a summary from gathered facts", agent=agent2), ] workflow = PraisonAIAgents( agents=[agent1, agent2], tasks=tasks, memory=MultiAgentMemoryConfig(user_id="solar_project"), ) workflow.start() - With Custom Embedder
python from praisonaiagents import Agent, Task, PraisonAIAgents, MultiAgentMemoryConfig agents = [ Agent(name="Expert", instructions="Provide domain expertise."), Agent(name="Summarizer", instructions="Summarize expert findings."), ] tasks = [ Task(description="Analyze cybersecurity vulnerabilities in cloud systems", agent=agents[0]), Task(description="Create an executive summary for non-technical stakeholders", agent=agents[1]), ] workflow = PraisonAIAgents( agents=agents, tasks=tasks, memory=MultiAgentMemoryConfig( user_id="security_review", embedder={"provider": "openai", "config": {"model": "text-embedding-3-small"}}, config={"provider": "rag"}, ), ) workflow.start()
Configuration Options
MultiAgentMemoryConfig SDK ReferenceFull parameter reference for MultiAgentMemoryConfig
Precedence ladder:
# Level 1: Bool (enable with defaults)
team = PraisonAIAgents(memory=True)
# Level 2: MultiAgentMemoryConfig (full control)
team = PraisonAIAgents(memory=MultiAgentMemoryConfig(
user_id="user-123",
embedder={"provider": "openai"},
))| Option | Type | Default | Description | |
|---|---|---|---|---|
user_id | `str \ | None` | None | Scope memory to a specific user or project |
embedder | `Any \ | None` | None | Embedder configuration (e.g., {"provider": "openai"}) |
How It Works
| Phase | What happens |
|---|---|
| 1. Store | First agent saves discoveries to shared memory |
| 2. Retrieve | Subsequent agents access all stored context |
| 3. Build | Later agents build on earlier agents’ work |
Configuration Options
CardFull list of options, types, and defaults — MultiAgentMemoryConfig
| Option | Type | Default | Description | |
|---|---|---|---|---|
user_id | `str \ | None` | None | Shared user/project identifier for scoped memory |
embedder | `Any \ | None` | None | Embedder configuration for semantic memory |
config | `dict \ | None` | None | Memory provider configuration |
Common Patterns
Pattern 1 — Project-scoped research memory
from praisonaiagents import Agent, Task, PraisonAIAgents, MultiAgentMemoryConfig
agents = [
Agent(name="Researcher", instructions="Research and document findings."),
Agent(name="Analyst", instructions="Analyze documented findings."),
Agent(name="Reporter", instructions="Create final reports."),
]
tasks = [
Task(description="Research market trends in renewable energy", agent=agents[0]),
Task(description="Identify key investment opportunities from research", agent=agents[1]),
Task(description="Write an investment recommendation report", agent=agents[2]),
]
result = PraisonAIAgents(
agents=agents,
tasks=tasks,
memory=MultiAgentMemoryConfig(user_id="renewable_energy_2025"),
).start()
print(result)Best Practices
Always set user_id for project isolation
Set user_id to a unique project or session identifier to prevent memory from bleeding between unrelated workflows. Without user_id, all workflows share the same memory namespace.
Use semantic memory for related topics
Configure the embedder when agents need to find semantically related information (not just exact matches). OpenAI’s text-embedding-3-small is a good default — fast and cost-effective.
Order tasks to build context
Tasks run in order by default. Place information-gathering tasks first and synthesis/writing tasks later so downstream agents have full context from upstream agents.
Isolating collections per agent
When several agents share one rag_db_path, give each a distinct collection_name so they coexist and can be reset independently.
from praisonaiagents import Agent
researcher = Agent(
name="Researcher",
memory={
"provider": "rag",
"rag_db_path": "./chroma_db",
"collection_name": "researcher_ltm",
},
)
writer = Agent(
name="Writer",
memory={
"provider": "rag",
"rag_db_path": "./chroma_db",
"collection_name": "writer_ltm",
},
)
# researcher.memory.reset_long_term() no longer wipes writer's memory.collection_name defaults to "memory_store". See Memory Configuration.
Per-agent isolation across backends
Two agents in one process no longer share one on-disk store by default. As of PraisonAI #4203, Agent(memory="sqlite" | "chroma" | {"provider": "mongodb"} | {"provider": "mem0"} | {"learn": True}) inherits the same per-agent isolation that FileMemory already had — each agent gets a per-instance agent-<uuid> id and its own default store when no explicit user_id is given.
from praisonaiagents import Agent
support = Agent(name="Support", memory="sqlite", instructions="Handle customer A's private ticket.")
sales = Agent(name="Sales", memory="sqlite", instructions="Draft outreach for customer B.")
# Distinct default files per agent — private data no longer crosses agents:
# short_term_agent-<uuidA>.db / long_term_agent-<uuidA>.db (Support)
# short_term_agent-<uuidB>.db / long_term_agent-<uuidB>.db (Sales)Each backend derives per-user defaults from the scoping user_id:
| Default | Bare store (no user_id) | Scoped store (user_id="team-x") |
|---|---|---|
| Short-term DB | short_term.db | short_term_team-x.db |
| Long-term DB | long_term.db | long_term_team-x.db |
| Chroma path | chroma_db/ | chroma_db_team-x/ |
| Collection | memory_store | memory_store_team-x |
Explicit values always win — user_id, short_db, long_db, rag_db_path, or collection_name in the caller’s dict bypass the auto-defaults. A bare store with no user_id keeps the original shared defaults, so existing single-store setups are unchanged.
Two agents can share memory by pointing both at the same db_path instead of isolating via short_db / long_db — the inverse of the isolation above. This is the opt-in shared-memory escape hatch, not the default; per-agent isolation still applies unless you set it. See the writer/reader walkthrough in Advanced Memory.
When to pass an explicit user_id:
Concurrency and shared user_id
When multiple agents share the same user_id and back FileMemory (or the file-backed learn store) on the same paths, concurrent writes are now merge-safe: each mutation re-reads the on-disk state under the instance lock before appending, so two agents recording facts against the same user_id no longer overwrite each other’s entries. This applies to add_short_term, add_long_term, add_entity, auto-promotion to long-term memory, and learn/stores.py BaseStore.add.
This is a bug fix, not a new API — no configuration change is required. If you previously worked around lost writes by serializing agent runs or by giving agents distinct user_ids, you can remove that workaround where sharing was actually the goal.
For hierarchical runs that share memory, see how the hierarchical process surfaces the final worker task’s output.