first stab at early concepts

This commit is contained in:
Joao Moura
2023-10-29 19:51:59 -03:00
parent 6d08ac3229
commit 308349442c
12 changed files with 1720 additions and 1 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
.DS_Store
.pytest_cache
__pycache__
dist/

View File

@@ -1 +1,51 @@
# CrewAI # CrewAI
## Virtual Env
```bash
poetry shell
```
## Running Tests
```bash
poetry run pytest
```
## Packaging
```bash
poetry build
```
### Installing Locally
```bash
pip install dist/*.tar.gz
```
# CrewAI
## Why?
## How?
## What is it?
Convention?
Convention of Roles
Convention over Tools
Convention over interactions (In what ways agents interact, how flexible, conversation patterns, where these happen [in a room, in isolation])
Convention over degree of guidance
You must be able to bring any tools <- Convention over tools
How does it compare to autogen?
Autogen is good to create conversational agents, these agents can then work
together autonomously, but there is no concepts of process, a process would need
to be programatically added.
ChatDev brings the idea of processes to the AI Agents but it's stiff and it's
customizations are not meant to be deployed at production settings
CrewAI is a python library that provide modules to build crews of AI Agents tha
What is the interface to interact with CrewAI?

0
__init__.py Normal file
View File

2
crewai/__init__.py Normal file
View File

@@ -0,0 +1,2 @@
from .crew import Crew
from .agent import Agent

48
crewai/agent.py Normal file
View File

@@ -0,0 +1,48 @@
"""Generic agent."""
from typing import List, Any
from pydantic import BaseModel, Field
from langchain.tools import Tool
from langchain.agents import AgentExecutor
from langchain.chat_models import ChatOpenAI as OpenAI
from langchain.tools.render import render_text_description
from langchain.agents.format_scratchpad import format_log_to_str
from langchain.agents.output_parsers import ReActSingleInputOutputParser
from .prompts import AGENT_EXECUTION_PROMPT
class Agent(BaseModel):
role: str = Field(description="Role of the agent")
goal: str = Field(description="Objective of the agent")
backstory: str = Field(description="Backstory of the agent")
tools: List[Tool] = Field(description="Tools at agents disposal")
llm: str = Field(description="LLM of the agent", default=OpenAI(
temperature=0.7,
model="gpt-4",
verbose=True
))
def execute(self, task: str) -> str:
prompt = AGENT_EXECUTION_PROMPT.partial(
tools=render_text_description(self.tools),
tool_names=self.__tools_names(),
backstory=self.backstory,
role=self.role,
goal=self.goal,
)
return self.__run(task, prompt, self.tools)
def __run(self, input: str, prompt: str, tools: List[Tool]) -> str:
chat_with_bind = self.llm.bind(stop=["\nObservation"])
agent = {
"input": lambda x: x["input"],
"agent_scratchpad": lambda x: format_log_to_str(x['intermediate_steps'])
} | prompt | chat_with_bind | ReActSingleInputOutputParser()
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, handle_parsing_errors=True)
return agent_executor.invoke({"input": input})['output']
def __tools_names(self) -> str:
return ", ".join([t.name for t in self.tools])

7
crewai/crew.py Normal file
View File

@@ -0,0 +1,7 @@
"""Crew of agents."""
from pydantic import BaseModel, Field
class Crew(BaseModel):
description: str = Field(description="Description and of the crew being created.")
goal: str = Field(description="Objective of the crew being created.")

39
crewai/prompts.py Normal file
View File

@@ -0,0 +1,39 @@
"""Prompts for generic agent."""
from langchain.prompts import PromptTemplate
AGENT_EXECUTION_PROMPT = PromptTemplate.from_template(
"""You are {role}.
{backstory}
Your main goal is: {goal}
TOOLS:
------
You have access to the following tools:
{tools}
To use a tool, please use the following format:
```
Thought: Do I need to use a tool? Yes
Action: the action to take, should be one of [{tool_names}]
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]
```
Begin!
Current Task: {input}
{agent_scratchpad}
"""
)

1409
poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

20
pyproject.toml Normal file
View File

@@ -0,0 +1,20 @@
[tool.poetry]
name = "crewai"
version = "0.1.0"
description = ""
authors = ["Joao Moura <joaomdmoura@gmail.com>"]
readme = "README.md"
[tool.poetry.dependencies]
python = ">=3.8.1,<4.0"
pydantic = "^2.4.2"
langchain = "^0.0.314"
openai = "^0.28.1"
[tool.poetry.group.test.dependencies]
pytest = "^7.4"
pytest-vcr = "^1.0.2"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

