Reliability improvements (#77)

* fixing identation for AgentTools
* updating gitignore to exclude quick test script
* startingprompt translation
* supporting individual task output
* adding agent to task output
* cutting new version
* Updating README example
This commit is contained in:
João Moura
2024-01-07 12:43:23 -03:00
committed by GitHub
parent 234a2c72b0
commit 7954f6b51c
11 changed files with 124 additions and 122 deletions

View File

@@ -155,9 +155,9 @@ class Agent(BaseModel):
)
executor_args["memory"] = summary_memory
agent_args["chat_history"] = lambda x: x["chat_history"]
prompt = Prompts.TASK_EXECUTION_WITH_MEMORY_PROMPT
prompt = Prompts().task_execution_with_memory()
else:
prompt = Prompts.TASK_EXECUTION_PROMPT
prompt = Prompts().task_execution()
execution_prompt = prompt.partial(
goal=self.goal,

View File

@@ -111,21 +111,21 @@ class Crew(BaseModel):
Returns:
Output of the crew.
"""
task_outcome = None
task_output = None
for task in self.tasks:
# Add delegation tools to the task if the agent allows it
if task.agent.allow_delegation:
tools = AgentTools(agents=self.agents).tools()
task.tools += tools
agent_tools = AgentTools(agents=self.agents).tools()
task.tools += agent_tools
self.__log("debug", f"Working Agent: {task.agent.role}")
self.__log("info", f"Starting Task: {task.description} ...")
self.__log("info", f"Starting Task: {task.description}")
task_outcome = task.execute(task_outcome)
self.__log("debug", f"Task output: {task_outcome}")
return task_outcome
task_output = task.execute(task_output)
self.__log(
"debug", f"\n\n[{task.agent.role}] Task output: {task_output}\n\n"
)
return task_output
def __log(self, level, message):
"""Log a message"""

View File

@@ -1,84 +1,53 @@
"""Prompts for generic agent."""
from textwrap import dedent
from typing import ClassVar
import json
import os
from typing import ClassVar, Dict, Optional
from langchain.prompts import PromptTemplate
from pydantic import BaseModel
from pydantic import BaseModel, Field, PrivateAttr, model_validator
class Prompts(BaseModel):
"""Prompts for generic agent."""
TASK_SLICE: ClassVar[str] = dedent(
"""\
Begin! This is VERY important to you, your job depends on it!
Current Task: {input}"""
_prompts: Optional[Dict[str, str]] = PrivateAttr()
language: Optional[str] = Field(
default="en",
description="Language of crewai prompts.",
)
@model_validator(mode="after")
def load_prompts(self) -> "Prompts":
"""Load prompts from file."""
dir_path = os.path.dirname(os.path.realpath(__file__))
prompts_path = os.path.join(dir_path, f"prompts/{self.language}.json")
with open(prompts_path, "r") as f:
self._prompts = json.load(f)["slices"]
return self
SCRATCHPAD_SLICE: ClassVar[str] = "\n{agent_scratchpad}"
MEMORY_SLICE: ClassVar[str] = dedent(
"""\
This is the summary of your work so far:
{chat_history}"""
)
def task_execution_with_memory(self) -> str:
return PromptTemplate.from_template(
self._prompts["role_playing"]
+ self._prompts["tools"]
+ self._prompts["memory"]
+ self._prompts["task"]
+ self.SCRATCHPAD_SLICE
)
ROLE_PLAYING_SLICE: ClassVar[str] = dedent(
"""\
You are {role}.
{backstory}
def task_execution_without_tools(self) -> str:
return PromptTemplate.from_template(
self._prompts["role_playing"]
+ self._prompts["task"]
+ self.SCRATCHPAD_SLICE
)
Your personal goal is: {goal}"""
)
TOOLS_SLICE: ClassVar[str] = dedent(
"""\
TOOLS:
------
You have access to the following tools:
{tools}
To use a tool, please use the exact following format:
```
Thought: Do I need to use a tool? Yes
Action: the action to take, should be one of [{tool_names}], just the name.
Action Input: the input to the action
Observation: the result of the action
```
When you have a response for your task, or if you do not need to use a tool, you MUST use the format:
```
Thought: Do I need to use a tool? No
Final Answer: [your response here]
```"""
)
VOTING_SLICE: ClassVar[str] = dedent(
"""\
You are working on a crew with your co-workers and need to decide who will execute the task.
These are your format instructions:
{format_instructions}
These are your co-workers and their roles:
{coworkers}"""
)
TASK_EXECUTION_WITH_MEMORY_PROMPT: ClassVar[str] = PromptTemplate.from_template(
ROLE_PLAYING_SLICE + TOOLS_SLICE + MEMORY_SLICE + TASK_SLICE + SCRATCHPAD_SLICE
)
TASK_EXECUTION_PROMPT: ClassVar[str] = PromptTemplate.from_template(
ROLE_PLAYING_SLICE + TOOLS_SLICE + TASK_SLICE + SCRATCHPAD_SLICE
)
CONSENSUNS_VOTING_PROMPT: ClassVar[str] = PromptTemplate.from_template(
ROLE_PLAYING_SLICE + VOTING_SLICE + TASK_SLICE + SCRATCHPAD_SLICE
)
def task_execution(self) -> str:
return PromptTemplate.from_template(
self._prompts["role_playing"]
+ self._prompts["tools"]
+ self._prompts["task"]
+ self.SCRATCHPAD_SLICE
)

8
crewai/prompts/en.json Normal file
View File

@@ -0,0 +1,8 @@
{
"slices": {
"task": "Begin! This is VERY important to you, your job depends on it!\n\nCurrent Task: {input}",
"memory": "This is the summary of your work so far:\n{chat_history}",
"role_playing": "You are {role}.\n{backstory}\n\nYour personal goal is: {goal}",
"tools": "TOOLS:\n------\nYou have access to the following tools:\n\n{tools}\n\nTo use a tool, please use the exact following format:\n\n```\nThought: Do I need to use a tool? Yes\nAction: the action to take, should be one of [{tool_names}], just the name.\nAction Input: the input to the action\nObservation: the result of the action\n```\n\nWhen you have a response for your task, or if you do not need to use a tool, you MUST use the format:\n\n```\nThought: Do I need to use a tool? No\nFinal Answer: [your response here]"
}
}

View File

@@ -5,6 +5,7 @@ from pydantic import UUID4, BaseModel, Field, field_validator, model_validator
from pydantic_core import PydanticCustomError
from crewai.agent import Agent
from crewai.tasks.task_output import TaskOutput
class Task(BaseModel):
@@ -19,6 +20,9 @@ class Task(BaseModel):
default_factory=list,
description="Tools the agent are limited to use for this task.",
)
output: Optional[TaskOutput] = Field(
description="Task output, it's final result.", default=None
)
id: UUID4 = Field(
default_factory=uuid.uuid4,
frozen=True,
@@ -46,9 +50,12 @@ class Task(BaseModel):
Output of the task.
"""
if self.agent:
return self.agent.execute_task(
result = self.agent.execute_task(
task=self.description, context=context, tools=self.tools
)
self.output = TaskOutput(description=self.description, result=result)
return result
else:
raise Exception(
f"The task '{self.description}' has no agent assigned, therefore it can't be executed directly and should be executed in a Crew using a specific process that support that, either consensual or hierarchical."

View File

@@ -0,0 +1,17 @@
from typing import Optional
from pydantic import BaseModel, Field, model_validator
class TaskOutput(BaseModel):
"""Class that represents the result of a task."""
description: str = Field(description="Description of the task")
summary: Optional[str] = Field(description="Summary of the task", default=None)
result: str = Field(description="Result of the task")
@model_validator(mode="after")
def set_summary(self):
excerpt = " ".join(self.description.split(" ")[0:10])
self.summary = f"{excerpt}..."
return self

View File

@@ -8,7 +8,7 @@ from crewai.agent import Agent
class AgentTools(BaseModel):
"""Tools for generic agent."""
"""Default tools around agent delegation"""
agents: List[Agent] = Field(description="List of agents in this crew.")
@@ -20,12 +20,12 @@ class AgentTools(BaseModel):
description=dedent(
f"""\
Useful to delegate a specific task to one of the
following co-workers: [{', '.join([agent.role for agent in self.agents])}].
The input to this tool should be a pipe (|) separated text of length
three, representing the co-worker you want to ask it to (one of the options),
following co-workers: [{', '.join([agent.role for agent in self.agents])}].
The input to this tool should be a pipe (|) separated text of length
three, representing the co-worker you want to ask it to (one of the options),
the task and all actual context you have for the task.
For example, `coworker|task|context`.
"""
"""
),
),
Tool.from_function(
@@ -34,12 +34,12 @@ class AgentTools(BaseModel):
description=dedent(
f"""\
Useful to ask a question, opinion or take from on
of the following co-workers: [{', '.join([agent.role for agent in self.agents])}].
The input to this tool should be a pipe (|) separated text of length
three, representing the co-worker you want to ask it to (one of the options),
of the following co-workers: [{', '.join([agent.role for agent in self.agents])}].
The input to this tool should be a pipe (|) separated text of length
three, representing the co-worker you want to ask it to (one of the options),
the question and all actual context you have for the question.
For example, `coworker|question|context`.
"""
"""
),
),
]