Agno agents forget everything by default. Here is how to add session memory, user memory, and persistent storage.
The Default Behaviour
Agno agents are stateless by default. Every new run starts fresh: the agent has no memory of previous conversations, no knowledge of user preferences, and no persistent state. This is fine for one-shot tasks. For any conversational or long-running use case, you need to configure memory explicitly.
Agno has three distinct memory systems, each serving a different purpose. Understanding which one to use -- and when -- is the gap this article fills.
The Three Memory Types
| Memory Type | What it stores | Scope | Persists? |
|---|---|---|---|
| Session Storage | Full conversation history for one session | Per session | Only with a DB backend |
| User Memory | Facts about a specific user across sessions | Per user (cross-session) | Yes, requires DB |
| Agent Memory (Knowledge) | Fixed reference knowledge the agent always has | Global (all users) | Yes, vector store |
Session Memory: Remembering the Conversation
Session memory stores the full message history for a conversation. Without it, the agent cannot refer back to anything said earlier in the same chat.
from agno.agent import Agent
from agno.models.anthropic import Claude
from agno.storage.postgres import PostgresStorage
# In-memory session storage (development only -- lost on restart)
agent = Agent(
model=Claude(id="claude-sonnet-4-6"),
add_history_to_messages=True, # inject conversation history into each prompt
num_history_responses=10, # how many past exchanges to include
)
# Persistent session storage with PostgreSQL (production)
agent = Agent(
model=Claude(id="claude-sonnet-4-6"),
storage=PostgresStorage(
table_name="agent_sessions",
db_url="postgresql://user:pass@host/dbname",
),
add_history_to_messages=True,
num_history_responses=10,
)
# Use session_id to link messages across requests
result = await agent.arun(
"What is the capital of France?",
session_id="user-123-session-456",
)
result2 = await agent.arun(
"And what language do they speak there?", # agent remembers France was mentioned
session_id="user-123-session-456", # same session_id = same conversation
)Always pass an explicit session_id. Without one, Agno generates a random UUID per run, which means every message starts a new conversation. Store the session_id in your application's session store (cookie, JWT, Redis) and pass it back with every request.User Memory: Remembering Facts Across Sessions
User memory stores facts about a specific user that should persist across multiple conversations. The agent can read these facts at the start of any session and update them during a conversation.
from agno.memory.db.postgres import PostgresMemoryDb
from agno.memory.agent import AgentMemory
agent = Agent(
model=Claude(id="claude-sonnet-4-6"),
memory=AgentMemory(
db=PostgresMemoryDb(
table_name="user_memories",
db_url="postgresql://user:pass@host/dbname",
),
create_user_memories=True, # agent saves facts it learns about the user
update_user_memories=True, # agent updates facts when they change
),
add_history_to_messages=True,
storage=PostgresStorage(
table_name="agent_sessions",
db_url="postgresql://user:pass@host/dbname",
),
)
# Session 1 -- agent learns the user's name and preferences
result = await agent.arun(
"Hi, I'm Sarah. I prefer concise answers and I work in healthcare.",
user_id="user-sarah-123",
session_id="session-001",
)
# Session 2 (days later) -- agent remembers Sarah
result = await agent.arun(
"Can you help me with a patient data workflow?",
user_id="user-sarah-123", # same user_id links to stored memories
session_id="session-002", # new session, but user memory persists
)
# Agent knows: user is Sarah, prefers concise answers, works in healthcareAgent Knowledge: Always-Available Reference Data
Agent knowledge (also called agent memory in some Agno versions) is a vector store containing reference documents that the agent always has access to. This is different from user memory -- it is the same for all users and represents the agent's domain expertise.
from agno.agent import Agent
from agno.knowledge.pdf import PDFKnowledgeBase
from agno.vectordb.postgres import PgVector
agent = Agent(
model=Claude(id="claude-sonnet-4-6"),
knowledge=PDFKnowledgeBase(
path="./knowledge-docs/", # folder of PDFs to index
vector_db=PgVector(
table_name="agent_knowledge",
db_url="postgresql://user:pass@host/dbname",
),
),
search_knowledge=True, # agent automatically searches knowledge on each run
)
# Load the knowledge base (run once, or on updates)
await agent.knowledge.aload()
result = await agent.arun("What is our refund policy?")
# Agent searches the PDFs and answers from the indexed contentFull Production Setup
agent = Agent(
model=Claude(id="claude-sonnet-4-6"),
# Session history
storage=PostgresStorage(
table_name="agent_sessions",
db_url=DB_URL,
),
add_history_to_messages=True,
num_history_responses=8,
# User memory
memory=AgentMemory(
db=PostgresMemoryDb(table_name="user_memories", db_url=DB_URL),
create_user_memories=True,
update_user_memories=True,
),
# Agent knowledge
knowledge=PDFKnowledgeBase(
path="./knowledge/",
vector_db=PgVector(table_name="agent_knowledge", db_url=DB_URL),
),
search_knowledge=True,
)Quick Reference
- Session storage: conversation history within one session -- use PostgresStorage
- User memory: facts about a user across all sessions -- use AgentMemory + PostgresMemoryDb
- Agent knowledge: reference documents for all users -- use PDFKnowledgeBase + PgVector
- Always pass explicit session_id and user_id -- never rely on auto-generated IDs in production
- Call knowledge.aload() once after indexing new documents
- num_history_responses controls token cost -- start at 8-10 and tune from there