An agent that triages support tickets using three tools is manageable. An agent that has access to your database, email, Slack, GitHub, and deployment pipeline is a liability. If you can limit the agent to a specific subtask with a bounded tool set, wrap it in a workflow.
→ Yes: Use a hybrid — workflow orchestration with a bounded agent step. Stop here.
→ No: Continue to Question 5.
Question 5: Is this a research or exploration task with no fixed deliverable format?
Open-ended research, competitive analysis, investigative debugging — tasks where the output shape depends on what the agent discovers — are the rare cases where a full agent loop makes sense. Even here, set a maximum iteration count and a timeout.
→ Yes: Use a full agent with guardrails. Set max iterations, cost caps, and human-in-the-loop for high-stakes actions.
For roughly 80% of production use cases, you will stop at Question 1 or 2. The remaining 20% will mostly land on Question 4 (hybrid). Full autonomous agents — Question 5 — represent maybe 2-3% of real production workloads.
The Hybrid Pattern in Practice
The most effective architecture in production is not pure workflow or pure agent. It is a workflow that delegates to agents only where reasoning is required.
Consider a customer support pipeline:
def support_pipeline(ticket):
# Step 1: Agent — classify the ticket (needs judgment)
classification = classify_agent.run(
f"Classify this ticket: {ticket.subject}\n{ticket.body}",
output_schema={"category": str, "priority": str, "sentiment": str}
)
# Step 2: Workflow — route based on classification (deterministic)
if classification.priority == "critical":
channel = "#incidents"
notify_oncall(ticket)
elif classification.category == "billing":
channel = "#billing-support"
else:
channel = "#general-support"
# Step 3: Agent — draft a response (needs judgment)
draft = response_agent.run(
f"Draft a response for this {classification.category} ticket. "
f"Priority: {classification.priority}. Sentiment: {classification.sentiment}.\n"
f"Ticket: {ticket.body}",
tools=[search_knowledge_base, check_account_status]
)
# Step 4: Workflow — deliver (deterministic)
post_to_slack(channel, format_ticket(ticket, classification, draft))
update_crm(ticket.id, classification, draft)
return {"classification": classification, "channel": channel, "draft": draft}
Steps 1 and 3 are agents — they handle ambiguity. Steps 2 and 4 are workflow — they are predictable and cheap. The workflow controls the overall sequencing so you can audit exactly what happened. The agents handle the parts that require judgment, within bounded scope.
This pattern gives you three things no pure architecture can:
-
Auditability at the system level (the workflow logs every step)
-
Flexibility where you need it (agents reason about ambiguous inputs)
-
Bounded blast radius when an agent does something unexpected (the workflow catches it at the next deterministic step)
Three Anti-Patterns That Cost Teams Months
The God Agent
You give one agent 15+ tools and a vague goal: "Handle customer requests." It works in demos because your test inputs are clean. In production, it picks the wrong tool 20% of the time, chains tool calls in ways you did not anticipate, and occasionally sends a customer a Slack message meant for your internal channel.
Fix: Split into specialized agents with 3-5 tools each, orchestrated by a workflow. A classification agent picks the category, then the workflow routes to the right specialist agent.
The Premature Agent
You deploy an agent for a task that has deterministic inputs, predictable outputs, and no judgment required. Parsing structured JSON, routing based on a field value, sending a templated notification. The agent works, but it costs 50x more, runs 10x slower, and introduces non-determinism where none was needed.
The test: If you can write the logic as a Python function with no LLM call and it handles 95%+ of cases correctly, it should be a workflow step.
The Workflow Pretending to Be an Agent
You build a massive decision tree with 47 branches to handle every edge case. Each branch has its own LLM prompt. You are maintaining a flowchart that looks like a city subway map and adding new branches every week. The system is brittle — every new edge case requires a code change.
The signal: If you keep adding branches to handle new cases and the workflow keeps growing, the problem space has variable execution paths. Replace the branching section with an agent that reasons about the cases, keeping the rest of the workflow deterministic.
Real-World Architecture Examples
Here is how the decision tree maps to four common use cases:
E-Commerce Order Processing → Pure Workflow
Order received → Validate payment → Check inventory →
Calculate shipping → Charge card → Send to fulfillment →
Email confirmation
Every step is predictable. The inputs are structured. The volume is high (thousands per hour). An agent here would add cost, latency, and non-determinism with zero benefit. Decision tree stops at Question 1.
Customer Support Inbox → Hybrid
Ticket received → [Agent: classify + assess priority] →
Workflow: route to team → [Agent: draft response with KB search] →
Workflow: send + log
The classification and response steps require judgment — a billing complaint about an unauthorized charge is different from a question about pricing, even though both mention "charges." The routing and delivery are deterministic. Decision tree stops at Question 4.
Code Review Automation → Agent-Heavy
PR opened → [Agent: read diff, check patterns, query docs,
assess risk, write review comments]
The agent needs to reason about what it sees in the diff. A security issue requires different analysis than a performance concern. The investigation path depends on the code — you cannot predefine it. Decision tree reaches Question 5, but scope is bounded (one PR, read-only actions plus comments), so it stays manageable.
Daily Engineering Report → Workflow + Agent Step
Cron trigger → Workflow: fetch metrics from Datadog →
Workflow: fetch open issues from GitHub →
Workflow: fetch deploy log → [Agent: analyze + write summary] →
Workflow: post to Slack
Three of five steps are deterministic API calls. Only the analysis requires judgment. Decision tree stops at Question 2. This is the most common pattern in production — and the one most teams over-engineer with a full agent.
Choosing Your Stack
The right tool depends on which side of the decision tree your use case lands.
For workflows: Temporal for complex orchestration with durable execution. Airflow for data pipelines. n8n or Zapier for no-code automation. AWS Step Functions for serverless workflows. All of these handle sequencing, retries, and error recovery out of the box.
For agents: LangGraph for stateful agent graphs with checkpointing. CrewAI for multi-agent teams with role-based coordination. The OpenAI Agents SDK for lightweight single-agent tasks. Each has a different abstraction level — choose based on how much control you need over the execution graph.
For hybrids: This is where platforms like Nebula fit — you define the pipeline as a workflow, and individual steps can be handled by agents with their own tools and reasoning. The workflow controls sequencing and error handling; the agents handle the ambiguous parts. This pattern works particularly well for teams that need observability across both the deterministic and non-deterministic parts of their system.
The key architectural requirement regardless of stack: observability. You need to see what the workflow executed (step-level logs) AND what the agent decided (reasoning traces). Without both, debugging production issues is guesswork.
Your Checklist Before You Choose
| Question |
If Yes |
If No |
| Can you draw the complete flowchart? |
Workflow |
Continue |
| Is ambiguity limited to 1-2 steps? |
Workflow + LLM step |
Continue |
| Can you bound the agent's scope? |
Hybrid pattern |
Continue |
| Is the task open-ended exploration? |
Full agent + guardrails |
Rethink the task |
| Are you handling >1000 executions/hour? |
Workflow (cost matters) |
Either |
| Is auditability a hard requirement? |
Workflow outer shell |
Either |
| Does the task change shape with new inputs? |
Agent for that subtask |
Workflow |
The default answer is a workflow. The burden of proof is on the agent — it needs to earn its complexity by solving a problem that deterministic logic cannot.
Start with a workflow. Add agent steps only where you need judgment. Measure the cost and accuracy of each agent step independently. And never go full autonomous agent on day one — you will regret it by day three.