# How to Design Effective Tool Descriptions for LLM Tool Calling in AI Agents

> Design effective tool descriptions for LLM tool calling in AI agents. Learn to use purpose-first phrasing, JSON-Schema, and negative examples for reliable, secure, and efficient tool invocation.

- Repository: [Bojie Li/ai-agent-book](https://github.com/bojieli/ai-agent-book)
- Tags: tutorial
- Published: 2026-07-22

---

**Effective tool descriptions use purpose-first phrasing, explicit JSON-Schema parameters, negative examples, and performance hints to enable LLMs to invoke external tools reliably while minimizing token overhead and security risks.**

The quality of your tool descriptions directly determines whether an AI agent can successfully bridge internal reasoning with external capabilities. In the `bojieli/ai-agent-book` repository, the authors demonstrate that well-crafted descriptions are the single most important factor for reliable LLM tool calling. This guide synthesizes the architectural patterns found in [`book-en/chapter4.md`](https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter4.md) and the reference implementations in [`extras/agent-lab/SCHEMA.md`](https://github.com/bojieli/ai-agent-book/blob/main/extras/agent-lab/SCHEMA.md) to provide a concrete framework for designing tool descriptions that maximize accuracy and minimize failures.

## Core Design Principles for LLM Tool Descriptions

### Purpose-First Phrasing

Start every description with a concise "use this tool when..." trigger. This creates a clear decision boundary that prevents both over-use and mis-use. According to the source code in [`book-en/chapter4.md`](https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter4.md), phrasing the description as a conditional statement helps the LLM classify whether the current task state warrants an external call.

**Bad:** "A tool that searches the web."

**Good:** "Use when you need up-to-date factual information that is not in the model's knowledge cutoff."

### Explicit Parameter Schemas with JSON-Schema

Define every argument using strict JSON-Schema with types, constraints, and examples. The [`extras/agent-lab/SCHEMA.md`](https://github.com/bojieli/ai-agent-book/blob/main/extras/agent-lab/SCHEMA.md) file mandates that each parameter include `description`, `type`, and optionally `example` fields. This guarantees syntactically valid calls and enables deterministic pre-validation.

```json
{
  "query": {
    "type": "string",
    "description": "The search query; keep it short (≤100 chars).",
    "example": "latest GPT-4 release notes"
  },
  "max_results": {
    "type": "integer",
    "description": "Maximum number of search results to return (1–5).",
    "minimum": 1,
    "maximum": 5,
    "default": 3
  }
}

```

### Negative Examples and Usage Boundaries

Explicitly state what the tool should **not** be used for. As implemented in [`book-en/chapter4.md`](https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter4.md), negative examples reduce false-positive calls for ambiguous tasks. For instance, instruct the model: "Do NOT use the web-search tool for private user data or personally identifiable information."

### Performance and Rate Limit Hints

Include latency estimates, rate limits, and batch-ability flags. The repository's Chapter 4 "Performance Tips" section shows that noting constraints like "≤5 calls/minute" helps the LLM decide whether to call immediately or defer, and enables efficient call grouping.

### Security-First Documentation

Never embed secret values or credentials in descriptions. The [`book-en/chapter4.md`](https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter4.md) "Security Risks" section warns against "Tool Description Poisoning"—where attackers inject instructions via compromised descriptions. Explicitly forbid passing credentials through parameters:

```json
{
  "security_notice": "Never pass API keys or passwords through this tool. Use environment variables only."
}

```

### Checklist-Style Optional Parameters

Add `expected_*` fields that force the model to reason before calling. As documented in [`book-en/chapter5.md`](https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter5.md), requiring the model to fill out checklist parameters (e.g., `expected_output_format`) empirically improves call validity by approximately 50% in ablation studies.

## Hierarchical Organization to Reduce Token Overhead

The [`book-en/chapter4.md`](https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter4.md) token-budget analysis demonstrates that exposing only tool names in the system prompt—while deferring full descriptions—reduces context size by approximately 46%. Implement a **progressive disclosure** architecture:

1. **Context Construction:** The system prompt contains only tool names and minimal metadata.
2. **Deferred Description Lookup:** When the model emits a `tool_call` intent, the runtime fetches the full JSON definition from [`extras/agent-lab/SCHEMA.md`](https://github.com/bojieli/ai-agent-book/blob/main/extras/agent-lab/SCHEMA.md) specifications.
3. **Dynamic Loading:** Full schemas are retrieved on-demand rather than loaded into every context window.

## Implementation Architecture

### Deferred Description Lookup

Instead of embedding full tool definitions in the system prompt, store standardized descriptions in a shared folder. The agent runtime performs lookups only when the LLM signals intent to use a specific tool, as shown in the [`chapter2/local_llm_serving/README.md`](https://github.com/bojieli/ai-agent-book/blob/main/chapter2/local_llm_serving/README.md) reference implementation.

### Schema Validation Layer

Before executing any external call, validate arguments against the JSON-Schema. Invalid calls are rejected early with deterministic error messages, preventing runtime failures. The validation layer in `chapter4/perception-tools/` demonstrates this pattern using `jsonschema` validation.

### Security Gate and Approval Models

Implement a lightweight side-car "approval model" that reviews raw tool call JSON before execution. As detailed in [`book-en/chapter4.md`](https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter4.md), this catches hidden instruction injection attempts that bypass static description filtering.

## Practical Implementation in Python

The following examples follow the structure used in [`chapter2/local_llm_serving/README.md`](https://github.com/bojieli/ai-agent-book/blob/main/chapter2/local_llm_serving/README.md) and [`chapter5/coding-agent/README.md`](https://github.com/bojieli/ai-agent-book/blob/main/chapter5/coding-agent/README.md).

### 1. Declaring a Tool with Pydantic

```python

# tools/search_web.py

from pydantic import BaseModel, Field

class SearchWebParams(BaseModel):
    query: str = Field(
        ..., 
        description="Search query (≤100 chars)."
    )
    max_results: int = Field(
        3,
        ge=1,
        le=5,
        description="Maximum number of results to return."
    )

TOOL_DESCRIPTION = {
    "name": "search_web",
    "description": "Use when you need up-to-date factual information not in training data.",
    "parameters": SearchWebParams.schema(),
    "usage_hint": "Call only for facts newer than 2023-01-01; do NOT request private data.",
    "rate_limit": "≤5 calls/minute",
    "batchable": False
}

```

### 2. Validation Before Invocation

```python
import json
from jsonschema import validate, ValidationError
from tools.search_web import TOOL_DESCRIPTION

def validate_tool_call(name: str, args: dict) -> dict:
    """Raise if args do not match the schema."""
    if name != TOOL_DESCRIPTION["name"]:
        raise ValueError(f"Unknown tool: {name}")
    
    schema = TOOL_DESCRIPTION["parameters"]
    try:
        validate(instance=args, schema=schema)
    except ValidationError as exc:
        raise ValueError(f"Invalid arguments for {name}: {exc.message}")
    return args

```

### 3. Execution and Observation

```python
import httpx

def call_search_web(args: dict) -> dict:
    """Execute the tool and return structured observation."""
    resp = httpx.get(
        "http://localhost:8000/search",
        params=args,
        timeout=10.0
    )
    resp.raise_for_status()
    return {"results": resp.json()}

```

### 4. Agent Loop Integration

```python
def agent_step(message: str, trajectory: list):
    # LLM generates tool_call (simplified)

    tool_call = llm_generate_tool_call(message)
    
    # Validation layer

    args = validate_tool_call(tool_call["name"], tool_call["args"])
    
    # Execution

    observation = call_search_web(args)
    
    # Append to trajectory for next reasoning step

    trajectory.append({
        "role": "tool", 
        "name": tool_call["name"], 
        "result": observation
    })

```

## Summary

- **Purpose-first phrasing** establishes clear decision boundaries for when to invoke tools, reducing mis-use.
- **Explicit JSON-Schema definitions** with constraints and examples ensure syntactically valid arguments.
- **Negative examples** explicitly document prohibited use cases, preventing false-positive calls.
- **Hierarchical organization** with deferred loading reduces token overhead by 46% compared to full inline descriptions.
- **Checklist parameters** can reduce invalid tool calls by 50% by forcing reasoning before execution.
- **Security gates** using approval models prevent prompt injection via compromised tool descriptions.

## Frequently Asked Questions

### What makes a tool description "effective" for LLM calling?

An effective description provides a clear conditional trigger ("use when..."), explicit input schemas with examples, negative constraints outlining prohibited uses, and operational metadata like rate limits. According to [`book-en/chapter4.md`](https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter4.md), descriptions lacking these elements result in ambiguous decision boundaries and higher failure rates.

### How do I prevent LLMs from calling tools with invalid arguments?

Define strict JSON-Schema constraints in the `parameters` field, including `type`, `minimum`, `maximum`, and `enum` restrictions. Implement a validation layer—like the one in [`chapter2/local_llm_serving/README.md`](https://github.com/bojieli/ai-agent-book/blob/main/chapter2/local_llm_serving/README.md)—that validates arguments against the schema before execution. This deterministic validation catches errors before they reach external APIs.

### Should I include all tool descriptions in the system prompt?

No. The `bojieli/ai-agent-book` repository recommends **deferred description lookup**: include only tool names in the system prompt, then fetch full descriptions on-demand when the model signals intent. This approach reduces context token usage by approximately 46% while maintaining full semantic fidelity.

### How do I protect against prompt injection through tool descriptions?

Never embed secrets or credentials in tool descriptions. Explicitly forbid passing sensitive data through parameters. Implement a security gate using a secondary "approval model" that reviews raw tool call JSON for hidden instructions before execution, as detailed in [`book-en/chapter4.md`](https://github.com/bojieli/ai-agent-book/blob/main/book-en/chapter4.md) under "Tool Description Poisoning" mitigation strategies.