Blog/AutoGen Persistent Memory
Tutorial · 6 min read

How to Give AutoGen Agents Persistent Memory Across Conversations

AutoGen's multi-agent coordination is powerful — but every run starts from zero. Users repeat themselves. Agents re-learn the same context on every invocation. Here's how to fix it.

Synap Team·

The Problem: Every AutoGen Run Starts Fresh

You've set up an AutoGen pipeline. Your agents coordinate beautifully — the planner delegates to the executor, the critic reviews the output, and the user proxy keeps things on track. It works exactly as intended.

Then your user runs it again the next day. The agents have no idea who they are, what was decided last time, or what preferences were expressed. They ask the same clarifying questions. They re-learn the same project constraints. They start from zero — again.

This is the amnesia problem. And it's not a bug in AutoGen — it's a fundamental property of how LLM API calls work. Every new session is a fresh context window. Without an external memory layer, agents cannot remember anything between runs.

Why Amnesia Hurts Multi-Agent Systems the Most

AutoGen's core strength is coordination — multiple agents with different roles working toward a shared goal. But coordination requires shared context. And shared context across runs requires memory.

The problem compounds in multi-agent pipelines:

  • User preferences are repeated every session. If the user told the planner agent they prefer concise outputs last Tuesday, the planner asks again on Wednesday.
  • Decisions made in one run don't carry over. The team agreed to use PostgreSQL. Next run, the executor proposes SQLite. The critic doesn't know to object.
  • Long-running projects accumulate context that can't fit in one prompt. A software project that's been running for weeks has thousands of decisions, constraints, and learnings — far more than any context window.
  • Different agents start from different states. Without a shared memory store, the planner and the executor may have contradictory views of project history.

The fix isn't to stuff more context into each run's system prompt — that gets expensive fast and still doesn't scale. The fix is a dedicated memory layer that agents can read from and write to between runs.

The Synap Solution: Store and Recall Between Agent Runs

Synap is a memory API built specifically for AI agents. Instead of re-engineering your AutoGen pipeline or managing your own vector store, you add two calls: one before the run to inject relevant context, and one after to store what was learned.

Here's the complete pattern:

python
# AutoGen + Synap — persistent agent memory
import autogen
from synap import SynapClient

synap = SynapClient(api_key="syn_your_key")

# Before agent run: inject user memory
user_context = synap.recall("user_456")
system_message = f"User context: {user_context}\n\nYou are a helpful assistant."

assistant = autogen.AssistantAgent(
    name="assistant",
    system_message=system_message,
    llm_config={"model": "gpt-4"}
)

# After agent run: store new memories
synap.remember("user_456", "User is building an e-commerce recommendation engine")

That's it. Two API calls wrap your existing AutoGen setup:

  • synap.recall(user_id)— Retrieves the most relevant memories for this user using semantic search
  • synap.remember(user_id, content)— Stores a new memory, encoded as a semantic vector with automatic deduplication

Synap handles the hard parts: embedding, semantic retrieval, deduplication, decay of stale memories, and cross-agent sharing — all keyed by your user or project ID.

Full Example: A Multi-Agent Pipeline That Remembers

Let's build a more complete example — an AutoGen two-agent chat where the assistant remembers user preferences and project context across multiple sessions.

Installation

bash
pip install synap-memory pyautogen

Memory-Aware AutoGen Agent

python
import autogen
from synap import SynapClient

synap = SynapClient(api_key="syn_your_key")

def run_agent_session(user_id: str, user_message: str) -> str:
    # 1. Recall relevant context from past sessions
    user_context = synap.recall(user_id, query=user_message)

    # 2. Inject memory into the system prompt
    system_message = f"""You are a helpful software engineering assistant.

Context from previous sessions with this user:
{user_context if user_context else "No previous context yet."}

Use this context to give personalized, continuous assistance.
Do not ask for information the user has already provided."""

    # 3. Set up AutoGen agents with injected memory
    assistant = autogen.AssistantAgent(
        name="assistant",
        system_message=system_message,
        llm_config={"model": "gpt-4", "temperature": 0},
    )
    user_proxy = autogen.UserProxyAgent(
        name="user_proxy",
        human_input_mode="NEVER",
        max_consecutive_auto_reply=1,
    )

    # 4. Run the agent conversation
    user_proxy.initiate_chat(assistant, message=user_message)
    response = user_proxy.last_message()["content"]

    # 5. Store what was learned for next time
    synap.remember(user_id, f"User asked: {user_message[:300]}")
    synap.remember(user_id, f"Assistant answered: {response[:300]}")

    return response


