How to Design Effective Tool Descriptions for LLM Tool Calling: 7 Patterns from ai-agent-book
Effective LLM tool descriptions separate concise metadata from detailed operational contracts, explicitly encoding what the tool does, required inputs, expected outputs, failure modes, and data provenance in a self-contained format that minimizes token usage while maximizing actionability.
When building AI agents capable of invoking external functions, the quality of your tool descriptions determines whether the LLM selects the correct function, formats arguments properly, and handles errors gracefully. The ai-agent-book repository demonstrates a disciplined, layered approach to designing these descriptions, separating what the model needs to know from the operational details that ensure reliable execution.
1. Separate Metadata from Operational Contracts
The repository distinguishes between metadata (the concise summary exposed to the LLM in the prompt) and the operational contract (implementation details, failure modes, and provenance). This separation occurs in chapter4/perception-tools/src/expanded_catalog.py.
First, register_expanded_tools registers tools with human-readable summaries:
mcp.add_tool(_make_mcp_function(spec), name=spec.name,
description=full_description(spec))
(See lines 1000‑1004 of expanded_catalog.py.)
Later, enrich_existing_tools appends the full operational contract containing provenance and failure conditions:
tool.description = (
f"{tool.description.rstrip()}.\n\n"
f"Operational provenance for {name}: {provenance}. … "
f"Tool‑specific failure conditions are {failures}."
)
(See lines 1016‑1028 of the same file.)
This architecture allows you to expose only essential information to the LLM by default while retaining rich, machine-readable context for debugging or advanced prompting scenarios.
2. Make Descriptions Self-Contained and Actionable
Every tool description must answer three questions without requiring external context: What does the tool do? What inputs are required? What does a successful response look like?
The full_description function generates concise summaries such as "MCP tool that retrieves a web page and returns its HTML." For input requirements, the parameters field supplies a JSON Schema. In chapter4/agent-with-event-trigger/agent.py, the _get_tools_description method (lines 65‑70) extracts the schema:
"parameters": getattr(mcp_tool, "inputSchema", {"type":"object","properties":{}})
By encoding these elements, the LLM can construct correct function call JSON without guessing parameter types or return structures.
3. Document Failure Modes Explicitly
LLMs often assume functions succeed by default. When a tool can fail due to network errors, rate limits, or invalid arguments, the description must spell out the failure shape so the model can decide whether to retry, fallback, or continue.
In expanded_catalog.py (lines 1024‑1026), the contract explicitly states:
"Tool‑specific failure conditions are {failures}."
This leads to structured error responses the model can parse:
{
"success": false,
"error": "Timeout after 30 s",
"metadata": {...}
}
The agent can then surface the error to the user or select an alternative tool rather than hallucinating a successful result.
4. Use Provenance to Avoid Hallucination
When tools return data fetched from external sources, descriptions must explicitly state that results contain source identifiers (URLs, timestamps, provider metadata). This discourages the model from inventing facts and enables downstream verification.
The operational contract in expanded_catalog.py (lines 19‑24) adds a prose block stating that the structured ActionResponse retains source identifiers. This pattern is reused across MCP-enabled agents in the repository to ensure the LLM understands the data lineage before synthesizing answers.
5. Keep the Prompt Footprint Small
Only the concise metadata enters the standard prompt. The heavier operational contract attaches only when the agent’s configuration enables tool-description enrichment. In agent.py, the _get_tools_description method checks self.config.enable_todo_list to determine whether to include enriched descriptions.
This conditional approach preserves the token budget during normal operation while allowing on-demand detail for complex debugging scenarios or high-stakes tool invocations.
6. Provide a Uniform JSON Schema
All tools in the repository use the OpenAI-compatible function schema, enabling the model to reason about any tool uniformly. The conversion occurs in _get_tools_description (lines 60‑70 of chapter4/agent-with-event-trigger/agent.py):
tools.append({
"type": "function",
"function": {
"name": tool_key,
"description": mcp_tool.description or mcp_tool.name,
"parameters": getattr(mcp_tool, "inputSchema", {"type":"object","properties":{}})
}
})
Adhering to a single schema simplifies few-shot prompting and tool-selection logic across diverse agent implementations.
7. End-to-End Implementation Flow
The repository implements a complete pipeline for designing effective tool descriptions:
- Registration:
register_expanded_toolsadds 70 real-backed tools with short summaries. - Enrichment:
enrich_existing_toolsdecorates each tool with a full operational contract fromEXISTING_TOOL_CONTRACTS. - Prompt Construction:
Agent._get_tools_descriptionbuilds the list of function definitions sent to the model. - Model Call: The LLM selects a function and fills
parametersaccording to the JSON schema. - Error Handling: If the response contains
"success": false, the agent retries, chooses another tool, or surfaces the error based on the documented failure modes.
Summary
- Separate concerns: Keep concise LLM-facing metadata distinct from detailed operational contracts containing failure modes and provenance.
- Answer three questions: Every description must clarify what the tool does, what inputs it requires, and what successful output looks like.
- Explicit failures: Document failure conditions so the LLM can handle errors rather than hallucinate success.
- Source provenance: Include data source identifiers in descriptions to prevent fact invention and enable verification.
- Token efficiency: Use conditional enrichment to keep prompt footprints small while retaining detailed contracts for debugging.
- Schema standardization: Adopt the OpenAI function-calling format in
_get_tools_descriptionfor uniform tool reasoning across your agent fleet.
Frequently Asked Questions
How long should an LLM tool description be?
Tool descriptions should be concise enough to fit within your token budget while containing sufficient detail for the model to select and use the tool correctly. The ai-agent-book approach uses a short human-readable sentence for the base description (e.g., "MCP tool that retrieves a web page and returns its HTML") and appends the full operational contract only when self.config.enable_todo_list is activated, keeping standard prompts lean.
What information must be included in a tool description to prevent LLM errors?
To prevent selection and formatting errors, include: (1) a clear statement of the tool's purpose, (2) a JSON Schema defining required parameters and types (as implemented in _get_tools_description), and (3) explicit documentation of failure modes and success response shapes. According to the expanded_catalog.py implementation, adding provenance details and failure conditions reduces hallucination and enables proper error recovery.
Should tool descriptions include error handling instructions for the LLM?
Yes, effective tool descriptions explicitly document failure modes so the LLM knows how to interpret error responses. In the ai-agent-book repository, the enrich_existing_tools function appends strings like "Tool‑specific failure conditions are {failures}" to the description, allowing the model to receive structured error JSON (e.g., {"success": false, "error": "Timeout"}) and decide whether to retry or select an alternative tool.
How do I convert existing MCP tools to OpenAI-compatible function descriptions?
Use a conversion method like _get_tools_description in chapter4/agent-with-event-trigger/agent.py. This function iterates over your MCP tools and maps them to the OpenAI function schema by extracting the name, description, and inputSchema fields, ensuring the resulting JSON includes "type": "function" and properly nested "function" objects with "parameters" definitions.
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 →