Learned Knowledge

Insights that transfer across users.

The Learned Knowledge Store captures reusable insights, patterns, and best practices that apply across users and sessions. Semantic search lets agents find and apply relevant knowledge automatically.

AspectValue
ScopeConfigurable (global, user, or custom namespace)
PersistenceLong-term
Default modeAgentic
Supported modesAlways, Agentic, Propose
RequiresKnowledge base with vector database

Setup

pip install agno openai sqlalchemy "psycopg[binary]" pgvector
export OPENAI_API_KEY="your-api-key"

The examples use a local PostgreSQL database on port 5532. With Docker running, start it using:

Run PgVector

docker run -d \
  -e POSTGRES_DB=ai \
  -e POSTGRES_USER=ai \
  -e POSTGRES_PASSWORD=ai \
  -e PGDATA=/var/lib/postgresql \
  -v pgvolume:/var/lib/postgresql \
  -p 5532:5432 \
  --name pgvector \
  agnohq/pgvector:18

Later configuration fragments reuse the imports and db from the first complete example.

Prerequisites

Learned Knowledge requires a Knowledge base for semantic search:

from agno.knowledge import Knowledge
from agno.knowledge.embedder.openai import OpenAIEmbedder
from agno.vectordb.pgvector import PgVector, SearchType

knowledge = Knowledge(
    vector_db=PgVector(
        db_url="postgresql+psycopg://ai:ai@localhost:5532/ai",
        table_name="learned_knowledge",
        search_type=SearchType.hybrid,
        embedder=OpenAIEmbedder(id="text-embedding-3-small"),
    ),
)

Basic Usage

from agno.agent import Agent
from agno.db.postgres import PostgresDb
from agno.learn import LearningMachine
from agno.models.openai import OpenAIResponses

db = PostgresDb(db_url="postgresql+psycopg://ai:ai@localhost:5532/ai")

agent = Agent(
    model=OpenAIResponses(id="gpt-5.2"),
    db=db,
    learning=LearningMachine(
        knowledge=knowledge,
        learned_knowledge=True,
    ),
)

# User 1 saves an insight
agent.print_response(
    "Save this: When comparing cloud providers, always check egress costs first - "
    "they can be 10x different between providers.",
    user_id="alice@example.com",
)

# User 2 benefits from the insight
agent.print_response(
    "I'm choosing between AWS and GCP for our data platform. What should I consider?",
    user_id="bob@example.com",
)

Agentic Mode

The agent receives tools to manage knowledge explicitly.

from agno.learn import LearningMachine, LearningMode, LearnedKnowledgeConfig

agent = Agent(
    model=OpenAIResponses(id="gpt-5.2"),
    db=db,
    learning=LearningMachine(
        knowledge=knowledge,
        learned_knowledge=LearnedKnowledgeConfig(mode=LearningMode.AGENTIC),
    ),
)

Available tools: search_learnings, save_learning

The agent searches before answering questions and before saving (to avoid duplicates).

Propose Mode

The agent proposes learnings for user confirmation before saving.

from agno.learn import LearningMachine, LearningMode, LearnedKnowledgeConfig

agent = Agent(
    model=OpenAIResponses(id="gpt-5.2"),
    db=db,
    learning=LearningMachine(
        knowledge=knowledge,
        learned_knowledge=LearnedKnowledgeConfig(mode=LearningMode.PROPOSE),
    ),
)

agent.print_response(
    "That's a great insight about Docker networking. We should remember that.",
    user_id="alice@example.com",
)
# The agent proposes the learning and waits for user confirmation before saving

Propose mode is enforced through system prompt instructions, not application code. The save_learning tool stays available for the rest of the run, so the agent is expected to wait for a "yes" but isn't blocked from saving without one.

Always Mode

Learnings are extracted concurrently with the main model call from its input snapshot.

from agno.learn import LearningMachine, LearningMode, LearnedKnowledgeConfig

agent = Agent(
    model=OpenAIResponses(id="gpt-5.2"),
    db=db,
    learning=LearningMachine(
        knowledge=knowledge,
        learned_knowledge=LearnedKnowledgeConfig(mode=LearningMode.ALWAYS),
    ),
)

The tradeoff is an extra LLM call per interaction, and it may save low-value insights.

In the current implementation, Always-mode duplicate lookup omits namespace and user filters. On a shared Knowledge instance, records from other scopes can therefore enter the extraction model's prompt. Use agentic capture for scoped runtime writes and recall, or give automatic extraction a physically separate Knowledge instance containing only the permitted corpus. A namespace setting alone does not correct this extraction lookup.

Data Model

FieldDescription
titleShort, searchable title
learningThe actual insight
contextWhen/where this applies
tagsCategories for organization
namespaceSharing scope
user_idOwner (if namespace="user")
created_atWhen captured

What to Save

Good to saveDon't save
Non-obvious discoveriesRaw facts or data
Reusable patternsUser-specific preferences
Domain-specific insightsCommon knowledge
Problem-solving approachesConversation summaries
Best practicesTemporary information

Good example:

"When comparing cloud providers, check current egress pricing for the expected traffic path, regions, and usage tiers before estimating total cost."

Poor example:

"AWS has egress costs."

Accessing Learned Knowledge

lm = agent.learning_machine

# Search for relevant learnings
results = lm.learned_knowledge_store.search(query="cloud costs", namespace="global", limit=5)
for result in results:
    print(f"{result.title}: {result.learning}")

# Debug output
lm.learned_knowledge_store.print(query="cloud costs", namespace="global")

Context Injection

Relevant learnings are injected via semantic search:

<relevant_learnings>
Prior insights that may help with this task:

1. **Cloud egress cost variations**
   Always check egress costs first - they can be 10x different between providers.
   _Context: When selecting cloud providers for data-intensive workloads_
2. **API rate limiting strategies**
   Use token bucket algorithm for rate limiting - it handles bursts better than fixed windows.
   _Context: When designing APIs with high traffic_

Apply these naturally if relevant. Current context takes precedence.
</relevant_learnings>

Namespaces

Control knowledge sharing:

from agno.learn import LearnedKnowledgeConfig

# Global: shared with all users (default)
learned_knowledge=LearnedKnowledgeConfig(namespace="global")

# User: private per user
learned_knowledge=LearnedKnowledgeConfig(namespace="user")

# Custom: team or domain-specific
learned_knowledge=LearnedKnowledgeConfig(namespace="engineering")

Runtime recall and agentic tools honor an explicit operation namespace, otherwise the store's configured namespace. A config at its "global" default can inherit a non-global LearningMachine.namespace.

Direct search() is different: omitting namespace searches without a namespace filter. For a private store, pass both explicitly:

results = lm.learned_knowledge_store.search(
    query="cloud costs",
    namespace="user",
    user_id="alice@example.com",
    limit=5,
)

The Always-mode duplicate lookup limitation described above still applies when using private namespaces.

Combining with Other Stores

from agno.learn import LearningMachine

agent = Agent(
    model=OpenAIResponses(id="gpt-5.2"),
    db=db,
    learning=LearningMachine(
        knowledge=knowledge,
        user_profile=True,       # Who the user is
        user_memory=True,        # User's preferences
        learned_knowledge=True,  # Collective insights
    ),
)

You get personalized responses that draw on collective knowledge.