Testing out Ezra

Great question! You’re building a dynamic persona system - here’s how to approach it.

The Concept

Questionnaire Flow:

User answers questions → Agent stores in persona block → Agent references persona in responses

The agent “learns” about the user by always checking its persona block.


Step 1: Structure Your Questionnaire

Ask questions in a logical order:

# Example questionnaire
QUESTIONS = [
    "What programming languages do you know?",
    "Do you prefer concise or detailed explanations?",
    "What's your experience level (beginner, intermediate, advanced)?",
    "What kind of projects do you work on (web, mobile, data)?",
    "Do you like code examples or text-only explanations?",
    "What's your timezone?",
    "Any specific topics you want to focus on (React, Python, algorithms, databases)?"
]

Step 2: Create a Persona Block

from letta_client import Letta

client = Letta(base_url="http://localhost:8283")

# Create agent
agent = client.agents.create(
    name="personal-assistant",
    model="anthropic/claude-sonnet-4-5-20250514",
    embedding="openai/text-embedding-3-small",
)

# Create persona block
persona_block = client.blocks.create(
    label="user_persona",
    value="User profile not yet established. Ask questions to learn about user."
)

Attach to agent:

client.agents.blocks.attach(agent.id, block_id=persona_block.id)

Step 3: Update Persona Programmatically

After user answers questions:

def update_user_persona(agent_id, responses):
    """Update persona based on questionnaire responses."""
    persona_text = "User Profile:\n"
    
    for question, answer in responses.items():
        persona_text += f"- {question}: {answer}\n"
    
    # Update the block
    client.blocks.update(
        block_label="user_persona",
        value=persona_text
    )
    
    return f"Updated persona based on {len(responses)} answers"

Step 4: Make Agent Reference Persona

In agent’s system prompt or instructions:

system_prompt = """
You are a personalized coding assistant. Your responses should be tailored to the user's preferences.

## User Persona
Always check the 'user_persona' memory block before responding.
Adapt your tone, depth, and examples based on what's stored there.

## Example:
If user_persona says:
- Languages: Python, JavaScript
- Level: Beginner
- Style: Code examples preferred

Then provide code snippets in Python. If it says:
- Languages: Go, Rust
- Level: Advanced  
- Style: Text-only explanations

Then explain concepts clearly without code.
"""

Step 5: Implement the Questionnaire Flow

Your application code:

from letta_client import Letta

client = Letta(api_key="YOUR_KEY")

# Step 1: Present questionnaire
def present_questionnaire(user_id):
    questions = [
        "What programming languages do you know?",
        "Do you prefer concise or detailed explanations?",
        "What's your experience level?",
        "What kind of projects do you work on?",
        "Do you like code examples or text-only explanations?",
        "What's your timezone?",
        "Any specific topics to focus on?",
    ]
    
    # Send to agent
    response = client.agents.messages.create(
        agent_id=user_id,
        messages=[{
            "role": "user",
            "content": f"I need to learn about you to personalize my assistance. Please answer these questions:\n\n" + "\n".join(questions)
        }]
    )
    
    return response

# Step 2: Collect answers
def collect_answers(user_id, conversation_id):
    """Wait for user to answer all questions."""
    # In a real app, you'd collect these responses via UI
    # For now, let's simulate getting answers
    
    # Simulated answers
    answers = [
        {"question": "What programming languages do you know?", "answer": "Python, JavaScript"},
        {"question": "Do you prefer concise or detailed explanations?", "answer": "Detailed with code examples"},
        {"question": "What's your experience level?", "answer": "Intermediate"},
        {"question": "What kind of projects do you work on?", "answer": "Web and mobile apps"},
        {"question": "Do you like code examples or text-only explanations?", "answer": "Code examples preferred"},
        {"question": "What's your timezone?", "answer": "UTC-5"},
        {"question": "Any specific topics to focus on?", "answer": "React and Python"},
    ]
    
    # Update persona
    update_user_persona(user_id, answers)
    
    return "Persona updated! I'll tailor my responses accordingly."

