Disclaimer: The notes below may refer to the TypeScript version or missing files as the Python version moves toward parity in the near future. Additional Python examples coming soon. TODO
Tip
Location within the framework beeai/tools
.
Tools in the context of an agent refer to additional functionalities or capabilities integrated with the agent to perform specific tasks beyond text processing.
These tools extend the agent's abilities, allowing it to interact with external systems, access information, and execute actions.
Name | Description |
---|---|
PythonTool |
Run arbitrary Python code in the remote environment. |
WikipediaTool |
Search for data on Wikipedia. |
GoogleSearchTool |
Search for data on Google using Custom Search Engine. |
DuckDuckGoTool |
Search for data on DuckDuckGo. |
SearXNGTool |
Privacy-respecting, hackable metasearch engine. |
SQLTool |
Execute SQL queries against relational databases. |
ElasticSearchTool |
Perform search or aggregation queries against an ElasticSearch database. |
CustomTool |
Run your own Python function in the remote environment. |
LLMTool |
Use an LLM to process input data. |
DynamicTool |
Construct to create dynamic tools. |
ArXivTool |
Retrieve research articles published on arXiv. |
WebCrawlerTool |
Retrieve content of an arbitrary website. |
OpenMeteoTool |
Retrieve current, previous, or upcoming weather for a given destination. |
MilvusDatabaseTool |
Perform retrieval queries (search, insert, delete, manage collections) against a MilvusDatabaseTool database. |
OpenAPITool |
Send requests to and receive responses from API server. |
MCPTool |
Discover and use tools exposed by arbitrary MCP Server. |
➕ Request |
All examples can be found here.
Tip
Would you like to use a tool from LangChain? See the example.
_Source: /examples/tools/base.py TODO
_Source: /examples/tools/advanced.py TODO
Tip
To learn more about caching, refer to the Cache documentation page.
_Source: agent.py TODO
import asyncio
import json
from urllib.parse import quote
import requests
from beeai_framework import BeeAgent, tool
from beeai_framework.agents.types import BeeInput, BeeRunInput
from beeai_framework.backend.chat import ChatModel
from beeai_framework.memory.unconstrained_memory import UnconstrainedMemory
from beeai_framework.tools.tool import StringToolOutput
from beeai_framework.utils import BeeLogger
logger = BeeLogger(__name__)
# defining a tool using the `tool` decorator
@tool
def basic_calculator(expression: str) -> int:
"""
A calculator tool that performs mathematical operations.
Args:
expression: The mathematical expression to evaluate (e.g., "2 + 3 * 4").
Returns:
The result of the mathematical expression
"""
try:
encoded_expression = quote(expression)
math_url = f"https://newton.vercel.app/api/v2/simplify/{encoded_expression}"
response = requests.get(
math_url,
headers={"Accept": "application/json"},
)
response.raise_for_status()
return StringToolOutput(json.dumps(response.json()))
except Exception as e:
raise RuntimeError(f"Error evaluating expression: {e!s}") from Exception
async def main() -> None:
# using the tool in an agent
chat_model = ChatModel.from_name("ollama:granite3.1-dense:8b")
agent = BeeAgent(BeeInput(llm=chat_model, tools=[basic_calculator], memory=UnconstrainedMemory()))
result = await agent.run(BeeRunInput(prompt="What is the square root of 36?"))
print(result.result.text)
if __name__ == "__main__":
asyncio.run(main())
Source: examples/tools/decorator.py
import asyncio
from beeai_framework.agents.bee import BeeAgent
from beeai_framework.agents.types import BeeInput, BeeRunInput
from beeai_framework.backend.chat import ChatModel
from beeai_framework.memory import UnconstrainedMemory
from beeai_framework.tools.search.duckduckgo import DuckDuckGoSearchTool
async def main() -> None:
chat_model = ChatModel.from_name("ollama:granite3.1-dense:8b")
agent = BeeAgent(BeeInput(llm=chat_model, tools=[DuckDuckGoSearchTool()], memory=UnconstrainedMemory()))
result = await agent.run(BeeRunInput(prompt="How tall is the mount Everest?"))
print(result.result.text)
if __name__ == "__main__":
asyncio.run(main())
Source: examples/tools/duckduckgo.py
import asyncio
from beeai_framework.agents.bee import BeeAgent
from beeai_framework.agents.types import BeeInput, BeeRunInput
from beeai_framework.backend.chat import ChatModel
from beeai_framework.memory import UnconstrainedMemory
from beeai_framework.tools.weather.openmeteo import OpenMeteoTool
async def main() -> None:
llm = ChatModel.from_name("ollama:granite3.1-dense:8b")
agent = BeeAgent(BeeInput(llm=llm, tools=[OpenMeteoTool()], memory=UnconstrainedMemory()))
result = await agent.run(BeeRunInput(prompt="What's the current weather in Las Vegas?"))
print(result.result.text)
if __name__ == "__main__":
asyncio.run(main())
Source: examples/tools/openmeteo.py
To create a new tool, you have the following options on how to do that:
- Implement the base
Tool TODO
class. - Initiate the
DynamicTool TODO
by passing your own handler (function) with thename
,description
andinput schema
. - Initiate the
CustomTool TODO
by passing your own Python function (code interpreter needed).
The recommended and most sustainable way to create a tool is by implementing the base Tool
class.
_Source: /examples/tools/custom/base.py TODO
Tip
inputSchema
can be asynchronous.
Tip
If you want to return an array or a plain object, use JSONToolOutput
or implement your own.
If your tool is more complex, you may want to use the full power of the tool abstraction, as the following example shows.
_Source: examples/tools/custom/openLibrary.py TODO
-
Implement the
Tool
class:-
MyNewToolOutput
is required, must be an implementation ofToolOutput
such asStringToolOutput
orJSONToolOutput
. -
ToolOptions
is optional (default BaseToolOptions), constructor parameters that are passed during tool creation -
ToolRunOptions
is optional (default BaseToolRunOptions), optional parameters that are passed to the run method
-
-
Be given a unique name:
Note: Convention and best practice is to set the tool's name to the name of its class
name = "MyNewTool"
-
Provide a natural language description of what the tool does:
❗Important: the agent uses this description to determine when the tool should be used. It's probably the most important aspect of your tool and you should experiment with different natural language descriptions to ensure the tool is used in the correct circumstances. You can also include usage tips and guidance for the agent in the description, but its advisable to keep the description succinct in order to reduce the probability of conflicting with other tools, or adversely affecting agent behavior.
description = "Takes X action when given Y input resulting in Z output"
-
Declare an input schema:
This is used to define the format of the input to your tool. The agent will formalise the natural language input(s) it has received and structure them into the fields described in the tool's input. The input schema can be specified using Zod (recommended) or JSONSchema. It must be a function (either sync or async). Zod effects (e.g.
z.object().transform(...)
) are not supported. The return value ofinputSchema
must always be an object and pass validation by thevalidateSchema()
function defined in schema.py TODO. Keep your tool input schema simple and provide schema descriptions to help the agent to interpret fields.Coming soon
-
Implement initialisation:
The unnamed static block is executed when your tool is called for the first time. It is used to register your tool as
serializable
(you can then use theserialize()
method).Coming soon
-
Implement the
_run()
method:Coming soon
The DynamicTool
allows you to create a tool without extending the base tool class.
_Source: /examples/tools/custom/dynamic.py TODO
The name
of the tool is required and must only contain characters between
a-z, A-Z, 0-9, or one of - or _.
The inputSchema
and description
are also both required.
If you want to use the Python function, use the CustomTool
.
_Source: /examples/tools/custom/python.py TODO
Tip
Environmental variables can be overridden (or defined) in the following ways:
- During the creation of a
CustomTool
, either via the constructor or the factory function (CustomTool.fromSourceCode
). - By passing them directly as part of the options when invoking:
myTool.run({ ... }, { env: { MY_ENV: 'MY_VALUE' } })
. - Dynamically during execution via
Emitter
:myTool.emitter.on("start", ({ options }) => { options.env.MY_ENV = 'MY_VALUE'; })
.
Important
Custom tools are executed within the code interpreter, but they cannot access any files.
Only PythonTool
does.
The MCPTool
allows you to instantiate tools given a connection to MCP server with tools capability.
_Source: /examples/tools/mcp.py TODO
If your tool is providing data to the agent, try to ensure that the data is relevant and free of extraneous metatdata. Preprocessing data to improve relevance and minimize unnecessary data conserves agent memory, improving overall performance.
If your tool encounters an error that is fixable, you can return a hint to the agent; the agent will try to reuse the tool in the context of the hint. This can improve the agent's ability to recover from errors.
When building tools, consider that the tool is being invoked by a somewhat unpredictable third party (the agent). You should ensure that sufficient guardrails are in place to prevent adverse outcomes.