Patterns and Best Practices#
Common Topology Patterns#
Star (Centralized Planner) - Edges only flow back and forth between the Planner and other Agents - Facilitates centralized scheduling and constraints - Example:
edges = [ ("planner", "a"), ("a", "planner"), ("planner", "b"), ("b", "planner"), ("planner", "c"), ("c", "planner"), ]
Pipeline (pipeline) - Linear sequence: A -> B -> C -> Sink - Suitable for fixed processes and strict stage division - Example:
edges = [("a", "b"), ("b", "c")]
All-to-All (Fully Connected) - Quick Experiment, Highest Degree of Freedom - Prone to Cycles, Recommend Setting a Smaller
max_turnsand Emphasize in Agent Prompt ‘Complete as FINISHED’Hybrid (hybrid) - For example: Planner coordinates the main line, but certain expert Agents are allowed to collaborate directly - Example:
edges = [ ("planner", "retriever"), ("retriever", "planner"), ("planner", "writer"), ("writer", "planner"), ("retriever", "writer"), # Allow direct handoff from retriever to writer ]
Key Points for Writing Agent Prompts#
Clarify role division: Capability boundaries and tool limitations, avoid Agent proactively asking users for follow-up questions.
Clear handoff process: explain when to use
handoff, and theinfoto carry (context/requirements/results)Unified Termination Protocol: When a direct answer to the user can be provided, the reply must end with
FINISHEDTransfer only one Agent at a time: Avoid competition and chaos caused by parallel processing (can be emphasized in the Planner’s prompt)
Handoff tool semantics#
Swarm injects customized
handofftools for each AgentThe optional values for
target_agentcome fromedges(if no edges then “All Other Agents”)The tool documentation string contains a clear list of goals, helping the LLM correctly invoke
Strictly Constrained Topology (Advanced)#
edges default to “soft constraint”: the router still allows jumping to any registered Agent (provided that the tool call in the message specifies the target). If a “hard constraint” is required, it can be achieved by inheriting Swarm and overriding the router:
from evofabric.core.multi_agent import Swarm
class StrictSwarm(Swarm):
def _create_router(self, current_agent_name: str):
base_router = super()._create_router(current_agent_name)
allowed = set(self._get_allowed_targets(current_agent_name))
def router(state):
nxt = base_router(state)
# Intercept jumps that are not in allowed (except for "end")
if nxt in self._agent_names and nxt != "end" and nxt not in allowed:
return current_agent_name
return nxt
return router
Other suggestions#
Set a reasonable
max_turnsto prevent the LLM from entering a loop under boundary conditionsThrough printing routing logs or capturing standard output, analyze the actual redirect path
If the Agent has no outgoing edges, it will not inject the handoff tool and can serve as the “convergence/endpoint” role