0
tests/__init__.py Normal file
View File

46
tests/agent_test.py Normal file
View File

@@ -0,0 +1,46 @@
"""Test Agent creation and execution basic functionality."""
import pytest
from langchain.chat_models import ChatOpenAI as OpenAI
from ..crewai import Agent
from ..crewai import prompts
def test_agent_creation():
agent = Agent(
role="test role",
goal="test goal",
backstory="test backstory",
tools=[],
)
assert agent.role == "test role"
assert agent.goal == "test goal"
assert agent.backstory == "test backstory"
assert agent.tools == []
def test_agent_default_value():
agent = Agent(
role="test role",
goal="test goal",
backstory="test backstory",
tools=[],
)
assert isinstance(agent.llm, OpenAI)
assert agent.llm.model_name == "gpt-4"
assert agent.llm.temperature == 0.7
assert agent.llm.verbose == True
@pytest.mark.vcr()
def test_agent_execution():
agent = Agent(
role="test role",
goal="test goal",
backstory="test backstory",
tools=[],
)
output = agent.execute("How much is 1 + 1?")
assert output == "2"

View File

@@ -0,0 +1,94 @@
interactions:
- request:
body: '{"messages": [{"role": "user", "content": "You are test role.\ntest backstory\n\nYour
main goal is: test goal\n\nTOOLS:\n------\n\nYou have access to the following
tools:\n\n\n\nTo use a tool, please use the following format:\n\n```\nThought:
Do I need to use a tool? Yes\nAction: the action to take, should be one of []\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]\n```\n\nBegin!\n\nCurrent Task: How much is 1 + 1?\n\n"}],
"model": "gpt-4", "max_tokens": null, "stream": false, "n": 1, "temperature":
0.7, "stop": ["\nObservation"]}'
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
Authorization:
- Bearer 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
Connection:
- keep-alive
Content-Length:
- '758'
Content-Type:
- application/json
User-Agent:
- OpenAI/v1 PythonBindings/0.28.1
X-OpenAI-Client-User-Agent:
- '{"bindings_version": "0.28.1", "httplib": "requests", "lang": "python", "lang_version":
"3.9.7", "platform": "macOS-10.16-x86_64-i386-64bit", "publisher": "openai",
"uname": "Darwin 22.4.0 Darwin Kernel Version 22.4.0: Mon Mar 6 21:00:17
PST 2023; root:xnu-8796.101.5~3/RELEASE_X86_64 x86_64"}'
method: POST
uri: https://api.openai.com/v1/chat/completions
response:
body:
string: !!binary |
H4sIAAAAAAAAA1SQS0/DMBCE7/kVqz23KGmbkOaCgCoSHCohcQNUGWdJXBxviLfipf535PTJxYf5
dsaz+xsBoKmwANSNEt12dpyXORuh2U/9vUiXDzflVOLSre8/ktssx1Fw8OuatBxcF5rbzpIYdjus
e1JCITXJ5nmWzNN4NoCWK7LBVncyno3jLJnuHQ0bTR4LeIoAAH6HN3RzFX1hAfHooLTkvaoJi+MQ
APZsg4LKe+NFOcHRCWp2Qm6o+9jwpm6kgAXDHTiiCoRh4wkUCLO9giU/u9I4ZeHa+U/qC5jgPmp7
7PBmnPHNqifl2YVcL9ztxrYRwMuw0+ZfTex6bjtZCb+TC4smabrLw9P5zujlHgqLsuf6JAqfbKM/
AAAA//8DAD/1vhO7AQAA
headers:
CF-Cache-Status:
- DYNAMIC
CF-RAY:
- 81def25b4addf8f1-NVT
Cache-Control:
- no-cache, must-revalidate
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Sun, 29 Oct 2023 22:45:05 GMT
Server:
- cloudflare
Transfer-Encoding:
- chunked
access-control-allow-origin:
- '*'
alt-svc:
- h3=":443"; ma=86400
openai-model:
- gpt-4-0613
openai-organization:
- clearbit-2
openai-processing-ms:
- '950'
openai-version:
- '2020-10-01'
strict-transport-security:
- max-age=15724800; includeSubDomains
x-ratelimit-limit-requests:
- '100'
x-ratelimit-limit-tokens:
- '150000'
x-ratelimit-remaining-requests:
- '99'
x-ratelimit-remaining-tokens:
- '149840'
x-ratelimit-reset-requests:
- 600ms
x-ratelimit-reset-tokens:
- 64ms
x-request-id:
- b6484701bea444a976e49f353baf7be5
status:
code: 200
message: OK
version: 1