Patterns and Best Practices#

Common Topology Patterns#

  1. 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"),
    ]
    
  2. Pipeline (pipeline) - Linear sequence: A -> B -> C -> Sink - Suitable for fixed processes and strict stage division - Example:

    edges = [("a", "b"), ("b", "c")]
    
  3. All-to-All (Fully Connected) - Quick Experiment, Highest Degree of Freedom - Prone to Cycles, Recommend Setting a Smaller max_turns and Emphasize in Agent Prompt ‘Complete as FINISHED’

  4. 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 the info to carry (context/requirements/results)

  • Unified Termination Protocol: When a direct answer to the user can be provided, the reply must end with FINISHED

  • Transfer 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 handoff tools for each Agent

  • The optional values for target_agent come from edges (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_turns to prevent the LLM from entering a loop under boundary conditions

  • Through 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