How the Agent = LLM + Context + Tools Formula Guides AI Agent Development
The Agent = LLM + Context + Tools formula structures autonomous agents as three composable components—an LLM reasoning engine, persistent state memory, and executable tool functions—enabling modular, traceable, and extensible AI systems.
The Agent = LLM + Context + Tools formula is the architectural blueprint underlying the bojieli/ai-agent-book repository. This decomposition treats an AI agent not as a monolithic black box, but as the tight integration of a reasoning engine, memory mechanism, and action interface. Understanding this formula reveals how modern autonomous systems balance intelligence with interaction according to the source code implementation.
Deconstructing the Three Core Components
The codebase treats an autonomous agent as the combination of three tightly-coupled components that map directly to specific implementation details in chapter1/web-search-agent/agent.py.
The LLM as the Reasoning Engine
The LLM provides the reasoning engine that generates thoughts, decides when to act, and produces the final answer. In the repository, the LLM is instantiated through an OpenAI-compatible client with a specific model name.
According to the source code in WebSearchAgent.__init__, the LLM backend is configured via the model parameter (e.g., kimi-k3), allowing any OpenAI-compatible provider (OpenAI, Anthropic, Moonshot, etc.) to be swapped by changing the client configuration.
Context as the Agent’s Memory
Context stores the dialogue history, the ReAct trace, and any intermediate observations so the LLM can "remember" what has been said or done. The context is updated after each step and fed back into the next prompt.
The implementation uses WebSearchAgent.conversation_history to maintain state, while the _emit helper appends to self.trace to create a readable log of every reasoning step.
Tools as the Action Interface
Tools are external functions that the LLM can call (e.g., $web_search). They are described in the model's tool list and invoked when the model emits an action step.
The available tool set is defined in WebSearchAgent._get_tools, while the thin wrapper search_impl forwards arguments to the underlying service.
The ReAct Loop: Putting the Formula into Motion
Putting these three pieces together yields the ReAct loop used throughout the book. This execution cycle demonstrates how the formula translates into runtime behavior:
- Thought – the LLM generates a reasoning step based on current context.
- Action – if the model decides it needs external data, it calls a tool (e.g.,
$web_search). - Observation – the tool returns a result, which is added to the context.
- Answer – after enough cycles, the LLM produces the final answer using the accumulated context.
The self.trace attribute maintains this history, providing transparency for debugging and teaching the design pattern.
Implementation Deep Dive: WebSearchAgent
The chapter1/web-search-agent/agent.py file demonstrates the concrete realization of the formula. The WebSearchAgent class implements the complete integration of LLM, Context, and Tools:
# Creating a web-search agent (LLM + Context + Tools)
from chapter1.web-search-agent.agent import WebSearchAgent
agent = WebSearchAgent(
api_key="YOUR_MOONSHOT_KEY", # LLM backend
model="kimi-k3", # LLM choice
verbose=True # Show ReAct trace (Context)
)
# Running the ReAct loop
question = "What are the health benefits of blueberries?"
answer = agent.search_and_answer(question, max_iterations=5)
print("🗣️ Final answer:", answer)
# The console displays intermediate Thought → Action → Observation steps
# because `verbose=True` triggers `_emit` which prints each trace entry.
The chapter1/web-search-agent/config.py file holds configuration constants such as SEARCH_TIMEOUT that affect how the LLM and tools interact, further demonstrating the separation of concerns.
Extending the Formula: Adding Custom Tools
The formula's modularity enables developers to extend agent capabilities without modifying the core reasoning engine. The following example from the repository demonstrates adding a calculator tool by extending _get_tools and _run_tool:
from chapter1.web-search-agent.agent import WebSearchAgent
class CalcAgent(WebSearchAgent):
def _get_tools(self):
# Keep the built-in web search tool and add a calculator
base = super()._get_tools()
base.append({
"type": "function",
"function": {
"name": "calc",
"description": "Simple arithmetic calculator",
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "Arithmetic expression, e.g. '2+3*4'"
}
},
"required": ["expression"]
}
}
})
return base
def _run_tool(self, tool_name, args):
if tool_name == "calc":
import math
try:
result = eval(args["expression"], {"__builtins__": {}}, {})
return {"result": result}
except Exception as e:
return {"error": str(e)}
return super()._run_tool(tool_name, args)
calc_agent = CalcAgent()
calc_agent.search_and_answer("What is 7*8 plus 12?")
The chapter8/self-evolving-tools/agent.py file extends this pattern further, demonstrating agents that can extend their tool set at runtime, reinforcing the modularity of the formula.
Architectural Benefits of the Separation
The Agent = LLM + Context + Tools blueprint guides developers to build systems with three specific architectural advantages:
- Separate concerns – LLM logic, state management (
conversation_history), and external services (search_impl) live in distinct functions and classes. - Enable composability – New tools are added by appending to the list returned by
_get_tools, as shown in theCalcAgentexample. - Maintain transparency – The ReAct trace (
self.trace) gives a readable log of every step, useful for debugging and for teaching the design pattern.
The abstract BaseAgent class in chapter8/gaia-experience/AWorld/aworld/core/agent/base.py demonstrates how this generic pattern scales across the entire book, providing a foundation for specialized implementations.
Summary
The Agent = LLM + Context + Tools formula provides a robust framework for AI agent development by decomposing complexity into three interchangeable components:
- The LLM serves as the reasoning engine, instantiated via
WebSearchAgent.__init__with configurable model parameters. - Context maintains state through
conversation_historyandtrace, enabling persistent memory across ReAct loop iterations. - Tools provide action capabilities through the
_get_toolsand_run_toolmethods, allowing external function execution.
This separation enables swapping LLM providers, enriching memory mechanisms, and extending tool sets without touching the core reasoning logic, as demonstrated by the CalcAgent extension pattern and the BaseAgent abstraction.
Frequently Asked Questions
What is the Agent = LLM + Context + Tools formula?
The Agent = LLM + Context + Tools formula is an architectural pattern that defines an autonomous agent as the combination of three components: an LLM that provides reasoning capabilities, a Context structure that stores conversation history and observations, and a Tools interface that enables external actions. According to the bojieli/ai-agent-book source code, this decomposition separates reasoning from state management and action execution.
How does the ReAct loop implement this formula?
The ReAct loop operationalizes the formula through a four-step cycle: the LLM generates a Thought, decides to call a Tool (Action), receives an Observation that updates the Context, and finally produces an Answer using the accumulated context. This loop is implemented in chapter1/web-search-agent/agent.py where _emit updates the trace and search_and_answer orchestrates the iterations.
Can I swap the LLM provider while keeping the same agent logic?
Yes. The repository demonstrates this flexibility in WebSearchAgent.__init__ (lines 94-100) where the LLM is instantiated through an OpenAI-compatible client. Changing the model parameter (e.g., from kimi-k3 to gpt-4) or the API endpoint allows you to swap providers without modifying the tool definitions or context management logic, as long as the new LLM supports function calling.
How do I add new tools to an existing agent?
New tools are added by extending the _get_tools method to include the tool schema and implementing the execution logic in _run_tool. The CalcAgent example in the repository shows this pattern: it appends a new function definition to the base tools list and adds a conditional branch in _run_tool to handle the calc tool name, demonstrating how the formula enables composable capability extension.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →