Skip to content

Commit

Permalink
docs: enhance decorator documentation and update LLM syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
tonykipkemboi committed Jan 10, 2025
1 parent 2131b94 commit 831951e
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 82 deletions.
5 changes: 2 additions & 3 deletions docs/concepts/planning.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,22 @@ From this point on, your crew will have planning enabled, and the tasks will be

#### Planning LLM

Now you can define the LLM that will be used to plan the tasks. You can use any ChatOpenAI LLM model available.
Now you can define the LLM that will be used to plan the tasks.

When running the base case example, you will see something like the output below, which represents the output of the `AgentPlanner`
responsible for creating the step-by-step logic to add to the Agents' tasks.

<CodeGroup>
```python Code
from crewai import Crew, Agent, Task, Process
from langchain_openai import ChatOpenAI

# Assemble your crew with planning capabilities and custom LLM
my_crew = Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
planning=True,
planning_llm=ChatOpenAI(model="gpt-4o")
planning_llm="gpt-4o"
)

# Run the crew
Expand Down
6 changes: 2 additions & 4 deletions docs/concepts/processes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ Processes enable individual agents to operate as a cohesive unit, streamlining t
To assign a process to a crew, specify the process type upon crew creation to set the execution strategy. For a hierarchical process, ensure to define `manager_llm` or `manager_agent` for the manager agent.

```python
from crewai import Crew
from crewai.process import Process
from langchain_openai import ChatOpenAI
from crewai import Crew, Process

