DEV Community

Cover image for πŸ€– AI Context Engineering (Part 4): AI Agents - From Tool Calling to Multi-Step Workflows
Fazal Mansuri
Fazal Mansuri

Posted on

πŸ€– AI Context Engineering (Part 4): AI Agents - From Tool Calling to Multi-Step Workflows

In Part 1, we explored why modern AI systems need more than carefully written prompts.

In Part 2, we looked at tokens, context windows and memory and why simply adding more context doesn't necessarily produce better results.

In Part 3, we went one step further:

  • RAG helps retrieve relevant information.
  • Tool Calling lets an AI application interact with external systems.
  • MCP provides a standardized way for AI applications to interact with tools.

But there's one important question left:

Who decides what should happen next?

Suppose a user asks:

Find the latest failed deployment,
identify the root cause,
create a GitHub issue,
and notify the team on Slack.
Enter fullscreen mode Exit fullscreen mode

That's no longer a single API call.

The system may need to:

1. Find the deployment
2. Retrieve its logs
3. Analyze the failure
4. Decide whether there is enough evidence
5. Create a GitHub issue
6. Send a Slack notification
7. Verify that everything succeeded
Enter fullscreen mode Exit fullscreen mode

Something has to coordinate these steps.

That's where AI agents come in.


🧠 First: What Actually Makes Something an AI Agent?

The word agent is used very loosely today.

Almost every application with an LLM is sometimes called an "AI agent."

That's not particularly useful.

A simple chatbot that answers:

What's the capital of France?
Enter fullscreen mode Exit fullscreen mode

isn't necessarily an agent.

Likewise:

Summarize this document.
Enter fullscreen mode Exit fullscreen mode

doesn't automatically make an application agentic.

A useful way to think about an agent is:

An AI agent is a system where an LLM participates in deciding and executing the steps required to accomplish a goal, often using tools and continuing until a defined completion condition is reached.

The important part is workflow execution.

Instead of:

Input β†’ LLM β†’ Output
Enter fullscreen mode Exit fullscreen mode

we have something closer to:

Goal
 ↓
LLM decides next step
 ↓
Tool / Action
 ↓
Result
 ↓
LLM evaluates result
 ↓
Next step
 ↓
...
 ↓
Final result
Enter fullscreen mode Exit fullscreen mode

This iterative loop is one of the core patterns behind agentic systems.


πŸ”„ The Agent Loop

Let's take a simple example.

The user says:

"Find the latest deployment failure and create a GitHub issue for it."
Enter fullscreen mode Exit fullscreen mode

A possible agent execution could look like:

                    User Goal
                       β”‚
                       β–Ό
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚    LLM    β”‚
                 β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
                       β”‚
                Choose next action
                       β”‚
                       β–Ό
                Deployment Tool
                       β”‚
                       β–Ό
                Tool Result
                       β”‚
                       β–Ό
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚    LLM    β”‚
                 β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
                       β”‚
                 Analyze result
                       β”‚
                       β–Ό
                 GitHub Tool
                       β”‚
                       β–Ό
                 Tool Result
                       β”‚
                       β–Ό
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚    LLM    β”‚
                 β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
                       β”‚
                       β–Ό
                 Final Answer
Enter fullscreen mode Exit fullscreen mode

Notice what's different.

The application doesn't necessarily hard-code:

Step 1 β†’ Step 2 β†’ Step 3
Enter fullscreen mode Exit fullscreen mode

Instead, the model can participate in deciding which available action should happen next.

That's the important shift.


πŸ†š Workflow vs Agent

This distinction is extremely important.

Imagine you have:

Step 1 β†’ Fetch Order
Step 2 β†’ Validate Payment
Step 3 β†’ Generate Invoice
Step 4 β†’ Send Email
Enter fullscreen mode Exit fullscreen mode

The sequence is always the same.

You probably don't need an agent.

A normal deterministic workflow is simpler.

User
 ↓
Fetch Order
 ↓
Validate Payment
 ↓
Generate Invoice
 ↓
Send Email
Enter fullscreen mode Exit fullscreen mode

Now consider:

Investigate why this customer's order failed.
Enter fullscreen mode Exit fullscreen mode

You don't necessarily know beforehand what steps are required.

The system might need to:

  • Look up the order
  • Check payment status
  • Inspect inventory
  • Search support tickets
  • Check logs
  • Compare previous attempts
  • Decide whether another investigation is necessary

The path depends on what the system discovers.

That's a much better candidate for an agent.

A useful rule:

If the workflow is predictable, prefer deterministic code. If the workflow requires dynamic decisions over multiple steps, an agent may be useful.

Even current agent guidance recommends starting with simpler deterministic approaches where they are sufficient rather than introducing unnecessary autonomy.


