# How to Set Up AI Agents with LLM, Context, and Tools: A Complete Implementation Guide

> Learn how to set up AI agents with LLM, context, and tools. This guide explains the three core components for building powerful AI agents.

- Repository: [Bojie Li/ai-agent-book](https://github.com/bojieli/ai-agent-book)
- Tags: how-to-guide
- Published: 2026-08-22

---

**Building AI agents requires three core components: an LLM client for reasoning, a tool registry for actions, and an agent loop that orchestrates the interaction between them.**

The `bojieli/ai-agent-book` repository provides a modular framework for setting up AI agents with LLM, Context, and Tools using a clean, extensible architecture. This implementation separates concerns into distinct layers—the reasoning engine, the action interface, and the orchestration logic—allowing developers to swap LLM providers or add capabilities without rewriting core logic. Understanding these three pillars is essential for building production-ready autonomous systems.

## Understanding the Three-Pillar Architecture

### LLM Context (The Reasoning Engine)

The **LLM Context** provides the cognitive capabilities that allow the agent to interpret tasks and generate responses. In [`chapter9/gaia-experience/gaia/llm_env.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/gaia-experience/gaia/llm_env.py), the framework implements a unified configuration system that reads from environment variables including `LLM_PROVIDER`, `LLM_MODEL`, and `LLM_API_KEY`. This design supports multiple backends—OpenAI, Moonshot, and ARK—through a thin wrapper class called `LLMClient` instantiated in [`chapter9/self-evolving-tools/agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/self-evolving-tools/agent.py).

### Tool Library (The Action Interface)

Tools are concrete actions the agent can perform on external systems, encapsulated as subclasses of `BaseTool` or `AsyncBaseTool`. The **Tool Library** registers these capabilities in a global `ToolsManager` class defined in [`chapter9/gaia-experience/AWorld/aworld/core/tool/base.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/gaia-experience/AWorld/aworld/core/tool/base.py). Concrete implementations like the web search tool in [`chapter5/coding-agent/tools/web_search_tool.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter5/coding-agent/tools/web_search_tool.py) demonstrate how each tool exposes a `run()` method that accepts structured JSON arguments and returns a `ToolResult` object.

### Agent Core (The Orchestration Layer)

The **Agent Core** implements the execution loop that ties reasoning to action. [`chapter9/gaia-experience/AWorld/aworld/core/agent/base.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/gaia-experience/AWorld/aworld/core/agent/base.py) defines `BaseAgent[Observation, List[ActionModel]]`, a generic class that handles the LLM-to-tool cycle. The concrete `LLMAgent` in [`chapter9/gaia-experience/AWorld/aworld/agents/llm_agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/gaia-experience/AWorld/aworld/agents/llm_agent.py) executes the loop: sending prompts to the LLM, parsing `tool_calls` JSON payloads, invoking registered tools, and feeding results back to the LLM for subsequent reasoning rounds.

## Environment Configuration and Setup

Before running agents, configure the LLM context through environment variables or CLI flags. The framework supports deterministic testing through an offline mode and production execution with live APIs.

Set the required environment variables:

```bash
export LLM_PROVIDER=openai            # Options: openai, moonshot, ark

export LLM_MODEL=gpt-4o-mini
export LLM_API_KEY=your-api-key-here
export LLM_BASE_URL=https://api.openai.com/v1  # Optional custom endpoint

```

Configuration is centralized in [`chapter9/prompt-auto-optimization/config.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/prompt-auto-optimization/config.py), which validates these settings before initializing the `LLMClient`. The `--model` and `--temperature` CLI flags in [`chapter9/self-evolving-tools/demo.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/self-evolving-tools/demo.py) allow runtime overrides without modifying environment variables.

## Running the Agent Loop

### Offline Mode for Testing

Use the `--offline` flag to test tool pipelines without consuming LLM API quota:

```bash
python -m chapter9.self-evolving-tools.demo --offline

```

When `--offline` is detected in [`chapter9/self-evolving-tools/agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/self-evolving-tools/agent.py), the system sets `model = None` and bypasses network calls, executing only the tool registration and validation logic.

### Full LLM-Backed Execution

For production runs with reasoning capabilities:

```bash
python -m chapter9.self-evolving-tools.demo \
    --model gpt-4o-mini \
    --temperature 0.2

```

This command loads the `LLMClient` with the specified provider, instantiates all registered tools via `ToolsManager`, and enters the interaction loop defined in the agent's `run()` method.

## Extending with Custom Tools

To add new capabilities, subclass `BaseTool` and register it with the global manager:

```python

# my_weather_tool.py

from chapter5.coding_agent.tools.base import BaseTool, ToolResult

class WeatherTool(BaseTool):
    """Fetch current weather for any city."""
    name = "weather"
    
    async def run(self, args: dict) -> ToolResult:
        city = args.get("city", "San Francisco")
        # Implementation details...

        return ToolResult(success=True, output=f"Weather in {city}: 72°F, sunny")

```

Register the tool before initializing the agent:

```python
from chapter9.gaia_experience.AWorld.aworld.core.tool.base import ToolsManager
from my_weather_tool import WeatherTool

ToolsManager.register(WeatherTool())

```

Once registered, the LLM can emit tool calls like `{"name": "weather", "arguments": {"city": "Tokyo"}}`, which the agent automatically routes to your implementation.

## Direct Programmatic Invocation

For integration into existing applications, instantiate the components directly:

```python
from chapter9.gaia_experience.AWorld.aworld.core.agent.base import BaseAgent
from chapter9.gaia_experience.gaia.llm_env import get_llm_client
from chapter9.gaia_experience.AWorld.aworld.core.tool.base import ToolsManager

# Initialize components

llm = get_llm_client()                 # Parses LLM_PROVIDER/LLM_MODEL from env

tools = ToolsManager()                 # Auto-loads built-in tools

agent = BaseAgent(llm=llm, tools=tools)

# Execute one reasoning cycle

prompt = "Summarize the latest news about AI safety."
response = agent.run_once(prompt)      # One LLM call + optional tool execution

print(response)

```

The `run_once()` method performs a single LLM request, parses any `tool_calls` fields, executes the corresponding tools, and returns the final synthesized output.

## Key Implementation Files

Understanding the source structure helps when debugging or extending the framework:

- **[`chapter9/self-evolving-tools/agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/self-evolving-tools/agent.py)** – Creates the `LLMClient` and handles the `--offline` flag for testing.
- **[`chapter9/gaia-experience/gaia/llm_env.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/gaia-experience/gaia/llm_env.py)** – Centralized environment parsing for provider selection and authentication.
- **[`chapter9/gaia-experience/AWorld/aworld/core/agent/base.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/gaia-experience/AWorld/aworld/core/agent/base.py)** – Generic `BaseAgent` class implementing the LLM-tool loop.
- **[`chapter9/gaia-experience/AWorld/aworld/core/tool/base.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/gaia-experience/AWorld/aworld/core/tool/base.py)** – Abstract `BaseTool` definitions and the `ToolsManager` registry.
- **[`chapter5/coding-agent/tools/web_search_tool.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter5/coding-agent/tools/web_search_tool.py)** – Reference implementation showing tool structure and error handling.
- **[`chapter9/self-evolving-tools/demo.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/self-evolving-tools/demo.py)** – CLI entry point demonstrating both offline and online execution modes.

## Summary

- **LLM Context** configuration relies on environment variables (`LLM_PROVIDER`, `LLM_MODEL`) parsed by [`llm_env.py`](https://github.com/bojieli/ai-agent-book/blob/main/llm_env.py) to instantiate a provider-agnostic client.
- **Tool Library** extensions require subclassing `BaseTool` and registering instances with `ToolsManager` before agent initialization.
- **Agent Core** orchestration uses `BaseAgent.run_once()` or the continuous loop in `LLMAgent` to alternate between LLM reasoning and tool execution.
- **Offline testing** is available via the `--offline` CLI flag that bypasses API calls while validating tool pipelines.
- The architecture is generic—any LLM backend or tool set can be plugged into the `BaseAgent` without modifying core loop logic.

## Frequently Asked Questions

### How does the agent decide when to invoke a tool?

The LLM generates a structured JSON payload containing a `tool_calls` field when it determines that external data or action is required to answer the prompt. The `BaseAgent` in [`chapter9/gaia-experience/AWorld/aworld/core/agent/base.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/gaia-experience/AWorld/aworld/core/agent/base.py) parses this field, extracts the tool name and arguments, and dispatches execution through `ToolsManager` before returning results to the LLM context.

### Can I run agents without an external LLM API?

Yes. The `--offline` flag forces the agent into a testing mode where the LLM client is bypassed entirely. In [`chapter9/self-evolving-tools/agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/self-evolving-tools/agent.py), this sets `model = None` and allows you to validate tool registration, argument parsing, and execution logic without network calls or API costs.

### What is the difference between BaseAgent and LLMAgent?

`BaseAgent` is the generic abstract class defined in [`chapter9/gaia-experience/AWorld/aworld/core/agent/base.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/gaia-experience/AWorld/aworld/core/agent/base.py) that handles the core observation-action loop. `LLMAgent`, located in [`chapter9/gaia-experience/AWorld/aworld/agents/llm_agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/gaia-experience/AWorld/aworld/agents/llm_agent.py), is a concrete implementation that specifically manages LLM API calls, conversation history, and tool call parsing for language model-based agents.

### How do I configure multiple LLM providers in the same application?

The `get_llm_client()` function in [`chapter9/gaia-experience/gaia/llm_env.py`](https://github.com/bojieli/ai-agent-book/blob/main/chapter9/gaia-experience/gaia/llm_env.py) reads environment variables to instantiate a single client. For multiple providers simultaneously, instantiate separate `LLMClient` objects manually with different configurations and inject them into distinct `BaseAgent` instances, as the framework does not enforce singleton patterns on the client level.