Skip to main content

Cloudsoft Zone Build, deploy and scale with practical guides to PHP, Node.js, React, DevOps and AI automation. Explore the guides

Cloudsoft Zone
AI and AutomationBusiness TechnologyJavaScriptNode.jsComparison

AI agents vs traditional workflow automation: when to use each

Use a workflow when you can write the steps down and an agent only when you cannot. Cost, reliability and audit compared, with a tested hybrid invoice workflow.

Cloudsoft Zone

Updated 14 min read

An instructor points at a large screen showing a UiPath automation workflow while service members and civilians follow along in a training room
Photograph: U.S. Space Force photo by DeAnna Murano / Public domain, via Wikimedia Commons
In this article

Use a deterministic workflow when you can write the steps down in advance, and an AI agent only when you cannot. That one rule settles most decisions. Invoice approval, employee onboarding and order notifications have known steps and need an audit trail, so they belong in a workflow, perhaps with a language model doing one well-defined step such as reading a PDF. Open-ended jobs such as investigating why an invoice does not match or researching a supplier suit an agent, kept inside limits and reporting to a person. This guide compares the two on cost, reliability and audit, and includes a tested hybrid that uses each where it fits.

Tested with: Node.js 24.18.0 (running TypeScript directly), TypeScript 6.0.3 (tsc --noEmit, strict) and @anthropic-ai/sdk 0.115.0. The workflow and audit trail ran locally; the model calls were type-checked, and replaced by labelled test doubles in the run.

What each term means

Anthropic's widely cited Building effective agents draws the line clearly. Workflows are "systems where LLMs and tools are orchestrated through predefined code paths". Agents are "systems where LLMs dynamically direct their own processes and tool usage". The difference is who decides the next step: your code or the model.

Traditional workflow automation, in tools such as Zapier, Make, n8n, robotic process automation (RPA) platforms or plain scheduled code, is the far end of that range: no model at all, just triggers, rules and API calls. Between the two sit workflows that call a model for one step, and agents that may only use a few read-only tools before handing back to a person.

Diagram of four columns from fixed workflow to workflow with an LLM step, bounded agent and autonomous agent, trading predictability for flexibility
The range from fixed workflows to autonomous agents; most business processes belong in the first two columns.

How they compare

Deterministic workflowWorkflow with an LLM stepAI agent
Who chooses the next stepYour rulesYour rulesThe model
Same input, same resultYesThe path, yes; the model's output can varyNo
Cost per runNear zero beyond platform feesOne or a few model callsMany calls, with context growing at each step
Handles unstructured inputPoorlyYes, in the model stepYes
Handles unforeseen casesFails or routes to a personFails or routes to a personTries something, which may be wrong
AuditSimple: rule X firedSimple, plus logged model outputNeeds full traces of every tool call
TestingUnit testsUnit tests plus an evaluation set for the model stepEvaluation sets and trace review

Reliability compounds

An agent that takes several steps multiplies its chances of going wrong. As an illustration, if each step were right 95% of the time and steps failed independently, a ten-step run would succeed only about 60% of the time (0.95 to the power of 10 is about 0.599). Real failure rates depend on the model, tools and task, so measure your own, but the shape holds: every extra decision the model makes is another chance for error. Anthropic's article puts it directly: "The autonomous nature of agents means higher costs, and the potential for compounding errors."

A deterministic workflow does not compound like this. Its failures are bugs or unexpected inputs, and both are reproducible, so you can fix them once and add a test.

Cost: a worked example

Take 10,000 supplier invoices a month and Claude Sonnet 4.6 at $3 per 1M input tokens and $15 per 1M output tokens. These token counts are our assumptions for illustration; measure your own.

  • Model extraction step: about 1,500 input tokens and 50 output tokens per invoice. 1,500 × $3/1M = $0.0045, plus 50 × $15/1M = $0.00075, so about $0.005 per invoice.
  • Agent investigation: five steps, with context growing from about 2,000 to 6,000 tokens, roughly 20,000 input tokens in total plus 1,500 output tokens. 20,000 × $3/1M = $0.06, plus 1,500 × $15/1M = $0.0225, so about $0.08 per invoice.

