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.
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.
Quick Start
- 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?") - 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?") - 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.") - 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?
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 toolHow It Works
| Phase | What happens |
|---|---|
| 1. Discover | Agent receives tool definitions alongside the user request |
| 2. Decide | LLM chooses whether to call a tool |
| 3. Execute | Agent runs the tool and captures the result |
| 4. Synthesize | LLM uses the tool result to form the final answer |
Common Patterns
Pattern 1 — Web research agent
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
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
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
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.
Declare a tool needs human sign-off in one line
Pattern 5 — Guard one tool’s arguments or result
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.
| Option | Type | Fires | Description | |
|---|---|---|---|---|
approval | bool | before the call | Pause and ask a human before the tool runs. See Tool Approval. | |
trust | str | on the result | Wrap external tool output in a prompt-injection fence. | |
input_guardrails | `callable \ | list` | before the call | Validate or rewrite the arguments before the tool runs. See Per-Tool Guardrails. |
output_guardrails | `callable \ | list` | on the raw result | Validate or substitute the result before it re-enters the LLM context. See 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.
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.