# AI Agent Tool Design Patterns: How Execution Tools Enable Self-Evolving Agents

> Discover AI agent execution tool design patterns. Learn how a five step pipeline enables self evolving agents to extend capabilities without human intervention.

- Repository: [Bojie Li/ai-agent-book](https://github.com/bojieli/ai-agent-book)
- Tags: deep-dive
- Published: 2026-08-01

---

**AI agent execution tools follow a five-step pipeline of discover, read, verify, create, and reuse, enabling agents to extend their own capabilities without human intervention.**

The **ai-agent-book** repository implements a **self-evolving AI agent** named *Alita* that autonomously builds, validates, and reuses execution tools through LLM-driven function calling. This article breaks down the core **AI agent tool design patterns** that power dynamic capability expansion, based on the source code in `chapter8/self-evolving-tools/`.

## The Five-Step Execution Tool Pipeline

The architecture in [`agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/agent.py) defines a strict evolution sequence that every new capability must traverse. Each step maps to a concrete function schema passed to the LLM.

### Step 0: Reuse — Query the Tool Library First

Before any external work, the agent invokes `search_tools` to check its persistent **tool library**. This minimizes redundant API calls and enables cumulative knowledge building.

The schema is defined in [`agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/agent.py) lines 73-82:

```python
{
    "name": "search_tools",
    "description": "Search for existing tools in the tool library...",
    "parameters": {
        "type": "object",
        "properties": {
            "query": {"type": "string", "description": "Keywords to search for"}
        },
        "required": ["query"]
    }
}

```

### Step 1: Discover — Find External Packages

When no existing tool matches, the agent calls `web_search` (lines 21-34) to locate free, open-source Python libraries. The LLM formulates search queries based on the user's intent.

### Step 2: Read — Extract Documentation

The `read_webpage` tool (lines 39-45) fetches and parses candidate library documentation, giving the LLM context for implementation.

### Step 3: Verify — Sandbox Execution with Real Output Validation

Critical to the **AI agent execution tool** pattern: the `code_interpreter` (lines 49-64) runs candidate code in a **sandboxed subprocess** and **mandates a real numeric output** for verification.

```python
{
    "name": "code_interpreter",
    "description": "Execute Python code in a sandboxed environment...",
    "parameters": {
        "type": "object",
        "properties": {
            "code": {"type": "string"},
            "packages": {"type": "array", "items": {"type": "string"}}
        }
    }
}

```

The **system prompt** enforces: *"You must verify the tool works by seeing real numeric output before creating it."* This prevents hallucinated tools from entering the library.

### Step 4: Create — Package Verified Logic

Upon successful verification, `create_tool` (lines 69-88) persists the new capability to [`tool_manager.py`](https://github.com/bojieli/ai-agent-book/blob/main/tool_manager.py)'s `ToolLibrary` class as a JSON-serialized function with schema, code, and test arguments.

### Step 5: Invoke — Immediate Reuse

Future queries hit `search_tools` and retrieve the newly created tool, completing the **self-evolution loop**.

## Core Implementation Files

| Component | File | Key Element |
|-----------|------|-------------|
| **LLM client builder** | [`agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/agent.py) lines 33-70 | `_PROVIDERS` dict with OpenAI, Moonshot, ARK, OpenRouter support |
| **Base tool schemas** | [`agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/agent.py) lines 21-90 | `BASE_TOOL_SCHEMAS` — JSON function definitions for LLM |
| **Tool persistence** | [`tool_manager.py`](https://github.com/bojieli/ai-agent-book/blob/main/tool_manager.py) | `ToolLibrary` class with JSON storage and normalization |
| **Sandbox runner** | [`base_tools.py`](https://github.com/bojieli/ai-agent-book/blob/main/base_tools.py) | Concrete `code_interpreter` implementation |
| **Execution orchestration** | [`scripts/sync_chapter2_figures.py`](https://github.com/bojieli/ai-agent-book/blob/main/scripts/sync_chapter2_figures.py) | Annotated message-tool-result loop |

## Key Design Patterns in AI Agent Execution Tools

### Function-Calling Driven Orchestration

The agent contains **no hard-coded branching logic**. All decisions flow from the LLM selecting among provided function schemas. This pattern, central to modern **AI agent tool design**, enables open-ended capability expansion without rewriting agent code.

### Verification-Before-Publication

The `code_interpreter` gate ensures only **functionally validated** tools enter the library. A tool must:
- Install its dependencies via pip
- Execute without errors
- Produce **observable, non-trivial output**

This mirrors continuous integration practices in software engineering.

### Provider-Agnostic Abstraction

The `build_client` helper (lines 33-70) normalizes across OpenAI, Moonshot, ARK, and OpenRouter APIs. The same execution pipeline runs regardless of backend, reducing vendor lock-in.

## Practical Example: Autonomous Tool Creation

Here's how the **AI agent execution tool** pipeline handles a stock price query:

```python

# User request

messages = [{"role": "user", "content": "Give me the latest price of AAPL"}]

# Agent execution flow (simplified from agent.py loop):

# 1. search_tools("stock price") → no match

# 2. web_search("open source python library stock price yfinance") → finds yfinance

# 3. read_webpage("https://github.com/ranaroussi/yfinance") → extracts API

# 4. code_interpreter(

#      code="import yfinance; print(yfinance.Ticker('AAPL').info['currentPrice'])",

#      packages=["yfinance"]

#    ) → outputs 187.43 (verified)

# 5. create_tool(

#      name="get_stock_price",

#      code="def run(symbol): import yfinance; return yfinance.Ticker(symbol).info['currentPrice']",

#      test_args={"symbol": "AAPL"}

#    )

# 6. Subsequent TSLA query: search_tools → instant reuse, no web search needed

```

Manual tool injection via `ToolLibrary` is also supported:

```python
from tool_manager import ToolLibrary

library = ToolLibrary()
library.add_tool(
    name="get_weather",
    description="Fetch current weather using weather-api package",
    parameters={"type": "object", "properties": {"city": {"type": "string"}}},
    code="""
def run(**kwargs):
    from weather import Weather
    return Weather().get_weather(kwargs['city'])
""",
    test_args={"city": "Paris"}
)

```

## System Prompt Enforcement Rules

The prompt in [`agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/agent.py) lines 73-82 encodes three invariants:

- **No fabrication** — All data must originate from tool execution
- **Mandatory verification** — Every new tool requires observed output
- **Mandatory reuse** — Always query `search_tools` before external discovery

These constraints transform an LLM into a **reliable, reproducible execution engine**.

## Summary

- **AI agent tool design** in ai-agent-book centers on a **five-step evolution pipeline**: reuse → discover → read → verify → create → invoke
- **`code_interpreter`** enforces verified execution through sandboxed subprocesses and mandatory real output
- **`ToolLibrary`** in [`tool_manager.py`](https://github.com/bojieli/ai-agent-book/blob/main/tool_manager.py) provides persistent, searchable tool storage
- **Function-calling architecture** eliminates hard-coded control flow, enabling open-ended self-evolution
- **Provider-agnostic client** supports OpenAI, Moonshot, ARK, and OpenRouter with unified interface

## Frequently Asked Questions

### How does the agent prevent creating broken or hallucinated tools?

The `code_interpreter` tool requires **observable, non-trivial output** before `create_tool` can execute. As implemented in [`base_tools.py`](https://github.com/bojieli/ai-agent-book/blob/main/base_tools.py), the sandbox runs candidate code with mandatory package installation and prints results. Only verified outputs trigger tool registration, mirroring test-driven development practices.

### Can the agent work with different LLM providers without code changes?

Yes. The `build_client` function in [`agent.py`](https://github.com/bojieli/ai-agent-book/blob/main/agent.py) (lines 33-70) abstracts provider selection through the `_PROVIDERS` dictionary. It handles OpenAI, Moonshot, ARK, and OpenRouter with automatic model mapping and API key routing, allowing the same execution pipeline across backends.

### What happens when a user asks for something similar to a previous request?

The `search_tools` function executes first on every query. If semantic similarity matches an existing tool — e.g., "stock price" matching `get_stock_price` — the agent **bypasses all discovery steps** and invokes the cached tool directly. This reuse pattern reduces latency and API costs significantly after initial tool creation.

### How is tool code safely executed without risking the host system?

The `code_interpreter` in [`base_tools.py`](https://github.com/bojieli/ai-agent-book/blob/main/base_tools.py) runs in a **subprocess sandbox** with isolated package installation. It optionally accepts a `packages` parameter for pip dependencies, executes the provided code, and captures stdout/stderr. This containment prevents host environment pollution while enabling dynamic dependency management.