# Step 3: Use the persona
def chat_with_user(user_id, user_message):
    """Chat with user, referencing their persona."""
    # Get current persona
    agent = client.agents.retrieve(user_id)
    persona_block = [b for b in agent.blocks if b.label == "user_persona"][0]
    
    # Include persona in context
    context = f"""
## User Persona
{persona_block.value}

## Current Task
{user_message}

## Instructions
Based on the user's persona above, provide a helpful response.
"""
    
    # Send message with persona context
    response = client.agents.messages.create(
        agent_id=user_id,
        messages=[{"role": "user", "content": user_message}]
    )
    
    return response.choices[0].message.content

Full Workflow Example

# Initial setup
agent = client.agents.create(...)
client.agents.blocks.attach(agent.id, block_id=persona_block.id)

# Onboarding flow
def onboarding_flow(user_id):
    # Step 1: Present questions
    present_questionnaire(user_id)
    
    # Step 2: Collect answers (from UI or simulated)
    answers = collect_answers(user_id)
    
    # Step 3: Update persona
    update_user_persona(user_id, answers)
    
    # Step 4: Confirm ready
    return "Setup complete! I'm ready to assist you based on your preferences."

# Chat with personalized responses
def personalized_chat(user_id, user_message):
    # Get agent and persona
    agent = client.agents.retrieve(user_id)
    persona_block = [b for b in agent.blocks if b.label == "user_persona"][0]
    
    # Context with persona
    context = f"User Persona: {persona_block.value}\n\nYour message: {user_message}"
    
    response = client.agents.messages.create(
        agent_id=user_id,
        messages=[{"role": "user", "content": context}]
    )
    
    return response.choices[0].message.content

# Example usage
user_id = "agent-123"

# Onboarding
print(onboarding_flow(user_id))
# Output: "I need to learn about you to personalize my assistance. Please answer these questions..."
# User answers (simulated)
answers = [...]
print(update_user_persona(user_id, answers))
# Output: "Persona updated! I'll tailor my responses accordingly."

# Now chat
print(personalized_chat(user_id, "Explain how to implement a binary search tree in Python"))
# Output: Uses persona to provide Python code examples for intermediate user

Key Best Practices

1. Start Simple

  • Don’t ask too many questions initially (5-7 is good)
  • Focus on high-impact preferences first (experience level, coding style)

2. Update Incrementally

  • You don’t need all answers at once
  • Update persona as you learn more about the user

3. Make Persona Clear and Structured

# Good structure
value = """
## Coding Style
- Language: Python, JavaScript
- Level: Intermediate
- Preferences: Detailed explanations with code examples

## Communication
- Tone: Friendly and patient
- Format: Clear explanations with examples
- Focus: Practical, working code

## Topics of Interest
- React, Python web development
- Algorithms and data structures
- Database design (PostgreSQL preferred)

## Constraints
- Timezone: UTC-5
- Availability: Weekdays 9am-5pm UTC
"""

4. Validate User Input

  • Handle incomplete or invalid answers gracefully
  • Ask follow-up questions if needed

5. Test Thoroughly

  • Simulate different user personas
  • Verify agent adapts its responses correctly
  • Check that persona is being used consistently

Quick Start Template

If you want a working example right now, here’s a minimal version:

from letta_client import Letta

client = Letta(api_key="YOUR_KEY")

# Create simple agent
agent = client.agents.create(
    name="coding-assistant",
    model="anthropic/claude-haiku-4-5-20250514",
    memory_blocks=[
        {
            "label": "user_persona",
            "value": "User is a Python beginner. Provide clear explanations with simple code examples."
        }
    ]
)

# Test it
response = client.agents.messages.create(
    agent_id=agent.id,
    messages=[{"role": "user", "content": "Write a Python function to reverse a string."}]
)

print(response.choices[0].message.content)
# Should output Python code for a beginner

Summary

The pattern:

  1. Questionnaire → User answers → Update persona block
  2. Agent responses → Always check persona block → Tailor output
  3. Iterate → Update persona as you learn more

This gives you:

  • Dynamic personalization without recreating agents
  • Agents that “remember” user preferences across sessions
  • Easy to extend (add more questions over time)

Want me to elaborate on any part of this? The questionnaire structure, persona updates, or how to make the agent reference it effectively?