03 · Agent Workflow Patterns (sequential · concurrent · group chat)

This lesson teaches that orchestration is a property of the workflow, not the agents — the same three agents drop into three different built-in graph shapes.

What this lesson demonstrates

Take three translation agents — French, Spanish, English, each instructed to answer only in its language — and drop the same three agents into whichever orchestration graph a WORKFLOW_PATTERN env var selects:

What this lesson demonstrates
WORKFLOW_PATTERN Builder Shape
sequential (default) NewSequentialWorkflowBuilder a chain: each agent sees the previous agent’s output
concurrent NewConcurrentWorkflowBuilder fan-out/fan-in: all agents run on the same input, results aggregate
groupchat NewGroupChatWorkflowBuilder + NewRoundRobinGroupChatManager agents take turns under a manager (round-robin, ≤ 5 iterations)

The agents never change — only the graph the builder produces does. That is the whole point.

The builders own the graph

switch pattern {
case "sequential":
    return agentworkflow.NewSequentialWorkflowBuilder(agents...).Build()
case "concurrent":
    return agentworkflow.NewConcurrentWorkflowBuilder(agents...).Build()
case "groupchat":
    return agentworkflow.NewGroupChatWorkflowBuilder(func(agents []*agent.Agent) *agentworkflow.GroupChatManager {
        return agentworkflow.NewRoundRobinGroupChatManager(agents, agentworkflow.RoundRobinGroupChatOptions{MaximumIterationCount: 5})
    }, agents...).
        WithName("Translation Round Robin Workflow").
        WithDescription("A workflow where three translation agents take turns responding in a round-robin fashion.").
        Build()
}

Each builder returns a *workflow.Workflow — a graph of executors and edges — so the difference between the patterns lives entirely in the wiring the builder emits, not in the agents. The group-chat path also shows fluent options: .WithName(...).WithDescription(...) ride the builder and land on the workflow, readable back via wf.Name() / wf.Description().

What to notice — running is uniform

Whatever the pattern, the run loop is identical: inproc.Default.RunStreaming, then push a workflow.TurnToken{EmitEvents: &true} to start the turn, then range over WatchStream reacting to OutputEvent / ErrorEvent / ExecutorFailedEvent. The program prints each streamed chunk prefixed with the emitting executor’s ID, and the shape of the interleaving — one agent after another, or all at once, or turn-taking — is the visible difference between the three patterns.

The gotcha: a group chat is bounded by MaximumIterationCount. Without that cap a round-robin of agents that always respond would never stop. Drop it to 1 and you get a single lap; raise it and the agents keep taking turns.

How it maps to the Agent Framework Go SDK

agentworkflow ships these three orchestration builders so you don’t hand-wire common topologies. Sequential and concurrent recur throughout 03-workflows (later lessons like the multi-model service and the concurrent fan-out/fan-in build on them); group chat with a manager is the foundation for human-in-the-loop and tool-approval group chats further on. All three run on the same in-process runner and need az login + FOUNDRY_PROJECT_ENDPOINT for a live run.

Run it: go run ./tutorial/03-workflows/01-start-here/03_agent_workflow_patterns (or WORKFLOW_PATTERN=concurrent / groupchat). The offline test builds every pattern with a fake credential and asserts each graph’s wiring; the live model run is gated behind AF_LIVE=1.


Next: 04 · Multi-Model Service (a sequential agent workflow)

Sources & References

The Go SDK this lesson exercises
Built-in agent orchestration patterns: sequential, concurrent, group chat