* Moved Messaging under Workflow and modularized main components. * Removed WorkflowService and added as_service() to AgenticWorkflow for pub/sub support in headless and service modes. * Added utility to safely retrieve instance methods decorated with a specific attribute * Updated Agent and Orchestrator workflows to support the latest messaging system changes. * Updated AgentActors to integrate with latest messaging system under workflows. * Made service_port optional to allow random port assignment. * dapr agents imports and logging * Updated Multi-agent workflows, deleted JSON logs and tested NVIDIA LLM client notebook * Integrated new messaging system into multi-agent quickstarts * Updated agentic workflows docs to reflect changes * Updated quickstart multi-agent workflows app to run in headless mode * Fixed Orchestrator as a service and exposed built-in route to start workflow over HTTP * Updated INFO logging to DEBUG * updated cookbook with latest changes * updated quickstart mukti-agent workflows to integrate orchestrator as service change * Updated docs to trigger agentic workflow over HTTP by default. * Upgrade Jinja2 to address sandbox breakout vulnerability |
||
---|---|---|
.. | ||
components | ||
services | ||
README.md | ||
dapr-llm.yaml | ||
dapr-random.yaml | ||
dapr-roundrobin.yaml | ||
requirements.txt |
README.md
Multi-Agent Event-Driven Workflows
This quickstart demonstrates how to create and orchestrate event-driven workflows with multiple autonomous agents using Dapr Agents. You'll learn how to set up agents as services, implement workflow orchestration, and enable real-time agent collaboration through pub/sub messaging.
Prerequisites
- Python 3.10 (recommended)
- pip package manager
- OpenAI API key
- Dapr CLI and Docker installed
Environment Setup
# Create a virtual environment
python3.10 -m venv .venv
# Activate the virtual environment
# On Windows:
.venv\Scripts\activate
# On macOS/Linux:
source .venv/bin/activate
# Install dependencies
pip install -r requirements.txt
Configuration
- Create a
.env
file for your API keys:
OPENAI_API_KEY=your_api_key_here
- Make sure Dapr is initialized on your system:
dapr init
- The quickstart includes the necessary Dapr components in the
components
directory:
statestore.yaml
: Agent state configurationpubsub.yaml
: Pub/Sub message bus configurationworkflowstate.yaml
: Workflow state configuration
Project Structure
components/ # Dapr configuration files
├── statestore.yaml # State store configuration
├── pubsub.yaml # Pub/Sub configuration
└── workflowstate.yaml # Workflow state configuration
services/ # Directory for agent services
├── hobbit/ # First agent's service
│ └── app.py # FastAPI app for hobbit
├── wizard/ # Second agent's service
│ └── app.py # FastAPI app for wizard
├── elf/ # Third agent's service
│ └── app.py # FastAPI app for elf
└── workflow-random/ # Workflow orchestrator
└── app.py # Workflow service
└── workflow-roundrobin/ # Roundrobin orchestrator
└── app.py # Workflow service
└── workflow-llm/ # LLM orchestrator
└── app.py # Workflow service
dapr-random.yaml # Multi-App Run Template using the random orchestrator
dapr-roundrobin.yaml # Multi-App Run Template using the roundrobin orchestrator
dapr-llm.yaml # Multi-App Run Template using the LLM orchestrator
Examples
Agent Service Implementation
Each agent is implemented as a separate service. Here's an example for the Hobbit agent:
from dapr_agents import Agent, AgentActor
from dotenv import load_dotenv
import asyncio
import logging
async def main():
try:
# Define Agent
hobbit_agent = Agent(
role="Hobbit",
name="Frodo",
goal="Take the ring to Mordor",
instructions=["Speak like Frodo"]
)
# Expose Agent as an Actor Service
hobbit_service = AgentActor(
agent=hobbit_agent,
message_bus_name="messagepubsub",
agents_state_store_name="agentstatestore",
service_port=8001,
)
await hobbit_service.start()
except Exception as e:
print(f"Error starting service: {e}")
if __name__ == "__main__":
load_dotenv()
logging.basicConfig(level=logging.INFO)
asyncio.run(main())
Similar implementations exist for the Wizard (Gandalf) and Elf (Legolas) agents.
Workflow Orchestrator Implementations
The workflow orchestrators manage the interaction between agents. Currently, Dapr Agents support three workflow types: RoundRobin, Random, and LLM-based. Here's an example for the Random workflow orchestrator (you can find examples for RoundRobin and LLM-based orchestrators in the project):
from dapr_agents import RandomOrchestrator
from dotenv import load_dotenv
import asyncio
import logging
async def main():
try:
random_workflow = RandomOrchestrator(
name="RandomOrchestrator",
message_bus_name="messagepubsub",
state_store_name="agenticworkflowstate",
state_key="workflow_state",
agents_registry_store_name="agentstatestore",
agents_registry_key="agents_registry",
max_iterations=3
).as_service(port=8004)
await random_workflow.start()
except Exception as e:
print(f"Error starting workflow: {e}")
if __name__ == "__main__":
load_dotenv()
logging.basicConfig(level=logging.INFO)
asyncio.run(main())
Running the Multi-Agent System
The project includes three dapr multi-app run configuration files (dapr-random.yaml
, dapr-roundrobin.yaml
and dapr-llm.yaml
) for running all services and an additional Client application for interacting with the agents:
Example: dapr-random.yaml
version: 1
common:
resourcesPath: ./components
logLevel: info
appLogDestination: console
daprdLogDestination: console
apps:
- appID: HobbitApp
appDirPath: ./services/hobbit/
appPort: 8001
command: ["python3", "app.py"]
- appID: WizardApp
appDirPath: ./services/wizard/
appPort: 8002
command: ["python3", "app.py"]
- appID: ElfApp
appDirPath: ./services/elf/
appPort: 8003
command: ["python3", "app.py"]
- appID: WorkflowApp
appDirPath: ./services/workflow-random/
command: ["python3", "app.py"]
appPort: 8004
- appID: ClientApp
appDirPath: ./services/client/
command: ["python3", "http_client.py"]
Start all services using the Dapr CLI:
dapr run -f dapr-random.yaml
You will see the agents engaging in a conversation about getting to Mordor, with different agents contributing based on their character.
You can also run the RoundRobin and LLM-based orchestrators using dapr-roundrobin.yaml
and dapr-llm.yaml
respectively:
dapr run -f dapr-roundrobin.yaml
dapr run -f dapr-llm.yaml
Expected output: The agents will engage in a conversation about getting to Mordor, with different agents contributing based on their character. Observe that in the logs, or checking the workflow state in Redis Insights.
Key Concepts
- Agent Service: Stateful service exposing an agent via API endpoints with independent lifecycle management
- Pub/Sub Messaging: Event-driven communication between agents for real-time collaboration
- State Store: Persistent storage for both agent registration and conversational memory
- Actor Model: Self-contained, sequential message processing via Dapr's Virtual Actor pattern
- Workflow Orchestration: Coordinating agent interactions in a durable and resilient manner
Workflow Types
Dapr Agents supports multiple workflow orchestration patterns:
- RoundRobin: Cycles through agents sequentially, ensuring equal task distribution
- Random: Selects agents randomly for tasks, useful for load balancing and testing
- LLM-based: Uses an LLM (default: OpenAI's models like gpt-4o) to intelligently select agents based on context and task requirements
Monitoring and Observability
- Console Logs: Monitor real-time workflow execution and agent interactions
- Dapr Dashboard: View components, configurations and service details at http://localhost:8080/
- Zipkin Tracing: Access distributed tracing at http://localhost:9411/zipkin/
- Dapr Metrics: Access agent performance metrics via (ex: HobbitApp) http://localhost:6001/metrics when configured
Troubleshooting
- Service Startup: If services fail to start, verify Dapr components configuration
- Communication Issues: Check Redis connection and pub/sub setup
- Workflow Errors: Check Zipkin traces for detailed request flows
- Port Conflicts: If ports are already in use, check which port is already in use
- System Reset: Clear Redis data through Redis Insights if needed
Next Steps
After completing this quickstart, you can:
- Add more agents to the workflow
- Switch to another workflow orchestration pattern (RoundRobin, LLM-based)
- Extend agents with custom tools
- Deploy agents and Dapr to a Kubernetes cluster. For more information on read Deploy Dapr on a Kubernetes cluster
- Check out the Cookbooks