Tools

Give agents the ability to search the web, run code, read files, and call APIs

Tools give agents the ability to take actions — search the web, run code, read files, and call APIs — beyond what an LLM knows from training.

python
from praisonaiagents import Agent
from praisonaiagents.tools import duckduckgo

agent = Agent(
    name="Researcher",
    instructions="You are a research assistant. Use web search for current information.",
    tools=[duckduckgo],
)

agent.start("What are the latest developments in fusion energy?")

The user asks a research question; the agent calls web search and returns an answer grounded in live results.

Diagram

Tools Flow

Yes

No

💬 User Request

🤖 Agent

🧠 Need tool?

🔧 Tool

📄 Result

✅ Response

Quick Start

  1. Built-in Tools
    python
    from praisonaiagents import Agent
    from praisonaiagents.tools import duckduckgo
    
    agent = Agent(
        instructions="Search the web to answer questions.",
        tools=[duckduckgo],
    )
    agent.start("What is today's top AI news?")
  2. Custom Tool Function
    python
    from praisonaiagents import Agent
    
    def get_stock_price(ticker: str) -> str:
        """Get the current stock price for a ticker symbol."""
        return f"${ticker}: $150.25 (mock data)"
    
    agent = Agent(
        instructions="You are a finance assistant.",
        tools=[get_stock_price],
    )
    agent.start("What is the current price of AAPL?")
  3. Multiple Tools
    python
    from praisonaiagents import Agent
    from praisonaiagents.tools import duckduckgo, wikipedia
    
    agent = Agent(
        instructions="You are a comprehensive research assistant.",
        tools=[duckduckgo, wikipedia],
    )
    agent.start("Research the history and current state of quantum computing.")
  4. Async def tools work on both sync and async loops
    python
    from praisonaiagents import Agent
    
    async def fetch_weather(city: str) -> str:
        """Fetch current weather for a city."""
        # ... any awaitable work ...
        return f"Weather for {city}: 72°F, sunny"
    
    agent = Agent(
        name="Weather Agent",
        instructions="Answer weather questions using the tool.",
        tools=[fetch_weather],
    )
    
    # As of PraisonAI PR #4634, the sync tool loop awaits async def tools
    # automatically via the built-in bridge — the tool body actually runs
    # and the model receives its real return value. Before PR #4634 the
    # coroutine was returned un-awaited and the model saw an empty string.
    agent.start("What is the weather in New York?")

Which Tools to Use?

Diagram
graph TB
    Q{What does the agent need to do?}
    Q -->|Search current info| Web[duckduckgo / tavily\nweb search tools]
    Q -->|Read/write files| File[file tools\nread_file, write_file]
    Q -->|Run code| Code[code execution\nExecutionConfig(code_execution=True)]
    Q -->|Call external APIs| Custom[custom function\ndef my_tool(param) -> str]
    Q -->|MCP server tools| MCP[MCP integration\ndocs/features/mcp]

    classDef decision fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef tool fill:#6366F1,stroke:#7C90A0,color:#fff

    class Q decision
    class Web,File,Code,Custom,MCP tool

How It Works

Diagram
ToolLLMAgentUserToolLLMAgentUser“What’s today’s weather in Tokyo?”Prompt with tool definitionsTool call: get_weather(“Tokyo”)Execute get_weather(“Tokyo”)“15°C, partly cloudy”Continue with tool result“Today in Tokyo it’s 15°C…”“Today in Tokyo it’s 15°C…”
PhaseWhat happens
1. DiscoverAgent receives tool definitions alongside the user request
2. DecideLLM chooses whether to call a tool
3. ExecuteAgent runs the tool and captures the result
4. SynthesizeLLM uses the tool result to form the final answer

Common Patterns

Pattern 1 — Web research agent

python
from praisonaiagents import Agent
from praisonaiagents.tools import duckduckgo, wikipedia

