core[major]: only use function description (#21622)

Do not prefix function signature

---

* Reason for this is that information is already present with tool
calling models.
* This will save on tokens for those models, and makes it more obvious
what the description is!
* The @tool can get more parameters to allow a user to re-introduce the
the signature if we want
This commit is contained in:
Eugene Yurtsev
2024-05-16 11:17:53 -04:00
committed by GitHub
parent 8498b41cda
commit 6ed0aa3239
4 changed files with 37 additions and 15 deletions

View File

@@ -837,8 +837,7 @@ class StructuredTool(BaseTool):
# Description example:
# search_api(query: str) - Searches the API for the query.
sig = signature(source_function)
description_ = f"{name}{sig} - {description_.strip()}"
description_ = f"{description_.strip()}"
_args_schema = args_schema
if _args_schema is None and infer_schema:
# schema name is appended within function
@@ -1057,7 +1056,16 @@ def render_text_description(tools: List[BaseTool]) -> str:
search: This tool is used for search
calculator: This tool is used for math
"""
return "\n".join([f"{tool.name}: {tool.description}" for tool in tools])
descriptions = []
for tool in tools:
if hasattr(tool, "func") and tool.func:
sig = signature(tool.func)
description = f"{tool.name}{sig} - {tool.description}"
else:
description = f"{tool.name} - {tool.description}"
descriptions.append(description)
return "\n".join(descriptions)
def render_text_description_and_args(tools: List[BaseTool]) -> str:
@@ -1074,7 +1082,12 @@ args: {"expression": {"type": "string"}}
tool_strings = []
for tool in tools:
args_schema = str(tool.args)
tool_strings.append(f"{tool.name}: {tool.description}, args: {args_schema}")
if hasattr(tool, "func") and tool.func:
sig = signature(tool.func)
description = f"{tool.name}{sig} - {tool.description}"
else:
description = f"{tool.name} - {tool.description}"
tool_strings.append(f"{description}, args: {args_schema}")
return "\n".join(tool_strings)

View File

@@ -332,9 +332,8 @@ def test_structured_tool_from_function_docstring() -> None:
"required": ["bar", "baz"],
}
prefix = "foo(bar: int, baz: str) -> str - "
assert foo.__doc__ is not None
assert structured_tool.description == prefix + textwrap.dedent(foo.__doc__.strip())
assert structured_tool.description == textwrap.dedent(foo.__doc__.strip())
def test_structured_tool_from_function_docstring_complex_args() -> None:
@@ -365,9 +364,8 @@ def test_structured_tool_from_function_docstring_complex_args() -> None:
"required": ["bar", "baz"],
}
prefix = "foo(bar: int, baz: List[str]) -> str - "
assert foo.__doc__ is not None
assert structured_tool.description == prefix + textwrap.dedent(foo.__doc__).strip()
assert structured_tool.description == textwrap.dedent(foo.__doc__).strip()
def test_structured_tool_lambda_multi_args_schema() -> None:
@@ -700,9 +698,8 @@ def test_structured_tool_from_function() -> None:
"required": ["bar", "baz"],
}
prefix = "foo(bar: int, baz: str) -> str - "
assert foo.__doc__ is not None
assert structured_tool.description == prefix + textwrap.dedent(foo.__doc__.strip())
assert structured_tool.description == textwrap.dedent(foo.__doc__.strip())
def test_validation_error_handling_bool() -> None:
@@ -906,3 +903,15 @@ async def test_async_tool_pass_context() -> None:
assert (
await foo.ainvoke({"bar": "baz"}, {"configurable": {"foo": "not-bar"}}) == "baz" # type: ignore
)
def test_tool_description() -> None:
def foo(bar: str) -> str:
"""The foo."""
return bar
foo1 = tool(foo)
assert foo1.description == "The foo." # type: ignore
foo2 = StructuredTool.from_function(foo)
assert foo2.description == "The foo."