Sending every invoice through the agent would cost about 10,000 × $0.0825 = $825 a month. A hybrid in which rules settle invoices that carry a PO number and match, the model extracts fields for the 30% without a PO number (3,000 × $0.00525 = $15.75), and the agent looks only at the 5% that do not match (500 × $0.0825 = $41.25) costs about $57 a month, with more predictable results. For comparison of platform fees on Zapier, Make and n8n, see our automation platform pricing guide.

A tested hybrid: rules decide, the agent explains

The pattern that works for most business processes is a deterministic workflow with two kinds of model use: a constrained model step for messy input, and a bounded agent for exceptions that writes a note but never acts.

Flow diagram of an invoice workflow: rules check the PO, a model extracts missing fields, a bounded agent explains mismatches and a person reviews
In the hybrid, rules make every decision; the model reads documents and the agent explains exceptions to a person.

The workflow itself has no model in it. It calls injected functions and records who made each decision:

TypeScript
// Deterministic invoice workflow. The model extracts fields; rules decide; an agent only explains exceptions.
export interface Invoice { id: string; supplier: string; poNumber?: string; total: number; text: string }
export interface PurchaseOrder { number: string; supplier: string; total: number }
export interface Extracted { poNumber: string; total: number; found: boolean }
export interface AgentNote { summary: string; steps: number; stoppedBy: 'answer' | 'step_limit' }
export interface AuditEntry { invoice: string; step: string; by: 'rule' | 'model' | 'agent'; outcome: string }
export interface Deps {
  findPO(number: string): PurchaseOrder | undefined;
  extract(text: string): Promise<Extracted>;
  investigate(invoice: Invoice, po: PurchaseOrder): Promise<AgentNote>;
}
export type Decision = 'approved' | 'human_review';

const TOLERANCE = (total: number) => Math.max(5, total * 0.01); // 1% or $5, whichever is larger

export async function processInvoice(inv: Invoice, deps: Deps, audit: AuditEntry[]): Promise<Decision> {
  const log = (step: string, by: AuditEntry['by'], outcome: string) => audit.push({ invoice: inv.id, step, by, outcome });

  let poNumber = inv.poNumber;
  if (!poNumber) {
    const x = await deps.extract(inv.text);
    log('extract PO number', 'model', x.found ? `found ${x.poNumber}` : 'not found');
    if (!x.found || Math.abs(x.total - inv.total) > 0.005) { log('check extraction', 'rule', 'extracted total disagrees or PO missing'); return 'human_review'; }
    poNumber = x.poNumber;
  }

  const po = deps.findPO(poNumber);
  if (!po) { log('find PO', 'rule', `${poNumber} does not exist`); return 'human_review'; }
  if (po.supplier !== inv.supplier) { log('match supplier', 'rule', `PO belongs to ${po.supplier}`); return 'human_review'; }

  const diff = inv.total - po.total;
  if (Math.abs(diff) <= TOLERANCE(po.total)) { log('match PO total', 'rule', `within tolerance (${diff.toFixed(2)})`); return 'approved'; }

  log('match PO total', 'rule', `differs by ${diff.toFixed(2)}`);
  const note = await deps.investigate(inv, po);           // the agent explains; it never approves
  log('investigate', 'agent', `${note.stoppedBy} after ${note.steps} steps: ${note.summary}`);
  return 'human_review';
}

The model functions are kept in their own module. Extraction uses a JSON schema through output_config.format, so its output always parses, and the workflow still checks the extracted total against the invoice. The investigator is a small tool-use loop with two read-only tools and a hard step limit:

