fix crash when using create_xml_agent with parameterless function as … (#26002)

When using `create_xml_agent` or `create_json_chat_agent` to create a
agent, and the function corresponding to the tool is a parameterless
function, the `XMLAgentOutputParser` or `JSONAgentOutputParser` will
parse the tool input into an empty string, `BaseTool` will parse it into
a positional argument.
So, the program will crash finally because we invoke a parameterless
function but with a positional argument.Specially, below code will raise
StopIteration in
[_parse_input](https://github.com/langchain-ai/langchain/blob/master/libs/core/langchain_core/tools/base.py#L419)
```python
from langchain import hub
from langchain.agents import AgentExecutor, create_json_chat_agent, create_xml_agent
from langchain_openai import ChatOpenAI

prompt = hub.pull("hwchase17/react-chat-json")

llm = ChatOpenAI()

# agent = create_xml_agent(llm, tools, prompt)
agent = create_json_chat_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

agent_executor.invoke(......)
```

---------

Co-authored-by: Erick Friis <erick@langchain.dev>
Co-authored-by: Bagatur <22008038+baskaryan@users.noreply.github.com>
Co-authored-by: Chester Curme <chester.curme@gmail.com>
This commit is contained in:
Qun 2024-12-20 02:00:46 +08:00 committed by GitHub
parent f69695069d
commit 033ac41760
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 16 additions and 0 deletions

View File

@ -605,6 +605,9 @@ class ChildTool(BaseTool):
def _to_args_and_kwargs(
self, tool_input: Union[str, dict], tool_call_id: Optional[str]
) -> tuple[tuple, dict]:
if self.args_schema is not None and not get_fields(self.args_schema):
# StructuredTool with no args
return (), {}
tool_input = self._parse_input(tool_input, tool_call_id)
# For backwards compatibility, if run_input is a string,
# pass as a positional argument.

View File

@ -575,6 +575,19 @@ def test_structured_tool_from_function_with_run_manager() -> None:
)
def test_structured_tool_from_parameterless_function() -> None:
"""Test parameterless function of structured tool."""
def foo() -> str:
"""Docstring."""
return "invoke foo"
structured_tool = StructuredTool.from_function(foo)
assert structured_tool.run({}) == "invoke foo"
assert structured_tool.run("") == "invoke foo"
def test_named_tool_decorator() -> None:
"""Test functionality when arguments are provided as input to decorator."""