# Example: Creating a crew with a sequential process
crew = Crew(
Expand All @@ -40,7 +38,7 @@ crew = Crew(
agents=my_agents,
tasks=my_tasks,
process=Process.hierarchical,
manager_llm=ChatOpenAI(model="gpt-4")
manager_llm="gpt-4o"
# or
# manager_agent=my_manager_agent
)
Expand Down
4 changes: 2 additions & 2 deletions docs/how-to/custom-manager-agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ result = crew.kickoff()
If you're using the hierarchical process and don't want to set a custom manager agent, you can specify the language model for the manager:

```python Code
from langchain_openai import ChatOpenAI
from crewai import LLM

manager_llm = ChatOpenAI(model_name="gpt-4")
manager_llm = LLM(model="gpt-4o")

crew = Crew(
agents=[researcher, writer],
Expand Down
234 changes: 161 additions & 73 deletions docs/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -75,56 +75,6 @@ Follow the steps below to get crewing! 🚣‍♂️
```
</Step>
<Step title="Modify your `crew.py` file">
```python crew.py
# src/latest_ai_development/crew.py
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai_tools import SerperDevTool
@CrewBase
class LatestAiDevelopmentCrew():
"""LatestAiDevelopment crew"""
@agent
def researcher(self) -> Agent:
return Agent(
config=self.agents_config['researcher'],
verbose=True,
tools=[SerperDevTool()]
)

@agent
def reporting_analyst(self) -> Agent:
return Agent(
config=self.agents_config['reporting_analyst'],
verbose=True
)

@task
def research_task(self) -> Task:
return Task(
config=self.tasks_config['research_task'],
)

@task
def reporting_task(self) -> Task:
return Task(
config=self.tasks_config['reporting_task'],
output_file='output/report.md' # This is the file that will be contain the final report.
)

@crew
def crew(self) -> Crew:
"""Creates the LatestAiDevelopment crew"""
return Crew(
agents=self.agents, # Automatically created by the @agent decorator
tasks=self.tasks, # Automatically created by the @task decorator
process=Process.sequential,
verbose=True,
)
```
</Step>
<Step title="[Optional] Add before and after crew functions">
```python crew.py
# src/latest_ai_development/crew.py
from crewai import Agent, Crew, Process, Task
Expand All @@ -145,6 +95,16 @@ Follow the steps below to get crewing! 🚣‍♂️
print(f"After kickoff function with result: {result}")
return result # You can return the result or modify it as needed
@callback
def log_progress(self, task: Task, output: str):
"""Log task completion progress."""
print(f"\n{'='*50}")
print(f"Task Completed: {task.description}")
print(f"Agent: {task.agent.role}")
print(f"Output Length: {len(output)} characters")
print(f"Completed at: {datetime.now().isoformat()}")
print(f"{'='*50}\n")

# ... remaining code
```
</Step>
Expand Down Expand Up @@ -301,38 +261,166 @@ Use the annotations to properly reference the agent and task in the `crew.py` fi

### Annotations include:

* `@agent`
* `@task`
* `@crew`
* `@tool`
* `@before_kickoff`
* `@after_kickoff`
* `@callback`
* `@output_json`
* `@output_pydantic`
* `@cache_handler`

```python crew.py
# ...
Here are examples of how to use each annotation in your CrewAI project, and when you should use them:

#### @agent
Used to define an agent in your crew. Use this when:
- You need to create a specialized AI agent with a specific role
- You want the agent to be automatically collected and managed by the crew
- You need to reuse the same agent configuration across multiple tasks

```python
@agent
def email_summarizer(self) -> Agent:
def research_agent(self) -> Agent:
return Agent(
config=self.agents_config["email_summarizer"],
role="Research Analyst",
goal="Conduct thorough research on given topics",
backstory="Expert researcher with years of experience in data analysis",
tools=[SerperDevTool()],
verbose=True
)
```

#### @task
Used to define a task that can be executed by agents. Use this when:
- You need to define a specific piece of work for an agent
- You want tasks to be automatically sequenced and managed
- You need to establish dependencies between different tasks

```python
@task
def email_summarizer_task(self) -> Task:
def research_task(self) -> Task:
return Task(
config=self.tasks_config["email_summarizer_task"],
description="Research the latest developments in AI technology",
expected_output="A comprehensive report on AI advancements",
agent=self.research_agent(),
output_file="output/research.md"
)
# ...
```

<Tip>
In addition to the [sequential process](../how-to/sequential-process), you can use the [hierarchical process](../how-to/hierarchical-process),
which automatically assigns a manager to the defined crew to properly coordinate the planning and execution of tasks through delegation and validation of results.
You can learn more about the core concepts [here](/concepts).
</Tip>
#### @crew
Used to define your crew configuration. Use this when:
- You want to automatically collect all @agent and @task definitions
- You need to specify how tasks should be processed (sequential or hierarchical)
- You want to set up crew-wide configurations

```python
@crew
def research_crew(self) -> Crew:
return Crew(
agents=self.agents, # Automatically collected from @agent methods
tasks=self.tasks, # Automatically collected from @task methods
process=Process.sequential,
verbose=True
)
```

#### @tool
Used to create custom tools for your agents. Use this when:
- You need to give agents specific capabilities (like web search, data analysis)
- You want to encapsulate external API calls or complex operations
- You need to share functionality across multiple agents

```python
@tool
def web_search_tool(query: str, max_results: int = 5) -> list[str]:
"""
Search the web for information.
Args:
query: The search query
max_results: Maximum number of results to return
Returns:
List of search results
"""
# Implement your search logic here
return [f"Result {i} for: {query}" for i in range(max_results)]
```

#### @before_kickoff
Used to execute logic before the crew starts. Use this when:
- You need to validate or preprocess input data
- You want to set up resources or configurations before execution
- You need to perform any initialization logic

```python
@before_kickoff
def validate_inputs(self, inputs: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
"""Validate and preprocess inputs before the crew starts."""
if inputs is None:
return None
if 'topic' not in inputs:
raise ValueError("Topic is required")
# Add additional context
inputs['timestamp'] = datetime.now().isoformat()
inputs['topic'] = inputs['topic'].strip().lower()
return inputs
```

#### @after_kickoff
Used to process results after the crew completes. Use this when:
- You need to format or transform the final output
- You want to perform cleanup operations
- You need to save or log the results in a specific way

```python
@after_kickoff
def process_results(self, result: CrewOutput) -> CrewOutput:
"""Process and format the results after the crew completes."""
result.raw = result.raw.strip()
result.raw = f"""
# Research Results
Generated on: {datetime.now().isoformat()}
{result.raw}
"""
return result
```

#### @callback
Used to handle events during crew execution. Use this when:
- You need to monitor task progress
- You want to log intermediate results
- You need to implement custom progress tracking or metrics

```python
@callback
def log_task_completion(self, task: Task, output: str):
"""Log task completion details for monitoring."""
print(f"Task '{task.description}' completed")
print(f"Output length: {len(output)} characters")
print(f"Agent used: {task.agent.role}")
print("-" * 50)
```

#### @cache_handler
Used to implement custom caching for task results. Use this when:
- You want to avoid redundant expensive operations
- You need to implement custom cache storage or expiration logic
- You want to persist results between runs

```python
@cache_handler
def custom_cache(self, key: str) -> Optional[str]:
"""Custom cache implementation for storing task results."""
cache_file = f"cache/{key}.json"
if os.path.exists(cache_file):
with open(cache_file, 'r') as f:
data = json.load(f)
# Check if cache is still valid (e.g., not expired)
if datetime.fromisoformat(data['timestamp']) > datetime.now() - timedelta(days=1):
return data['result']
return None
```

<Note>
These decorators are part of the CrewAI framework and help organize your crew's structure by automatically collecting agents, tasks, and handling various lifecycle events.
They should be used within a class decorated with `@CrewBase`.
</Note>

### Replay Tasks from Latest Crew Kickoff

Expand Down

0 comments on commit 831951e

Please sign in to comment.