TypeScript
import Anthropic from '@anthropic-ai/sdk';
import type { Extracted, Invoice, PurchaseOrder, AgentNote } from './workflow.ts';

const client = new Anthropic();
const MODEL = process.env.CLAUDE_MODEL ?? 'claude-sonnet-4-6';

// Extraction with a JSON schema: the output always parses; the workflow still checks the values.
export async function extract(text: string): Promise<Extracted> {
  const res = await client.messages.create({
    model: MODEL,
    max_tokens: 300,
    system: 'Extract the purchase order number and invoice total from the invoice text. If there is no PO number, set found to false and poNumber to "".',
    messages: [{ role: 'user', content: text }],
    output_config: {
      format: {
        type: 'json_schema',
        schema: {
          type: 'object',
          properties: { poNumber: { type: 'string' }, total: { type: 'number' }, found: { type: 'boolean' } },
          required: ['poNumber', 'total', 'found'],
          additionalProperties: false,
        },
      },
    },
  });
  const block = res.content.find((b) => b.type === 'text');
  if (res.stop_reason !== 'end_turn' || !block || block.type !== 'text') throw new Error(`extraction stopped: ${res.stop_reason}`);
  return JSON.parse(block.text) as Extracted;
}

// A bounded agent: read-only tools, a step limit, and its only output is a note for a person.
export function makeInvestigator(tools: { poLines(po: string): string; recentInvoices(supplier: string): string }, maxSteps = 5) {
  return async (inv: Invoice, po: PurchaseOrder): Promise<AgentNote> => {
    const messages: Anthropic.MessageParam[] = [{
      role: 'user',
      content: `Invoice ${inv.id} from ${inv.supplier} totals ${inv.total}; PO ${po.number} totals ${po.total}. ` +
        'Find the most likely reason for the difference using the tools. Reply with a two-sentence note for the accounts team. You cannot approve or pay anything.',
    }];
    const toolDefs: Anthropic.Tool[] = [
      { name: 'po_lines', description: 'List the lines of a purchase order', input_schema: { type: 'object', properties: { po: { type: 'string' } }, required: ['po'] } },
      { name: 'recent_invoices', description: 'List this supplier\'s invoices from the last 90 days', input_schema: { type: 'object', properties: { supplier: { type: 'string' } }, required: ['supplier'] } },
    ];
    for (let step = 1; step <= maxSteps; step++) {
      const res = await client.messages.create({ model: MODEL, max_tokens: 1024, tools: toolDefs, messages });
      if (res.stop_reason !== 'tool_use') {
        const text = res.content.flatMap((b) => (b.type === 'text' ? [b.text] : [])).join(' ').trim();
        return { summary: text, steps: step, stoppedBy: 'answer' };
      }
      messages.push({ role: 'assistant', content: res.content });
      const results: Anthropic.ToolResultBlockParam[] = res.content.flatMap((b) => {
        if (b.type !== 'tool_use') return [];
        const input = b.input as { po?: string; supplier?: string };
        const out = b.name === 'po_lines' ? tools.poLines(String(input.po)) : b.name === 'recent_invoices' ? tools.recentInvoices(String(input.supplier)) : 'unknown tool';
        return [{ type: 'tool_result' as const, tool_use_id: b.id, content: out }];
      });
      messages.push({ role: 'user', content: results });
    }
    return { summary: 'No conclusion within the step limit; needs manual review.', steps: maxSteps, stoppedBy: 'step_limit' };
  };
}

To test the workflow logic without network calls, the run below passes test doubles for extract and investigate. Three invoices go through: one matches its purchase order within tolerance, one has no PO number so the model extracts it, and one is $160 over and goes to a person with the agent's note.

TypeScript
// Runs the workflow on three invoices. extract() and investigate() are test doubles here so the run is
// offline and repeatable; production passes extract and makeInvestigator(...) from model.ts.
import { processInvoice, type AuditEntry, type Deps, type Invoice, type PurchaseOrder } from './workflow.ts';

