Deciding when to use RPA vs AI agents is less about hype and more about matching execution models to task structure. RPA excels at deterministic, high-volume flows with stable interfaces; AI agents earn their latency and cost only when the input is ambiguous and the steps can’t be fully prescribed.
The core distinction: deterministic vs probabilistic
RPA (robotic process automation) is code you wrote yesterday that clicks buttons or calls APIs in a fixed sequence. It does not interpret; it asserts. If a field moves or a schema changes, it breaks, and that is by design—failures are loud and localized.
AI agents wrap an LLM in a loop with tools. They plan at runtime, parse unstructured input, and tolerate messy reality. The cost is nondeterminism: same input can yield different actions, and a hallucinated step can silently corrupt data.
The question of when to use RPA vs AI agents reduces to three variables: input variability, step predictability, and failure blast radius.
A decision framework in four steps
Follow this ordered path before writing any code.
1. Map the task to a state machine
Draw the flow. If you can express it as a DAG where every node has typed inputs and outputs, RPA is viable.
{
"nodes": ["fetch_csv", "validate_rows", "post_to_erp"],
"edges": [["fetch_csv", "validate_rows"], ["validate_rows", "post_to_erp"]]
}
If you cannot draw that because the next step depends on reading a sentence like “cancel the duplicate order from last week,” you are in agent territory.
2. Measure input variability
Collect 50 real inputs. If 49 conform to a schema, RPA with a strict validator is cheaper. If they are PDFs, free-text emails, or screenshots, an agent with a parsing tool will ship faster than a regex farm.
3. Define failure tolerance
RPA throws on bad data; you fix the script. An agent may invent a value. For financial postings, keep a human approval gate or restrict the agent to read-only summarization and let RPA execute the write.
4. Estimate change frequency
UI scrapers break when the vendor redesigns. Prompt-based agents drift when the model updates. If the underlying system is stable for years, RPA pays off. If the business process itself mutates monthly, agent prompts are easier to revise than a 2,000-line UiPath workflow.
When RPA is the right call
Use RPA for transport, not interpretation. Examples that ship reliably:
- Polling a known REST endpoint and mirroring records to a warehouse.
- Submitting forms in a legacy portal that has no API but a stable DOM.
- Nightly CSV reconciliation between two systems.
Minimal Python RPA stub:
import requests, csv
def sync_orders():
resp = requests.get("https://legacy.example.com/orders.csv", timeout=10)
resp.raise_for_status()
for row in csv.DictReader(resp.text.splitlines()):
requests.post("https://erp.example.com/api/orders",
json={"id": row["id"], "total": float(row["total"])})
Pitfall: teams bolt on “smart” string matching inside RPA. That is the start of a brittle agent wearing RPA clothes. Keep RPA stupid and observable.
When AI agents earn their cost
Agents justify themselves when the bottleneck is understanding, not throughput. Concrete fits:
- Triage of inbound support emails with attachments in unknown formats.
- Navigating a vendor UI that rearranges fields per session.
- Translating a natural-language spec into a first-pass SQL query.
A minimal agent loop using an OpenAI-compatible client:
from openai import OpenAI
# One OpenAI-compatible endpoint across 240+ models with automatic fallback on degradation.
client = OpenAI(base_url="https://api.n4n.ai/v1", api_key="YOUR_KEY")
tools = [{"type": "function", "function": {
"name": "lookup_user",
"parameters": {"type": "object", "properties": {"email": {"type": "string"}}}
}}]
messages = [{"role": "user", "content": "Find jane@acme.com and summarize her last ticket"}]
resp = client.chat.completions.create(model="auto", messages=messages, tools=tools)
# Inspect resp.choices[0].message.tool_calls, execute, append result, loop.
Tradeoff: each loop iteration is a model call. At production volume, you need per-token metering and cache-control forwarding to keep cost sane. The gateway above honors client routing directives and provider cache hints, which matters when you chain ten tool calls.
Hybrid patterns that actually work
The false dichotomy ends here. Most production systems should use RPA as the hands and agents as the eyes.
Pattern: RPA fetches the email and attachments, writes them to a staging bucket. An agent reads, classifies, and emits a structured command ({"action": "refund", "order_id": "X"}). RPA validates the command against business rules and executes the API call. This confines nondeterminism to the interpret step and keeps writes deterministic.
# agent output contract
assert command["action"] in {"refund", "escalate", "ignore"}
rpa_execute(command) # never lets the LLM call the money movement API directly
Common pitfalls
- Agent as glorified cron. If the steps never change, you are paying token tax for a
forloop. - RPA parsing PDFs with OCR regex. You will spend more time maintaining patterns than the agent would cost.
- No observability. Log every RPA step and every agent tool call. Without traces, you cannot tell if a failure came from a selector or a hallucination.
- Skipping schema validation on agent output. Treat agent JSON like external untrusted input—validate with pydantic or jsonschema before any side effect.
Implementation checklist
- Write the state machine for the happy path. If it compiles to static code in an hour, do RPA.
- Sample real inputs. If >20% fall outside structured schemas, scope an agent for the interpretation layer.
- Define the write boundary. RPA owns all mutating calls; agent proposes.
- Stand up a gateway client with fallback so model outages don’t stall the agent loop.
- Add a validation shim between agent output and RPA input.
- Instrument both with structured logs and per-step latency metrics.
- Schedule a monthly review of agent prompts and RPA selectors; they rot at different rates.
The decision of when to use RPA vs AI agents is not permanent. Start with RPA where you can, insert an agent only at the seam where structure ends, and keep the deterministic core intact.