AI & ML
Your n8n Workflow Has 40 Nodes. Should Any of Them Be an AI Agent?
Hossein Hezami Dev.to (EN Zone)
1 views
Open an n8n workflow with 40 nodes and two thoughts usually appear at the same time.
First: This is getting out of hand.
Second: Could an AI agent replace half of it?
Sometimes the answer is yes. Often, the answer is: Only a small part, and only if you keep the dangerous bits deterministic.
A large workflow is not automatically a bad workflow. Forty nodes can represent forty clear, testable, observable steps. Or they can represent a fragile pile of string parsing, nested IF nodes, retry hacks, and manual exception handling that is begging for a smarter component.
The trick is knowing which kind of complexity you have.
TL;DR
A 40-node n8n workflow is not automatically wrong.
Deterministic nodes are valuable because they are predictable, auditable, and cheap.
AI agents are useful for ambiguity: messy text, dynamic tool selection, extraction, classification, and open-ended reasoning.
AI agents are usually wrong for fixed business rules, financial math, permissions, and direct side effects.
The best production pattern is usually a deterministic spine with a few carefully bounded agentic joints.
📋 Table of Contents
The 40-node panic
1. A large workflow is not the same thing as a bad workflow
2. Replace brittle text handling before replacing business logic
3. Routing belongs in a Switch node until routing becomes fuzzy
4. Agents are useful when the next step is not known in advance
5. Keep side effects outside the agent's direct control
6. Force the agent to return structured data you can validate
7. Treat the agent like an expensive, slow external API
8. The hybrid pattern: deterministic spine, agentic joints
The decision framework I would use
The 40-node panic
n8n workflows tend to grow in a very natural way.
You start with a webhook. Then you add a filter. Then an API call. Then a Switch node. Then an error path. Then a retry. Then a formatting step. Then another API. Then a Slack message. Then a database lookup. Then another branch for a special customer.
Before long, the canvas looks like a subway map.
At that point, an AI agent can look attractive because it promises to collapse complexity into intent:
“Read the incoming message, figure out what needs to happen, use the right tools, and produce the result.”
That is powerful. It is also exactly the kind of power that can make a production system harder to reason about.
The right question is not:
“Can an agent replace this workflow?”
It is:
“Which nodes are doing deterministic work, which nodes are compensating for ambiguity, and which nodes are performing actions that should never be uncontrolled?”
That distinction is the whole game.
1. A large workflow is not the same thing as a bad workflow
Scenario:
Your n8n workflow has 40 nodes. Some are HTTP Request nodes, some are Switch nodes, some handle retries, some format payloads, and some write to a database. It works. It is just visually intimidating.
Why it matters:
A node count is a weak signal of quality.
A workflow with 40 small, explicit steps can be easier to operate than a workflow with 3 magical black boxes. At least with explicit nodes you can see:
where data enters,
where it transforms,
where external calls happen,
where errors are handled,
and where side effects occur.
An agent can reduce visual complexity while increasing behavioral complexity. That trade is not always worth it.
Solution:
Before adding an agent, classify your nodes.
A useful audit looks like this:
Node category
Example
Keep deterministic?
Agent candidate?
Input validation
Required fields, auth checks
Yes
No
Business rules
Refund eligibility, SLA calculation
Yes
Rarely
External API calls
CRM lookup, ticket creation
Yes
Maybe as tool
Formatting
JSON to CSV, date normalization
Yes
No
Routing
Known categories
Yes
Maybe if fuzzy
Text interpretation
Emails, support messages, notes
Sometimes
Often
Side effects
Send email, update record, charge card
Yes
No, not directly
Error handling
Retry, fallback, alerting
Yes
No
This audit usually reveals something important: the workflow is not “40 nodes of confusion.” It is mostly deterministic plumbing with a few ambiguous interpretation steps hidden inside.
Those ambiguous steps are where an agent may belong.
💡 Practical note:
If a workflow is hard to understand because nobody knows what the business rules are, replacing it with an agent will not fix the problem. It will hide the problem inside a prompt.
2. Replace brittle text handling before replacing business logic
Scenario:
Your workflow receives support emails. You have a chain of IF nodes checking whether the subject contains “refund”, “invoice”, “login”, or “broken”. It works until someone writes, “I was charged twice and cannot access my account.”
Now the ticket matches two categories, or none.
Why it matters:
This is where deterministic automation often becomes fragile: unstructured human language.
A deterministic workflow is excellent when inputs are structured:
webhook payloads,
database rows,
API responses,
form submissions,
scheduled jobs.
It becomes much less pleasant when inputs are messy:
emails,
chat messages,
PDFs,
support tickets,
meeting notes,
uploaded documents,
free-form comments.
That is a natural place for an LLM or agent-assisted step.
Solution:
Use the model to extract structured data, then use normal n8n nodes to apply business logic.
For example, instead of asking the agent to decide the final action, ask it to produce a constrained object:
{
"intent": "billing_issue",
"sub_intent": "duplicate_charge",
"account_email": "user@example.com",
"order_id": "ORD-12345",
"urgency": "high",
"summary": "Customer says they were charged twice and cannot log in.",
"confidence": "medium"
}
Then your workflow can validate and route that object deterministically.
// n8n Code node example
const allowedIntents = [
"billing_issue",
"account_access",
"bug_report",
"feature_request",
"unknown",
];
const extracted = $json.extracted;
if (!extracted || typeof extracted !== "object") {
throw new Error("Extraction result is missing.");
}
if (!allowedIntents.includes(extracted.intent)) {
return [{
json: {
route: "human_review",
reason: `Unrecognized intent: ${extracted.intent}`,
extracted,
},
}];
}
if (!extracted.account_email && !extracted.order_id) {
return [{
json: {
route: "ask_for_details",
reason: "Missing account identifiers.",
extracted,
},
}];
}
return [{
json: {
route: extracted.intent,
extracted,
},
}];
The agent handles ambiguity. The workflow handles consequences.
Why this works:
You are not asking the model to run your business. You are asking it to convert messy input into a shape your automation can understand.
That is one of the safest and most useful places to put an AI component.
3. Routing belongs in a Switch node until routing becomes fuzzy
Scenario:
Your workflow routes incoming requests to billing, support, sales, or engineering. You have 12 IF nodes, some regex, and a few “else” branches nobody fully trusts.
The obvious fix seems to be:
“Let an agent classify the message.”
Sometimes that is correct. Sometimes you are just replacing a cheap, predictable router with an expensive, nondeterministic one.
Why it matters:
Routing is a classic automation decision. If the categories are stable and the signals are clear, deterministic routing is better.
A Switch node or simple Code node is:
fast,
cheap,
predictable,
easy to test,
easy to audit,
and not subject to model drift.
An AI classifier is useful when categories are fuzzy, language is varied, and the routing logic would otherwise become an unmaintainable pile of string matching.
Solution:
Start deterministic. Move to model-assisted routing only when deterministic routing fails in practice.
A simple deterministic router in an n8n Code node might look like this:
const subject = ($json.subject ?? "").toLowerCase();
const body = ($json.body ?? "").toLowerCase();
const text = `${subject} ${body}`;
let route = "general";
if (text.includes("refund") || text.includes("invoice") || text.includes("charge")) {
route = "billing";
} else if (text.includes("password") || text.includes("login") || text.includes("2fa")) {
route = "account_access";
} else if (text.includes("error") || text.includes("bug") || text.includes("crash")) {
route = "engineering";
}
return [{ json: { route } }];
This is not glamorous, but it is operationally boring. Boring is valuable.
If the categories become ambiguous, you can use a model to classify into a fixed enum:
{
"route": "billing",
"confidence": 0.92,
"reason": "Customer mentions a duplicate charge."
}
Then keep a deterministic fallback:
const result = $json.classification;
if (!result || !["billing", "account_access", "engineering", "general"].includes(result.route)) {
return [{ json: { route: "human_review" } }];
}
if (typeof result.confidence === "number" && result.confidence < 0.7) {
return [{ json: { route: "human_review", reason: "Low classification confidence." } }];
}
return [{ json: { route: result.route } }];
Why this works:
You preserve deterministic behavior where possible and only introduce nondeterminism where the problem is genuinely fuzzy.
⚠️ Gotcha:
If the agent can route a message but cannot explain why, you have made debugging harder. Ask for a route, confidence, and short rationale.
4. Agents are useful when the next step is not known in advance
Scenario:
A user asks:
“Find the latest invoice for Acme Corp, check whether it was paid, and if not, draft a polite reminder to the billing contact.”
This looks simple, but the workflow path depends on what it discovers.
If the customer has one invoice, the path is simple. If there are ten invoices, the agent may need to filter. If the invoice status is missing, it may need another lookup. If the billing contact is missing, it may need to search the CRM.
This is different from a fixed pipeline.
Why it matters:
Deterministic workflows shine when the path is known:
Validate input.
Call API.
Transform data.
Write record.
Send notification.
Agents shine when the path is dynamic:
choose a tool,
observe the result,
decide what to do next,
possibly call another tool,
and stop when enough evidence exists.
That loop is the core value of an agent.
Solution:
Use an agent for bounded investigation tasks, not for the entire business process.
Good agent tasks inside n8n include:
“Find the most relevant support article for this ticket.”
“Extract missing fields from this email thread.”
“Determine whether this request needs billing, technical support, or human review.”
“Summarize this conversation and identify unresolved questions.”
“Choose which internal API to call based on the user’s intent.”
Less appropriate agent tasks include:
calculating tax,
applying refund policy math,
enforcing permissions,
changing production data,
sending money,
or executing irreversible operations.
Why this works:
You use the agent where adaptability matters. You keep the workflow where predictability matters.
A useful rule:
If the workflow can be drawn as a stable flowchart, keep it as a workflow.
If the workflow keeps growing branches because the world is messy, consider an agent for the messy part.
5. Keep side effects outside the agent's direct control
Scenario:
You give an agent access to tools like updateTicket, sendEmail, createRefund, and deleteRecord. It mostly works. Then one ambiguous request causes it to email the wrong person or close a ticket that should stay open.
Why it matters:
An agent that can decide and act is more powerful, but also more dangerous.
The problem is not that models are useless. The problem is that production systems need boundaries. If the agent can directly perform side effects, every prompt ambiguity becomes a potential operational incident.
Solution:
Separate decision-making from execution.
The agent can propose an action. The workflow should decide whether that action is allowed.
A simple tool-policy wrapper might look like this:
const MUTATING_TOOLS = new Set([
"updateTicket",
"sendEmail",
"createRefund",
"closeAccount",
]);
function authorizeToolCall(toolCall, context) {
const { name, args } = toolCall;
if (!name) {
return { allowed: false, reason: "Tool name missing." };
}
if (MUTATING_TOOLS.has(name) && !context.allowMutations) {
return {
allowed: false,
reason: "Mutating tools are disabled for this workflow run.",
};
}
if (name === "sendEmail") {
const to = String(args.to ?? "").toLowerCase();
if (!to.endsWith("@yourcompany.example")) {
return {
allowed: false,
reason: "External email sends require explicit approval.",
};
}
}
if (name === "createRefund" && Number(args.amount ?? 0) > 500) {
return {
allowed: false,
reason: "Refunds above threshold require human approval.",
};
}
return { allowed: true };
}
In an n8n workflow, this kind of logic can sit between the agent output and the actual action nodes.
The flow becomes:
Agent proposes tool call
→ policy check
→ validation
→ approval gate if needed
→ deterministic execution node
→ audit log
Not:
Agent thinks
→ Agent acts
→ Hope
Why this works:
It gives you the adaptability of an agent without giving it unchecked authority over your systems.
🚨 Production warning:
If an agent can write to your database, send external messages, or trigger payments, it needs guardrails, logging, and probably a human approval path.
6. Force the agent to return structured data you can validate
Scenario:
The agent returns a helpful paragraph:
“It looks like the customer is asking for a refund because their order arrived late. I recommend processing it, but the order number might be ORD-12345.”
Your workflow now has to parse that prose. If the wording changes, the automation breaks.
Why it matters:
A workflow needs stable data, not vibes.
If an agent returns free-form text, you have moved the ambiguity problem from the beginning of the workflow to the middle of it.
Solution:
Require structured output.
The agent should return something like:
{
"intent": "refund_request",
"order_id": "ORD-12345",
"reason": "late_delivery",
"recommended_action": "review_refund",
"confidence": "medium",
"missing_fields": []
}
Then validate it before using it.
const raw = $json.agent_output;
let parsed;
try {
parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
} catch {
throw new Error("Agent output was not valid JSON.");
}
const allowedIntents = [
"refund_request",
"order_status",
"account_access",
"technical_issue",
"unknown",
];
const allowedActions = [
"no_action",
"ask_for_details",
"route_to_support",
"review_refund",
"human_review",
];
if (!allowedIntents.includes(parsed.intent)) {
throw new Error(`Invalid intent: ${parsed.intent}`);
}
if (!allowedActions.includes(parsed.recommended_action)) {
throw new Error(`Invalid recommended_action: ${parsed.recommended_action}`);
}
if (parsed.intent === "refund_request" && !parsed.order_id) {
parsed.recommended_action = "ask_for_details";
parsed.missing_fields = ["order_id"];
}
return [{ json: parsed }];
This does not require the model to be perfect. It requires the workflow to accept only usable output.
Why this works:
Structured output turns the agent into a component with an interface. That interface can be validated, tested, logged, and rejected when necessary.
🔍 Why this matters:
If you cannot validate an agent’s output, you cannot safely automate based on it.
7. Treat the agent like an expensive, slow external API
Scenario:
Your workflow runs every minute. Each run calls an agent. The agent sometimes retries, sometimes expands its reasoning, sometimes calls multiple tools. Latency becomes unpredictable. Costs creep upward.
Why it matters:
An agent is not just another function node. It may involve:
model inference,
multiple tool calls,
retries,
token growth,
external API calls,
and unpredictable latency.
That makes it behave more like a slow, expensive, nondeterministic external service.
Production workflows need budgets for that kind of service.
Solution:
Give the agent explicit limits and fallback behavior.
A practical budget object might look like this:
const agentBudget = {
maxSeconds: 20,
maxToolCalls: 4,
maxRetries: 1,
maxInputTokens: 4000,
fallbackRoute: "human_review",
};
Then enforce those limits around the agent call.
In n8n terms, that may mean:
using timeout settings where available,
calling the agent through a service that enforces limits,
limiting the number of agent loop iterations,
restricting available tools,
caching repeated classifications,
and routing failures to a safe fallback.
A fallback is not optional.
If the agent times out, returns invalid JSON, exceeds budget, or produces low confidence output, the workflow should do something deliberate:
send to human review,
ask the user for clarification,
use a deterministic fallback,
or queue for later processing.
Why this works:
It prevents an agent from becoming an unbounded cost and latency multiplier inside an otherwise normal automation pipeline.
A good mental model:
An agent should be treated like a contractor with a limited scope, a deadline, and a requirement to return a specific form.
Not like an employee with unlimited access and no review process.
8. The hybrid pattern: deterministic spine, agentic joints
The best production answer is rarely:
“Replace the whole workflow with an agent.”
It is usually:
“Keep the deterministic spine. Add agents at the joints where the world is messy.”
A deterministic spine is the part of the workflow that must be reliable:
authentication,
input validation,
permissions,
business rules,
calculations,
database writes,
notifications,
audit logging,
error handling.
Agentic joints are the places where ambiguity enters:
interpreting an email,
classifying a request,
extracting entities,
summarizing a thread,
choosing a relevant knowledge-base article,
deciding whether more information is needed,
proposing a next best action.
A production-friendly shape often looks like this:
Webhook / trigger
→ validate payload
→ normalize input
→ agent: extract/classify/summarize
→ validate agent output
→ deterministic routing
→ policy check
→ action node
→ audit log
→ error fallback
This gives you several advantages:
The workflow remains testable.
Side effects remain controlled.
Agent failures have safe fallbacks.
Business logic remains visible.
The agent can be improved without rewriting the whole automation.
You can measure whether the agent is actually helping.
It also makes the workflow easier to explain to non-developers.
You can say:
“The AI step reads the message and extracts structured fields. The workflow decides what happens next.”
That is much easier to trust than:
“The AI decides.”
The decision framework I would use
If I were looking at a 40-node n8n workflow and deciding whether to introduce an AI agent, I would use a simple framework.
Use deterministic nodes when:
the input is already structured,
the logic is stable,
the rules are financial, legal, or security-related,
the output must be exactly reproducible,
the step performs a side effect,
or the cost of being wrong is high.
Examples:
calculating totals,
checking permissions,
updating records,
sending invoices,
triggering deployments,
enforcing rate limits,
writing audit logs.
Consider an AI agent when:
the input is messy,
categories are fuzzy,
the next step depends on discovered context,
the task involves interpretation,
or the workflow keeps growing brittle branches around human language.
Examples:
classifying support tickets,
extracting names, dates, order IDs, and intents,
summarizing long email threads,
finding the right internal document,
deciding whether a request is incomplete,
suggesting a response draft,
routing ambiguous inquiries.
Keep the agent away from:
irreversible actions,
payment operations,
production data deletion,
credential handling,
secret management,
external messaging without review,
and any action that requires formal accountability.
A useful comparison:
Workflow problem
Better approach
Fixed API sequence
Normal n8n workflow
Known routing rules
Switch / IF / Code node
Messy email interpretation
AI extraction step
Dynamic tool selection
Bounded agent
Refund calculation
Deterministic logic
Drafting a response
Agent with human review
Sending money or deleting data
Deterministic approval flow, not direct agent action
Audit trail
Explicit workflow nodes and logs
The core question is not whether AI agents are impressive. They can be.
The core question is whether a particular node in your workflow needs judgment, or whether it needs reliability.
If the node is doing math, enforcement, permissions, or side effects, keep it deterministic.
If the node is staring at messy human input and trying to figure out what it means, that is where an agent may finally earn its place.
Read original: https://dev.to/hosseinhezami/your-n8n-workflow-has-40-nodes-should-any-of-them-be-an-ai-agent-14bk
← Previous
Mastering Routing in FastAPI: From Flat Files to Clean Architecture
Next →
Apple Introduces AirPods 5
Related
What Your 'AI Agent' Is Actually Doing: 8 Terms Explained Simply
AI & ML
0
DEV Community
I Built SelfContext So I Could Stop Re-explaining Myself to AI
AI & ML
0
DEV Community
How I Would Design an n8n AI System That Can Recover From Its Own Failures
AI & ML
5
Dev.to (EN Zone)
AI Coding Agents Explained (With a Real Example)
AI & ML
6
Dev.to (EN Zone)
Comments0
No comments yet — be the first