Skip to content

Orchestration: Sequential

Key Points

  • Sequential pattern: Agent A → Agent B → Agent C. Output of one feeds the next.
  • Use when steps have a clear linear order: research → draft → polish; or extract → transform → summarize.
  • Output of each agent enriches the conversation passed to the next.
  • More predictable than free-form multi-agent; easier to debug.

Concept

[User input]
[Researcher Agent] — finds relevant docs
   │  context+findings
[Writer Agent] — drafts based on findings
   │  draft
[Editor Agent] — polishes
[Final output]

Each agent has a focused role.

Code

var researcher = new ChatClientAgent(chat)
{
    Name = "Researcher",
    Instructions = "Find relevant documents for the user's question. List 3-5 sources.",
    Tools = [AIFunctionFactory.Create(SearchDocs)]
};

var writer = new ChatClientAgent(chat)
{
    Name = "Writer",
    Instructions = "Write a concise answer based on the researcher's sources. Cite each fact.",
};

var editor = new ChatClientAgent(chat)
{
    Name = "Editor",
    Instructions = "Polish for clarity and grammar. Keep citations intact."
};

// Sequential orchestration
var orchestration = new SequentialOrchestration([researcher, writer, editor]);

var response = await orchestration.InvokeAsync("Explain quantum tunneling");

SequentialOrchestration runs each agent in turn; appends output to messages; passes to next.

Implementation pattern

If not using a built-in helper:

public class SequentialOrchestration(IList<Agent> agents)
{
    public async Task<AgentResponse> InvokeAsync(string input, CancellationToken ct = default)
    {
        var messages = new List<ChatMessage> { new(ChatRole.User, input) };
        AgentResponse? final = null;

        foreach (var agent in agents)
        {
            var resp = await agent.InvokeAsync(messages, ct);
            messages.AddRange(resp.Messages);
            final = resp;
        }

        return final!;
    }
}

With handoff messages

For agents to know context:

messages.Insert(0, new ChatMessage(ChatRole.System,
    $"This is a multi-step pipeline. Current stage: {agent.Name}. Previous outputs are in conversation."));

Streaming

await foreach (var update in orchestration.InvokeStreamingAsync(input))
{
    Console.WriteLine($"[{update.AgentName}] {update.Text}");
}

Caller can show "Researcher is searching..." → "Writer is drafting..." → etc.

Use cases

  • Content generation: research → draft → polish.
  • Code review: linter → test runner → semantic review.
  • Data pipeline: extract → transform → summarize.
  • Customer issue: classifier → router → resolver.

Trade-offs

Aspect Pros Cons
Predictable Easy to debug Less flexible than free-form
Linear Clear contract Can't skip; can't loop
Cost Each step adds tokens Multiplies model calls

When NOT sequential

  • Steps are independent → parallel/concurrent.
  • Steps depend on dynamic decisions → handoff or group chat.
  • Steps loop with conditions → workflow engine.

Token cost

Researcher: ~3K input + 1K output = $0.005 (gpt-4o-mini)
Writer:    ~5K input + 1K output = $0.008
Editor:    ~6K input + 800 output = $0.009
Total:     ~$0.022 per request

Cumulative input grows with each stage.

Optimization

  • Have early stages output structured summaries rather than dumping everything.
  • Use cheaper model for early stages.
  • Cache early-stage outputs if input deterministic.

Senior considerations

  • Each agent should have a CRISP role.
  • Test stages independently before composing.
  • Limit total iterations (no infinite chains).
  • Trace per-stage with OTel.

Cross-references