Better agent execution error handling (#54)

A few quality of life improvements around cache handling and repeated tool usage
This commit is contained in:
João Moura
2024-01-05 11:04:59 -03:00
committed by GitHub
parent 6b054651a7
commit 3f9c4df32d
16 changed files with 38 additions and 43 deletions

View File

@@ -1,4 +1,4 @@
from .cache_handler import CacheHandler from .cache.cache_handler import CacheHandler
from .executor import CrewAgentExecutor from .executor import CrewAgentExecutor
from .output_parser import CrewAgentOutputParser from .output_parser import CrewAgentOutputParser
from .tools_handler import ToolsHandler from .tools_handler import ToolsHandler

2
crewai/agents/cache/__init__.py vendored Normal file
View File

@@ -0,0 +1,2 @@
from .cache_handler import CacheHandler
from .cache_hit import CacheHit

View File

@@ -0,0 +1,20 @@
from langchain_core.exceptions import OutputParserException
class TaskRepeatedUsageException(OutputParserException):
"""Exception raised when a task is used twice in a roll."""
error: str = "TaskRepeatedUsageException"
message: str = "\nI just used the {tool} tool with input {tool_input}. So I already know the result of that.\n"
def __init__(self, tool: str, tool_input: str):
self.tool = tool
self.tool_input = tool_input
self.message = self.message.format(tool=tool, tool_input=tool_input)
super().__init__(
error=self.error, observation=self.message, send_to_llm=True, llm_output=""
)
def __str__(self):
return self.message

View File

@@ -9,7 +9,7 @@ from langchain_core.exceptions import OutputParserException
from langchain_core.tools import BaseTool from langchain_core.tools import BaseTool
from ..tools.cache_tools import CacheTools from ..tools.cache_tools import CacheTools
from .cache_hit import CacheHit from .cache.cache_hit import CacheHit
class CrewAgentExecutor(AgentExecutor): class CrewAgentExecutor(AgentExecutor):

View File

@@ -3,10 +3,9 @@ from typing import Union
from langchain.agents.output_parsers import ReActSingleInputOutputParser from langchain.agents.output_parsers import ReActSingleInputOutputParser
from langchain_core.agents import AgentAction, AgentFinish from langchain_core.agents import AgentAction, AgentFinish
from langchain_core.exceptions import OutputParserException
from .cache_handler import CacheHandler from .cache import CacheHandler, CacheHit
from .cache_hit import CacheHit from .exceptions import TaskRepeatedUsageException
from .tools_handler import ToolsHandler from .tools_handler import ToolsHandler
FINAL_ANSWER_ACTION = "Final Answer:" FINAL_ANSWER_ACTION = "Final Answer:"
@@ -67,9 +66,7 @@ class CrewAgentOutputParser(ReActSingleInputOutputParser):
"input": tool_input, "input": tool_input,
} }
if usage == last_tool_usage: if usage == last_tool_usage:
raise OutputParserException( raise TaskRepeatedUsageException(tool=action, tool_input=tool_input)
f"""\nI just used the {action} tool with input {tool_input}. So I already know the result of that."""
)
result = self.cache.read(action, tool_input) result = self.cache.read(action, tool_input)
if result: if result:

View File

@@ -3,7 +3,7 @@ from typing import Any, Dict
from langchain.callbacks.base import BaseCallbackHandler from langchain.callbacks.base import BaseCallbackHandler
from ..tools.cache_tools import CacheTools from ..tools.cache_tools import CacheTools
from .cache_handler import CacheHandler from .cache.cache_handler import CacheHandler
class ToolsHandler(BaseCallbackHandler): class ToolsHandler(BaseCallbackHandler):

View File

