A single AI agent calling tools in a loop works great for simple tasks. It breaks down fast when you need parallel execution, specialised sub-agents, or reliable handoffs between steps. That's where agentic workflow patterns come in.
This post covers the four patterns we use most at SymbiotesAI, with real implementation guidance for each.
Pattern 1: Sequential Chain
The simplest pattern — each agent's output becomes the next agent's input.
const result = await chain([
researchAgent,
summaryAgent,
formattingAgent,
], initialInput)Use when: Tasks have clear sequential dependencies. Research → draft → review pipelines are the classic example.
Watch out for: Error propagation. If step 2 fails, you've wasted all the compute from step 1. Add checkpointing.
Pattern 2: Fan-Out / Fan-In
Spawn multiple specialised agents in parallel, then aggregate their results.
const [legal, technical, financial] = await Promise.all([
legalReviewAgent.run(document),
technicalReviewAgent.run(document),
financialReviewAgent.run(document),
])
const summary = await aggregatorAgent.run({ legal, technical, financial })Use when: Sub-tasks are independent and latency matters. Document analysis, multi-source research, and batch classification all benefit here.
Watch out for: Rate limits. Spawning 20 parallel Claude calls will hit your API limits fast. Implement a concurrency limiter.
Pattern 3: Orchestrator + Workers
A top-level orchestrator agent decomposes the task and delegates to specialised worker agents dynamically.
const orchestrator = new Agent({
tools: [
codeWriterAgent.asTool(),
testWriterAgent.asTool(),
reviewerAgent.asTool(),
],
systemPrompt: `You are an engineering orchestrator. Break tasks into subtasks
and delegate to the appropriate specialist agent.`,
})Use when: The task structure isn't known upfront. The orchestrator decides at runtime which workers to call and in what order.
Watch out for: Runaway loops. Always set a maxIterations limit and add circuit breakers.
Pattern 4: Human-in-the-Loop
Pause the workflow at defined checkpoints to get human approval before proceeding.
const draft = await draftingAgent.run(brief)
const approved = await humanReview.request({
content: draft,
timeout: '24h',
fallback: 'reject',
})
if (approved) {
await publishingAgent.run(draft)
}Use when: The stakes are high — financial transactions, public communications, legal documents. Automation handles the heavy lifting; humans handle the final call.
Choosing the Right Pattern
| Scenario | Pattern |
|---|---|
| Fixed multi-step pipeline | Sequential Chain |
| Independent parallel tasks | Fan-Out / Fan-In |
| Dynamic task decomposition | Orchestrator + Workers |
| High-stakes decisions | Human-in-the-Loop |
Most real systems combine patterns. A document processing pipeline might fan out to parallel reviewers, aggregate with an orchestrator, then gate on human approval before writing to the database.
What Makes Agentic Workflows Fail
After building dozens of these systems, the failures cluster around the same root causes:
- No idempotency — agents re-run side effects when retried
- No structured output — agents return prose when the next step expects JSON
- No state persistence — crash mid-pipeline means starting over
- Infinite loops — missing exit conditions in orchestrator loops
Build with these in mind from day one, not after your first production incident.
