Skip to content

Commit

Permalink
Reliability improvements (#77)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
joaomdmoura authored Jan 7, 2024
1 parent 234a2c7 commit 7954f6b
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 123 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ __pycache__
dist/
.env
assets/*
.idea
.idea
test.py
44 changes: 22 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,14 @@ pip install duckduckgo-search
import os
from crewai import Agent, Task, Crew, Process

os.environ["OPENAI_API_KEY"] = "YOUR KEY"

# You can choose to use a local model through Ollama for example.
# In this case we will use OpenHermes 2.5 as an example.
#
# from langchain.llms import Ollama
# ollama_llm = Ollama(model="openhermes")

# If you are using an ollama like above you don't need to set OPENAI_API_KEY.
os.environ["OPENAI_API_KEY"] = "Your Key"

# Define your tools, custom or not.
# Install duckduckgo-search for this example:
#
# !pip install -U duckduckgo-search

from langchain.tools import DuckDuckGoSearchRun
Expand All @@ -65,50 +61,54 @@ search_tool = DuckDuckGoSearchRun()
researcher = Agent(
role='Senior Research Analyst',
goal='Uncover cutting-edge developments in AI and data science in',
backstory="""You are a Senior Research Analyst at a leading tech think tank.
Your expertise lies in identifying emerging trends and technologies in AI and
data science. You have a knack for dissecting complex data and presenting
backstory="""You work at a leading tech think tank.
Your expertise lies in identifying emerging trends.
You have a knack for dissecting complex data and presenting
actionable insights.""",
verbose=True,
allow_delegation=False,
tools=[search_tool]
# (optional) llm=ollama_llm, If you wanna use a local modal through Ollama, default is GPT4 with temperature=0.7

# You can pass an optional llm attribute specifying what mode you wanna use.
# It can be a local model through Ollama / LM Studio or a remote
# model like OpenAI, Mistral, Antrophic of others (https://python.langchain.com/docs/integrations/llms/)
#
# Examples:
# llm=ollama_llm # was defined above in the file
# llm=ChatOpenAI(model_name="gpt-3.5", temperature=0.7)
)
writer = Agent(
role='Tech Content Strategist',
goal='Craft compelling content on tech advancements',
backstory="""You are a renowned Tech Content Strategist, known for your insightful
and engaging articles on technology and innovation. With a deep understanding of
the tech industry, you transform complex concepts into compelling narratives.""",
backstory="""You are a renowned Content Strategist, known for
your insightful and engaging articles.
You transform complex concepts into compelling narratives.""",
verbose=True,
# (optional) llm=ollama_llm, If you wanna use a local modal through Ollama, default is GPT4 with temperature=0.7
allow_delegation=True
allow_delegation=True,
# (optional) llm=ollama_llm
)

# Create tasks for your agents
task1 = Task(
description="""Conduct a comprehensive analysis of the latest advancements in AI in 2024.
Identify key trends, breakthrough technologies, and potential industry impacts.
Compile your findings in a detailed report. Your final answer MUST be a full analysis report""",
Your final answer MUST be a full analysis report""",
agent=researcher
)

task2 = Task(
description="""Using the insights from the researcher's report, develop an engaging blog
description="""Using the insights provided, develop an engaging blog
post that highlights the most significant AI advancements.
Your post should be informative yet accessible, catering to a tech-savvy audience.
Aim for a narrative that captures the essence of these breakthroughs and their
implications for the future. Your final answer MUST be the full blog post of at least 3 paragraphs.""",
Make it sound cool, avoid complex words so it doesn't sound like AI.
Your final answer MUST be the full blog post of at least 4 paragraphs.""",
agent=writer
)

# Instantiate your crew with a sequential process
crew = Crew(
agents=[researcher, writer],
tasks=[task1, task2],
verbose=2, # Crew verbose more will let you know what tasks are being worked on, you can set it to 1 or 2 to different logging levels
process=Process.sequential # Sequential process will have tasks executed one after the other and the outcome of the previous one is passed as extra content into this next.
verbose=2, # You can set it to 1 or 2 to different logging levels
)

# Get your crew to work!
Expand Down
4 changes: 2 additions & 2 deletions crewai/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ def __create_agent_executor(self) -> CrewAgentExecutor:
)
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,
Expand Down
18 changes: 9 additions & 9 deletions crewai/crew.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,21 +111,21 @@ def __sequential_loop(self) -> str:
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"""
Expand Down
111 changes: 40 additions & 71 deletions crewai/prompts.py
Original file line number Diff line number Diff line change
@@ -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.",
)

SCRATCHPAD_SLICE: ClassVar[str] = "\n{agent_scratchpad}"

MEMORY_SLICE: ClassVar[str] = dedent(
"""\
This is the summary of your work so far:
{chat_history}"""
)

ROLE_PLAYING_SLICE: ClassVar[str] = dedent(
"""\
You are {role}.
{backstory}
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:
@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")

```
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
```
with open(prompts_path, "r") as f:
self._prompts = json.load(f)["slices"]
return self

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
)
SCRATCHPAD_SLICE: ClassVar[str] = "\n{agent_scratchpad}"

CONSENSUNS_VOTING_PROMPT: ClassVar[str] = PromptTemplate.from_template(
ROLE_PLAYING_SLICE + VOTING_SLICE + TASK_SLICE + SCRATCHPAD_SLICE
)
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
)

def task_execution_without_tools(self) -> str:
return PromptTemplate.from_template(
self._prompts["role_playing"]
+ self._prompts["task"]
+ self.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 changes: 8 additions & 0 deletions crewai/prompts/en.json
Original file line number Diff line number Diff line change
@@ -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]"
}
}
9 changes: 8 additions & 1 deletion crewai/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from pydantic_core import PydanticCustomError

from crewai.agent import Agent
from crewai.tasks.task_output import TaskOutput


class Task(BaseModel):
Expand All @@ -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,
Expand Down Expand Up @@ -46,9 +50,12 @@ def execute(self, context: str = None) -> str:
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."
Expand Down
17 changes: 17 additions & 0 deletions crewai/tasks/task_output.py
Original file line number Diff line number Diff line change
@@ -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
18 changes: 9 additions & 9 deletions crewai/tools/agent_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


class AgentTools(BaseModel):
"""Tools for generic agent."""
"""Default tools around agent delegation"""

agents: List[Agent] = Field(description="List of agents in this crew.")

Expand All @@ -20,12 +20,12 @@ def tools(self):
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(
Expand All @@ -34,12 +34,12 @@ def tools(self):
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`.
"""
"""
),
),
]
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

[tool.poetry]
name = "crewai"
version = "0.1.16"
version = "0.1.23"
description = "Cutting-edge framework for orchestrating role-playing, autonomous AI agents. By fostering collaborative intelligence, CrewAI empowers agents to work together seamlessly, tackling complex tasks."
authors = ["Joao Moura <[email protected]>"]
readme = "README.md"
Expand Down
Loading

0 comments on commit 7954f6b

Please sign in to comment.