-
Notifications
You must be signed in to change notification settings - Fork 27.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Decorator for easier tool building #33439
Conversation
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
a1522dd
to
86aa070
Compare
cc @Rocketknight1 |
86aa070
to
98f5463
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👌
tests/agents/test_final_answer.py
Outdated
|
||
if is_torch_available(): | ||
import torch | ||
|
||
|
||
class FinalAnswerToolTester(unittest.TestCase, ToolTesterMixin): | ||
class FinalAnswerToolTester(unittest.TestCase): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expected to remove the tool tester mixin here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had removed it because FinalAnswerTool does not need the input/output type testing that other tools do need, but indeed we can keep it (and it may be useful if some tests are added to `ToolTes) so I added it back!
56abb9b
to
d6f703f
Compare
4ade18f
to
66d5283
Compare
f5e5d0c
to
43fdb5f
Compare
src/transformers/agents/tools.py
Outdated
def tool(tool_function: Callable) -> Tool: | ||
""" | ||
Decorator that turns a function into an instance of a specific Tool subclass | ||
|
||
Args: | ||
tool_function: Your function. Should have type hints for each input and a type hint for the output. | ||
Should also have a docstring description including an 'Args:' part where each argument is described. | ||
""" | ||
parameters = get_json_schema(tool_function)["function"] | ||
if "return" not in parameters: | ||
raise TypeHintParsingException("Tool return type not found: make sure your function has a return type hint!") | ||
class_name = f"{parameters['name'].capitalize()}Tool" | ||
|
||
class SpecificTool(Tool): | ||
name = parameters["name"] | ||
description = parameters["description"] | ||
inputs = parameters["parameters"]["properties"] | ||
output_type = parameters["return"]["type"] | ||
|
||
@wraps(tool_function) | ||
def forward(self, *args, **kwargs): | ||
return tool_function(*args, **kwargs) | ||
|
||
original_signature = inspect.signature(tool_function) | ||
new_parameters = [inspect.Parameter("self", inspect.Parameter.POSITIONAL_OR_KEYWORD)] + list( | ||
original_signature.parameters.values() | ||
) | ||
new_signature = original_signature.replace(parameters=new_parameters) | ||
SpecificTool.forward.__signature__ = new_signature | ||
|
||
SpecificTool.__name__ = class_name | ||
return SpecificTool() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We discussed this a little on Slack but I've been thinking about it: Do you think users will get confused because of the different approaches taken in chat templates / agents?
Chat templates: Tools are passed as JSON schema. Users can also directly pass Python functions, and these will be automatically converted to JSON schema.
Agents: Tools are passed as Tool
objects. Users can convert functions to Tool
objects using the @tool
decorator.
Do we need both approaches? We could have a more unified API by, for example, removing the tool
decorator and instead converting functions to Tool
objects if they're passed to agents, the same way we do in chat templates. That way, even if the internal objects are different, the API for users would be the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for taking a look @Rocketknight1 !
So it seems to me that a fundamental difference is that in Chat templates, you can pass a JSON scheme : this is completely impossible for our tools since the JSON cannot encode the internal logic of the tool's forward pass.
But we can add the functionality to accept raw functions as tools, and only convert them to tools upon agent initialization! So we would support both Tool
objects and passing raw functions.
I think we can keep supporting the decorator as well, since applying a decorator directly to the tool has the advantage to let the users try out the tool before it's passed to the agent initialization (which I personnally often do to make sure they work properly). Anyway this decorator is just the tool
function, which we will need in any case for converting functions to Tools.
So I'd say let's keep the usage of tool
as a decorator and add support for raw functions on agent initialization (which will also use tool
behind the hood for conversion to Tool
objects)! Wdyt as well @LysandreJik ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok let's merge this for now, since the solution you propose @Rocketknight1 only needs to add support for raw functions in the tools
list upon agent initialization, which we can do in a later PR!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure!
ab80049
to
d42c4e4
Compare
d42c4e4
to
1004967
Compare
* Decorator for tool building
* Decorator for tool building
* Decorator for tool building
* Decorator for tool building
What does this PR do?
We need an easier way to create tools than the heavy Tool class : but at the same time this class is useful since it's flexible. Se I just add a
@tool
decorator to make it easy to create a tool from a function, provided that it has the proper type hints and description.