Agents

May 31, 2026

In this blog post, I'm gonna explain what agents are, how they're different from workflows, what an agent harness is, and we're gonna also build a simple agent.

So, agents, agentic-ai, ai-engineering, whatever you call it, these things have been on hype for a while now. Everyone is talking about them, and everyone in tech is using them too (think again if you think you're not). So, I wanted to understand from the ground up, what are they exactly, how do they work under the hood and what's the magic beneath them.

Let's get started.

So, what's an agent? It's nothing but an LLM put on steroids. Or maybe I should say, it's about giving LLMs access to tools so they can work toward an end goal, not just talk about it.

Without agents, an LLM used to work purely as an information retrieval system. You used to have some problem/query, then you'd ask the LLM about the same, and the LLM would give you the answer and then at the last, it's you who has to implement/do it.

The last part is where I want you to focus on. It's the part that agents solve. With an LLM, you'd still have to understand the response and then do the action. The LLM isn't powerful enough to do the task for you on its own. And this is where agents come into play.

Agents basically integrate LLMs with other tools to complete the loop, to go from information retrieval to actually doing the task for you.

How does it do that? By using tools that you give it access to.

If you're coming from a software engineering background or have a decent idea about APIs, an LLM is like an application that doesn't expose its APIs to users and an agent is like an application that enables API access to users so that they can build on top of it, but just with more power.

Don't think that tools = APIs, no. Tools in case of agents can be anything that you want. APIs can be one of the tools but it's not the only one.

Now, you know the problem that agents solve. Let's deep dive into understanding how they work.

An agent is basically a loop that repetitively calls the LLM and tools until the end goal is achieved.

Here's what that loop looks like:

flowchart TD
    A[User query] --> B[LLM]
    B --> C{End goal achieved?}
    C -->|No| D[Call tool]
    D --> E[Tool result]
    E --> B
    C -->|Yes| F[Return response]

I think explaining an agent with the help of pseudo code is the best way to understand it compared to reading paragraphs about it.

const userQuery = "What is the current time in EST timezone?";

/**
 * Get the current time in the user's timezone
 * @returns {string}
 */
function getCurrentTime() {
  return new Date().toLocaleTimeString();
}

/**
 * Convert the time to EST timezone
 * @param {string} time - The time to convert
 * @returns {string}
 */
function convertToEST(time) {
  return new Date(time).toLocaleTimeString("en-US", {
    timeZone: "America/New_York",
  });
}

const tools = {
  getCurrentTime,
  convertToEST,
};

function run(tools, userQuery) {
  const messages = [
    {
      role: "system",
      content: `You are a helpful assistant that can answer questions and help with tasks. You have the following tools available to you: ${Object.keys(tools).join(", ")}. You must use the tools to answer the user's question if required.`,
    },
    {
      role: "user",
      content: userQuery,
    },
  ];

  let llmResponse = llm.generate(messages);

  while (!llmResponse.isEndGoalAchieved) {
    const toolResult = tools[llmResponse.tool](llmResponse.toolArgs);
    messages.push({ role: "tool", content: toolResult });
    llmResponse = llm.generate(messages);
  }

  return llmResponse.response;
}

console.log(run(tools, userQuery));

This is basically it. This is how agents work. We have coded a very basic vanilla agent here. When we empower an LLM with tools/functions that it can call, it becomes an agent.

And how do we do that? We do that by defining the tools/functions using docstrings that tell what the function does, what arguments it takes and what it returns, so that the LLM can call/use the relevant tool. We are not writing docstrings for us, we are writing them for the LLM.

Now, let's walk through the code and understand it further.

First, we define the tools/functions that we want to use and let the LLM access. In our case, those are getCurrentTime and convertToEST. Then we define the most important part of our agent — the run function, or the agent loop. It's a loop that repetitively calls the LLM and tools until the end goal is achieved.

On the first pass, the LLM reads the user query and decides it needs getCurrentTime. We run that tool, pass the result back, and the LLM decides it needs convertToEST. Once it has the final answer, it sets isEndGoalAchieved to true and we return the response.

One thing to keep in mind: in production, real agent frameworks (Cursor, LangGraph, etc.) handle a lot more than this: retries when a tool fails, token limits, error handling, and more. Our example is intentionally barebones so you can see the core loop.

Hope you now know what agents are.

Now, let's understand how agents are different from workflows.

A workflow is a predefined sequence of steps. Step 1 runs, then step 2, then step 3 — in a fixed order. If this, then that. Same path every time.

An agent lets the LLM decide which tool to call and when. The path isn't fixed. Same goal, different route depending on the query.

Example: "What's the weather in NYC?" vs "What's the weather in NYC and email it to me?" A rigid workflow might break on the second query because it wasn't designed for emailing. An agent can pick an extra tool on the fly.

Workflows are great when you know exactly what needs to happen every time. Agents are great when the steps depend on the input.

Now, let's understand what's an agent harness?

The agent harness is everything in an agent except the LLM. The tools that you define and code, how you run the agent loop, how you give access to the tools, guardrails, logging that you do — all of this is part of the agent harness. The agent harness is basically the thin software layer that converts an LLM into an agent. That's it.

What's next?

If you want to go further from here:

  1. Try an agent framework — pick something like LangGraph or the Cursor SDK and build the same time-zone agent with real tool calling instead of pseudo code.
  2. Add one more tool — extend the example with something like sendEmail or searchWeb and see how the LLM picks different paths for different queries.
  3. Read about the harness — look at how a framework handles retries, logging, and guardrails. That's where most of the real engineering lives once you understand the loop.

The loop is the easy part. The harness is where it gets interesting.