const pos: PurchaseOrder[] = [
  { number: 'PO-7710', supplier: 'Northwind Supplies', total: 1250.0 },
  { number: 'PO-7714', supplier: 'Contoso Office', total: 480.0 },
];
const deps: Deps = {
  findPO: (n) => pos.find((p) => p.number === n),
  extract: async () => ({ poNumber: 'PO-7714', total: 480.0, found: true }),
  investigate: async () => ({ summary: 'PO line 3 priced at old rate', steps: 3, stoppedBy: 'answer' }),
};
const invoices: Invoice[] = [
  { id: 'INV-2291', supplier: 'Northwind Supplies', poNumber: 'PO-7710', total: 1254.9, text: '' },
  { id: 'INV-2292', supplier: 'Contoso Office', total: 480.0, text: 'Invoice ... Your ref: PO-7714 ... Total due 480.00' },
  { id: 'INV-2293', supplier: 'Northwind Supplies', poNumber: 'PO-7710', total: 1410.0, text: '' },
];

const audit: AuditEntry[] = [];
for (const inv of invoices) console.log(`${inv.id}: ${await processInvoice(inv, deps, audit)}`);
console.log('\naudit trail');
for (const a of audit) console.log(`  ${a.invoice}  ${a.by.padEnd(5)}  ${a.step.padEnd(18)} ${a.outcome}`);
Terminal output of the hybrid workflow: two invoices approved by rules, one sent to human review, followed by an audit trail of rule, model and agent steps
Our run of the workflow with test doubles for the model: every approval in the audit trail was made by a rule.

The audit trail is the point. An auditor, or you in six months, can see that the two approvals were made by rules and that the model's only influence on money was reading a PO number that a rule then verified. That is much easier to defend than "the agent decided".

Real examples, sorted

Keep these as deterministic workflows

  • Order and shipping notifications: triggered by events, fixed content, no judgement.
  • Employee onboarding and offboarding: a checklist of accounts to create or remove, which must be complete and auditable.
  • Invoice approval and payment runs: rules and approval limits, with a model at most reading documents.
  • Data sync between systems: CRM to accounting, shop to warehouse. Mappings, retries and idempotency matter more than intelligence.

Add a model step to a workflow

  • Support ticket triage: the model classifies and extracts the order number; rules route by category.
  • Document intake: the model reads invoices, CVs or forms into a schema; rules validate the fields.
  • Drafting replies: the model drafts, a person or a rule-based check approves before sending.

Use a bounded agent

  • Exception investigation: why does this invoice not match, why did this payment fail. The steps vary with the case.
  • Research and preparation: gather supplier information, summarise a customer's history before a call, compare contract versions.
  • Internal question answering across several systems, with read-only access.

In each agent case the agent's output is information for a person, not an action on the world.

When an agent is the wrong choice

  • The steps are known. Write them down; that is a workflow.
  • Mistakes are expensive and hard to reverse: payments, deletions, contract changes, messages to many customers.
  • You need the same answer every time for compliance or fairness, such as eligibility, pricing or credit decisions.
  • Volume is high and margins are thin. Model calls per step add up quickly, as the example shows.
  • Nobody will read the traces. An agent nobody monitors is an incident waiting for a date.

When a fixed workflow is the wrong choice

  • The input is unstructured and varied: free-text emails, scanned documents, voice notes.
  • The number of cases is too large to enumerate, and most are rare.
  • The task is exploration: finding information whose location you do not know in advance.

Even then, start with a workflow plus one model step and see how far it gets before adding agent autonomy.

