# Agents What are CrewAI Agents and how to use them. ## What is an agent? An agent is an **autonomous unit** programmed to: Think of an agent as a member of a team, with specific skills and a particular job to do. Agents can have different roles like `Researcher`, `Writer`, or `Customer Support`, each contributing to the overall goal of the crew. ## Agent attributes | Attribute | Parameter | Description | | :-------------------------------------- | :----------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Role** | `role` | Defines the agent's function within the crew. It determines the kind of tasks the agent is best suited for. | | **Goal** | `goal` | The individual objective that the agent aims to achieve. It guides the agent's decision-making process. | | **Backstory** | `backstory` | Provides context to the agent's role and goal, enriching the interaction and collaboration dynamics. | | **LLM** *(optional)* | `llm` | Represents the language model that will run the agent. It dynamically fetches the model name from the `OPENAI_MODEL_NAME` environment variable, defaulting to "gpt-4" if not specified. | | **Tools** *(optional)* | `tools` | Set of capabilities or functions that the agent can use to perform tasks. Expected to be instances of custom classes compatible with the agent's execution environment. Tools are initialized with a default value of an empty list. | | **Function Calling LLM** *(optional)* | `function_calling_llm` | Specifies the language model that will handle the tool calling for this agent, overriding the crew function calling LLM if passed. Default is `None`. | | **Max Iter** *(optional)* | `max_iter` | Max Iter is the maximum number of iterations the agent can perform before being forced to give its best answer. Default is `25`. | | **Max RPM** *(optional)* | `max_rpm` | Max RPM is the maximum number of requests per minute the agent can perform to avoid rate limits. It's optional and can be left unspecified, with a default value of `None`. | | **Max Execution Time** *(optional)* | `max_execution_time` | Max Execution Time is the maximum execution time for an agent to execute a task. It's optional and can be left unspecified, with a default value of `None`, meaning no max execution time. | | **Verbose** *(optional)* | `verbose` | Setting this to `True` configures the internal logger to provide detailed execution logs, aiding in debugging and monitoring. Default is `False`. | | **Allow Delegation** *(optional)* | `allow_delegation` | Agents can delegate tasks or questions to one another, ensuring that each task is handled by the most suitable agent. Default is `False`. | | **Step Callback** *(optional)* | `step_callback` | A function that is called after each step of the agent. This can be used to log the agent's actions or to perform other operations. It will overwrite the crew `step_callback`. | | **Cache** *(optional)* | `cache` | Indicates if the agent should use a cache for tool usage. Default is `True`. | | **System Template** *(optional)* | `system_template` | Specifies the system format for the agent. Default is `None`. | | **Prompt Template** *(optional)* | `prompt_template` | Specifies the prompt format for the agent. Default is `None`. | | **Response Template** *(optional)* | `response_template` | Specifies the response format for the agent. Default is `None`. | | **Allow Code Execution** *(optional)* | `allow_code_execution` | Enable code execution for the agent. Default is `False`. | | **Max Retry Limit** *(optional)* | `max_retry_limit` | Maximum number of retries for an agent to execute a task when an error occurs. Default is `2`. | | **Use System Prompt** *(optional)* | `use_system_prompt` | Adds the ability to not use system prompt (to support o1 models). Default is `True`. | | **Respect Context Window** *(optional)* | `respect_context_window` | Summary strategy to avoid overflowing the context window. Default is `True`. | | **Code Execution Mode** *(optional)* | `code_execution_mode` | Determines the mode for code execution: 'safe' (using Docker) or 'unsafe' (direct execution on the host machine). Default is `safe`. | ## Creating an agent **Agent interaction**: Agents can interact with each other using CrewAI's built-in delegation and communication mechanisms. This allows for dynamic task management and problem-solving within the crew. To create an agent, you would typically initialize an instance of the `Agent` class with the desired properties. Here's a conceptual example including all attributes: ```python Code example from crewai import Agent agent = Agent( role='Data Analyst', goal='Extract actionable insights', backstory="""You're a data analyst at a large company. You're responsible for analyzing data and providing insights to the business. You're currently working on a project to analyze the performance of our marketing campaigns.""", tools=[my_tool1, my_tool2], # Optional, defaults to an empty list llm=my_llm, # Optional function_calling_llm=my_llm, # Optional max_iter=15, # Optional max_rpm=None, # Optional max_execution_time=None, # Optional verbose=True, # Optional allow_delegation=False, # Optional step_callback=my_intermediate_step_callback, # Optional cache=True, # Optional system_template=my_system_template, # Optional prompt_template=my_prompt_template, # Optional response_template=my_response_template, # Optional config=my_config, # Optional crew=my_crew, # Optional tools_handler=my_tools_handler, # Optional cache_handler=my_cache_handler, # Optional callbacks=[callback1, callback2], # Optional allow_code_execution=True, # Optional max_retry_limit=2, # Optional use_system_prompt=True, # Optional respect_context_window=True, # Optional code_execution_mode='safe', # Optional, defaults to 'safe' ) ``` ## Setting prompt templates Prompt templates are used to format the prompt for the agent. You can use to update the system, regular and response templates for the agent. Here's an example of how to set prompt templates: ```python Code example agent = Agent( role="{topic} specialist", goal="Figure {goal} out", backstory="I am the master of {role}", system_template="""<|start_header_id|>system<|end_header_id|> {{ .System }}<|eot_id|>""", prompt_template="""<|start_header_id|>user<|end_header_id|> {{ .Prompt }}<|eot_id|>""", response_template="""<|start_header_id|>assistant<|end_header_id|> {{ .Response }}<|eot_id|>""", ) ``` ## Bring your third-party agents Extend your third-party agents like LlamaIndex, Langchain, Autogen or fully custom agents using the the CrewAI's `BaseAgent` class. **BaseAgent** includes attributes and methods required to integrate with your crews to run and delegate tasks to other agents within your own crew. CrewAI is a universal multi-agent framework that allows for all agents to work together to automate tasks and solve problems. ```python Code example from crewai import Agent, Task, Crew from custom_agent import CustomAgent # You need to build and extend your own agent logic with the CrewAI BaseAgent class then import it here. from langchain.agents import load_tools langchain_tools = load_tools(["google-serper"], llm=llm) agent1 = CustomAgent( role="agent role", goal="who is {input}?", backstory="agent backstory", verbose=True, ) task1 = Task( expected_output="a short biography of {input}", description="a short biography of {input}", agent=agent1, ) agent2 = Agent( role="agent role", goal="summarize the short bio for {input} and if needed do more research", backstory="agent backstory", verbose=True, ) task2 = Task( description="a tldr summary of the short biography", expected_output="5 bullet point summary of the biography", agent=agent2, context=[task1], ) my_crew = Crew(agents=[agent1, agent2], tasks=[task1, task2]) crew = my_crew.kickoff(inputs={"input": "Mark Twain"}) ``` ## Conclusion Agents are the building blocks of the CrewAI framework. By understanding how to define and interact with agents, you can create sophisticated AI systems that leverage the power of collaborative intelligence. The `code_execution_mode` attribute provides flexibility in how agents execute code, allowing for both secure and direct execution options. # CLI Learn how to use the CrewAI CLI to interact with CrewAI. # CrewAI CLI Documentation The CrewAI CLI provides a set of commands to interact with CrewAI, allowing you to create, train, run, and manage crews & flows. ## Installation To use the CrewAI CLI, make sure you have CrewAI installed: ```shell pip install crewai ``` ## Basic Usage The basic structure of a CrewAI CLI command is: ```shell crewai [COMMAND] [OPTIONS] [ARGUMENTS] ``` ## Available Commands ### 1. Create Create a new crew or pipeline. ```shell crewai create [OPTIONS] TYPE NAME ``` * `TYPE`: Choose between "crew" or "pipeline" * `NAME`: Name of the crew or pipeline * `--router`: (Optional) Create a pipeline with router functionality Example: ```shell crewai create crew my_new_crew crewai create pipeline my_new_pipeline --router ``` ### 2. Version Show the installed version of CrewAI. ```shell crewai version [OPTIONS] ``` * `--tools`: (Optional) Show the installed version of CrewAI tools Example: ```shell crewai version crewai version --tools ``` ### 3. Train Train the crew for a specified number of iterations. ```shell crewai train [OPTIONS] ``` * `-n, --n_iterations INTEGER`: Number of iterations to train the crew (default: 5) * `-f, --filename TEXT`: Path to a custom file for training (default: "trained\_agents\_data.pkl") Example: ```shell crewai train -n 10 -f my_training_data.pkl ``` ### 4. Replay Replay the crew execution from a specific task. ```shell crewai replay [OPTIONS] ``` * `-t, --task_id TEXT`: Replay the crew from this task ID, including all subsequent tasks Example: ```shell crewai replay -t task_123456 ``` ### 5. Log-tasks-outputs Retrieve your latest crew\.kickoff() task outputs. ```shell crewai log-tasks-outputs ``` ### 6. Reset-memories Reset the crew memories (long, short, entity, latest\_crew\_kickoff\_outputs). ```shell crewai reset-memories [OPTIONS] ``` * `-l, --long`: Reset LONG TERM memory * `-s, --short`: Reset SHORT TERM memory * `-e, --entities`: Reset ENTITIES memory * `-k, --kickoff-outputs`: Reset LATEST KICKOFF TASK OUTPUTS * `-a, --all`: Reset ALL memories Example: ```shell crewai reset-memories --long --short crewai reset-memories --all ``` ### 7. Test Test the crew and evaluate the results. ```shell crewai test [OPTIONS] ``` * `-n, --n_iterations INTEGER`: Number of iterations to test the crew (default: 3) * `-m, --model TEXT`: LLM Model to run the tests on the Crew (default: "gpt-4o-mini") Example: ```shell crewai test -n 5 -m gpt-3.5-turbo ``` ### 8. Run Run the crew. ```shell crewai run ``` Make sure to run these commands from the directory where your CrewAI project is set up. Some commands may require additional configuration or setup within your project structure. ### 9. API Keys When running `crewai create crew` command, the CLI will first show you the top 5 most common LLM providers and ask you to select one. Once you've selected an LLM provider, you will be prompted for API keys. #### Initial API key providers The CLI will initially prompt for API keys for the following services: * OpenAI * Groq * Anthropic * Google Gemini When you select a provider, the CLI will prompt you to enter your API key. #### Other Options If you select option 6, you will be able to select from a list of LiteLLM supported providers. When you select a provider, the CLI will prompt you to enter the Key name and the API key. See the following link for each provider's key name: * [LiteLLM Providers](https://docs.litellm.ai/docs/providers) # Collaboration Exploring the dynamics of agent collaboration within the CrewAI framework, focusing on the newly integrated features for enhanced functionality. ## Collaboration Fundamentals Collaboration in CrewAI is fundamental, enabling agents to combine their skills, share information, and assist each other in task execution, embodying a truly cooperative ecosystem. * **Information Sharing**: Ensures all agents are well-informed and can contribute effectively by sharing data and findings. * **Task Assistance**: Allows agents to seek help from peers with the required expertise for specific tasks. * **Resource Allocation**: Optimizes task execution through the efficient distribution and sharing of resources among agents. ## Enhanced Attributes for Improved Collaboration The `Crew` class has been enriched with several attributes to support advanced functionalities: | Feature | Description | | :-------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Language Model Management** (`manager_llm`, `function_calling_llm`) | Manages language models for executing tasks and tools. `manager_llm` is required for hierarchical processes, while `function_calling_llm` is optional with a default value for streamlined interactions. | | **Custom Manager Agent** (`manager_agent`) | Specifies a custom agent as the manager, replacing the default CrewAI manager. | | **Process Flow** (`process`) | Defines execution logic (e.g., sequential, hierarchical) for task distribution. | | **Verbose Logging** (`verbose`) | Provides detailed logging for monitoring and debugging. Accepts integer and boolean values to control verbosity level. | | **Rate Limiting** (`max_rpm`) | Limits requests per minute to optimize resource usage. Setting guidelines depend on task complexity and load. | | **Internationalization / Customization** (`language`, `prompt_file`) | Supports prompt customization for global usability. [Example of file](https://github.com/joaomdmoura/crewAI/blob/main/src/crewai/translations/en.json) | | **Execution and Output Handling** (`full_output`) | Controls output granularity, distinguishing between full and final outputs. | | **Callback and Telemetry** (`step_callback`, `task_callback`) | Enables step-wise and task-level execution monitoring and telemetry for performance analytics. | | **Crew Sharing** (`share_crew`) | Allows sharing crew data with CrewAI for model improvement. Privacy implications and benefits should be considered. | | **Usage Metrics** (`usage_metrics`) | Logs all LLM usage metrics during task execution for performance insights. | | **Memory Usage** (`memory`) | Enables memory for storing execution history, aiding in agent learning and task efficiency. | | **Embedder Configuration** (`embedder`) | Configures the embedder for language understanding and generation, with support for provider customization. | | **Cache Management** (`cache`) | Specifies whether to cache tool execution results, enhancing performance. | | **Output Logging** (`output_log_file`) | Defines the file path for logging crew execution output. | | **Planning Mode** (`planning`) | Enables action planning before task execution. Set `planning=True` to activate. | | **Replay Feature** (`replay`) | Provides CLI for listing tasks from the last run and replaying from specific tasks, aiding in task management and troubleshooting. | ## Delegation (Dividing to Conquer) Delegation enhances functionality by allowing agents to intelligently assign tasks or seek help, thereby amplifying the crew's overall capability. ## Implementing Collaboration and Delegation Setting up a crew involves defining the roles and capabilities of each agent. CrewAI seamlessly manages their interactions, ensuring efficient collaboration and delegation, with enhanced customization and monitoring features to adapt to various operational needs. ## Example Scenario Consider a crew with a researcher agent tasked with data gathering and a writer agent responsible for compiling reports. The integration of advanced language model management and process flow attributes allows for more sophisticated interactions, such as the writer delegating complex research tasks to the researcher or querying specific information, thereby facilitating a seamless workflow. ## Conclusion The integration of advanced attributes and functionalities into the CrewAI framework significantly enriches the agent collaboration ecosystem. These enhancements not only simplify interactions but also offer unprecedented flexibility and control, paving the way for sophisticated AI-driven solutions capable of tackling complex tasks through intelligent collaboration and delegation. # Crews Understanding and utilizing crews in the crewAI framework with comprehensive attributes and functionalities. ## What is a Crew? A crew in crewAI represents a collaborative group of agents working together to achieve a set of tasks. Each crew defines the strategy for task execution, agent collaboration, and the overall workflow. ## Crew Attributes | Attribute | Parameters | Description | | :------------------------------------ | :--------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Tasks** | `tasks` | A list of tasks assigned to the crew. | | **Agents** | `agents` | A list of agents that are part of the crew. | | **Process** *(optional)* | `process` | The process flow (e.g., sequential, hierarchical) the crew follows. Default is `sequential`. | | **Verbose** *(optional)* | `verbose` | The verbosity level for logging during execution. Defaults to `False`. | | **Manager LLM** *(optional)* | `manager_llm` | The language model used by the manager agent in a hierarchical process. **Required when using a hierarchical process.** | | **Function Calling LLM** *(optional)* | `function_calling_llm` | If passed, the crew will use this LLM to do function calling for tools for all agents in the crew. Each agent can have its own LLM, which overrides the crew's LLM for function calling. | | **Config** *(optional)* | `config` | Optional configuration settings for the crew, in `Json` or `Dict[str, Any]` format. | | **Max RPM** *(optional)* | `max_rpm` | Maximum requests per minute the crew adheres to during execution. Defaults to `None`. | | **Language** *(optional)* | `language` | Language used for the crew, defaults to English. | | **Language File** *(optional)* | `language_file` | Path to the language file to be used for the crew. | | **Memory** *(optional)* | `memory` | Utilized for storing execution memories (short-term, long-term, entity memory). | | **Memory Config** *(optional)* | `memory_config` | Configuration for the memory provider to be used by the crew. | | **Cache** *(optional)* | `cache` | Specifies whether to use a cache for storing the results of tools' execution. Defaults to `True`. | | **Embedder** *(optional)* | `embedder` | Configuration for the embedder to be used by the crew. Mostly used by memory for now. Default is `{"provider": "openai"}`. | | **Full Output** *(optional)* | `full_output` | Whether the crew should return the full output with all tasks outputs or just the final output. Defaults to `False`. | | **Step Callback** *(optional)* | `step_callback` | A function that is called after each step of every agent. This can be used to log the agent's actions or to perform other operations; it won't override the agent-specific `step_callback`. | | **Task Callback** *(optional)* | `task_callback` | A function that is called after the completion of each task. Useful for monitoring or additional operations post-task execution. | | **Share Crew** *(optional)* | `share_crew` | Whether you want to share the complete crew information and execution with the crewAI team to make the library better, and allow us to train models. | | **Output Log File** *(optional)* | `output_log_file` | Whether you want to have a file with the complete crew output and execution. You can set it using True and it will default to the folder you are currently in and it will be called logs.txt or passing a string with the full path and name of the file. | | **Manager Agent** *(optional)* | `manager_agent` | `manager` sets a custom agent that will be used as a manager. | | **Manager Callbacks** *(optional)* | `manager_callbacks` | `manager_callbacks` takes a list of callback handlers to be executed by the manager agent when a hierarchical process is used. | | **Prompt File** *(optional)* | `prompt_file` | Path to the prompt JSON file to be used for the crew. | | **Planning** *(optional)* | `planning` | Adds planning ability to the Crew. When activated before each Crew iteration, all Crew data is sent to an AgentPlanner that will plan the tasks and this plan will be added to each task description. | | **Planning LLM** *(optional)* | `planning_llm` | The language model used by the AgentPlanner in a planning process. | **Crew Max RPM**: The `max_rpm` attribute sets the maximum number of requests per minute the crew can perform to avoid rate limits and will override individual agents' `max_rpm` settings if you set it. ## Crew Output The output of a crew in the CrewAI framework is encapsulated within the `CrewOutput` class. This class provides a structured way to access results of the crew's execution, including various formats such as raw strings, JSON, and Pydantic models. The `CrewOutput` includes the results from the final task output, token usage, and individual task outputs. ### Crew Output Attributes | Attribute | Parameters | Type | Description | | :--------------- | :------------- | :------------------------- | :--------------------------------------------------------------------------------------------------- | | **Raw** | `raw` | `str` | The raw output of the crew. This is the default format for the output. | | **Pydantic** | `pydantic` | `Optional[BaseModel]` | A Pydantic model object representing the structured output of the crew. | | **JSON Dict** | `json_dict` | `Optional[Dict[str, Any]]` | A dictionary representing the JSON output of the crew. | | **Tasks Output** | `tasks_output` | `List[TaskOutput]` | A list of `TaskOutput` objects, each representing the output of a task in the crew. | | **Token Usage** | `token_usage` | `Dict[str, Any]` | A summary of token usage, providing insights into the language model's performance during execution. | ### Crew Output Methods and Properties | Method/Property | Description | | :-------------- | :------------------------------------------------------------------------------------------------ | | **json** | Returns the JSON string representation of the crew output if the output format is JSON. | | **to\_dict** | Converts the JSON and Pydantic outputs to a dictionary. | | \***\*str\*\*** | Returns the string representation of the crew output, prioritizing Pydantic, then JSON, then raw. | ### Accessing Crew Outputs Once a crew has been executed, its output can be accessed through the `output` attribute of the `Crew` object. The `CrewOutput` class provides various ways to interact with and present this output. #### Example ```python Code # Example crew execution crew = Crew( agents=[research_agent, writer_agent], tasks=[research_task, write_article_task], verbose=True ) crew_output = crew.kickoff() # Accessing the crew output print(f"Raw Output: {crew_output.raw}") if crew_output.json_dict: print(f"JSON Output: {json.dumps(crew_output.json_dict, indent=2)}") if crew_output.pydantic: print(f"Pydantic Output: {crew_output.pydantic}") print(f"Tasks Output: {crew_output.tasks_output}") print(f"Token Usage: {crew_output.token_usage}") ``` ## Memory Utilization Crews can utilize memory (short-term, long-term, and entity memory) to enhance their execution and learning over time. This feature allows crews to store and recall execution memories, aiding in decision-making and task execution strategies. ## Cache Utilization Caches can be employed to store the results of tools' execution, making the process more efficient by reducing the need to re-execute identical tasks. ## Crew Usage Metrics After the crew execution, you can access the `usage_metrics` attribute to view the language model (LLM) usage metrics for all tasks executed by the crew. This provides insights into operational efficiency and areas for improvement. ```python Code # Access the crew's usage metrics crew = Crew(agents=[agent1, agent2], tasks=[task1, task2]) crew.kickoff() print(crew.usage_metrics) ``` ## Crew Execution Process * **Sequential Process**: Tasks are executed one after another, allowing for a linear flow of work. * **Hierarchical Process**: A manager agent coordinates the crew, delegating tasks and validating outcomes before proceeding. **Note**: A `manager_llm` or `manager_agent` is required for this process and it's essential for validating the process flow. ### Kicking Off a Crew Once your crew is assembled, initiate the workflow with the `kickoff()` method. This starts the execution process according to the defined process flow. ```python Code # Start the crew's task execution result = my_crew.kickoff() print(result) ``` ### Different Ways to Kick Off a Crew Once your crew is assembled, initiate the workflow with the appropriate kickoff method. CrewAI provides several methods for better control over the kickoff process: `kickoff()`, `kickoff_for_each()`, `kickoff_async()`, and `kickoff_for_each_async()`. * `kickoff()`: Starts the execution process according to the defined process flow. * `kickoff_for_each()`: Executes tasks for each agent individually. * `kickoff_async()`: Initiates the workflow asynchronously. * `kickoff_for_each_async()`: Executes tasks for each agent individually in an asynchronous manner. ```python Code # Start the crew's task execution result = my_crew.kickoff() print(result) # Example of using kickoff_for_each inputs_array = [{'topic': 'AI in healthcare'}, {'topic': 'AI in finance'}] results = my_crew.kickoff_for_each(inputs=inputs_array) for result in results: print(result) # Example of using kickoff_async inputs = {'topic': 'AI in healthcare'} async_result = my_crew.kickoff_async(inputs=inputs) print(async_result) # Example of using kickoff_for_each_async inputs_array = [{'topic': 'AI in healthcare'}, {'topic': 'AI in finance'}] async_results = my_crew.kickoff_for_each_async(inputs=inputs_array) for async_result in async_results: print(async_result) ``` These methods provide flexibility in how you manage and execute tasks within your crew, allowing for both synchronous and asynchronous workflows tailored to your needs. ### Replaying from a Specific Task You can now replay from a specific task using our CLI command `replay`. The replay feature in CrewAI allows you to replay from a specific task using the command-line interface (CLI). By running the command `crewai replay -t `, you can specify the `task_id` for the replay process. Kickoffs will now save the latest kickoffs returned task outputs locally for you to be able to replay from. ### Replaying from a Specific Task Using the CLI To use the replay feature, follow these steps: 1. Open your terminal or command prompt. 2. Navigate to the directory where your CrewAI project is located. 3. Run the following command: To view the latest kickoff task IDs, use: ```shell crewai log-tasks-outputs ``` Then, to replay from a specific task, use: ```shell crewai replay -t ``` These commands let you replay from your latest kickoff tasks, still retaining context from previously executed tasks. # Flows Learn how to create and manage AI workflows using CrewAI Flows. ## Introduction CrewAI Flows is a powerful feature designed to streamline the creation and management of AI workflows. Flows allow developers to combine and coordinate coding tasks and Crews efficiently, providing a robust framework for building sophisticated AI automations. Flows allow you to create structured, event-driven workflows. They provide a seamless way to connect multiple tasks, manage state, and control the flow of execution in your AI applications. With Flows, you can easily design and implement multi-step processes that leverage the full potential of CrewAI's capabilities. 1. **Simplified Workflow Creation**: Easily chain together multiple Crews and tasks to create complex AI workflows. 2. **State Management**: Flows make it super easy to manage and share state between different tasks in your workflow. 3. **Event-Driven Architecture**: Built on an event-driven model, allowing for dynamic and responsive workflows. 4. **Flexible Control Flow**: Implement conditional logic, loops, and branching within your workflows. 5. **Input Flexibility**: Flows can accept inputs to initialize or update their state, with different handling for structured and unstructured state management. ## Getting Started Let's create a simple Flow where you will use OpenAI to generate a random city in one task and then use that city to generate a fun fact in another task. ### Passing Inputs to Flows Flows can accept inputs to initialize or update their state before execution. The way inputs are handled depends on whether the flow uses structured or unstructured state management. #### Structured State Management In structured state management, the flow's state is defined using a Pydantic `BaseModel`. Inputs must match the model's schema, and any updates will overwrite the default values. ```python from crewai.flow.flow import Flow, listen, start from pydantic import BaseModel class ExampleState(BaseModel): counter: int = 0 message: str = "" class StructuredExampleFlow(Flow[ExampleState]): @start() def first_method(self): # Implementation flow = StructuredExampleFlow() flow.kickoff(inputs={"counter": 10}) ``` In this example, the `counter` is initialized to `10`, while `message` retains its default value. #### Unstructured State Management In unstructured state management, the flow's state is a dictionary. You can pass any dictionary to update the state. ```python from crewai.flow.flow import Flow, listen, start class UnstructuredExampleFlow(Flow): @start() def first_method(self): # Implementation flow = UnstructuredExampleFlow() flow.kickoff(inputs={"counter": 5, "message": "Initial message"}) ``` Here, both `counter` and `message` are updated based on the provided inputs. **Note:** Ensure that inputs for structured state management adhere to the defined schema to avoid validation errors. ### Example Flow ```python # Existing example code ``` In the above example, we have created a simple Flow that generates a random city using OpenAI and then generates a fun fact about that city. The Flow consists of two tasks: `generate_city` and `generate_fun_fact`. The `generate_city` task is the starting point of the Flow, and the `generate_fun_fact` task listens for the output of the `generate_city` task. When you run the Flow, it will generate a random city and then generate a fun fact about that city. The output will be printed to the console. **Note:** Ensure you have set up your `.env` file to store your `OPENAI_API_KEY`. This key is necessary for authenticating requests to the OpenAI API. ### @start() The `@start()` decorator is used to mark a method as the starting point of a Flow. When a Flow is started, all the methods decorated with `@start()` are executed in parallel. You can have multiple start methods in a Flow, and they will all be executed when the Flow is started. ### @listen() The `@listen()` decorator is used to mark a method as a listener for the output of another task in the Flow. The method decorated with `@listen()` will be executed when the specified task emits an output. The method can access the output of the task it is listening to as an argument. #### Usage The `@listen()` decorator can be used in several ways: 1. **Listening to a Method by Name**: You can pass the name of the method you want to listen to as a string. When that method completes, the listener method will be triggered. ```python @listen("generate_city") def generate_fun_fact(self, random_city): # Implementation ``` 2. **Listening to a Method Directly**: You can pass the method itself. When that method completes, the listener method will be triggered. ```python @listen(generate_city) def generate_fun_fact(self, random_city): # Implementation ``` ### Flow Output Accessing and handling the output of a Flow is essential for integrating your AI workflows into larger applications or systems. CrewAI Flows provide straightforward mechanisms to retrieve the final output, access intermediate results, and manage the overall state of your Flow. #### Retrieving the Final Output When you run a Flow, the final output is determined by the last method that completes. The `kickoff()` method returns the output of this final method. Here's how you can access the final output: ```python from crewai.flow.flow import Flow, listen, start class OutputExampleFlow(Flow): @start() def first_method(self): return "Output from first_method" @listen(first_method) def second_method(self, first_output): return f"Second method received: {first_output}" flow = OutputExampleFlow() final_output = flow.kickoff() print("---- Final Output ----") print(final_output) ``` ```text ---- Final Output ---- Second method received: Output from first_method ``` In this example, the `second_method` is the last method to complete, so its output will be the final output of the Flow. The `kickoff()` method will return the final output, which is then printed to the console. #### Accessing and Updating State In addition to retrieving the final output, you can also access and update the state within your Flow. The state can be used to store and share data between different methods in the Flow. After the Flow has run, you can access the state to retrieve any information that was added or updated during the execution. Here's an example of how to update and access the state: ```python from crewai.flow.flow import Flow, listen, start from pydantic import BaseModel class ExampleState(BaseModel): counter: int = 0 message: str = "" class StateExampleFlow(Flow[ExampleState]): @start() def first_method(self): self.state.message = "Hello from first_method" self.state.counter += 1 @listen(first_method) def second_method(self): self.state.message += " - updated by second_method" self.state.counter += 1 return self.state.message flow = StateExampleFlow() final_output = flow.kickoff() print(f"Final Output: {final_output}") print("Final State:") print(flow.state) ``` ```text Final Output: Hello from first_method - updated by second_method Final State: counter=2 message='Hello from first_method - updated by second_method' ``` In this example, the state is updated by both `first_method` and `second_method`. After the Flow has run, you can access the final state to see the updates made by these methods. By ensuring that the final method's output is returned and providing access to the state, CrewAI Flows make it easy to integrate the results of your AI workflows into larger applications or systems, while also maintaining and accessing the state throughout the Flow's execution. ## Flow State Management Managing state effectively is crucial for building reliable and maintainable AI workflows. CrewAI Flows provides robust mechanisms for both unstructured and structured state management, allowing developers to choose the approach that best fits their application's needs. ### Unstructured State Management In unstructured state management, all state is stored in the `state` attribute of the `Flow` class. This approach offers flexibility, enabling developers to add or modify state attributes on the fly without defining a strict schema. ```python from crewai.flow.flow import Flow, listen, start class UnstructuredExampleFlow(Flow): @start() def first_method(self): self.state.message = "Hello from structured flow" self.state.counter = 0 @listen(first_method) def second_method(self): self.state.counter += 1 self.state.message += " - updated" @listen(second_method) def third_method(self): self.state.counter += 1 self.state.message += " - updated again" print(f"State after third_method: {self.state}") flow = UnstructuredExampleFlow() flow.kickoff() ``` **Key Points:** * **Flexibility:** You can dynamically add attributes to `self.state` without predefined constraints. * **Simplicity:** Ideal for straightforward workflows where state structure is minimal or varies significantly. ### Structured State Management Structured state management leverages predefined schemas to ensure consistency and type safety across the workflow. By using models like Pydantic's `BaseModel`, developers can define the exact shape of the state, enabling better validation and auto-completion in development environments. ```python from crewai.flow.flow import Flow, listen, start from pydantic import BaseModel class ExampleState(BaseModel): counter: int = 0 message: str = "" class StructuredExampleFlow(Flow[ExampleState]): @start() def first_method(self): self.state.message = "Hello from structured flow" @listen(first_method) def second_method(self): self.state.counter += 1 self.state.message += " - updated" @listen(second_method) def third_method(self): self.state.counter += 1 self.state.message += " - updated again" print(f"State after third_method: {self.state}") flow = StructuredExampleFlow() flow.kickoff() ``` **Key Points:** * **Defined Schema:** `ExampleState` clearly outlines the state structure, enhancing code readability and maintainability. * **Type Safety:** Leveraging Pydantic ensures that state attributes adhere to the specified types, reducing runtime errors. * **Auto-Completion:** IDEs can provide better auto-completion and error checking based on the defined state model. ### Choosing Between Unstructured and Structured State Management * **Use Unstructured State Management when:** * The workflow's state is simple or highly dynamic. * Flexibility is prioritized over strict state definitions. * Rapid prototyping is required without the overhead of defining schemas. * **Use Structured State Management when:** * The workflow requires a well-defined and consistent state structure. * Type safety and validation are important for your application's reliability. * You want to leverage IDE features like auto-completion and type checking for better developer experience. By providing both unstructured and structured state management options, CrewAI Flows empowers developers to build AI workflows that are both flexible and robust, catering to a wide range of application requirements. ## Flow Control ### Conditional Logic: `or` The `or_` function in Flows allows you to listen to multiple methods and trigger the listener method when any of the specified methods emit an output. ```python from crewai.flow.flow import Flow, listen, or_, start class OrExampleFlow(Flow): @start() def start_method(self): return "Hello from the start method" @listen(start_method) def second_method(self): return "Hello from the second method" @listen(or_(start_method, second_method)) def logger(self, result): print(f"Logger: {result}") flow = OrExampleFlow() flow.kickoff() ``` ```text Logger: Hello from the start method Logger: Hello from the second method ``` When you run this Flow, the `logger` method will be triggered by the output of either the `start_method` or the `second_method`. The `or_` function is used to listen to multiple methods and trigger the listener method when any of the specified methods emit an output. ### Conditional Logic: `and` The `and_` function in Flows allows you to listen to multiple methods and trigger the listener method only when all the specified methods emit an output. ```python from crewai.flow.flow import Flow, and_, listen, start class AndExampleFlow(Flow): @start() def start_method(self): self.state["greeting"] = "Hello from the start method" @listen(start_method) def second_method(self): self.state["joke"] = "What do computers eat? Microchips." @listen(and_(start_method, second_method)) def logger(self): print("---- Logger ----") print(self.state) flow = AndExampleFlow() flow.kickoff() ``` ```text ---- Logger ---- {'greeting': 'Hello from the start method', 'joke': 'What do computers eat? Microchips.'} ``` When you run this Flow, the `logger` method will be triggered only when both the `start_method` and the `second_method` emit an output. The `and_` function is used to listen to multiple methods and trigger the listener method only when all the specified methods emit an output. ### Router The `@router()` decorator in Flows allows you to define conditional routing logic based on the output of a method. You can specify different routes based on the output of the method, allowing you to control the flow of execution dynamically. ```python import random from crewai.flow.flow import Flow, listen, router, start from pydantic import BaseModel class ExampleState(BaseModel): success_flag: bool = False class RouterFlow(Flow[ExampleState]): @start() def start_method(self): print("Starting the structured flow") random_boolean = random.choice([True, False]) self.state.success_flag = random_boolean @router(start_method) def second_method(self): if self.state.success_flag: return "success" else: return "failed" @listen("success") def third_method(self): print("Third method running") @listen("failed") def fourth_method(self): print("Fourth method running") flow = RouterFlow() flow.kickoff() ``` ```text Starting the structured flow Third method running Fourth method running ``` In the above example, the `start_method` generates a random boolean value and sets it in the state. The `second_method` uses the `@router()` decorator to define conditional routing logic based on the value of the boolean. If the boolean is `True`, the method returns `"success"`, and if it is `False`, the method returns `"failed"`. The `third_method` and `fourth_method` listen to the output of the `second_method` and execute based on the returned value. When you run this Flow, the output will change based on the random boolean value generated by the `start_method`. ## Adding Crews to Flows Creating a flow with multiple crews in CrewAI is straightforward. You can generate a new CrewAI project that includes all the scaffolding needed to create a flow with multiple crews by running the following command: ```bash crewai create flow name_of_flow ``` This command will generate a new CrewAI project with the necessary folder structure. The generated project includes a prebuilt crew called `poem_crew` that is already working. You can use this crew as a template by copying, pasting, and editing it to create other crews. ### Folder Structure After running the `crewai create flow name_of_flow` command, you will see a folder structure similar to the following: | Directory/File | Description | | :--------------------- | :------------------------------------------------------------------ | | `name_of_flow/` | Root directory for the flow. | | ├── `crews/` | Contains directories for specific crews. | | │ └── `poem_crew/` | Directory for the "poem\_crew" with its configurations and scripts. | | │ ├── `config/` | Configuration files directory for the "poem\_crew". | | │ │ ├── `agents.yaml` | YAML file defining the agents for "poem\_crew". | | │ │ └── `tasks.yaml` | YAML file defining the tasks for "poem\_crew". | | │ ├── `poem_crew.py` | Script for "poem\_crew" functionality. | | ├── `tools/` | Directory for additional tools used in the flow. | | │ └── `custom_tool.py` | Custom tool implementation. | | ├── `main.py` | Main script for running the flow. | | ├── `README.md` | Project description and instructions. | | ├── `pyproject.toml` | Configuration file for project dependencies and settings. | | └── `.gitignore` | Specifies files and directories to ignore in version control. | ### Building Your Crews In the `crews` folder, you can define multiple crews. Each crew will have its own folder containing configuration files and the crew definition file. For example, the `poem_crew` folder contains: * `config/agents.yaml`: Defines the agents for the crew. * `config/tasks.yaml`: Defines the tasks for the crew. * `poem_crew.py`: Contains the crew definition, including agents, tasks, and the crew itself. You can copy, paste, and edit the `poem_crew` to create other crews. ### Connecting Crews in `main.py` The `main.py` file is where you create your flow and connect the crews together. You can define your flow by using the `Flow` class and the decorators `@start` and `@listen` to specify the flow of execution. Here's an example of how you can connect the `poem_crew` in the `main.py` file: ```python #!/usr/bin/env python from random import randint from pydantic import BaseModel from crewai.flow.flow import Flow, listen, start from .crews.poem_crew.poem_crew import PoemCrew class PoemState(BaseModel): sentence_count: int = 1 poem: str = "" class PoemFlow(Flow[PoemState]): @start() def generate_sentence_count(self): print("Generating sentence count") self.state.sentence_count = randint(1, 5) @listen(generate_sentence_count) def generate_poem(self): print("Generating poem") result = PoemCrew().crew().kickoff(inputs={"sentence_count": self.state.sentence_count}) print("Poem generated", result.raw) self.state.poem = result.raw @listen(generate_poem) def save_poem(self): print("Saving poem") with open("poem.txt", "w") as f: f.write(self.state.poem) def kickoff(): poem_flow = PoemFlow() poem_flow.kickoff() def plot(): poem_flow = PoemFlow() poem_flow.plot() if __name__ == "__main__": kickoff() ``` In this example, the `PoemFlow` class defines a flow that generates a sentence count, uses the `PoemCrew` to generate a poem, and then saves the poem to a file. The flow is kicked off by calling the `kickoff()` method. ### Running the Flow (Optional) Before running the flow, you can install the dependencies by running: ```bash crewai install ``` Once all of the dependencies are installed, you need to activate the virtual environment by running: ```bash source .venv/bin/activate ``` After activating the virtual environment, you can run the flow by executing one of the following commands: ```bash crewai flow kickoff ``` or ```bash uv run kickoff ``` The flow will execute, and you should see the output in the console. ### Adding Additional Crews Using the CLI Once you have created your initial flow, you can easily add additional crews to your project using the CLI. This allows you to expand your flow's capabilities by integrating new crews without starting from scratch. To add a new crew to your existing flow, use the following command: ```bash crewai flow add-crew ``` This command will create a new directory for your crew within the `crews` folder of your flow project. It will include the necessary configuration files and a crew definition file, similar to the initial setup. #### Folder Structure After adding a new crew, your folder structure will look like this: | Directory/File | Description | | :--------------------------- | :------------------------------------------------------------------ | | `name_of_flow/` | Root directory for the flow. | | ├── `crews/` | Contains directories for specific crews. | | │ ├── `poem_crew/` | Directory for the "poem\_crew" with its configurations and scripts. | | │ │ ├── `config/` | Configuration files directory for the "poem\_crew". | | │ │ │ ├── `agents.yaml` | YAML file defining the agents for "poem\_crew". | | │ │ │ └── `tasks.yaml` | YAML file defining the tasks for "poem\_crew". | | │ │ └── `poem_crew.py` | Script for "poem\_crew" functionality. | | └── `name_of_crew/` | Directory for the new crew. | | ├── `config/` | Configuration files directory for the new crew. | | │ ├── `agents.yaml` | YAML file defining the agents for the new crew. | | │ └── `tasks.yaml` | YAML file defining the tasks for the new crew. | | └── `name_of_crew.py` | Script for the new crew functionality. | You can then customize the `agents.yaml` and `tasks.yaml` files to define the agents and tasks for your new crew. The `name_of_crew.py` file will contain the crew's logic, which you can modify to suit your needs. By using the CLI to add additional crews, you can efficiently build complex AI workflows that leverage multiple crews working together. ## Plot Flows Visualizing your AI workflows can provide valuable insights into the structure and execution paths of your flows. CrewAI offers a powerful visualization tool that allows you to generate interactive plots of your flows, making it easier to understand and optimize your AI workflows. ### What are Plots? Plots in CrewAI are graphical representations of your AI workflows. They display the various tasks, their connections, and the flow of data between them. This visualization helps in understanding the sequence of operations, identifying bottlenecks, and ensuring that the workflow logic aligns with your expectations. ### How to Generate a Plot CrewAI provides two convenient methods to generate plots of your flows: #### Option 1: Using the `plot()` Method If you are working directly with a flow instance, you can generate a plot by calling the `plot()` method on your flow object. This method will create an HTML file containing the interactive plot of your flow. ```python # Assuming you have a flow instance flow.plot("my_flow_plot") ``` This will generate a file named `my_flow_plot.html` in your current directory. You can open this file in a web browser to view the interactive plot. #### Option 2: Using the Command Line If you are working within a structured CrewAI project, you can generate a plot using the command line. This is particularly useful for larger projects where you want to visualize the entire flow setup. ```bash crewai flow plot ``` This command will generate an HTML file with the plot of your flow, similar to the `plot()` method. The file will be saved in your project directory, and you can open it in a web browser to explore the flow. ### Understanding the Plot The generated plot will display nodes representing the tasks in your flow, with directed edges indicating the flow of execution. The plot is interactive, allowing you to zoom in and out, and hover over nodes to see additional details. By visualizing your flows, you can gain a clearer understanding of the workflow's structure, making it easier to debug, optimize, and communicate your AI processes to others. ## Advanced In this section, we explore more complex use cases of CrewAI Flows, starting with a self-evaluation loop. This pattern is crucial for developing AI systems that can iteratively improve their outputs through feedback. ### 1) Self-Evaluation Loop The self-evaluation loop is a powerful pattern that allows AI workflows to automatically assess and refine their outputs. This example demonstrates how to set up a flow that generates content, evaluates it, and iterates based on feedback until the desired quality is achieved. #### Overview The self-evaluation loop involves two main Crews: 1. **ShakespeareanXPostCrew**: Generates a Shakespearean-style post on a given topic. 2. **XPostReviewCrew**: Evaluates the generated post, providing feedback on its validity and quality. The process iterates until the post meets the criteria or a maximum retry limit is reached. This approach ensures high-quality outputs through iterative refinement. #### Importance This pattern is essential for building robust AI systems that can adapt and improve over time. By automating the evaluation and feedback loop, developers can ensure that their AI workflows produce reliable and high-quality results. #### Main Code Highlights Below is the `main.py` file for the self-evaluation loop flow: ```python from typing import Optional from crewai.flow.flow import Flow, listen, router, start from pydantic import BaseModel from self_evaluation_loop_flow.crews.shakespeare_crew.shakespeare_crew import ( ShakespeareanXPostCrew, ) from self_evaluation_loop_flow.crews.x_post_review_crew.x_post_review_crew import ( XPostReviewCrew, ) class ShakespeareXPostFlowState(BaseModel): x_post: str = "" feedback: Optional[str] = None valid: bool = False retry_count: int = 0 class ShakespeareXPostFlow(Flow[ShakespeareXPostFlowState]): @start("retry") def generate_shakespeare_x_post(self): print("Generating Shakespearean X post") topic = "Flying cars" result = ( ShakespeareanXPostCrew() .crew() .kickoff(inputs={"topic": topic, "feedback": self.state.feedback}) ) print("X post generated", result.raw) self.state.x_post = result.raw @router(generate_shakespeare_x_post) def evaluate_x_post(self): if self.state.retry_count > 3: return "max_retry_exceeded" result = XPostReviewCrew().crew().kickoff(inputs={"x_post": self.state.x_post}) self.state.valid = result["valid"] self.state.feedback = result["feedback"] print("valid", self.state.valid) print("feedback", self.state.feedback) self.state.retry_count += 1 if self.state.valid: return "complete" return "retry" @listen("complete") def save_result(self): print("X post is valid") print("X post:", self.state.x_post) with open("x_post.txt", "w") as file: file.write(self.state.x_post) @listen("max_retry_exceeded") def max_retry_exceeded_exit(self): print("Max retry count exceeded") print("X post:", self.state.x_post) print("Feedback:", self.state.feedback) def kickoff(): shakespeare_flow = ShakespeareXPostFlow() shakespeare_flow.kickoff() def plot(): shakespeare_flow = ShakespeareXPostFlow() shakespeare_flow.plot() if __name__ == "__main__": kickoff() ``` #### Code Highlights * **Retry Mechanism**: The flow uses a retry mechanism to regenerate the post if it doesn't meet the criteria, up to a maximum of three retries. * **Feedback Loop**: Feedback from the `XPostReviewCrew` is used to refine the post iteratively. * **State Management**: The flow maintains state using a Pydantic model, ensuring type safety and clarity. For a complete example and further details, please refer to the [Self Evaluation Loop Flow repository](https://github.com/crewAIInc/crewAI-examples/tree/main/self_evaluation_loop_flow). ## Next Steps If you're interested in exploring additional examples of flows, we have a variety of recommendations in our examples repository. Here are five specific flow examples, each showcasing unique use cases to help you match your current problem type to a specific example: 1. **Email Auto Responder Flow**: This example demonstrates an infinite loop where a background job continually runs to automate email responses. It's a great use case for tasks that need to be performed repeatedly without manual intervention. [View Example](https://github.com/crewAIInc/crewAI-examples/tree/main/email_auto_responder_flow) 2. **Lead Score Flow**: This flow showcases adding human-in-the-loop feedback and handling different conditional branches using the router. It's an excellent example of how to incorporate dynamic decision-making and human oversight into your workflows. [View Example](https://github.com/crewAIInc/crewAI-examples/tree/main/lead-score-flow) 3. **Write a Book Flow**: This example excels at chaining multiple crews together, where the output of one crew is used by another. Specifically, one crew outlines an entire book, and another crew generates chapters based on the outline. Eventually, everything is connected to produce a complete book. This flow is perfect for complex, multi-step processes that require coordination between different tasks. [View Example](https://github.com/crewAIInc/crewAI-examples/tree/main/write_a_book_with_flows) 4. **Meeting Assistant Flow**: This flow demonstrates how to broadcast one event to trigger multiple follow-up actions. For instance, after a meeting is completed, the flow can update a Trello board, send a Slack message, and save the results. It's a great example of handling multiple outcomes from a single event, making it ideal for comprehensive task management and notification systems. [View Example](https://github.com/crewAIInc/crewAI-examples/tree/main/meeting_assistant_flow) 5. **Self Evaluation Loop Flow**: This flow demonstrates a self-evaluation loop where AI workflows automatically assess and refine their outputs through feedback. It involves generating content, evaluating it, and iterating until the desired quality is achieved. This pattern is crucial for developing robust AI systems that can adapt and improve over time. [View Example](https://github.com/crewAIInc/crewAI-examples/tree/main/self_evaluation_loop_flow) By exploring these examples, you can gain insights into how to leverage CrewAI Flows for various use cases, from automating repetitive tasks to managing complex, multi-step processes with dynamic decision-making and human feedback. Also, check out our YouTube video on how to use flows in CrewAI below!