|
| 1 | +--- |
| 2 | +title: Production Architecture |
| 3 | +description: Best practices for building production-ready AI applications with CrewAI |
| 4 | +icon: server |
| 5 | +mode: "wide" |
| 6 | +--- |
| 7 | + |
| 8 | +# The Flow-First Mindset |
| 9 | + |
| 10 | +When building production AI applications with CrewAI, **we recommend starting with a Flow**. |
| 11 | + |
| 12 | +While it's possible to run individual Crews or Agents, wrapping them in a Flow provides the necessary structure for a robust, scalable application. |
| 13 | + |
| 14 | +## Why Flows? |
| 15 | + |
| 16 | +1. **State Management**: Flows provide a built-in way to manage state across different steps of your application. This is crucial for passing data between Crews, maintaining context, and handling user inputs. |
| 17 | +2. **Control**: Flows allow you to define precise execution paths, including loops, conditionals, and branching logic. This is essential for handling edge cases and ensuring your application behaves predictably. |
| 18 | +3. **Observability**: Flows provide a clear structure that makes it easier to trace execution, debug issues, and monitor performance. We recommend using [CrewAI Tracing](/en/observability/tracing) for detailed insights. Simply run `crewai login` to enable free observability features. |
| 19 | + |
| 20 | +## The Architecture |
| 21 | + |
| 22 | +A typical production CrewAI application looks like this: |
| 23 | + |
| 24 | +```mermaid |
| 25 | +graph TD |
| 26 | + Start((Start)) --> Flow[Flow Orchestrator] |
| 27 | + Flow --> State{State Management} |
| 28 | + State --> Step1[Step 1: Data Gathering] |
| 29 | + Step1 --> Crew1[Research Crew] |
| 30 | + Crew1 --> State |
| 31 | + State --> Step2{Condition Check} |
| 32 | + Step2 -- "Valid" --> Step3[Step 3: Execution] |
| 33 | + Step3 --> Crew2[Action Crew] |
| 34 | + Step2 -- "Invalid" --> End((End)) |
| 35 | + Crew2 --> End |
| 36 | +``` |
| 37 | + |
| 38 | +### 1. The Flow Class |
| 39 | +Your `Flow` class is the entry point. It defines the state schema and the methods that execute your logic. |
| 40 | + |
| 41 | +```python |
| 42 | +from crewai.flow.flow import Flow, listen, start |
| 43 | +from pydantic import BaseModel |
| 44 | + |
| 45 | +class AppState(BaseModel): |
| 46 | + user_input: str = "" |
| 47 | + research_results: str = "" |
| 48 | + final_report: str = "" |
| 49 | + |
| 50 | +class ProductionFlow(Flow[AppState]): |
| 51 | + @start() |
| 52 | + def gather_input(self): |
| 53 | + # ... logic to get input ... |
| 54 | + pass |
| 55 | + |
| 56 | + @listen(gather_input) |
| 57 | + def run_research_crew(self): |
| 58 | + # ... trigger a Crew ... |
| 59 | + pass |
| 60 | +``` |
| 61 | + |
| 62 | +### 2. State Management |
| 63 | +Use Pydantic models to define your state. This ensures type safety and makes it clear what data is available at each step. |
| 64 | + |
| 65 | +- **Keep it minimal**: Store only what you need to persist between steps. |
| 66 | +- **Use structured data**: Avoid unstructured dictionaries when possible. |
| 67 | + |
| 68 | +### 3. Crews as Units of Work |
| 69 | +Delegate complex tasks to Crews. A Crew should be focused on a specific goal (e.g., "Research a topic", "Write a blog post"). |
| 70 | + |
| 71 | +- **Don't over-engineer Crews**: Keep them focused. |
| 72 | +- **Pass state explicitly**: Pass the necessary data from the Flow state to the Crew inputs. |
| 73 | + |
| 74 | +```python |
| 75 | + @listen(gather_input) |
| 76 | + def run_research_crew(self): |
| 77 | + crew = ResearchCrew() |
| 78 | + result = crew.kickoff(inputs={"topic": self.state.user_input}) |
| 79 | + self.state.research_results = result.raw |
| 80 | +``` |
| 81 | + |
| 82 | +## Control Primitives |
| 83 | + |
| 84 | +Leverage CrewAI's control primitives to add robustness and control to your Crews. |
| 85 | + |
| 86 | +### 1. Task Guardrails |
| 87 | +Use [Task Guardrails](/en/concepts/tasks#task-guardrails) to validate task outputs before they are accepted. This ensures that your agents produce high-quality results. |
| 88 | + |
| 89 | +```python |
| 90 | +def validate_content(result: TaskOutput) -> Tuple[bool, Any]: |
| 91 | + if len(result.raw) < 100: |
| 92 | + return (False, "Content is too short. Please expand.") |
| 93 | + return (True, result.raw) |
| 94 | + |
| 95 | +task = Task( |
| 96 | + ..., |
| 97 | + guardrail=validate_content |
| 98 | +) |
| 99 | +``` |
| 100 | + |
| 101 | +### 2. Structured Outputs |
| 102 | +Always use structured outputs (`output_pydantic` or `output_json`) when passing data between tasks or to your application. This prevents parsing errors and ensures type safety. |
| 103 | + |
| 104 | +```python |
| 105 | +class ResearchResult(BaseModel): |
| 106 | + summary: str |
| 107 | + sources: List[str] |
| 108 | + |
| 109 | +task = Task( |
| 110 | + ..., |
| 111 | + output_pydantic=ResearchResult |
| 112 | +) |
| 113 | +``` |
| 114 | + |
| 115 | +### 3. LLM Hooks |
| 116 | +Use [LLM Hooks](/en/learn/llm-hooks) to inspect or modify messages before they are sent to the LLM, or to sanitize responses. |
| 117 | + |
| 118 | +```python |
| 119 | +@before_llm_call |
| 120 | +def log_request(context): |
| 121 | + print(f"Agent {context.agent.role} is calling the LLM...") |
| 122 | +``` |
| 123 | + |
| 124 | +## Deployment Patterns |
| 125 | + |
| 126 | +When deploying your Flow, consider the following: |
| 127 | + |
| 128 | +### CrewAI Enterprise |
| 129 | +The easiest way to deploy your Flow is using CrewAI Enterprise. It handles the infrastructure, authentication, and monitoring for you. |
| 130 | + |
| 131 | +Check out the [Deployment Guide](/en/enterprise/guides/deploy-crew) to get started. |
| 132 | + |
| 133 | +```bash |
| 134 | +crewai deploy create |
| 135 | +``` |
| 136 | + |
| 137 | +### Async Execution |
| 138 | +For long-running tasks, use `kickoff_async` to avoid blocking your API. |
| 139 | + |
| 140 | +### Persistence |
| 141 | +Use the `@persist` decorator to save the state of your Flow to a database. This allows you to resume execution if the process crashes or if you need to wait for human input. |
| 142 | + |
| 143 | +```python |
| 144 | +@persist |
| 145 | +class ProductionFlow(Flow[AppState]): |
| 146 | + # ... |
| 147 | +``` |
| 148 | + |
| 149 | +## Summary |
| 150 | + |
| 151 | +- **Start with a Flow.** |
| 152 | +- **Define a clear State.** |
| 153 | +- **Use Crews for complex tasks.** |
| 154 | +- **Deploy with an API and persistence.** |
0 commit comments