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

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 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 lines 73-82:

{
    "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.

{
    "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'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 lines 33-70 _PROVIDERS dict with OpenAI, Moonshot, ARK, OpenRouter support
Base tool schemas agent.py lines 21-90 BASE_TOOL_SCHEMAS — JSON function definitions for LLM
Tool persistence tool_manager.py ToolLibrary class with JSON storage and normalization
Sandbox runner base_tools.py Concrete code_interpreter implementation
Execution orchestration 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:


# 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:

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 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 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, 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 (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 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.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →