EN

Language

Our editions

Written for each audience, not translated word for word.

How to build an agent: a tested example in five steps

How-toBy Lucas Matías García TorresUpdated (first published )Data checked 8 min read

Reviewed by Lucas Matías García Torres on . How we work.

Leer en español

An industrial robotic arm placing small metal cubes connected by glowing orange cables

Short answer

How to build an agent: give a model that supports tool calling a few well-described tools, run a loop that executes its tool calls and sends the results back, and add guardrails such as a step limit, business rules in code and human approval for irreversible actions. Anthropic advises starting with the API directly and simple patterns, not a framework. This guide includes a 60-line JavaScript support agent with no dependencies that works with OpenAI, DeepSeek or a free local model, tested against a scripted stand-in of the API.

Prices and limits change often: check the vendor's page before you pay. How we make money.

How to build an agent, in practice, comes down to four parts: a model that can call tools, the tools themselves, a loop that runs the tool calls and feeds the results back, and rules that stop the agent from doing damage. Anthropic, which has worked with "dozens of teams" building agents, says the most successful ones "weren't using complex frameworks or specialized libraries" but "simple, composable patterns", and that agents "are typically just LLMs using tools based on environmental feedback in a loop". This guide builds exactly that: a working support agent in about 60 lines of JavaScript with no dependencies, which runs against OpenAI, DeepSeek or a free local model, plus the guardrails, costs and decisions around it.

Step 1: decide whether you need an agent at all

Anthropic draws a line between two kinds of systems. Workflows are "systems where LLMs and tools are orchestrated through predefined code paths"; agents are systems where the model "dynamically direct[s] its own processes and tool usage". Its advice is to find "the simplest solution possible" and notes that agentic systems "often trade latency and cost for better task performance". For many applications, it says, a single well-prompted model call with retrieval and examples "is usually enough".

A quick test before you build:

  • The steps are always the same (summarize, then translate, then file): build a workflow, a fixed chain of calls. It is cheaper and easier to test.
  • The steps depend on what the model finds (look up the customer, check the order, decide whether a refund applies): an agent makes sense.
  • The task is open-ended and you cannot predict the number of steps: an agent, with a hard limit on steps and a person approving anything risky.

If you are not sure what counts as an agent, our explainer on what an agent is covers the definitions, and n8n vs Zapier vs Make compares the no-code route for workflows.

Step 2: pick a model and define the tools

Any model with tool calling (also called function calling) will do. OpenAI's documentation describes the flow in five steps: send the request with the tools the model may call, receive a tool call, run your own code with its arguments, send the result back, and receive a final answer "or more tool calls". The same message format is accepted by DeepSeek's API and, locally, by Ollama and llama.cpp, which is why the example below works with all of them.

Tools are where most of the quality comes from. OpenAI's guidance is to write "clear and detailed function names, parameter descriptions, and instructions", to use the system prompt to say when to use each one, and to "pass the intern test": could a person use the function correctly with nothing but its description? It recommends strict mode so that calls "reliably adhere to the function schema". Anthropic calls this the agent-computer interface and recommends crafting it "through thorough tool documentation and testing".

If your tools already exist as MCP servers (the open standard for connecting LLM applications to tools and data), your agent can use them through an MCP client instead of custom functions; see what MCP is.

Step 3: write the loop

The example is a support agent for a small shop with two tools: one finds a customer's orders, the other refunds an order. Save it as agent.mjs and run it with Node 18 or later; it needs no packages.

// agent.mjs: a minimal tool-using agent (Node 18 or later, no dependencies)
import readline from "node:readline/promises";

const BASE_URL = process.env.BASE_URL ?? "https://api.openai.com/v1";
const MODEL = process.env.MODEL ?? "gpt-6-luna";
const API_KEY = process.env.API_KEY ?? "";
const MAX_STEPS = 8;

// Stand-in for your real database
const orders = { "ana@example.com": [{ id: "A-1001", item: "Headphones", total: 79, status: "delivered", daysSinceDelivery: 9 }] };

