n8n AI agent: build one on your own VPS
Build a working AI agent in n8n: the AI Agent node, a Claude model credential, an HTTP Request tool, memory, a trigger, and the settings that cap cost.
What an n8n AI agent is, and where it differs from a chain
An n8n AI agent is a single AI Agent node with sub-nodes attached to it: one chat model, one or more tools, and an optional memory. You state a goal in plain language, and the model decides which tools to call and in what order until it can answer. Everything below is the configuration around that one idea.
A chain works the other way round. In a Basic LLM Chain you decide the steps and the model only fills in text. In an agent the model decides the steps, so the same question can cost one model call today and nine tomorrow. That single difference drives every setting in this guide.
This assumes n8n is already running behind HTTPS on a machine you control. If it is not, start with self-hosting n8n on Docker with a real certificate, because the API key you are about to store needs the encryption-key backup that guide insists on. For the non-agent patterns, webhook summarizers and scheduled classifiers, see Claude and n8n workflow patterns.
Check your version before you trust any field name here, because n8n changes the AI nodes often.
docker compose exec n8n n8n --versionThe names in this guide match n8n current stable as of July 2026. Since version 1.82.0 every AI Agent node runs as a Tools Agent, so the old agent-type dropdown no longer exists.
Step 1: pick the trigger
For a conversational agent, add a Chat Trigger node. Leave Make Chat Publicly Available turned off while you build, so only the editor's chat panel can reach it. Turn it on when the agent is finished and you have decided on authentication.
The Chat Trigger hands the agent a field called chatInput. That name matters in step 3, and getting it wrong is the most common first failure.
For an unattended agent, use a Schedule Trigger or a Webhook node instead. Neither produces chatInput, so you will write the prompt yourself.
Step 2: the model credential
Drop an AI Agent node on the canvas. n8n immediately shows an empty Chat Model connector underneath it. Attach an Anthropic Chat Model sub-node there.
Create the credential from the Anthropic Console at platform.claude.com, under Settings and then API Keys. The key is shown once. API usage is billed per token and is separate from any Claude.ai subscription, so the account needs billing set up before the first run.
Pick the model per agent, not per company. A one-tool agent that looks something up and reports it runs fine on Haiku, which as of July 2026 lists at $1 per million input tokens and $5 per million output. Once the agent has several tools and has to plan across them, move to Sonnet. The failure you are avoiding is a cheap model that calls the wrong tool four times, which costs more than the expensive model calling the right one once.
Set Maximum Number of Tokens in the sub-node's options. It caps the length of each response the model produces. Left at a large default, one confused run can produce a very long answer and bill you for it.
One caveat from the n8n docs that catches everyone: expressions inside a sub-node always resolve against the first input item, never per item. Put per-item expressions in the root node's prompt fields.
Step 3: the prompt the agent receives
Open the AI Agent node. The Prompt parameter has two settings.
- Take from previous node automatically expects an incoming field named
chatInput. This is the right choice behind a Chat Trigger. - Define below reveals a Prompt (User Message) field where you write static text or an expression. This is the right choice behind a Schedule Trigger or a Webhook node.
With a Webhook node in front, a POST body lands under $json.body, so the prompt field looks like this.
Check the current status of {{ $json.body.service }} and tell me
whether it is up. If it is down, say for how long. No preamble.Step 4: give the agent one tool
An AI Agent node with no tool sub-node refuses to run. Start with one, because a single working tool teaches you more than four half-configured ones.
Attach an HTTP Request node to the agent's Tool connector. Configure it exactly as you would a normal HTTP Request node, then test that endpoint from a shell first.
curl -s -H 'Accept: application/json' \
https://status.example.com/api/status/database | head -c 400If that curl returns an error or an HTML login page, the agent will fail too, and the failure will read like a model problem when it is really a URL or an authentication problem. Fix it at the shell, not in the node.
The tool's Description field is not documentation for your colleagues. It is the only thing the model reads when deciding whether this tool is relevant. Write it as a plain statement of what comes back: "Returns the current up or down state and the downtime duration for one monitored service, as JSON."
To let the model fill in part of the request, use the $fromAI() expression. It works only in tools connected to an AI Agent node, and it does not work in the Code tool.
{{ $fromAI('service', 'The name of the service to look up', 'string') }}The arguments are key, then an optional description, type and defaultValue. The key must be 1 to 64 characters, using letters, digits, underscores and hyphens. The type is one of string, number, boolean or json, and defaults to string. A fuller call looks like this.
{{ $fromAI('limit', 'How many records to return', 'number', 20) }}The key is a hint, not a reference to existing data. $fromAI('service') does not read a field called service from anywhere. It tells the model "produce a value and call it service", and the model looks through the conversation, the input data and other tool results to find one. In a chat workflow it may simply ask the user.
Step 5: memory, and why the agent forgets
Without a memory sub-node, every message starts from nothing. Attach a Simple Memory sub-node to hold the recent conversation.
It has two parameters. Session Key decides which conversation this is, so two users with different keys get separate histories. Context Window Length is how many previous interactions get replayed into the prompt.
Context Window Length is a cost dial as much as a quality dial, because every remembered turn is resent as input tokens on every later call. A window of 20 on a chatty agent means you pay for the same early messages twenty times.
Simple Memory does not work in an active production workflow when n8n runs in queue mode, because the history lives in the workflow's own data rather than in a shared store. On a queue-mode instance, use the Postgres Chat Memory sub-node instead and point it at a database both the main process and the workers can reach.
Step 6: the System Message
Open the agent's Options and add a System Message. This is where the job description goes, and it is the highest-leverage text in the workflow.
You are an infrastructure status assistant. Always call the status
tool before answering a question about whether something is running.
Never guess. If the tool returns an error, say so and stop."Always call the status tool before answering" is doing real work there. Without it, a model that thinks it already knows the answer will skip the tool and reply from memory, which is confidently wrong the moment your infrastructure changes.
Why does the agent loop, and what stops it
Also under Options is Max Iterations, which defaults to 10. One iteration is one model call plus one tool result fed back into the context. So a single agent run is not one API call, it is up to ten, and each one carries the whole growing conversation as input.
Lower it. Most single-tool agents finish in two iterations, and a limit of 3 or 4 turns a runaway loop into a clean failure you can see in the execution list.
While you are debugging, turn on Return Intermediate Steps. The final output then includes the tool calls the agent made along the way, which is how you tell "the model never called the tool" apart from "the tool returned nothing useful". Turn it back off before you go live, because those steps are noise for the end user.
Watch a run happen from the shell.
docker compose logs -f n8nKeeping an unattended agent from spending quietly
An agent behind a Chat Trigger has a human in it, and that human stops it when the answer looks wrong. An agent behind a Schedule Trigger has nobody watching. The full treatment is in AI agent cost control on an always-on VPS. Four settings do most of the work here.
- Cap Maximum Number of Tokens on the model sub-node, so no single response can run long.
- Set Max Iterations to the smallest number that still completes the task.
- Keep tool responses small. A tool that returns a 4,000-line JSON blob puts all of it into the next model call, and then into every call after that in the same run.
- Ask whether the agent needs a schedule at all. A job running every five minutes fires 288 times a day. Whatever one run costs, that is the figure you multiply.
Deactivate the workflow while you iterate. An active workflow with a Schedule Trigger keeps running against the version n8n has saved, which is not always the version on your screen.
FAQ
Why does my AI Agent node refuse to execute?
The AI Agent node requires a chat model sub-node and at least one tool sub-node. A node with a model but no tool fails before it makes any API call. Attach one tool, even a trivial one, and run it again.
The agent answers, but it never calls my tool. What is wrong?
Almost always the tool's Description field. The model chooses tools by reading those descriptions, so a description like "HTTP Request" tells it nothing about when the tool applies. Rewrite it to say what data comes back and in what situation it is useful, then add a line to the System Message instructing the agent to call that tool before answering.
Why does the same question cost a different amount each run?
Because the model chooses the number of steps. Each iteration resends the full conversation so far, including previous tool output, so a run that takes four iterations costs far more than four times a single call. Max Iterations is the ceiling on that, and Return Intermediate Steps shows you how many steps a given run actually used.
My memory works in the editor but not in production. What changed?
Check whether the instance runs in queue mode. Simple Memory stores history in the workflow's own execution data, which does not survive being handed to a separate worker process, so an active production workflow loses it. Swap in the Postgres Chat Memory sub-node, which keeps history in the database every worker shares.