Production checklist for hybrids

  • Give the model the narrowest job: extract, classify or draft, with a schema.
  • Validate model output with rules before it changes any state.
  • Limit agents: read-only tools by default, a step cap, a token or cost budget, and a timeout.
  • Keep people in the loop for money and customer-facing actions, with the agent's note attached.
  • Log who decided each step: rule, model, agent or person, with inputs and outputs.
  • Treat everything an agent reads as untrusted, including emails and documents, since they can carry instructions; see our prompt injection guide.
  • Evaluate the model steps on a fixed set of real examples before each prompt or model change.

Drawing the line between rules and model steps is where most automation projects succeed or fail, and it is easier with someone who has mapped many processes. Our workflow automation service designs and builds these hybrids on the tools you already use.

Common mistakes

  • Replacing a working workflow with an agent because agents are new. You trade predictability for flexibility you did not need.
  • Letting the agent approve instead of explain. Keep decisions with money attached in rules or with people.
  • No step or cost limit, so a confused agent loops until someone notices the bill.
  • Logging only the final answer. Without the tool calls you cannot tell why an agent did something.
  • Skipping retries and idempotency in the deterministic parts. Most automation failures are still timeouts and duplicate webhooks, not model errors.

Adding AI to a workflow you already run

If you already have automations in a platform or in your own code, you do not need to rebuild them. A safe sequence is:

  1. Find the manual step. Look for the point where the workflow stops and a person reads something: an email, an attachment, a free-text field. That is usually the only place a model is needed.
  2. Run the model in shadow mode. Let it produce its output alongside the person for a few weeks, store both, and compare. You get an evaluation set from real cases at no extra risk.
  3. Switch on with a fallback. When agreement is high enough for that step, let the model's output flow into the workflow, with rules checking it and anything that fails the checks going to the same person as before.
  4. Only then consider an agent for the cases that still need a person, and give it the job of preparing the case, not closing it.

Each stage is reversible, and at no point does a model gain the power to approve, pay or send without a rule or a person agreeing.

Summary

Deterministic workflows are cheap, predictable and easy to audit, and should carry most business processes. Language models earn a place as a single, constrained step where inputs are messy. Agents are worth their extra cost and risk for open-ended investigation and research, inside limits and reporting to a person. Build the workflow first, add model steps where rules cannot read the input, and give an agent only the exceptions.

Have a process that is half rules and half judgement? Cloudsoft Zone builds workflow automation that combines deterministic steps, AI where it helps and human approval where it matters.

Frequently asked questions

  • Are AI agents replacing tools like Zapier, Make and n8n?

    No. Those platforms run deterministic workflows that most business processes still need, and they now offer AI steps and agent features of their own. The practical question is which steps need a model, not which tool category wins.

  • What is the difference between an AI workflow and an AI agent?

    In a workflow your code decides the sequence of steps and may call a model for some of them. In an agent the model decides which tool to use next and when to stop. Workflows are more predictable; agents handle open-ended tasks.

  • Are AI agents more expensive than workflows?

    Usually, because an agent makes several model calls per task and each call resends a growing context. In our worked example an agent investigation cost about 16 times a single extraction call per invoice. Limit agents to the cases that need them.

  • How do I make an AI agent auditable?

    Log every model call and tool call with inputs, outputs and timestamps, record who made each decision, give the agent read-only tools where possible, and keep approvals that move money or contact customers with rules or people.

Advertise on CloudSoftZone

Your next customer could start right here.

Introduce your tool, product or business to readers exploring technology.

Advertise with us

Explore placements and request a private quote

Sources

  1. Building effective agents — Anthropic, 2024-12-19
  2. Structured outputs — Anthropic
  3. Tool use with Claude — Anthropic
  4. Pricing — Anthropic
  5. Running TypeScript natively — Node.js

Written with substantial AI assistance. Facts checked against cited sources. Editorial policy.

Comments

No comments yet. Be the first to join the conversation.

Leave a comment

Every comment is read by a moderator before it appears. Your email address is never published; it is used only to contact you about this comment.

Never published. Used only to contact you about this comment.

Loading the security check…

Comments are moderated before publication.