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.
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
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?
isn't necessarily an agent.
Likewise:
Summarize this document.
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
we have something closer to:
Goal
β
LLM decides next step
β
Tool / Action
β
Result
β
LLM evaluates result
β
Next step
β
...
β
Final result
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."
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
Notice what's different.
The application doesn't necessarily hard-code:
Step 1 β Step 2 β Step 3
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
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
Now consider:
Investigate why this customer's order failed.
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
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
the context is relatively straightforward.
But an agent might execute several actions.
After the first tool:
User request
+
Tool result
After the second:
User request
+
Tool result 1
+
Tool result 2
After the third:
User request
+
Tool result 1
+
Tool result 2
+
Tool result 3
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)
Another:
get_payment_status(order_id)
Another:
create_github_issue(title, body)
Another:
send_slack_message(channel, message)
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()
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()
or:
transfer_money()
or:
send_email()
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()
The model interprets a user's request incorrectly.
Without safeguards:
User
β
LLM
β
delete_customer()
β
π₯
A production system should instead introduce controls.
User
β
Agent
β
Tool Request
β
Permission Check
β
Validation
β
Human Approval? ββ Yes βββ Human
β No
Execute Tool
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
For example:
User:
"Why did deployment #482 fail?"
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
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")
}
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
Notice the safety mechanism:
for step := 0; step < 10; step++ {
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
Not necessarily.
Imagine two systems.
System A
Agent
β
20 tools
β
Unlimited steps
β
No approval
β
No validation
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
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
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
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
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
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
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
β
ββββ ...
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
π¨ 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
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
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)