const tools = [
  { type: "function", function: { name: "find_orders", description: "List a customer's orders by email address.",
    parameters: { type: "object", properties: { email: { type: "string" } }, required: ["email"], additionalProperties: false } } },
  { type: "function", function: { name: "refund_order", description: "Refund one order by id. Allowed only for delivered orders within 14 days; a person must approve it.",
    parameters: { type: "object", properties: { order_id: { type: "string" } }, required: ["order_id"], additionalProperties: false } } },
];

async function approve(question) {
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
  const answer = await rl.question(`${question} [y/N] `);
  rl.close();
  return answer.trim().toLowerCase() === "y";
}

const run = {
  find_orders: ({ email }) => orders[email] ?? [],
  refund_order: async ({ order_id }) => {
    const order = Object.values(orders).flat().find((o) => o.id === order_id);
    // The rule lives in code, not only in the prompt
    if (!order || order.status !== "delivered" || order.daysSinceDelivery > 14) return { refused: "Not eligible under the refund policy." };
    return (await approve(`Refund ${order.id} (${order.total} EUR)?`)) ? { refunded: order.id } : { refused: "A person declined the refund." };
  },
};

async function chat(messages) {
  const res = await fetch(`${BASE_URL}/chat/completions`, {
    method: "POST",
    headers: { "Content-Type": "application/json", Authorization: `Bearer ${API_KEY}` },
    body: JSON.stringify({ model: MODEL, messages, tools }),
  });
  if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
  return (await res.json()).choices[0].message;
}

const messages = [
  { role: "system", content: "You are the support agent of a small shop. Use the tools and never invent order data. If a refund is refused, explain why." },
  { role: "user", content: process.argv[2] ?? "I'm ana@example.com and my headphones arrived broken. Can I get a refund?" },
];

for (let step = 1; step <= MAX_STEPS; step++) {
  const msg = await chat(messages);
  messages.push(msg);
  if (!msg.tool_calls?.length) {
    console.log(msg.content);
    process.exit(0);
  }
  for (const call of msg.tool_calls) {
    const args = JSON.parse(call.function.arguments || "{}");
    const tool = run[call.function.name];
    const result = tool ? await tool(args) : { error: `Unknown tool ${call.function.name}` };
    console.log(`[step ${step}] ${call.function.name}(${JSON.stringify(args)}) => ${JSON.stringify(result)}`);
    messages.push({ role: "tool", tool_call_id: call.id, content: JSON.stringify(result) });
  }
}
console.log(`Stopped after ${MAX_STEPS} steps without a final answer.`);

To run it, set API_KEY and run node agent.mjs. For DeepSeek, also set BASE_URL=https://api.deepseek.com and MODEL=deepseek-flash. For a free local test with Ollama, pull a model that supports tools, such as qwen3, and set BASE_URL=http://localhost:11434/v1 and MODEL=qwen3; our guide to running an LLM locally covers the setup.

How we tested it. We ran the file against a local test server that answers in the documented Chat Completions format: a scripted stand-in, not a real model. Four checks passed: the full path with a person approving the refund, a person declining it, an ineligible order refused by code before anyone is asked, and an unknown tool plus a model that never stops, cut off at 8 steps. With a real model the wording will vary, and small local models can call tools less reliably than large hosted ones.

Step 4: add guardrails before anything else

Anthropic warns that the autonomy of agents means "higher costs, and the potential for compounding errors", and recommends "extensive testing in sandboxed environments, along with the appropriate guardrails". The example builds in four of them:

  1. A hard limit on steps. Anthropic suggests stopping conditions "such as a maximum number of iterations". Here it is 8.
  2. Business rules in code. The 14-day refund rule is checked by the function, so a confused or manipulated model cannot talk its way past it.
  3. A person approves irreversible actions. Nothing is refunded without a "y" at the keyboard; in production that becomes an approval in your back office.
  4. Unknown tools are refused, and the model only gets the data its tools return.

Two risks from OWASP's 2025 Top 10 for LLM applications matter most here: prompt injection (LLM01), where text from a customer or a web page tries to give the model new instructions, and excessive agency (LLM06), where an agent has more permissions than the task needs. The defense is the same: give each tool the minimum permissions, and keep the rules and the approvals outside the model.

