Skip to main content

Custom Orchestration

The orchestrator routes each conversation turn to the right agent and controls the flow of information between agents and users. Implement AbstractOrchestrator to define custom routing logic.

Prerequisites

  • AgenticAI Core SDK installed and configured.
  • At least one agent configured and converted to AgentMeta. See Creating Agents.

Message handling protocol

Incoming messages

The orchestrator’s _handle_message method receives a List[MessageItem]. The last item is either:
  • A user message (role='user') — when the user sends a query.
  • An agent response (role='tool') — when an agent completes its task.

Outgoing messages

The method must return one of: ToolCall fields:
  • tool_name — the agent to invoke, or "route_to_user" to respond to the user.
  • message — the content sent to the agent or shown to the user.
  • input, thought, reason — optional context for debugging and tracing.

Special agent: route_to_user

route_to_user is a built-in proxy for the user. Use it to deliver final answers or request clarification. The message field in the ToolCall is exactly what the user sees.

Create a custom orchestrator

Subclass AbstractOrchestrator and override _handle_message:

Routing strategies

Keyword-based routing

Round-robin routing

Task-based routing

Use memory in orchestrators

Use RequestContext to persist and retrieve orchestration state across turns:

Add distributed tracing

Decorate _handle_message and _select_agent with @tracer.observe to capture routing spans:

Common orchestration flows

User → agent → user (single-agent turn):
User → agent → agent → user (chained agents):
User → user (direct response, no agent):

Register the orchestrator

Pass the orchestrator class to app.start:

Best practices

  • message field: This is the most important field in ToolCall. For agents, it contains the task or question to process. For route_to_user, it is the exact response the user sees.
  • Error handling: Handle both success and error cases. Return ErrorMessage for routing failures and always implement a route_to_user fallback.
  • Logging: Use thought and reason fields for debugging routing decisions. Log agent selection outcomes and track agent performance.
  • State management: Use memory stores to track conversation context and agent selection history across turns.
  • Performance: Keep routing logic lightweight. Avoid blocking calls in _handle_message. Use tracing to identify latency bottlenecks.