Skip to content
Snippets Groups Projects
Unverified Commit 0becb754 authored by Ming's avatar Ming Committed by GitHub
Browse files

ReAct Agent should be informed when it tried to use a non-existent tool (#12207)

* ReAct Agents should know when it tried to use a non-existent tool

* ignore the storage folder

* async
parent d740d9d8
No related branches found
No related tags found
No related merge requests found
llama_index/core/_static llama_index/core/_static
storage/
.DS_Store .DS_Store
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
......
...@@ -232,24 +232,27 @@ class ReActAgentWorker(BaseAgentWorker): ...@@ -232,24 +232,27 @@ class ReActAgentWorker(BaseAgentWorker):
# call tool with input # call tool with input
reasoning_step = cast(ActionReasoningStep, current_reasoning[-1]) reasoning_step = cast(ActionReasoningStep, current_reasoning[-1])
tool = tools_dict[reasoning_step.action] if reasoning_step.action in tools_dict:
with self.callback_manager.event( tool = tools_dict[reasoning_step.action]
CBEventType.FUNCTION_CALL, with self.callback_manager.event(
payload={ CBEventType.FUNCTION_CALL,
EventPayload.FUNCTION_CALL: reasoning_step.action_input, payload={
EventPayload.TOOL: tool.metadata, EventPayload.FUNCTION_CALL: reasoning_step.action_input,
}, EventPayload.TOOL: tool.metadata,
) as event: },
try: ) as event:
tool_output = tool.call(**reasoning_step.action_input) try:
except Exception as e: tool_output = tool.call(**reasoning_step.action_input)
tool_output = ToolOutput( except Exception as e:
content=f"Error: {e!s}", tool_output = ToolOutput(
tool_name=tool.metadata.name, content=f"Error: {e!s}",
raw_input={"kwargs": reasoning_step.action_input}, tool_name=tool.metadata.name,
raw_output=e, raw_input={"kwargs": reasoning_step.action_input},
) raw_output=e,
event.on_end(payload={EventPayload.FUNCTION_OUTPUT: str(tool_output)}) )
event.on_end(payload={EventPayload.FUNCTION_OUTPUT: str(tool_output)})
else:
tool_output = self._handle_nonexistent_tool_name(reasoning_step)
task.extra_state["sources"].append(tool_output) task.extra_state["sources"].append(tool_output)
...@@ -276,24 +279,27 @@ class ReActAgentWorker(BaseAgentWorker): ...@@ -276,24 +279,27 @@ class ReActAgentWorker(BaseAgentWorker):
# call tool with input # call tool with input
reasoning_step = cast(ActionReasoningStep, current_reasoning[-1]) reasoning_step = cast(ActionReasoningStep, current_reasoning[-1])
tool = tools_dict[reasoning_step.action] if reasoning_step.action in tools_dict:
with self.callback_manager.event( tool = tools_dict[reasoning_step.action]
CBEventType.FUNCTION_CALL, with self.callback_manager.event(
payload={ CBEventType.FUNCTION_CALL,
EventPayload.FUNCTION_CALL: reasoning_step.action_input, payload={
EventPayload.TOOL: tool.metadata, EventPayload.FUNCTION_CALL: reasoning_step.action_input,
}, EventPayload.TOOL: tool.metadata,
) as event: },
try: ) as event:
tool_output = await tool.acall(**reasoning_step.action_input) try:
except Exception as e: tool_output = await tool.acall(**reasoning_step.action_input)
tool_output = ToolOutput( except Exception as e:
content=f"Error: {e!s}", tool_output = ToolOutput(
tool_name=tool.metadata.name, content=f"Error: {e!s}",
raw_input={"kwargs": reasoning_step.action_input}, tool_name=tool.metadata.name,
raw_output=e, raw_input={"kwargs": reasoning_step.action_input},
) raw_output=e,
event.on_end(payload={EventPayload.FUNCTION_OUTPUT: str(tool_output)}) )
event.on_end(payload={EventPayload.FUNCTION_OUTPUT: str(tool_output)})
else:
tool_output = self._handle_nonexistent_tool_name(reasoning_step)
task.extra_state["sources"].append(tool_output) task.extra_state["sources"].append(tool_output)
...@@ -303,6 +309,26 @@ class ReActAgentWorker(BaseAgentWorker): ...@@ -303,6 +309,26 @@ class ReActAgentWorker(BaseAgentWorker):
print_text(f"{observation_step.get_content()}\n", color="blue") print_text(f"{observation_step.get_content()}\n", color="blue")
return current_reasoning, False return current_reasoning, False
def _handle_nonexistent_tool_name(self, reasoning_step):
# We still emit a `tool_output` object to the task, so that the LLM can know
# it has hallucinated in the next reasoning step.
with self.callback_manager.event(
CBEventType.FUNCTION_CALL,
payload={
EventPayload.FUNCTION_CALL: reasoning_step.action_input,
},
) as event:
# TODO(L10N): This should be localized.
content = f"Error: No such tool named `{reasoning_step.action}`."
tool_output = ToolOutput(
content=content,
tool_name=reasoning_step.action,
raw_input={"kwargs": reasoning_step.action_input},
raw_output=content,
)
event.on_end(payload={EventPayload.FUNCTION_OUTPUT: str(tool_output)})
return tool_output
def _get_response( def _get_response(
self, self,
current_reasoning: List[BaseReasoningStep], current_reasoning: List[BaseReasoningStep],
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment