User Profile

Structured facts about users.

The User Profile Store captures structured fields about users: name, preferred name, and custom fields you define.

AspectValue
ScopePer user
PersistenceForever (updated as new info is learned)
Default modeAlways
Supported modesAlways, Agentic

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.

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(user_profile=True),
)

# Session 1: Share information
agent.print_response(
    "Hi! I'm Alice Chen, but please call me Ali.",
    user_id="alice@example.com",
    session_id="session_1",
)

# Session 2: Profile is recalled automatically
agent.print_response(
    "What's my name?",
    user_id="alice@example.com",
    session_id="session_2",
)

Always Mode

Extraction starts concurrently with the main model call using the current input snapshot. No tools are visible to the agent.

from agno.learn import LearningMachine, LearningMode, UserProfileConfig

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

The tradeoff is an extra LLM call per interaction.

Agentic Mode

The agent receives an update_profile tool and decides when to update.

from agno.learn import LearningMachine, LearningMode, UserProfileConfig

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

agent.print_response(
    "Please remember that my name is Bob Smith.",
    user_id="bob@example.com",
)

The tradeoff is that the agent may miss implicit profile info.

Default Fields

FieldDescription
nameFull name
preferred_nameName they prefer to be called

Custom Schemas

Extend the base schema for your domain:

from dataclasses import dataclass, field
from typing import Optional
from agno.learn.schemas import UserProfile

@dataclass
class CustomerProfile(UserProfile):
    company: Optional[str] = field(
        default=None,
        metadata={"description": "Company or organization"}
    )
    plan_tier: Optional[str] = field(
        default=None,
        metadata={"description": "Subscription tier: free | pro | enterprise"}
    )
    role: Optional[str] = field(
        default=None,
        metadata={"description": "Job title or role"}
    )
    timezone: Optional[str] = field(
        default=None,
        metadata={"description": "User's timezone"}
    )

agent = Agent(
    model=OpenAIResponses(id="gpt-5.2"),
    db=db,
    learning=LearningMachine(
        user_profile=UserProfileConfig(schema=CustomerProfile),
    ),
)

The metadata["description"] tells the LLM what each field captures.

Accessing Profile Data

lm = agent.learning_machine

# Get profile
profile = lm.user_profile_store.get(user_id="alice@example.com")
if profile is not None:
    print(profile.name)
    print(profile.preferred_name)

# Debug output
lm.user_profile_store.print(user_id="alice@example.com")

Context Injection

Profiles are automatically injected into the system prompt:

<user_profile>
Name: Alice Chen
Preferred Name: Ali
Company: Acme Corp
Role: Data Scientist
</user_profile>

No manual context building is needed.

User Profile vs User Memory

User ProfileUser Memory
Structured fieldsUnstructured text
Fixed schemaFlexible observations
Updated in placeAppended over time
Keyed recall by user IDKeyed recall of the user's memory entries

Use User Profile for: name, company, role, preferences with defined values.

Use User Memory for: observations like "prefers detailed explanations" or "works on ML projects."