agent = Agent(
    name="Researcher",
    instructions="You research topics using web search and Wikipedia.",
    tools=[duckduckgo, wikipedia],
)
response = agent.start("Explain the history of the Internet Protocol (TCP/IP).")
print(response)

Pattern 2 — Custom API tool

python
from praisonaiagents import Agent

def get_weather(city: str) -> str:
    """Fetch the current weather for a given city."""
    return f"{city}: 22°C, sunny (mock)"

def get_forecast(city: str, days: int = 3) -> str:
    """Get weather forecast for a city for the next N days."""
    return f"{city}: sunny for {days} days (mock)"

agent = Agent(
    instructions="You are a weather assistant.",
    tools=[get_weather, get_forecast],
)
agent.start("What's the weather in Paris and will it rain this week?")

Pattern 3 — Tool search for large toolsets

python
from praisonaiagents import Agent

agent = Agent(
    instructions="You have access to many tools. Use them as needed.",
    tools=[...],
    tool_search=True,
)
agent.start("Find the best tool for calculating compound interest.")

Pattern 4 — Gate a custom tool behind approval

python
from praisonaiagents import Agent, tool

@tool(approval=True)
def send_refund(order_id: str, amount: float) -> str:
    """Issue a refund on an order."""
    return f"Refunded {amount} for {order_id}"

agent = Agent(
    instructions="Help support agents process refunds.",
    tools=[send_refund],
)
agent.start("Refund $30 on order O-101")

Declare approval right on the @tool decorator — the agent pauses and asks a human before the tool runs. See Tool Approval.

Tool Approval

Declare a tool needs human sign-off in one line

Pattern 5 — Guard one tool’s arguments or result

python
from praisonaiagents import Agent, tool

def internal_recipients_only(arguments: dict):
    if not arguments.get("to", "").endswith("@corp.com"):
        return False, "Recipient is outside the company domain."
    return True, arguments

@tool(input_guardrails=[internal_recipients_only])
def send_email(to: str, body: str) -> str:
    """Send an email."""
    return f"sent to {to}"

agent = Agent(instructions="Send emails on request.", tools=[send_email])
agent.start("Email alice@gmail.com the release notes")

Declare input_guardrails= / output_guardrails= on the @tool decorator — alongside approval and trust — to validate, rewrite, or block just that one tool. A blocked call feeds a message back to the model rather than raising at the user.

OptionTypeFiresDescription
approvalboolbefore the callPause and ask a human before the tool runs. See Tool Approval.
truststron the resultWrap external tool output in a prompt-injection fence.
input_guardrails`callable \list`before the callValidate or rewrite the arguments before the tool runs. See Per-Tool Guardrails.
output_guardrails`callable \list`on the raw resultValidate or substitute the result before it re-enters the LLM context. See Per-Tool Guardrails.
Per-Tool Guardrails

Guard one tool’s arguments and results without hand-wrapping the function


Timeouts

Cap how long a tool may run with ToolConfig(timeout=...) — a stuck tool no longer hangs the agent.

python
from praisonaiagents import Agent, ToolConfig

agent = Agent(
    name="Runner",
    instructions="Call tools with a 10s ceiling.",
    tools=[my_slow_tool],
    tool_config=ToolConfig(timeout=10),
)

Best Practices

Write clear docstrings for custom tools

The LLM reads your tool’s docstring to decide when and how to use it. Write clear, specific descriptions: “Fetch the current stock price for a given ticker symbol (e.g., ‘AAPL’, ‘GOOGL’). Returns price in USD.”

Return strings from tools

Tools should return strings (or JSON-serializable data that gets converted to strings). Complex objects confuse the LLM — format results as readable text.

Use tool_search for large toolsets

When you have more than 10–15 tools, enable tool_search=True to let the agent dynamically find the right tools instead of sending all tool definitions with every request.

Set timeouts for external tools

Wrap external API calls with timeouts using ToolConfig(timeout=30). Without timeouts, a slow API can block the entire agent run.


Related