🧩 An Agent Is Not "Just an LLM"

A production agent normally consists of several pieces.

At a high level:

             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
             β”‚       Agent       β”‚
             β”‚                   β”‚
             β”‚   Instructions    β”‚
             β”‚        +          β”‚
             β”‚       LLM         β”‚
             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β–Ό            β–Ό            β–Ό
       Memory         RAG         Tools
          β”‚            β”‚            β”‚
          β–Ό            β–Ό            β–Ό
       State        Knowledge    Actions
Enter fullscreen mode Exit fullscreen mode

The model is only one component.

The surrounding system provides:

  • Instructions
  • Tools
  • Context
  • State
  • Memory
  • Guardrails
  • Execution limits
  • Observability

This is exactly where Context Engineering becomes especially important.


πŸ“¦ The Agent's Context Keeps Changing

Here's an important connection to Parts 1–3.

In a simple LLM request:

User
 ↓
Prompt
 ↓
LLM
Enter fullscreen mode Exit fullscreen mode

the context is relatively straightforward.

But an agent might execute several actions.

After the first tool:

User request
+
Tool result
Enter fullscreen mode Exit fullscreen mode

After the second:

User request
+
Tool result 1
+
Tool result 2
Enter fullscreen mode Exit fullscreen mode

After the third:

User request
+
Tool result 1
+
Tool result 2
+
Tool result 3
Enter fullscreen mode Exit fullscreen mode

And so on.

If you keep everything forever, the context can become unnecessarily large.

Remember Part 2:

More context β‰  better context.

An agent therefore needs to manage context carefully.

It may need to:

  • Keep important state
  • Remove irrelevant tool output
  • Summarize previous steps
  • Retrieve information again when necessary
  • Preserve the user's original goal
  • Track what has already been completed

This is one reason agent engineering and context engineering are deeply connected.


πŸ”§ Tools Give Agents Their Hands

We discussed Tool Calling in Part 3.

Now look at it from the agent's perspective.

A tool might expose:

get_order(order_id)
Enter fullscreen mode Exit fullscreen mode

Another:

get_payment_status(order_id)
Enter fullscreen mode Exit fullscreen mode

Another:

create_github_issue(title, body)
Enter fullscreen mode Exit fullscreen mode

Another:

send_slack_message(channel, message)
Enter fullscreen mode Exit fullscreen mode

The agent can decide which tool is useful for the current step.

Conceptually:

User Goal
   β”‚
   β–Ό
  Agent
   β”‚
   β”œβ”€β”€ get_order()
   β”‚
   β”œβ”€β”€ get_payment_status()
   β”‚
   β”œβ”€β”€ create_github_issue()
   β”‚
   └── send_slack_message()
Enter fullscreen mode Exit fullscreen mode

But there's an important engineering principle here:

Giving an agent a tool does not mean the agent should always be allowed to use it.

A tool that reads data is very different from a tool that:

delete_database()
Enter fullscreen mode Exit fullscreen mode

or:

transfer_money()
Enter fullscreen mode Exit fullscreen mode

or:

send_email()
Enter fullscreen mode Exit fullscreen mode

This is where guardrails become critical.


πŸ›‘ Agents Need Boundaries

Autonomy sounds exciting until the system makes the wrong decision.

Imagine an agent has this tool:

delete_customer()
Enter fullscreen mode Exit fullscreen mode

The model interprets a user's request incorrectly.

Without safeguards:

User
 ↓
LLM
 ↓
delete_customer()
 ↓
πŸ’₯
Enter fullscreen mode Exit fullscreen mode

A production system should instead introduce controls.

User
 ↓
Agent
 ↓
Tool Request
 ↓
Permission Check
 ↓
Validation
 ↓
Human Approval? ── Yes ──→ Human
 ↓ No
Execute Tool
Enter fullscreen mode Exit fullscreen mode

Depending on the action, you might require:

  • Authentication
  • Authorization
  • Input validation
  • Business-rule validation
  • Rate limits
  • Human approval
  • Audit logging

The more consequential the action, the stronger the controls should be.

Agent systems therefore aren't just an AI problem.

They're also a systems engineering and security problem. Current agent guidance explicitly treats guardrails and controlled tool access as important parts of agent design.


πŸ” What About ReAct?

You may have heard the term ReAct while reading about AI agents.

ReAct stands for:

Reason + Act

The research introduced a pattern where a model alternates between reasoning about a task and taking actions through tools, using the resulting observations to continue the task.

Conceptually:

Question
   ↓
Reason
   ↓
Action
   ↓
Observation
   ↓
Reason
   ↓
Action
   ↓
Observation
   ↓
Final Answer
Enter fullscreen mode Exit fullscreen mode

For example:

User:
"Why did deployment #482 fail?"
Enter fullscreen mode Exit fullscreen mode

The agent might need to:

β†’ Get deployment #482
β†’ Inspect failure details
β†’ Retrieve relevant logs
β†’ Analyze the error
β†’ Decide whether more information is needed
β†’ Produce an explanation
Enter fullscreen mode Exit fullscreen mode

The important lesson isn't:

"Every agent must use ReAct."

It shouldn't be treated that way.

ReAct is one influential approach to combining reasoning and action. Modern agent systems can use different orchestration strategies depending on the problem.


πŸ‘¨β€πŸ’» What Does an Agent Loop Look Like in Go?

You don't need an AI framework to understand the underlying architecture.

At its core, an agent can be thought of as a loop.

Here's a simplified orchestration skeleton:

type ToolResult struct {
    Name   string
    Output string
}

type AgentDecision struct {
    ToolName string
    Input    string
    Done     bool
    Answer   string
}

func runAgent(ctx context.Context, goal string) (string, error) {
    var history []ToolResult

    for step := 0; step < 10; step++ {
        decision, err := askModel(ctx, goal, history)
        if err != nil {
            return "", err
        }

        if decision.Done {
            return decision.Answer, nil
        }

        tool, ok := getTool(decision.ToolName)
        if !ok {
            return "", fmt.Errorf("unknown tool: %s", decision.ToolName)
        }

        result, err := tool.Execute(ctx, decision.Input)
        if err != nil {
            return "", err
        }

        history = append(history, ToolResult{
            Name:   decision.ToolName,
            Output: result,
        })
    }

    return "", errors.New("agent exceeded maximum steps")
}
Enter fullscreen mode Exit fullscreen mode

The important part isn't the exact implementation.

It's the architecture:

        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚   Ask Model   β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                β”‚
                β–Ό
        Tool needed?
          /       \
        Yes        No
         β”‚          β”‚
         β–Ό          β–Ό
     Execute      Finish
       Tool
         β”‚
         β–Ό
    Tool Result
         β”‚
         └──────────────┐
                        β”‚
                        β–Ό
                   Ask Model
Enter fullscreen mode Exit fullscreen mode

Notice the safety mechanism:

for step := 0; step < 10; step++ {
Enter fullscreen mode Exit fullscreen mode

That's not just an implementation detail.

It's an execution boundary.

Without a maximum number of steps, a poorly behaving agent could continue looping indefinitely.

Real systems need explicit termination conditions and failure handling. Agent orchestration commonly uses limits such as maximum turns, successful final output, tool completion or errors to stop execution.


⚠️ Why "Fully Autonomous" Isn't Always Better

There's a tendency to think:

More autonomy
     =
Better agent
Enter fullscreen mode Exit fullscreen mode

Not necessarily.

Imagine two systems.

System A

Agent
 ↓
20 tools
 ↓
Unlimited steps
 ↓
No approval
 ↓
No validation
Enter fullscreen mode Exit fullscreen mode

It sounds powerful.

It is also difficult to predict, debug, secure and operate.

System B

Agent
 ↓
5 well-defined tools
 ↓
Maximum 8 steps
 ↓
Permission checks
 ↓
Human approval for risky actions
 ↓
Full tracing
Enter fullscreen mode Exit fullscreen mode

System B may be much more useful in production.

The goal isn't maximum autonomy.

The goal is:

Enough autonomy to solve the problem while keeping behavior observable, bounded and controllable.


🧠 Single Agent vs Multi-Agent

Once developers understand agents, another idea quickly appears:

"Why not create multiple agents?"

For example:

                Manager Agent
                 /     |     \
                /      |      \
               β–Ό       β–Ό       β–Ό
          Research   Coding   Testing
            Agent     Agent    Agent
Enter fullscreen mode Exit fullscreen mode

This can be useful for genuinely different responsibilities.

But it also introduces additional complexity:

  • More model calls
  • More context passing
  • More failure points
  • More latency
  • More difficult debugging
  • More coordination logic

You don't need multiple agents just because you can build them.

A single agent with good tools can often handle many workflows.

A sensible progression is:

Deterministic Workflow
        ↓
Single Agent
        ↓
Multiple Specialized Agents
Enter fullscreen mode Exit fullscreen mode

Move to the next level only when the problem actually requires it. Current agent design guidance similarly recommends starting incrementally rather than immediately building complex multi-agent architectures.


πŸ” The Part Developers Often Miss: Observability

Here's where agent systems become very different from normal APIs.

Imagine your API returns:

500 Internal Server Error
Enter fullscreen mode Exit fullscreen mode

You inspect logs.

Fine.

But an agent might fail because:

User Request
    ↓
Tool A
    ↓
Tool B
    ↓
Wrong tool selected
    ↓
Bad result
    ↓
Agent makes another decision
    ↓
Final answer is incorrect
Enter fullscreen mode Exit fullscreen mode

The final output alone doesn't tell you what happened.

You need visibility into the execution trace.

For example:

Run ID: 8f21

Step 1
Tool: search_deployments
Input: production
Result: deployment #482

Step 2
Tool: get_logs
Input: #482
Result: database connection timeout

Step 3
Tool: search_docs
Input: database connection timeout
Result: connection pool documentation

Step 4
Decision: create GitHub issue

Step 5
Tool: create_issue
Result: issue #921
Enter fullscreen mode Exit fullscreen mode

This makes agent behavior much easier to debug.

Observability and tracing are now treated as important parts of production agent development because the system's behavior spans multiple model and tool steps.


🧩 The Complete Picture

Now let's connect everything from Parts 1–4.

A modern AI application might look like this:

                         USER
                           β”‚
                           β–Ό
                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                  β”‚  AI Application β”‚
                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                           β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚    AGENT    β”‚
                    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β–Ό            β–Ό            β–Ό
             RAG         Tools        Memory
              β”‚            β”‚            β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β–Ό
                    Context Builder
                           β”‚
                           β–Ό
                          LLM
                           β”‚
                           β–Ό
                    Next Decision
                           β”‚
                           └──────→ Tool / RAG
                                      β”‚
                                      └──→ ...
Enter fullscreen mode Exit fullscreen mode

This is where the entire series starts to come together.


πŸ“Œ The Mental Model

If you remember only four things from this article, remember this:

Part 1 - Context Engineering

Give the model the right information for the task.

Part 2 - Context Management

Don't confuse more context with better context.

Part 3 - RAG + Tools + MCP

Retrieve knowledge and give the system controlled access to external capabilities.

Part 4 - Agents

Let the system decide and execute multiple steps toward a goal-within defined boundaries.

That's the progression.

Prompt
  ↓
Context
  ↓
Context + Tools
  ↓
Context + Tools + Decisions
  ↓
Agent
Enter fullscreen mode Exit fullscreen mode

🚨 When Should You NOT Build an Agent?

This might be the most important advice in the entire article.

If your workflow is:

Receive Request
     ↓
Validate
     ↓
Insert Database Row
     ↓
Return Response
Enter fullscreen mode Exit fullscreen mode

Don't build an agent.

Use normal application code.

If your workflow is:

Understand user's goal
     ↓
Find relevant information
     ↓
Choose among several tools
     ↓
Inspect results
     ↓
Decide what to do next
     ↓
Possibly perform more actions
     ↓
Stop when the goal is satisfied
Enter fullscreen mode Exit fullscreen mode

An agent may make sense.

Use agents where dynamic decision-making provides real value-not simply because agents are trending.


🎯 Key Takeaways

  • An AI agent is more than an LLM wrapped in a chatbot.
  • Agents use models to participate in multi-step workflow execution.
  • Tools allow agents to retrieve information or take actions.
  • An agent typically operates through an iterative loop: decide β†’ act β†’ observe β†’ decide again.
  • RAG provides knowledge; tools provide capabilities.
  • Context changes as an agent executes more steps, making context management especially important.
  • Not every workflow needs an agent. Deterministic workflows are often simpler and more predictable.
  • Agents should have explicit boundaries such as step limits, permissions, validation and approval for sensitive actions.
  • Observability is critical because the final answer doesn't tell you everything that happened during an agent run.
  • Multi-agent systems can be useful, but they also introduce additional complexity and should not be the default.
  • The goal isn't maximum autonomy. It's useful autonomy with control.

πŸš€ What's Next?

We've now built the foundation:

Part 1: What is Context Engineering?

Part 2: Tokens, Context Windows & Memory

Part 3: RAG, Tool Calling & MCP

Part 4: AI Agents & Multi-Step Workflows

But there's a problem.

An agent can have:

  • Thousands of documents
  • Dozens of tools
  • Long conversation history
  • Multiple tool results
  • Previous execution state

And if we keep putting everything into the context...

πŸ’Έ Token costs increase.

🐌 Latency increases.

🧠 Relevant information gets buried.

And eventually, simply giving the model more context can make the system worse.

So the next question becomes:

How do we decide what context an AI actually needs-and what should be removed?

That's where we go next.

AI Context Engineering - Part 5: Context Optimization

We'll look at practical techniques such as:

  • Context compression
  • Summarization
  • Relevance ranking
  • Context pruning
  • Caching
  • Token optimization
  • Context prioritization
  • And how to reduce cost without sacrificing useful information

Because in production AI systems:

The goal isn't to give the model everything.

The goal is to give it exactly what it needs. πŸš€


Top comments (0)