You understand the Actor Model from Lesson 1: actors encapsulate state and behavior, process messages one at a time, and communicate through asynchronous messages. Now it's time to build one.
In this lesson, you'll create a HelloAgent actor that stores greeting messages. Each user gets their own actor instance with isolated state. When user "alice" sends greetings, they're stored separately from user "bob's" greetings. This is the foundation for building AI agents where each conversation, each task, each user session has its own stateful actor.
By the end of this lesson, you'll have a working actor that:
Building a Dapr actor requires four pieces working together:
Let's build each piece.
The actor interface declares what methods your actor exposes. It's a contract that clients use to invoke the actor. In Python, you define it as an abstract base class extending ActorInterface:
Output: No output yet - this is just the interface definition. The ... (ellipsis) is valid Python syntax for abstract method bodies.
Notice the dual naming:
The decorator name is what external clients use when invoking the actor via HTTP or ActorProxy. The Python method name is what you use internally. This follows Dapr's convention across all SDKs.
The actor implementation extends both the Actor base class and your interface:
Output: No direct output - this defines the class. When the actor is activated, you'll see log messages like:
The _state_manager: Every actor has a built-in state manager that persists data to the configured state store. You don't manage Redis connections - you just call get_state() and set_state().
The _on_activate lifecycle hook: This runs when the actor is first invoked or when it's reactivated after being garbage-collected due to idleness. Use it to initialize default state.
Unique state keys: Each actor instance uses its own key (history-{actor_id}). Actor "alice" stores state under history-alice, actor "bob" under history-bob. Complete isolation.
Error handling in _on_activate: The try/except ensures the actor initializes even if state retrieval has issues. A robust actor shouldn't crash on activation.
Now connect the actor to your FastAPI application using DaprActor:
Output: When the application starts, you'll see:
DaprActor(app) adds several routes to your FastAPI application that Dapr uses internally:
You don't call these endpoints directly - Dapr's sidecar does. But you can verify registration:
Output:
The entities array confirms HelloAgent is registered.
Create FastAPI endpoints that invoke the actor using ActorProxy:
Output: After sending greetings:
Response:
Retrieving history:
Response:
This creates a client for communicating with a specific actor:
The proxy handles all communication with the Dapr sidecar. Your HTTP request to /greet/alice becomes an internal call through Dapr to the HelloAgent actor with ID "alice".
Actors need a state store with actor support enabled. Add this metadata to your state store component:
Output: No direct output - this is configuration. When applied, Dapr uses this state store for actor persistence.
The actorStateStore: "true" metadata is required for actors. Without it:
If your actor state isn't persisting, check this setting first.
You can inspect actor state directly in Redis:
Output:
The key format is {app-id}||{actor-type}||{actor-id}||{state-key}.
Output:
Here's the full main.py combining all pieces:
Run the application with Dapr:
Then test with curl or the Swagger UI at http://localhost:8000/docs:
Output: Alice's history:
Bob's history:
Each actor ID creates a separate actor instance with isolated state.
You extended your dapr-deployment skill in Lesson 0 to include actor patterns. Does it now cover the complete actor creation workflow?
"Using my dapr-deployment skill, generate a complete actor that tracks user preferences with get_preference and set_preference methods. Include the interface, implementation, registration, and invocation code."
Does your skill produce:
If the generated code is missing pieces:
Open your AI companion and work through these scenarios collaboratively.
"Help me create a HelloAgent actor that stores greeting messages. I need an actor interface with AddGreeting and GetGreetingHistory methods, an implementation that limits history, and FastAPI registration."
"I created my HelloAgent actor but I'm getting ACTOR_TYPE_NOT_FOUND when I invoke it. Help me debug this. What should I check in the startup registration and sidecar logs?"
"I want to extend my HelloAgent to track timestamps with each greeting. Show me how to add timestamps safely using ISO format strings and verify the data serializes correctly to Redis."