Skip to content
Letta Platform Letta Platform Letta Docs
Sign up
Tutorials
Multi-agent patterns

The round-robin pattern

Distribute tasks evenly across multiple agents using a rotating sequence to ensure fair workload distribution.

Distribute incoming tasks evenly across multiple agents in a fixed rotation sequence. Each agent processes tasks in turn, ensuring fair workload distribution and preventing any single agent from being overwhelmed.

The round-robin pattern works well when you need to:

  • Distribute high-volume tasks evenly across multiple agents
  • Prevent workload concentration on any single agent
  • Ensure fair processing where each agent gets equal opportunities
  • Maintain diverse perspectives by rotating agents through different tasks

A social media platform receives flagged content for moderation review. Three moderator agents review flagged posts in rotation:

  • Agent A reviews posts 1, 4, 7, 10…
  • Agent B reviews posts 2, 5, 8, 11…
  • Agent C reviews posts 3, 6, 9, 12…

Each agent maintains memory of previous decisions, learning moderation patterns and policy edge cases over time.

The pattern uses three key components:

  1. A pool of agents with similar capabilities that process tasks independently
  2. A rotation index maintained by the client to track which agent receives the next task
  3. Client orchestration that distributes tasks sequentially to agents in the rotation order

Create multiple agents with similar capabilities:

from letta_client import Letta
import os
client = Letta(api_key=os.getenv("LETTA_API_KEY"))
# Create three moderator agents
moderator_a = client.agents.create(
name="moderator_a",
model="anthropic/claude-sonnet-4-5-20250929",
memory_blocks=[{
"label": "persona",
"value": "I review flagged social media posts for policy violations. I evaluate content against community guidelines and make moderation decisions."
}]
)
moderator_b = client.agents.create(
name="moderator_b",
model="anthropic/claude-sonnet-4-5-20250929",
memory_blocks=[{
"label": "persona",
"value": "I review flagged social media posts for policy violations. I evaluate content against community guidelines and make moderation decisions."
}]
)
moderator_c = client.agents.create(
name="moderator_c",
model="anthropic/claude-sonnet-4-5-20250929",
memory_blocks=[{
"label": "persona",
"value": "I review flagged social media posts for policy violations. I evaluate content against community guidelines and make moderation decisions."
}]
)

Each agent has the same capabilities but maintains independent memory of their own moderation history.

Create a list of agents and initialize the rotation index:

# Define rotation order
moderators = [moderator_a, moderator_b, moderator_c]
# Track current position in rotation
current_index = 0

For each incoming task, send it to the current agent and advance the rotation:

# Example: flagged posts arriving for review
flagged_posts = [
"Post 1: User shared potentially misleading health information",
"Post 2: Comment contains targeted harassment",
"Post 3: Image may violate copyright",
"Post 4: Spam advertisement posted multiple times",
"Post 5: Hate speech reported by users"
]
# Distribute posts to moderators in round-robin fashion
for post in flagged_posts:
current_moderator = moderators[current_index]
response = client.agents.messages.create(
agent_id=current_moderator.id,
messages=[{"role": "user", "content": f"Review this flagged post: {post}"}]
)
print(f"{current_moderator.name} reviewed: {post}")
print(f"Decision: {response.messages[-1].content}\n")
# Advance to next moderator (with wraparound)
current_index = (current_index + 1) % len(moderators)

The modulo operation % len(moderators) ensures the index wraps back to 0 after reaching the last agent.

Each agent processes tasks independently and maintains its own memory:

# Check what each moderator remembers
for moderator in moderators:
messages = client.agents.messages.list(agent_id=moderator.id)
print(f"{moderator.name} has reviewed {len(messages)} posts")
from letta_client import Letta
import os
client = Letta(api_key=os.getenv("LETTA_API_KEY"))
# Create three agents
agents = []
for i in range(3):
agent = client.agents.create(
name=f"agent_{i}",
model="anthropic/claude-sonnet-4-5-20250929",
memory_blocks=[{
"label": "persona",
"value": f"I am agent {i}. I process tasks assigned to me."
}]
)
agents.append(agent)
# Distribute tasks in round-robin
tasks = ["Task 1", "Task 2", "Task 3", "Task 4", "Task 5", "Task 6"]
current_index = 0
for task in tasks:
current_agent = agents[current_index]
client.agents.messages.create(
agent_id=current_agent.id,
messages=[{"role": "user", "content": task}]
)
print(f"{current_agent.name} received {task}")
current_index = (current_index + 1) % len(agents)

Output:

agent_0 received Task 1
agent_1 received Task 2
agent_2 received Task 3
agent_0 received Task 4
agent_1 received Task 5
agent_2 received Task 6
  • Define clear agent capabilities: Each agent in the pool should have similar capabilities. The round-robin pattern assumes agents are interchangeable. For specialized routing, use the supervisor-worker pattern instead.
  • Track rotation state: Maintain the rotation index as part of your application state. If your application restarts, persist the index to resume the rotation.
  • Monitor agent workload: Verify that the client distributes tasks evenly across agents. Large differences in task counts may indicate an issue with rotation logic.
  • Consider agent capacity: The round-robin pattern assumes all agents have equal processing capacity. If agents process tasks at different speeds, consider weighted distribution or dynamic load balancing.
  • Use consistent agent ordering: Maintain a consistent rotation order across application restarts for predictable task distribution.