Skip to content

Chapter 7 · Tools: Built-in Toolkit Principles and Usage ​

Learning objectives: Understand the complete tool-call execution loop in Agno, learn to use built-in toolkits, and clarify "how a Python function becomes a model-callable tool."

7.1 Why Agents Need Tools ​

Large models can only generate text — they don't know today's stock price, can't query your database, and can't send an email. Tools bridge this gap: register Python functions with the Agent, and the model "requests calls" to these functions when needed. Agno handles the actual execution and feeds results back to the model.

Key insight

Tools are not magical plugins — fundamentally, it's a loop: the model outputs "I want to call get_weather(city='Beijing')" → the framework executes the function → the result is appended to context → the model continues reasoning. This loop continues until the model stops requesting tools and gives a final answer.

The official docs describe the execution flow in five steps:

  1. The Agent sends the current context and tool definitions (schema) to the model;
  2. The model returns a normal answer, or requests one/more tool calls;
  3. Agno validates arguments and executes each requested tool;
  4. Tool results join the model's context;
  5. The loop continues until the model gives a final answer.

7.2 How Functions Become Tool Schemas ​

This is the most important principle in this chapter: Agno auto-builds the tool schema from the function name, docstring, and type annotations. Here's an official-style example:

python
import os
from agno.agent import Agent
from agno.models.openai import OpenAIChat


def lookup_order(order_id: str) -> dict:
    """Return the status and delivery date for an order.

    Args:
        order_id: The order ID to look up.
    """
    return {
        "order_id": order_id,
        "status": "shipped",
        "delivery_date": "2026-07-22",
    }


agent = Agent(
    # Unified third-party OpenAI-compatible model
    model=OpenAIChat(
        id="deepseek-chat",
        api_key=os.getenv("DEEPSEEK_API_KEY"),
        base_url="https://api.deepseek.com/v1",
    ),
    tools=[lookup_order],  # Pass the function directly
    instructions="Use the order tool when a customer asks about a delivery.",
)

agent.print_response("When will order ORD-123 arrive?")

The model actually receives a JSON Schema roughly equivalent to:

json
{
  "name": "lookup_order",
  "description": "Return the status and delivery date for an order.",
  "parameters": {
    "type": "object",
    "properties": {
      "order_id": {
        "type": "string",
        "description": "The order ID to look up."
      }
    },
    "required": ["order_id"]
  }
}

From this we can derive three iron rules for writing tools (called "Design Tools for Reliable Calls" in the official docs):

  • Function names must be specific: lookup_order is far better than do_something; the model picks tools by name;
  • Write docstrings that explain "when to use": it's the model's instruction manual;
  • Type annotations + parameter descriptions must be complete: they directly determine the accuracy of the input schema.

7.3 Built-in Toolkit Practice ​

Writing custom tools is flexible, but common needs (search, quotes, web reading) already have community wrappers. Agno bundles related functions into a Toolkit — functions in one package share internal state and work collaboratively. Using DuckDuckGoTools as the most common example:

bash
pip install -U agno ddgs   # DuckDuckGoTools requires the ddgs library
python
# search_agent.py —— Let the Agent search the web
import os
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools.duckduckgo import DuckDuckGoTools

agent = Agent(
    model=OpenAIChat(
        id="deepseek-chat",
        api_key=os.getenv("DEEPSEEK_API_KEY"),
        base_url="https://api.deepseek.com/v1",
    ),
    tools=[DuckDuckGoTools()],
    instructions=["Cite source links when answering"],
    markdown=True,
    debug_mode=True,  # v2 way to inspect tool calls: prints detailed run logs
)

agent.print_response("What are the big events in AI Agent space this week?")

After running, you'll see a process like this in the logs:

text
● Tool call: web_search(query="AI Agent big events this week")      ← Model initiates
● Tool result: [{"title": "...", "url": "..."}, ...]                  ← Function execution result
● Final answer (citing links from search results)

Note: Agno removed the old show_tool_calls=True parameter starting in 2.x (also in 3.x). To see tool call details, use debug_mode=True; in streaming mode, listen for tool events in RunContentEvent.

Other commonly used toolkits include YFinanceTools (financial quotes), HackerNewsTools, Newspaper4kTools (web reading), FileTools (local files), and more — see the official Toolkit Index for the full list. Here's a combined example:

python
# stock_agent.py —— Quote tool + search tool working together
import os
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools.duckduckgo import DuckDuckGoTools
from agno.tools.yfinance import YFinanceTools

