Skip to main content

01 - AI Agents: Introduction, What They Are and When to Use Them

An AI agent picks its own next step; a workflow does not. How to tell them apart in code, what they cost and when an agent is really worth it.

What do you think about this article?

01 - AI Agents: Introduction, What They Are and When to Use Them
AI AgentsPhoto:Pavel DanilyukPexels

At a Glance

An AI agent picks its own next step; a workflow does not. How to tell them apart in code, what they cost and when an agent is really worth it.

The problem: an automation that doesn't know which way to go

You have a task that a language model cannot close on its own: answering a customer who asks where their order is requires consulting an order system and, if the order does not exist, searching by another key. You can write this logic as a sequence of fixed steps, or you can let the model choose the next step. The first solution is called a workflow, the second an agent. This series is about the second, and this first article exists to help you decide when it is worth choosing: often the answer is "not yet".

The distinction we use is the one from Anthropic's article Building effective agents: workflows are systems where models and tools are orchestrated through predefined code paths; agents are systems where the model dynamically directs its own process and its use of tools, keeping control over how it accomplishes the task. The same source recommends looking for the simplest possible solution and increasing complexity only when needed, which can mean not building an agentic system at all, because these systems usually trade latency and cost for better task performance.

What is an AI agent?

The definition of an agent comes from Russell and Norvig's textbook, Artificial Intelligence: A Modern Approach: anything that can be viewed as perceiving its environment through sensors and acting upon that environment through actuators. A thermostat fits this definition. What makes an agent based on a language model interesting is that the choice of action is not written in the code, but produced by the model at every turn, starting from what it has seen so far.

A model used directly, by contrast, is a function: it receives a prompt, returns text, and the loop ends. To become an agent it needs a ring around it, that is, a program that executes the actions the model proposes, puts the result back into the context and calls the model again until it decides to stop. The concrete capabilities that this ring makes possible are four.

  • Multi-step decisions: breaking the goal down and adapting the plan to intermediate results, as in the case of the order that cannot be found.
  • External tools: calling APIs, querying databases, reading and writing files.
  • Memory across turns: keeping in the context what has already been observed and, if needed, saving it outside the context.
  • Error handling: if a tool fails, the model sees the error and can try again another way.

None of these four items is magic: they are all code that you write around a call to the model. The most delicate is the last one, because an error repeated without a cap on turns is the fastest way to burn budget; this is why the listing below has an explicit limit, max_turns.

Workflow and agent compared, in a few lines

The listing solves the same problem in two ways. workflow is the fixed path: it looks up the order and reports its status, whatever it finds. agent is a loop in which model returns an (action, argument) pair, the code runs the corresponding tool and appends the result to observations. The "model" here is fake: it follows a script for each request, but chooses the action based on how many observations it already has, as a real model would with its context. This way the example is reproducible and calls no service.

# Fake model: it follows a script, so the example is reproducible.
# In a real system this function would be a call to an LLM.
SCRIPTS = {
    "A-1042": [("find_order", "A-1042"),
               ("answer", "Parcel A-1042 is out for delivery, arriving tomorrow.")],
    "A-9999": [("find_order", "A-9999"),
               ("find_customer", "mario@example.com"),
               ("answer", "I can't find A-9999; Mario's order is A-1042, out for delivery.")],
}
ORDERS = {"A-1042": "out for delivery"}
CUSTOMERS = {"mario@example.com": ["A-1042"]}

def model(request, observations):
    """Returns the next action, chosen from what it has seen so far."""
    return SCRIPTS[request][len(observations)]

TOOLS = {
    "find_order": lambda k: ORDERS.get(k, "order does not exist"),
    "find_customer": lambda k: CUSTOMERS.get(k, []),
}

def workflow(request):
    """Fixed path, decided by the programmer: always and only these two steps."""
    status = TOOLS["find_order"](request)
    return f"Status of order {request}: {status}", 1

def agent(request, max_turns=5):
    """The model decides the next step; the code runs it and reports back."""
    observations = []
    for turn in range(1, max_turns + 1):
        action, argument = model(request, observations)
        if action == "answer":
            return argument, turn - 1          # tool calls made
        observations.append(TOOLS[action](argument))
    return "Turn limit reached", max_turns

for r in ("A-1042", "A-9999"):
    print(r, "| workflow:", workflow(r))
    print(r, "| agent   :", agent(r))

# Output:
# A-1042 | workflow: ('Status of order A-1042: out for delivery', 1)
# A-1042 | agent   : ('Parcel A-1042 is out for delivery, arriving tomorrow.', 1)
# A-9999 | workflow: ('Status of order A-9999: order does not exist', 1)
# A-9999 | agent   : ("I can't find A-9999; Mario's order is A-1042, out for delivery.", 2)

Run twice with Python 3.14.4 (python3 -I), the program printed identical output both times. For A-1042 the two approaches coincide, and the workflow is simpler and cheaper: one tool call. The interesting case is A-9999: the workflow answers "order does not exist" and stops, while the agent sees that observation, chooses find_customer and arrives at a useful answer, with two tool calls instead of one. The price of flexibility is precisely that second turn: in a real system every turn is a call to the model, with cost and latency. The line you cannot remove is the for with max_turns: without it, a script (or a model) that never says "answer" runs forever.

The listing is a teaching sketch: the script is not a model and does not prove that a real model would choose well. It only shows the structure, that is, where the decision lives (inside model) and where the control lives (inside agent). We build the complete loop, with real models and tools, in the following articles, starting from Fundamentals: OODA Loop, ReAct and Tool Calling.

Agent, LLM and chatbot: the differences that matter

"Chatbot", "LLM" and "agent" are used as synonyms, but they describe different architectures. The table compares them on the points that change design choices.

FeatureRule-based chatbotDirect LLMAgent
Who decides the stepHand-written treeNo step: one answerThe model, at every turn
External toolsOnly those hard-wired in the treeNone, unless code around itYes, chosen by the model
MemorySession stateOnly the context windowContext plus an optional external store
Cost and latencyLow and predictableOne callSeveral calls, number not known in advance
PredictabilityHighMediumLower, a cap on turns is needed

What matters most in the table is the last row: every bit of extra autonomy is paid for in predictability. The rule-based chatbot is the most boring and the easiest to test; the agent is the most capable and the hardest to reproduce. That is why the choice is not "which is more modern", but "how much task variability justifies the cost of not knowing the steps in advance".

When to use an agent, and when not to

A practical criterion: if you can write down on paper the steps, in order, for all the cases you expect, you have a workflow. An agent makes sense when the steps depend on what is discovered along the way and you cannot list them beforehand. Some cases where this really happens:

  • Support on irregular cases: the order that cannot be found, the refund that depends on the customer's history.
  • Research with multiple sources: the next question depends on what was found in the previous one.
  • Code with verification: write, run the tests, read the error, fix, with a cap on attempts.
  • Exploratory data analysis: the next hypothesis comes from the result of the previous query.

The common thread is that the number and order of the steps are not known at the start, and that a mistake midway can be recovered. When this does not hold, the agent's advantage disappears and the costs remain. In the Anthropic article cited above, the example uses are precisely customer support and coding agents, where the result can be verified.

Signs that you don't need an agent

  • A known algorithm exists: sorting, validating a format, computing an amount. A normal function is faster, free and deterministic.
  • Latency must be minimal: a loop with several calls to the model is not compatible with a response in a few milliseconds.
  • The outcome must be reproducible: documents with a fixed format or decisions that must be justified identically on every run.
  • The data is sensitive and the controls are missing: without minimal permissions, tracing and human approval, giving tools to a model is a risk, not a feature.

These items do not add up: one is enough to stop you. In particular the last one does not depend on the model but on what you allow it to do, and it is the topic of Security and Safety: Jailbreaking and Guardrails. Before building an agent, always try the poorest case: a single call to the model with the right context, then a workflow, and only after that the loop.

The frameworks: three philosophies, not three races

You don't need a framework to write an agent: the listing above is the proof. Frameworks serve what sits around the loop, that is, saved state, resumption after an error, human approvals, observability. The versions on the PyPI registry on 2026-11-12: langgraph 1.2.21, crewai 1.15.41, ag2 1.3.1, autogen-agentchat 0.7.5, agent-framework 1.26.0, openai-agents 0.24.0. Frameworks change fast: always check the version before copying an example.

LangGraph

The official documentation defines it as a low-level orchestration framework and a runtime for long-running, stateful agents: you describe the flow as a graph of shared state, nodes and edges, mixing deterministic steps and model-driven steps. It focuses on durable execution, streaming and human intervention, and imposes neither prompts nor agent architecture. The higher-level piece is in the langchain package: the create_agent function, described as a minimal, configurable wrapper around the model loop. The migration guide to version 1 says that langgraph.prebuilt.create_react_agent used to be recommended and now langchain.agents.create_agent is, and that legacy chains such as LLMChain and other deprecated features are in the langchain-classic package. We look at it in LangChain and LangGraph: Agents with AgentExecutor and Tools.

CrewAI