@@ -1,24 +0,0 @@
import uuid
from typing import Optional
from pydantic import UUID4, BaseModel, Field, field_validator
from pydantic_core import PydanticCustomError
class CrewAIBaseModel(BaseModel):
"""Base model with unique identifier."""
__hash__ = object.__hash__
id: UUID4 = Field(
default_factory=uuid.uuid4,
frozen=True,
description="Unique identifier for the object, not set by user.",
)
@field_validator("id", mode="before")
@classmethod
def _deny_user_set_id(cls, v: Optional[UUID4]) -> None:
if v:
raise PydanticCustomError(
"may_not_set_field", "This field is not to be set by the user.", {}
)

View File

@@ -15,7 +15,7 @@ from pydantic import (
from pydantic_core import PydanticCustomError from pydantic_core import PydanticCustomError
from crewai.agent import Agent from crewai.agent import Agent
from crewai.agents import CacheHandler from crewai.agents.cache import CacheHandler
from crewai.process import Process from crewai.process import Process
from crewai.task import Task from crewai.task import Task
from crewai.tools.agent_tools import AgentTools from crewai.tools.agent_tools import AgentTools

View File

@@ -53,10 +53,10 @@ class AgentTools(BaseModel):
try: try:
agent, task, information = command.split("|") agent, task, information = command.split("|")
except ValueError: except ValueError:
return "\nError executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|task|information`." return "\nError executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|task|information`.\n"
if not agent or not task or not information: if not agent or not task or not information:
return "\nError executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|question|information`." return "\nError executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|question|information`.\n"
agent = [ agent = [
available_agent available_agent
@@ -65,7 +65,7 @@ class AgentTools(BaseModel):
] ]
if len(agent) == 0: if len(agent) == 0:
return f"\nError executing tool. Co-worker mentioned on the Action Input not found, it must to be one of the following options: {', '.join([agent.role for agent in self.agents])}." return f"\nError executing tool. Co-worker mentioned on the Action Input not found, it must to be one of the following options: {', '.join([agent.role for agent in self.agents])}.\n"
agent = agent[0] agent = agent[0]
result = agent.execute_task(task, information) result = agent.execute_task(task, information)

View File

@@ -1,7 +1,7 @@
from langchain.tools import Tool from langchain.tools import Tool
from pydantic import BaseModel, ConfigDict, Field from pydantic import BaseModel, ConfigDict, Field
from crewai.agents import CacheHandler from crewai.agents.cache import CacheHandler
class CacheTools(BaseModel): class CacheTools(BaseModel):

View File

@@ -4,7 +4,7 @@ import pytest
from langchain.chat_models import ChatOpenAI as OpenAI from langchain.chat_models import ChatOpenAI as OpenAI
from crewai.agent import Agent from crewai.agent import Agent
from crewai.agents import CacheHandler from crewai.agents.cache import CacheHandler
def test_agent_creation(): def test_agent_creation():

View File

@@ -48,7 +48,7 @@ def test_delegate_work_with_wrong_input():
assert ( assert (
result result
== "\nError executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|task|information`." == "\nError executing tool. Missing exact 3 pipe (|) separated values. For example, `coworker|task|information`.\n"
) )
@@ -59,7 +59,7 @@ def test_delegate_work_to_wrong_agent():
assert ( assert (
result result
== "\nError executing tool. Co-worker mentioned on the Action Input not found, it must to be one of the following options: researcher." == "\nError executing tool. Co-worker mentioned on the Action Input not found, it must to be one of the following options: researcher.\n"
) )
@@ -70,5 +70,5 @@ def test_ask_question_to_wrong_agent():
assert ( assert (
result result
== "\nError executing tool. Co-worker mentioned on the Action Input not found, it must to be one of the following options: researcher." == "\nError executing tool. Co-worker mentioned on the Action Input not found, it must to be one of the following options: researcher.\n"
) )

View File

@@ -5,7 +5,7 @@ import json
import pytest import pytest
from crewai.agent import Agent from crewai.agent import Agent
from crewai.agents import CacheHandler from crewai.agents.cache import CacheHandler
from crewai.crew import Crew from crewai.crew import Crew
from crewai.process import Process from crewai.process import Process
from crewai.task import Task from crewai.task import Task