Browse Source

Remove isinstance check from FunctionTool (#3987) (#4056)

* Remove isinstance check from FunctionTool (#3987)

* Move __init__ Args to class docstring

---------

Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
tags/v0.4.0.dev4
Gerardo Moreno GitHub 1 year ago
parent
commit
eca8a95c61
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
3 changed files with 72 additions and 4 deletions
  1. +13
    -1
      python/packages/autogen-core/docs/src/user-guide/core-user-guide/framework/tools.ipynb
  2. +46
    -2
      python/packages/autogen-core/src/autogen_core/components/tools/_function_tool.py
  3. +13
    -1
      python/packages/autogen-core/tests/test_tools.py

+ 13
- 1
python/packages/autogen-core/docs/src/user-guide/core-user-guide/framework/tools.ipynb View File

@@ -59,6 +59,13 @@
"print(code_execution_tool.return_value_as_string(result))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
@@ -82,6 +89,11 @@
"To create a custom function tool, you just need to create a Python function\n",
"and use the {py:class}`~autogen_core.components.tools.FunctionTool` class to wrap it.\n",
"\n",
"The {py:class}`~autogen_core.components.tools.FunctionTool` class uses descriptions and type annotations\n",
"to inform the LLM when and how to use a given function. The description provides context\n",
"about the function’s purpose and intended use cases, while type annotations inform the LLM about\n",
"the expected parameters and return type.\n",
"\n",
"For example, a simple tool to obtain the stock price of a company might look like this:"
]
},
@@ -296,7 +308,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.9"
"version": "3.12.7"
}
},
"nbformat": 4,


+ 46
- 2
python/packages/autogen-core/src/autogen_core/components/tools/_function_tool.py View File

@@ -13,6 +13,52 @@ from ._base import BaseTool


class FunctionTool(BaseTool[BaseModel, BaseModel]):
"""
Create custom tools by wrapping standard Python functions.

`FunctionTool` offers an interface for executing Python functions either asynchronously or synchronously.
Each function must include type annotations for all parameters and its return type. These annotations
enable `FunctionTool` to generate a schema necessary for input validation, serialization, and for informing
the LLM about expected parameters. When the LLM prepares a function call, it leverages this schema to
generate arguments that align with the function's specifications.

.. note::

It is the user's responsibility to verify that the tool's output type matches the expected type.

Args:
func (Callable[..., ReturnT | Awaitable[ReturnT]]): The function to wrap and expose as a tool.
description (str): A description to inform the model of the function's purpose, specifying what
it does and the context in which it should be called.
name (str, optional): An optional custom name for the tool. Defaults to
the function's original name if not provided.

Example:

.. code-block:: python

import random
from autogen_core.base import CancellationToken
from autogen_core.components.tools import FunctionTool
from typing_extensions import Annotated


async def get_stock_price(ticker: str, date: Annotated[str, "Date in YYYY/MM/DD"]) -> float:
# Simulates a stock price retrieval by returning a random float within a specified range.
return random.uniform(10, 200)


# Initialize a FunctionTool instance for retrieving stock prices.
stock_price_tool = FunctionTool(get_stock_price, description="Fetch the stock price for a given ticker.")

# Execute the tool with cancellation support.
cancellation_token = CancellationToken()
result = await stock_price_tool.run_json({"ticker": "AAPL", "date": "2021/01/01"}, cancellation_token)

# Output the result as a formatted string.
print(stock_price_tool.return_value_as_string(result))
"""

def __init__(self, func: Callable[..., Any], description: str, name: str | None = None) -> None:
self._func = func
signature = get_typed_signature(func)
@@ -46,6 +92,4 @@ class FunctionTool(BaseTool[BaseModel, BaseModel]):
cancellation_token.link_future(future)
result = await future

if not isinstance(result, self.return_type()):
raise ValueError(f"Expected return type {self.return_type()}, got {type(result)}")
return result

+ 13
- 1
python/packages/autogen-core/tests/test_tools.py View File

@@ -1,5 +1,5 @@
import inspect
from typing import Annotated
from typing import Annotated, List

import pytest
from autogen_core.base import CancellationToken
@@ -324,3 +324,15 @@ def test_convert_tools_accepts_both_tool_and_schema() -> None:

assert len(converted_tool_schema) == 2
assert converted_tool_schema[0] == converted_tool_schema[1]


@pytest.mark.asyncio
async def test_func_tool_return_list() -> None:
def my_function() -> List[int]:
return [1, 2]

tool = FunctionTool(my_function, description="Function tool.")
result = await tool.run_json({}, CancellationToken())
assert isinstance(result, list)
assert result == [1, 2]
assert tool.return_value_as_string(result) == "[1, 2]"

Loading…
Cancel
Save