agent = Agent(
    model=OpenAIChat(
        id="deepseek-chat",
        api_key=os.getenv("DEEPSEEK_API_KEY"),
        base_url="https://api.deepseek.com/v1",
    ),
    tools=[
        YFinanceTools(enable_stock_price=True, enable_analyst_recommendations=True),
        DuckDuckGoTools(),
    ],
    instructions=[
        "Use the quote tool for real-time financial data",
        "Search news with the search engine and cite sources",
        "Present data comparisons in tables",
    ],
    markdown=True,
    debug_mode=True,
)

agent.print_response("Compare NVIDIA and AMD latest stock prices and analyst ratings")

7.4 Toolkit Parameters and Surface Reduction ​

Toolkits are not black boxes — most expose constructor parameters to control behavior, and support unified reduction of exposed functions. Using DuckDuckGoTools as an example:

python
# toolkit_params.py —— Precisely control toolkit behavior
from agno.tools.duckduckgo import DuckDuckGoTools

tools = DuckDuckGoTools(
    enable_news=False,       # Disable news search, keep only web_search
    fixed_max_results=3,     # Cap results at 3
    region="cn-zh",          # Region setting
    timeout=15,              # Timeout in seconds
)

Additionally, the Agent level has two universal parameters to further narrow the exposure surface:

python
agent = Agent(
    # ...model config as above...
    tools=[YFinanceTools(all=True)],
    include_tools=["get_current_stock_price"],  # Whitelist only these functions
    # exclude_tools=["get_company_profile"],    # Or exclude specific functions
)

Why reduce the tool surface

The more tools exposed, the harder it is for the model to choose, and the higher the mis-call rate (the official docs explicitly state "Expose only the tools needed for the task"). In production, an Agent with 2 well-chosen tools is almost always more reliable than one with 20 scattered tools.

7.5 Tool Execution Controls ​

Agno provides a set of fine-grained controls. Here we cover the two most common; the rest (human confirmation, external execution) are covered in Chapter 21 on Guardrails:

ConfigPurpose
tool_call_limit=NCap the max number of tool calls per run to prevent infinite loops burning tokens
read_chat_history=TrueGive the model an extra get_chat_history() tool for on-demand history lookback
Inject run_context into toolsFramework auto-injects runtime context (user, session state, etc.); never enters the model schema

run_context is the key to understanding subsequent chapters (session state): as long as the tool function declares this parameter, Agno auto-passes it at execution time, and does not count it in the model-visible parameters:

python
# run_context_demo.py —— Framework-injected hidden parameter
import os
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.run import RunContext


def who_is_calling(run_context: RunContext) -> str:
    """Get the current user id of this session."""
    # run_context is injected by the framework; the model cannot see it
    return f"Current user: {run_context.user_id or 'anonymous'}"


agent = Agent(
    model=OpenAIChat(
        id="deepseek-chat",
        api_key=os.getenv("DEEPSEEK_API_KEY"),
        base_url="https://api.deepseek.com/v1",
    ),
    tools=[who_is_calling],
)

agent.print_response("Who am I?", user_id="gao", session_id="s1")

Other built-in injected parameters include agent, team, and images / videos / audios / files (access to multimodal inputs carried in this run).

Chapter Summary ​

  • Tools = Python functions registered with an Agent; execution is a "request → execute →回填 → reason again" loop;
  • Function name + docstring + type annotations together form the model-visible tool schema; quality of all three directly determines call reliability;
  • Built-in Toolkits are ready out of the box (DuckDuckGoTools, YFinanceTools, etc.); constructor params allow precise control;
  • Reduce exposure with include_tools / exclude_tools; fewer tools are better;
  • v2+ inspect tool calls with debug_mode=True (show_tool_calls removed); run_context: RunContext is a framework-injected hidden parameter.

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. What does Agno use to generate a tool schema from a plain Python function?

2. To inspect an Agent's tool call process in Agno, what is the correct approach?

3. Regarding declaring run_context: RunContext in a tool, which statement is correct?

4. An Agent has 20 tools but the model frequently picks the wrong one. What is the most effective fix?

🛠️ Hands-On Exercises ​

  1. Write a word_count(text: str) -> dict tool (count characters/words); have the Agent answer "how many words in this passage" via it; capture a full tool-call loop log with debug_mode=True.
  2. Install ddgs; build a "daily tech news" Agent with DuckDuckGoTools(fixed_max_results=3) that requires citing source links in answers.
  3. Add tool_call_limit=3 to the Agent from section 7.5; then deliberately ask a question that tempts continuous searches (e.g., "look up stock prices for 5 companies in sequence"); observe the Agent's behavior after hitting the cap.

After completing the hands-on exercises, proceed to Chapter 8: Custom Tools and Toolkit Development.