Step 5: test, measure the cost and only then add a framework

Evaluate on real cases. Collect 30 to 50 real requests, including awkward ones, and check the agent's final answer and the tools it called. Anthropic's summary is to "start with simple prompts, optimize them with comprehensive evaluation, and add multi-step agentic systems only when simpler solutions fall short".

Estimate the cost per conversation. Each step is a full model call, and every call resends the conversation so far. Suppose an average conversation takes three calls of about 1,000 input tokens and 100 output tokens each, and you handle 10,000 conversations a month: 30 million input tokens and 3 million output tokens. At list prices checked on October 10, 2026, that is about $4.50 a month on GPT-6 Luna or Claude Haiku 5.5, $12.60 on DeepSeek V4.1 Flash at peak hours and $90 on Claude Sonnet 5.5 or GPT-6.1 Sol, before reasoning tokens, which are billed as output. The detail per provider is in our LLM API pricing comparison and our guide to DeepSeek API pricing.

Add a framework when the loop gets crowded. Anthropic lists frameworks such as the Claude Agent SDK and AWS's Strands Agents, and warns that they "often create extra layers of abstraction" that make prompts and responses harder to debug; its advice is to start with the API directly and, if you adopt a framework, "ensure you understand the underlying code". OpenAI's Agents SDK has "a very small set of primitives": agents with instructions and tools, handoffs between agents, guardrails that validate inputs and outputs, and built-in tracing. Move to one of them when you need several agents, tracing or resumable runs, not to get the first one working.

What we checked

  • Building effective agents (Anthropic, December 19, 2024): the most successful implementations used simple, composable patterns rather than complex frameworks; workflows orchestrate LLMs and tools through predefined code paths, agents dynamically direct their own processes and tool usage; find the simplest solution possible; agentic systems trade latency and cost for performance; single LLM calls with retrieval and examples are usually enough for many applications; frameworks listed include the Claude Agent SDK and Strands Agents SDK by AWS and can add abstraction layers that obscure prompts and responses; start with LLM APIs directly and understand the underlying code; agents are typically just LLMs using tools based on environmental feedback in a loop; stopping conditions such as a maximum number of iterations; higher costs and compounding errors, extensive testing in sandboxed environments with guardrails; craft the agent-computer interface through thorough tool documentation and testing; start simple, evaluate, add agentic systems only when simpler solutions fall short. (Anthropic, )
  • OpenAI function calling guide: tool calling is a multi-step conversation in five steps (request with tools, receive a tool call, execute code, send the tool output, receive a final response or more tool calls); Chat Completions returns tool_calls with an id and a function name and JSON arguments, and results are sent back as role tool messages with tool_call_id; assume several calls per response; write clear and detailed names, parameter descriptions and instructions, use the system prompt to say when to use each function, pass the intern test; strict mode makes calls reliably adhere to the schema and is recommended, with additionalProperties false and all fields required; Chat Completions remain non-strict by default. (OpenAI, )
  • OpenAgents SDK: a very small set of primitives (agents with instructions and tools, agents as tools and handoffs, guardrails that validate inputs and outputs), a built-in loop that continues until the task is complete, and built-in tracing. (OpenAI, )
  • Ollama's OpenAI-compatible /v1/chat/completions supports tools. (Ollama, )
  • The qwen3 family in the Ollama library is tagged with the tools and thinking capabilities, in sizes from 0.6b to 235b. (Ollama, )
  • llama-server supports function calling and tool use for about any model through its OpenAI-compatible API. (ggml-org / llama.cpp, )
  • DeepSeek's OpenAI-format base URL is https://api.deepseek.com; deepseek-flash supports tool calls; V4.1 Flash costs $0.30 input and $1.20 output per million tokens at peak hours. (DeepSeek, )
  • OpenAI Standard prices per million tokens: GPT-6 Luna $0.10 input and $0.50 output; GPT-6.1 Sol $2 and $10. (OpenAI, )
  • Claude Haiku 5.5 costs $0.10 input and $0.50 output per million tokens up to 100,000 prompt tokens; Claude Sonnet 5.5 costs $2 and $10. (Anthropic, )
  • MCP is an open standard for connecting LLM applications to tools and data. (Model Context Protocol, )
  • OWASP 2025 Top 10 for LLM applications: prompt injection (LLM01) and excessive agency (LLM06). (OWASP GenAI Security Project, )

What may change

  • Model names, prices and SDK features change often; the loop in the example follows the Chat Completions tool-calling format, which several providers copy. This page is reviewed quarterly.
  • The example was tested against a scripted stand-in of the API, not against a paid model; real models word their answers differently and small local models call tools less reliably.

Frequently asked questions

Do I need a framework to build an agent?

No. Anthropic recommends starting with LLM APIs directly, because many patterns take a few lines of code and frameworks can hide the prompts and responses you need to debug. A working agent is a model with tool calling, your tools and a loop; add a framework when you need several agents, tracing or resumable runs.

What is the difference between a workflow and an agent?

In Anthropic's terms, a workflow runs models and tools through predefined code paths, while an agent lets the model decide its own steps and tool use. Workflows are cheaper and more predictable for fixed tasks; agents suit tasks where the steps depend on what the model finds.

How much does it cost to run an agent?

It depends on the model and the number of steps. For 10,000 conversations a month of three calls each, at about 1,000 input and 100 output tokens per call, list prices on October 10, 2026 give about $4.50 on GPT-6 Luna or Claude Haiku 5.5 and $90 on Claude Sonnet 5.5, before reasoning tokens.

How do I stop an agent from doing something dangerous?

Limit the number of steps, enforce business rules inside the tool code instead of the prompt, ask a person to approve irreversible actions, give each tool the minimum permissions and refuse unknown tools. OWASP lists prompt injection and excessive agency among the top risks for LLM applications.

Can I build an agent for free?

Yes, for testing. The example in this guide runs against Ollama on your own computer with a model that supports tools, such as qwen3, through Ollama's OpenAI-compatible endpoint, so no API key or payment is needed. Small local models may call tools less reliably than large hosted ones.

Sources

  1. Building effective agents (December 19, 2024): workflows vs agents, patterns, frameworks and guardrails, Anthropic. Accessed October 10, 2026.
  2. Function calling (OpenAI API guide): tool calling flow, handling tool calls, best practices and strict mode, OpenAI. Accessed October 10, 2026.
  3. OpenAI Agents SDK (Python): primitives, agent loop, guardrails and tracing, OpenAI. Accessed October 10, 2026.
  4. Ollama: OpenAI compatibility (chat completions, responses, embeddings, models), Ollama. Accessed October 10, 2026.
  5. Ollama library: qwen3 (capabilities tools and thinking, sizes), Ollama. Accessed October 10, 2026.
  6. llama.cpp HTTP server: features, defaults (context, port, slots, GPU layers) and router mode, ggml-org / llama.cpp. Accessed October 10, 2026.
  7. DeepSeek API: models and pricing (V4.1 Flash and V4 Pro, cache hit and miss, peak and off-peak, concurrency, deduction rules), DeepSeek. Accessed October 10, 2026.
  8. OpenAI API pricing: Standard, Batch, Flex and priority tables for GPT-6 models, OpenAI. Accessed October 10, 2026.
  9. Claude API pricing: models (Sonnet 5.5 cache reads at 0.05x, Haiku 5.5 with its 100K-token tier), prompt caching, batch, long context and tokenizer note, Anthropic. Accessed October 10, 2026.
  10. What is the Model Context Protocol (MCP)?, Model Context Protocol. Accessed October 6, 2026.
  11. OWASP Top 10 for LLM Applications 2025, OWASP GenAI Security Project. Accessed October 6, 2026.

Spotted an error or an outdated price? Tell us and we will fix it.

Change history

  • : Wording revised; no figure, date or source changed.
  • : First published. Guidance checked against Anthropic's agent guide, OpenAI's function calling and Agents SDK documentation and Ollama's compatibility page on October 10, 2026; example code tested the same day against a local stand-in of the Chat Completions API (4 of 4 checks passed).

Next review: .

Part of our Agents & Automation guide.

Other topics