CrewAI describes itself as an open source framework that combines Crews, teams of autonomous agents that collaborate on delegated tasks, with Flows, event-driven flows that manage state and execution. It is the natural choice when the problem divides into roles (researcher, analyst, editor) and you want to declare the roles rather than write the loop. The trade-off is that part of the coordination logic lives inside the framework: more convenient, less visible. It is covered in CrewAI: Collaborative Agent Teams.

AutoGen, AG2 and Microsoft Agent Framework

Here the situation has changed recently and must be read from the sources. The AutoGen documentation now reports that the project is archived and no longer maintained by Microsoft, that it discourages use in production, and that new users should start from the Microsoft Agent Framework, with a migration guide for those already using AutoGen. The ag2ai/ag2 repository instead notes that the ag2 package no longer includes the autogen import name or the classic classes, now gathered in "AG2 Classic". If you find a tutorial with import autogen, check which package and which version it refers to. The topic is covered in AutoGen and AG2: Emergent Multi-Agent Conversation.

CriterionLangGraphCrewAIAutoGen / AG2
ParadigmState graphTeams (Crews) and flows (Flows)Conversation between agents
When it fitsCustom flow with resumption and approvalsProblem divided into rolesCheck the project status first
Price to payMore structural codeCoordination hidden in the frameworkUncertainty about package and maintenance

The table is not a ranking. If you start from zero and your flow is sequential, none of the three is needed: the loop in the listing is enough. Frameworks are justified when you find yourself rewriting state saving, resumption and human approval, and want to stop doing it by hand.

Anatomy of an agent: five components

Every agent, with any framework, has five parts. In the listing you can see them all: the model (model), the instructions (the script, which in a real system is the system prompt), the tools (TOOLS), the memory (observations) and the orchestrator (agent).

  • The model chooses the next step. A more capable model makes fewer mistakes, a smaller one costs less: the choice is a compromise, not a hierarchy.
  • The system prompt gives role, constraints and format. If it is vague, the behavior is unpredictable; if it is too rigid, the model cannot adapt.
  • The tools are functions with a name, a description and a parameter schema. The description is what the model reads to decide when to use them.
  • The memory is the current context (short term) plus an optional external store (long term).
  • The orchestrator is the loop that executes, accumulates and stops: it holds turn limits, timeouts and error handling.

Of the five parts, the one where mistakes are most frequent is the tool: an ambiguous description makes the model call the wrong function, and no model compensates for a badly written schema. Tool design is covered in Advanced Tool Calling: APIs, Web and Custom Tools, and memory in Memory Systems: Context, History and Knowledge Graphs.

Standards for tools: MCP

The Model Context Protocol (MCP) is, according to the specification, an open protocol for integration between applications based on language models and external data sources and tools. The practical reason is to avoid a different adapter for every application-tool pair: an MCP server exposes tools, and every client that speaks MCP can use them. For an agent it means that some of the tools can come from outside instead of being written by you, with a security consequence not to be overlooked: every MCP server you connect widens what the model can do.

Frequently asked questions

What is the difference between a workflow and an agent?

In a workflow the steps are written in the code and the model only fills in fields; in an agent the model chooses the next step at every turn. The practical consequence is that the workflow is predictable and the agent adapts to irregular cases, with more calls to the model.

Do I need a framework to build an agent?

No: a minimal agent is a loop that calls the model, runs the requested tool and puts the result back into the context, as in the listing in this article. Frameworks help when you need saved state, resumption after an error and human approval.

How much does an agent cost compared to a single call?

Every turn of the loop is a call to the model, and the number of turns is not known in advance: that is why a cap is always needed. The real cost depends on the model and the task, so it has to be measured on your case and cannot be deduced from a general rule.

What you can do now

You can tell a workflow from an agent and recognize in the code where the decision lives. You can use the criterion of listable steps to decide whether you really need an agent, and you know the cost to pay: more calls, less predictability, a cap on turns to always impose. In the next article, Fundamentals: OODA Loop, ReAct and Tool Calling, we open the loop and see how the model proposes an action and how the program executes it.

The rest of the series develops what is only sketched here: orchestrating several agents in production, testing and evaluating agents, production deployment, the cost of tokens, a constructed example of a research assistant and, at the end, the capabilities and limits of agents.

Sources

AI Agents Complete Guide

The complete guide to AI Agents: architectures, patterns, implementation and real-world use cases. 10 chapters, 172 pages, practical Python examples.

Commenti

Caricamento commenti...

Sign in to comment

Discuss this article in the community

Join the Telegram group to discuss with other developers, ask questions and share your experiences.

Did you like this article?

Explore other content on the blog or discover my projects