# Session 1 — user shares project context
run_agent_session("user_456", "I'm building a recommendation engine using collaborative filtering.")
run_agent_session("user_456", "We're using PostgreSQL for storage and Python + FastAPI for the backend.")

# --- Next day, new Python process ---

# Session 2 — agents already know the project
response = run_agent_session("user_456", "What database should I use for storing user interaction logs?")
# Agent knows: PostgreSQL is already in the stack, recommends it without asking
print(response)

What just happened? On Session 2, synap.recall() retrieved the PostgreSQL and FastAPI context from Session 1 and injected it into the system prompt before AutoGen ran. The agent gave a contextually aware answer — no repeated questions, no context re-entry.

Sharing Memory Across Multiple Agents

Because Synap keys memories by your own ID (user ID, project ID, or any string), every agent in your pipeline can read the same memory store. A planner agent and an executor agent stay in sync automatically:

python
project_id = "proj_ecommerce_rec_engine"

# Planner agent stores architectural decisions
synap.remember(project_id, "Architecture decision: use Redis for session caching")
synap.remember(project_id, "Decided to use collaborative filtering over content-based")

# Executor agent recalls the same decisions — no sync code needed
context = synap.recall(project_id, query="what caching layer should I use?")
# Returns: "Architecture decision: use Redis for session caching"

executor_system = f"Project context:\n{context}\n\nYou implement decisions already made."

Bonus: CrewAI Equivalent

Using CrewAI instead of AutoGen? The same pattern applies — inject context into agent backstories before the crew runs, and store new learnings after:

python
from crewai import Agent, Task, Crew
from synap import SynapClient

synap = SynapClient(api_key="syn_your_key")

def run_crew_session(user_id: str, goal: str):
    # Recall user context before spinning up the crew
    user_context = synap.recall(user_id, query=goal)

    researcher = Agent(
        role="Senior Researcher",
        goal=f"Research {goal} thoroughly",
        backstory=f"""You are an expert researcher with deep domain knowledge.
Context about this user from previous sessions:
{user_context if user_context else "New user — no prior context."}
Use this to tailor your research to their specific situation.""",
        verbose=False,
    )

    writer = Agent(
        role="Technical Writer",
        goal="Write clear, actionable summaries",
        backstory=f"""You produce concise technical documentation.
User context: {user_context}""",
        verbose=False,
    )

    research_task = Task(
        description=f"Research: {goal}",
        agent=researcher,
        expected_output="Detailed research findings",
    )
    write_task = Task(
        description="Summarize findings for the user",
        agent=writer,
        expected_output="Concise summary with action items",
    )

    crew = Crew(agents=[researcher, writer], tasks=[research_task, write_task])
    result = crew.kickoff()

    # Store what the crew learned
    synap.remember(user_id, f"Research completed: {goal}")
    synap.remember(user_id, f"Key findings: {str(result)[:400]}")

    return result

The pattern is identical regardless of framework: recall before, remember after. Synap sits outside the framework as a shared memory store, so you can mix AutoGen, CrewAI, and LangChain agents — all reading from the same user-keyed memory.

Why Not Just Use a Database?

FeatureDIY DatabaseSynap
Semantic retrieval❌ Exact match only✅ Meaning-based recall
Context compression❌ Manual summarization✅ Automatic
Cross-agent sharing❌ Schema design required✅ Shared by key
Memory decay / forgetting❌ Manual expiry logic✅ Forgetting curve
Deduplication❌ Manual hashing✅ Automatic
Time to ship❌ Days of infra work✅ 2 API calls

Performance: Sub-10ms Recall

synap.recall() returns in under 10ms (p99). It uses Redis-backed caching on top of a pgvector semantic index, so retrieval is a single round-trip — not a multi-step embedding pipeline. For agent pipelines where latency compounds across multiple agent turns, this is essentially invisible overhead.

Live API · Ready now

Stop Rebuilding Context Every Run

Synap Memory API gives your AutoGen and CrewAI agents persistent memory across every session. Two API calls. No vector store to manage. No schema to design.

Includes 1M memory operations/month · Python SDK · 365-day retention · 30-day money-back guarantee