├── .gitignore ├── .githooks └── pre-commit ├── .github └── workflows │ └── clean-notebooks.yml ├── LICENSE ├── README.md ├── scripts └── clean_notebooks.py ├── Custom LLM └── gemini_search_grounding_crewai.ipynb └── Guardrails └── task_guardrails.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .venv -------------------------------------------------------------------------------- /.githooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | REPO_ROOT="$(git rev-parse --show-toplevel)" 5 | cd "$REPO_ROOT" 6 | 7 | NOTEBOOKS=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.ipynb$' || true) 8 | 9 | if [ -z "$NOTEBOOKS" ]; then 10 | exit 0 11 | fi 12 | 13 | echo "Sanitizing notebooks..." 14 | python3 scripts/clean_notebooks.py $NOTEBOOKS >/dev/null 2>&1 || true 15 | 16 | for nb in $NOTEBOOKS; do 17 | if ! git diff --quiet -- "$nb"; then 18 | git add "$nb" 19 | echo "Cleaned and staged: $nb" 20 | fi 21 | done 22 | 23 | exit 0 24 | 25 | 26 | -------------------------------------------------------------------------------- /.github/workflows/clean-notebooks.yml: -------------------------------------------------------------------------------- 1 | name: Clean Notebooks 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '**/*.ipynb' 7 | 8 | jobs: 9 | sanitize: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Set up Python 14 | uses: actions/setup-python@v5 15 | with: 16 | python-version: '3.x' 17 | - name: Run notebook sanitizer 18 | run: | 19 | python3 scripts/clean_notebooks.py . 20 | - name: Check for uncommitted changes 21 | run: | 22 | if ! git diff --quiet; then 23 | echo "Notebook sanitation required. Please run: python3 scripts/clean_notebooks.py . && commit changes." 24 | echo "Files needing sanitation:" 25 | git status --porcelain | awk '$1 ~ /M|A|??/ {print $2}' 26 | exit 1 27 | fi 28 | 29 | 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 crewAI, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🚀 CrewAI Quickstarts 2 | 3 | A comprehensive collection of **CrewAI quickstarts and feature demos** designed to help developers learn and master the CrewAI framework through hands-on examples. Each quickstart provides a foundation that you can build upon and customize to suit your needs. 4 | 5 |

6 | Homepage 7 | · 8 | Docs 9 | · 10 | Start Cloud Trial 11 | · 12 | Blog 13 | · 14 | Forum 15 |

16 | 17 |

18 | 19 | GitHub Repo stars 20 | 21 | 22 | GitHub forks 23 | 24 | 25 | GitHub issues 26 | 27 | 28 | GitHub pull requests 29 | 30 | 31 | License: MIT 32 | 33 |

34 | 35 | --- 36 | 37 | ## Getting Started 38 | 39 | To get started with the quickstarts, you will need to have the following: 40 | 41 | - Python 3.8 or higher 42 | - Jupyter Notebook 43 | - An API key from a provider of your choice (e.g., OpenAI, Anthropic, Cohere) 44 | - Other API keys for external tools (e.g., SerperDev) 45 | 46 | --- 47 | 48 | ### Running the Examples 49 | 50 | Each quickstart is self-contained and can be run independently: 51 | 52 | 1. Navigate to the specific quickstart directory 53 | 2. Open the Jupyter notebook or Python file in your preferred IDE 54 | 3. Follow the instructions in the example 55 | 4. Experiment and modify the code to learn! 56 | 57 | --- 58 | 59 | ## Support 60 | 61 | - **Documentation**: [CrewAI Official Docs](https://docs.crewai.com/) 62 | - **Community**: [CrewAI Forum](https://community.crewai.com/) 63 | - **Issues**: [GitHub Issues](https://github.com/crewAIInc/crewAI-quickstarts/issues) 64 | - **Discussions**: [GitHub Discussions](https://github.com/crewAIInc/crewAI-quickstarts/discussions) 65 | 66 | --- 67 | 68 | ## License 69 | 70 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 71 | 72 | --- 73 | 74 | **Happy Learning! 🎉** 75 | 76 | *Start your CrewAI journey today and build amazing multi-agent systems!* -------------------------------------------------------------------------------- /scripts/clean_notebooks.py: -------------------------------------------------------------------------------- 1 | """Sanitize Jupyter notebooks by removing metadata.widgets entries. 2 | 3 | This script fixes a common issue with notebooks exported from tools like 4 | Google Colab where notebook-level or cell-level `metadata.widgets` causes 5 | GitHub and some nbconvert versions to fail rendering with errors such as: 6 | "the 'state' key is missing from 'metadata.widgets'". 7 | 8 | Usage: 9 | python3 scripts/clean_notebooks.py [...] 10 | 11 | Behavior: 12 | - Recursively finds *.ipynb files for any directory arguments. 13 | - Removes `metadata.widgets` at both the notebook and cell level. 14 | - Writes changes back in-place. 15 | - Safe to run repeatedly (idempotent). 16 | """ 17 | import argparse 18 | import json 19 | import sys 20 | from pathlib import Path 21 | 22 | 23 | def remove_widgets_metadata(nb_data: dict) -> bool: 24 | """Remove metadata.widgets from notebook and cells. Returns True if modified.""" 25 | modified = False 26 | metadata = nb_data.get("metadata", {}) 27 | if isinstance(metadata, dict) and "widgets" in metadata: 28 | metadata.pop("widgets", None) 29 | nb_data["metadata"] = metadata 30 | modified = True 31 | 32 | cells = nb_data.get("cells", []) 33 | for cell in cells: 34 | cell_md = cell.get("metadata", {}) 35 | if isinstance(cell_md, dict) and "widgets" in cell_md: 36 | cell_md.pop("widgets", None) 37 | cell["metadata"] = cell_md 38 | modified = True 39 | 40 | return modified 41 | 42 | 43 | def process_notebook(path: Path) -> bool: 44 | try: 45 | with path.open("r", encoding="utf-8") as f: 46 | nb = json.load(f) 47 | except Exception as e: 48 | print(f"Failed to read {path}: {e}", file=sys.stderr) 49 | return False 50 | 51 | modified = remove_widgets_metadata(nb) 52 | if not modified: 53 | print(f"No changes: {path}") 54 | return False 55 | 56 | try: 57 | with path.open("w", encoding="utf-8") as f: 58 | json.dump(nb, f, ensure_ascii=False, indent=1) 59 | f.write("\n") 60 | print(f"Fixed: {path}") 61 | return True 62 | except Exception as e: 63 | print(f"Failed to write {path}: {e}", file=sys.stderr) 64 | return False 65 | 66 | 67 | def main(): 68 | parser = argparse.ArgumentParser(description="Remove metadata.widgets from Jupyter notebooks.") 69 | parser.add_argument("paths", nargs="*", help="Notebook files or directories to process") 70 | args = parser.parse_args() 71 | 72 | if not args.paths: 73 | print("Provide notebook file paths or directories.", file=sys.stderr) 74 | sys.exit(2) 75 | 76 | notebook_files = [] 77 | for p in args.paths: 78 | path = Path(p) 79 | if path.is_dir(): 80 | notebook_files.extend(path.rglob("*.ipynb")) 81 | elif path.is_file() and path.suffix == ".ipynb": 82 | notebook_files.append(path) 83 | else: 84 | print(f"Skipping non-notebook path: {path}") 85 | 86 | if not notebook_files: 87 | print("No notebooks found.", file=sys.stderr) 88 | sys.exit(1) 89 | 90 | any_modified = False 91 | for nb_path in notebook_files: 92 | modified = process_notebook(nb_path) 93 | any_modified = any_modified or modified 94 | 95 | sys.exit(0 if any_modified else 0) 96 | 97 | 98 | if __name__ == "__main__": 99 | main() 100 | 101 | 102 | -------------------------------------------------------------------------------- /Custom LLM/gemini_search_grounding_crewai.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "id": "gNzpQJPNNoyJ" 7 | }, 8 | "source": [ 9 | "# **Using Gemini with Google Search Grounding in CrewAI**\n", 10 | "\n", 11 | "In this notebook, we’ll build a **custom LLM class** that always enables\n", 12 | "Google Search grounding for Gemini. This allows our agents to fetch\n", 13 | "**fresh, up-to-date information from the web** instead of relying only on\n", 14 | "the model’s training data.\n", 15 | "\n", 16 | "---\n", 17 | "\n", 18 | "**Why a Custom LLM?**\n", 19 | "\n", 20 | "CrewAI provides a generic `LLM` wrapper, but it doesn’t yet expose Gemini’s\n", 21 | "`googleSearch` grounding flag. By extending the base `LLM` class, we can\n", 22 | "inject the right tool configuration and ensure every call to Gemini has\n", 23 | "search enabled." 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": { 29 | "id": "l2aA3unROQv7" 30 | }, 31 | "source": [ 32 | "## Install dependecies" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 11, 38 | "metadata": { 39 | "collapsed": true, 40 | "id": "clG-JAhj-jcF" 41 | }, 42 | "outputs": [ 43 | { 44 | "name": "stdout", 45 | "output_type": "stream", 46 | "text": [ 47 | "Note: you may need to restart the kernel to use updated packages.\n" 48 | ] 49 | } 50 | ], 51 | "source": [ 52 | "%uv pip install -U --quiet crewai crewai-tools" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "metadata": { 58 | "id": "1iQYyDDeOMK2" 59 | }, 60 | "source": [ 61 | "## Set up API Key\n", 62 | "\n", 63 | "We’ll use the **Google AI Studio API** (not Vertex). \n", 64 | "To run this notebook, you’ll need a Gemini API key:\n", 65 | "\n", 66 | "🔑 **Generate your API key here:** \n", 67 | "[Google AI Studio – API Key Setup](https://aistudio.google.com/app/apikey)\n", 68 | "\n", 69 | "```bash\n", 70 | "export GEMINI_API_KEY=\"AIza...\" # replace with your key\n", 71 | "```" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 12, 77 | "metadata": { 78 | "id": "LcrII_IaCAox" 79 | }, 80 | "outputs": [ 81 | { 82 | "name": "stdout", 83 | "output_type": "stream", 84 | "text": [ 85 | "✅ GEMINI API key set successfully!\n" 86 | ] 87 | } 88 | ], 89 | "source": [ 90 | "import os\n", 91 | "\n", 92 | "GEMINI_API_KEY = os.getenv('GEMINI_API_KEY')\n", 93 | "\n", 94 | "if GEMINI_API_KEY:\n", 95 | " os.environ['GEMINI_API_KEY'] = GEMINI_API_KEY\n", 96 | " print('✅ GEMINI API key set successfully!')\n", 97 | "else:\n", 98 | " raise ValueError('Please enter GEMINI API key in the environment variables')" 99 | ] 100 | }, 101 | { 102 | "cell_type": "markdown", 103 | "metadata": { 104 | "id": "GU-recdaObWV" 105 | }, 106 | "source": [ 107 | "## Implementing `GeminiWithGoogleSearch`\n", 108 | "\n", 109 | "We define a custom subclass of LLM that:\n", 110 | "\n", 111 | "* Forces the model to use Gemini AI Studio (e.g., gemini/gemini-2.5-pro)\n", 112 | "* Injects the googleSearch grounding tool\n", 113 | "* Passes through CrewAI’s extra arguments (from_task, etc.)\n", 114 | "* Enables `web_search_options` so LiteLLM actually performs the search\n" 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": 13, 120 | "metadata": { 121 | "id": "meRmQateBrjg" 122 | }, 123 | "outputs": [], 124 | "source": [ 125 | "from typing import Any, List, Dict, Union\n", 126 | "from crewai import LLM\n", 127 | "\n", 128 | "class GeminiWithGoogleSearch(LLM):\n", 129 | " \"\"\"\n", 130 | " Custom Gemini LLM using Google AI Studio (NOT Vertex) with Google Search grounding.\n", 131 | " - Injects the 'googleSearch' tool each call\n", 132 | " - Enables LiteLLM's web_search_options so search actually runs\n", 133 | " Requires: os.environ['GEMINI_API_KEY'] or pass api_key=...\n", 134 | " \"\"\"\n", 135 | "\n", 136 | " def __init__(self, model: str | None = None, api_key: str | None = None, **kwargs):\n", 137 | " model = model or os.getenv(\"MODEL\", \"gemini/gemini-2.5-pro\")\n", 138 | " api_key = GEMINI_API_KEY\n", 139 | " if not api_key:\n", 140 | " raise ValueError(\"Missing GEMINI_API_KEY. Set the env var or pass api_key=...\")\n", 141 | "\n", 142 | " super().__init__(model=model, api_key=api_key, **kwargs)\n", 143 | "\n", 144 | " def call(\n", 145 | " self,\n", 146 | " messages: Union[str, List[Dict[str, str]]],\n", 147 | " tools: List[Dict] | None = None,\n", 148 | " callbacks: List[Any] | None = None,\n", 149 | " available_functions: Dict[str, Any] | None = None,\n", 150 | " **kwargs,\n", 151 | " ) -> Union[str, Any]:\n", 152 | " # Inject Gemini's search tool in camelCase\n", 153 | " _tools: List[Dict] = list(tools) if tools else []\n", 154 | " has_google_search = any(\n", 155 | " isinstance(t, dict) and (\"googleSearch\" in t or \"google_search\" in t)\n", 156 | " for t in _tools\n", 157 | " )\n", 158 | " if not has_google_search:\n", 159 | " _tools.insert(0, {\"googleSearch\": {}})\n", 160 | "\n", 161 | " return super().call(\n", 162 | " messages=messages,\n", 163 | " tools=_tools,\n", 164 | " callbacks=callbacks,\n", 165 | " available_functions=available_functions,\n", 166 | " **kwargs,\n", 167 | " )" 168 | ] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "metadata": { 173 | "id": "w_IOeD3zO0RU" 174 | }, 175 | "source": [ 176 | "## Test it with a single Agent\n", 177 | "\n", 178 | "With our new custom LLM, we create a **Company Researcher** agent whose\n", 179 | "job is to find fresh information about a given company.\n", 180 | "\n", 181 | "We’ll test the agent by asking:\n", 182 | "\n", 183 | "> “Fundraising information for OpenRouter Inc.”\n", 184 | "\n", 185 | "\n", 186 | "If everything is working, Gemini should use Google Search to retrieve\n", 187 | "recent funding announcements instead of hallucinating from old data." 188 | ] 189 | }, 190 | { 191 | "cell_type": "code", 192 | "execution_count": 14, 193 | "metadata": { 194 | "colab": { 195 | "base_uri": "https://localhost:8080/", 196 | "height": 1000 197 | }, 198 | "id": "-gFRUzswDsbd", 199 | "outputId": "9dea4622-909c-4599-b041-739c371c758a" 200 | }, 201 | "outputs": [ 202 | { 203 | "data": { 204 | "text/html": [ 205 | "
\n"
206 |             ],
207 |             "text/plain": []
208 |           },
209 |           "metadata": {},
210 |           "output_type": "display_data"
211 |         },
212 |         {
213 |           "data": {
214 |             "text/html": [
215 |               "
╭─────────────────────────────────────────────── LiteAgent Started ───────────────────────────────────────────────╮\n",
216 |               "                                                                                                                 \n",
217 |               "  LiteAgent Session Started                                                                                      \n",
218 |               "  Name: Company Researcher                                                                                       \n",
219 |               "  id: 02995baa-5082-44d4-b6a7-d1f6d9174c2c                                                                       \n",
220 |               "  role: Company Researcher                                                                                       \n",
221 |               "  goal: Fetch current information for a given company and return proper Markdown                                 \n",
222 |               "  backstory: Specializes in searching with Google-grounded Gemini responses.                                     \n",
223 |               "  tools: []                                                                                                      \n",
224 |               "  verbose: True                                                                                                  \n",
225 |               "  Tool Args:                                                                                                     \n",
226 |               "                                                                                                                 \n",
227 |               "                                                                                                                 \n",
228 |               "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
229 |               "
\n" 230 | ], 231 | "text/plain": [ 232 | "\u001b[36m╭─\u001b[0m\u001b[36m──────────────────────────────────────────────\u001b[0m\u001b[36m LiteAgent Started \u001b[0m\u001b[36m──────────────────────────────────────────────\u001b[0m\u001b[36m─╮\u001b[0m\n", 233 | "\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n", 234 | "\u001b[36m│\u001b[0m \u001b[1;36mLiteAgent Session Started\u001b[0m \u001b[36m│\u001b[0m\n", 235 | "\u001b[36m│\u001b[0m \u001b[37mName: \u001b[0m\u001b[36mCompany Researcher\u001b[0m \u001b[36m│\u001b[0m\n", 236 | "\u001b[36m│\u001b[0m \u001b[37mid: \u001b[0m\u001b[36m02995baa-5082-44d4-b6a7-d1f6d9174c2c\u001b[0m \u001b[36m│\u001b[0m\n", 237 | "\u001b[36m│\u001b[0m \u001b[37mrole: \u001b[0m\u001b[36mCompany Researcher\u001b[0m \u001b[36m│\u001b[0m\n", 238 | "\u001b[36m│\u001b[0m \u001b[37mgoal: \u001b[0m\u001b[36mFetch current information for a given company and return proper Markdown\u001b[0m \u001b[36m│\u001b[0m\n", 239 | "\u001b[36m│\u001b[0m \u001b[37mbackstory: \u001b[0m\u001b[36mSpecializes in searching with Google-grounded Gemini responses.\u001b[0m \u001b[36m│\u001b[0m\n", 240 | "\u001b[36m│\u001b[0m \u001b[37mtools: \u001b[0m\u001b[36m[]\u001b[0m \u001b[36m│\u001b[0m\n", 241 | "\u001b[36m│\u001b[0m \u001b[37mverbose: \u001b[0m\u001b[36mTrue\u001b[0m \u001b[36m│\u001b[0m\n", 242 | "\u001b[36m│\u001b[0m \u001b[37mTool Args: \u001b[0m \u001b[36m│\u001b[0m\n", 243 | "\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n", 244 | "\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n", 245 | "\u001b[36m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" 246 | ] 247 | }, 248 | "metadata": {}, 249 | "output_type": "display_data" 250 | }, 251 | { 252 | "data": { 253 | "text/html": [ 254 | "
\n",
255 |               "
\n" 256 | ], 257 | "text/plain": [ 258 | "\n" 259 | ] 260 | }, 261 | "metadata": {}, 262 | "output_type": "display_data" 263 | }, 264 | { 265 | "data": { 266 | "text/html": [ 267 | "
\n"
268 |             ],
269 |             "text/plain": []
270 |           },
271 |           "metadata": {},
272 |           "output_type": "display_data"
273 |         },
274 |         {
275 |           "data": {
276 |             "text/html": [
277 |               "
╭───────────────────────────────────────────── ✅ Agent Final Answer ─────────────────────────────────────────────╮\n",
278 |               "                                                                                                                 \n",
279 |               "  Agent: Company Researcher                                                                                      \n",
280 |               "                                                                                                                 \n",
281 |               "  Final Answer:                                                                                                  \n",
282 |               "  ## OpenRouter Inc. Secures $40 Million in Funding Across Two Rounds                                            \n",
283 |               "                                                                                                                 \n",
284 |               "  OpenRouter Inc., a startup that provides a unified API for accessing over 400 large language models, has       \n",
285 |               "  raised a total of $40.5 million in funding over two rounds. This places the company's valuation at             \n",
286 |               "  approximately $500 million.                                                                                    \n",
287 |               "                                                                                                                 \n",
288 |               "  The company's latest funding was a **$28 million Series A round in April 2025, led by Menlo Ventures**. This   \n",
289 |               "  followed a **$12.5 million seed round in February 2025, led by Andreessen Horowitz**. Other notable investors  \n",
290 |               "  across both rounds include Sequoia Capital, Soma Capital, and angel investor Fred Ehrsam.                      \n",
291 |               "                                                                                                                 \n",
292 |               "  ### Funding Rounds at a Glance:                                                                                \n",
293 |               "                                                                                                                 \n",
294 |               "  | Date | Funding Round | Amount | Lead Investor |                                                              \n",
295 |               "  |---|---|---|---|                                                                                              \n",
296 |               "  | April 2025 | Series A | $28 million | Menlo Ventures |                                                       \n",
297 |               "  | February 2025 | Seed | $12.5 million | Andreessen Horowitz |                                                 \n",
298 |               "                                                                                                                 \n",
299 |               "  Founded in 2023 by Alex Atallah, co-founder of OpenSea, and Louis Vichy, OpenRouter aims to simplify the       \n",
300 |               "  development of AI applications by providing a single point of access to a wide array of models from providers  \n",
301 |               "  like OpenAI, Google, and Anthropic. Their platform is designed to help developers and enterprises seamlessly   \n",
302 |               "  switch between different AI models without the need to rewrite code or manage multiple contracts.              \n",
303 |               "                                                                                                                 \n",
304 |               "  The influx of capital will be used to accelerate product development, expand the number of supported AI        \n",
305 |               "  models, and enhance the platform's enterprise capabilities. OpenRouter has seen significant traction,          \n",
306 |               "  processing over 8.4 trillion tokens per month and managing an annualized inference spending that surpassed     \n",
307 |               "  $100 million in April 2025. This represents a tenfold increase in six months. The company monetizes its        \n",
308 |               "  service by taking a 5% commission on customer inference spending.                                              \n",
309 |               "                                                                                                                 \n",
310 |               "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
311 |               "
\n" 312 | ], 313 | "text/plain": [ 314 | "\u001b[32m╭─\u001b[0m\u001b[32m────────────────────────────────────────────\u001b[0m\u001b[32m ✅ Agent Final Answer \u001b[0m\u001b[32m────────────────────────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", 315 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 316 | "\u001b[32m│\u001b[0m \u001b[37mAgent: \u001b[0m\u001b[1;92mCompany Researcher\u001b[0m \u001b[32m│\u001b[0m\n", 317 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 318 | "\u001b[32m│\u001b[0m \u001b[37mFinal Answer:\u001b[0m \u001b[32m│\u001b[0m\n", 319 | "\u001b[32m│\u001b[0m \u001b[92m## OpenRouter Inc. Secures $40 Million in Funding Across Two Rounds\u001b[0m \u001b[32m│\u001b[0m\n", 320 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 321 | "\u001b[32m│\u001b[0m \u001b[92mOpenRouter Inc., a startup that provides a unified API for accessing over 400 large language models, has \u001b[0m \u001b[32m│\u001b[0m\n", 322 | "\u001b[32m│\u001b[0m \u001b[92mraised a total of $40.5 million in funding over two rounds. This places the company's valuation at \u001b[0m \u001b[32m│\u001b[0m\n", 323 | "\u001b[32m│\u001b[0m \u001b[92mapproximately $500 million.\u001b[0m \u001b[32m│\u001b[0m\n", 324 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 325 | "\u001b[32m│\u001b[0m \u001b[92mThe company's latest funding was a **$28 million Series A round in April 2025, led by Menlo Ventures**. This \u001b[0m \u001b[32m│\u001b[0m\n", 326 | "\u001b[32m│\u001b[0m \u001b[92mfollowed a **$12.5 million seed round in February 2025, led by Andreessen Horowitz**. Other notable investors\u001b[0m \u001b[32m│\u001b[0m\n", 327 | "\u001b[32m│\u001b[0m \u001b[92macross both rounds include Sequoia Capital, Soma Capital, and angel investor Fred Ehrsam.\u001b[0m \u001b[32m│\u001b[0m\n", 328 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 329 | "\u001b[32m│\u001b[0m \u001b[92m### Funding Rounds at a Glance:\u001b[0m \u001b[32m│\u001b[0m\n", 330 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 331 | "\u001b[32m│\u001b[0m \u001b[92m| Date | Funding Round | Amount | Lead Investor |\u001b[0m \u001b[32m│\u001b[0m\n", 332 | "\u001b[32m│\u001b[0m \u001b[92m|---|---|---|---|\u001b[0m \u001b[32m│\u001b[0m\n", 333 | "\u001b[32m│\u001b[0m \u001b[92m| April 2025 | Series A | $28 million | Menlo Ventures |\u001b[0m \u001b[32m│\u001b[0m\n", 334 | "\u001b[32m│\u001b[0m \u001b[92m| February 2025 | Seed | $12.5 million | Andreessen Horowitz |\u001b[0m \u001b[32m│\u001b[0m\n", 335 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 336 | "\u001b[32m│\u001b[0m \u001b[92mFounded in 2023 by Alex Atallah, co-founder of OpenSea, and Louis Vichy, OpenRouter aims to simplify the \u001b[0m \u001b[32m│\u001b[0m\n", 337 | "\u001b[32m│\u001b[0m \u001b[92mdevelopment of AI applications by providing a single point of access to a wide array of models from providers\u001b[0m \u001b[32m│\u001b[0m\n", 338 | "\u001b[32m│\u001b[0m \u001b[92mlike OpenAI, Google, and Anthropic. Their platform is designed to help developers and enterprises seamlessly \u001b[0m \u001b[32m│\u001b[0m\n", 339 | "\u001b[32m│\u001b[0m \u001b[92mswitch between different AI models without the need to rewrite code or manage multiple contracts.\u001b[0m \u001b[32m│\u001b[0m\n", 340 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 341 | "\u001b[32m│\u001b[0m \u001b[92mThe influx of capital will be used to accelerate product development, expand the number of supported AI \u001b[0m \u001b[32m│\u001b[0m\n", 342 | "\u001b[32m│\u001b[0m \u001b[92mmodels, and enhance the platform's enterprise capabilities. OpenRouter has seen significant traction, \u001b[0m \u001b[32m│\u001b[0m\n", 343 | "\u001b[32m│\u001b[0m \u001b[92mprocessing over 8.4 trillion tokens per month and managing an annualized inference spending that surpassed \u001b[0m \u001b[32m│\u001b[0m\n", 344 | "\u001b[32m│\u001b[0m \u001b[92m$100 million in April 2025. This represents a tenfold increase in six months. The company monetizes its \u001b[0m \u001b[32m│\u001b[0m\n", 345 | "\u001b[32m│\u001b[0m \u001b[92mservice by taking a 5% commission on customer inference spending.\u001b[0m \u001b[32m│\u001b[0m\n", 346 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 347 | "\u001b[32m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" 348 | ] 349 | }, 350 | "metadata": {}, 351 | "output_type": "display_data" 352 | }, 353 | { 354 | "data": { 355 | "text/html": [ 356 | "
\n",
357 |               "
\n" 358 | ], 359 | "text/plain": [ 360 | "\n" 361 | ] 362 | }, 363 | "metadata": {}, 364 | "output_type": "display_data" 365 | }, 366 | { 367 | "data": { 368 | "text/html": [ 369 | "
\n"
370 |             ],
371 |             "text/plain": []
372 |           },
373 |           "metadata": {},
374 |           "output_type": "display_data"
375 |         },
376 |         {
377 |           "data": {
378 |             "text/html": [
379 |               "
╭───────────────────────────────────────────── LiteAgent Completion ──────────────────────────────────────────────╮\n",
380 |               "                                                                                                                 \n",
381 |               "  LiteAgent Completed                                                                                            \n",
382 |               "  Name: Company Researcher                                                                                       \n",
383 |               "  id: 02995baa-5082-44d4-b6a7-d1f6d9174c2c                                                                       \n",
384 |               "  role: Company Researcher                                                                                       \n",
385 |               "  goal: Fetch current information for a given company and return proper Markdown                                 \n",
386 |               "  backstory: Specializes in searching with Google-grounded Gemini responses.                                     \n",
387 |               "  tools: []                                                                                                      \n",
388 |               "  verbose: True                                                                                                  \n",
389 |               "  Tool Args:                                                                                                     \n",
390 |               "                                                                                                                 \n",
391 |               "                                                                                                                 \n",
392 |               "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
393 |               "
\n" 394 | ], 395 | "text/plain": [ 396 | "\u001b[32m╭─\u001b[0m\u001b[32m────────────────────────────────────────────\u001b[0m\u001b[32m LiteAgent Completion \u001b[0m\u001b[32m─────────────────────────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", 397 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 398 | "\u001b[32m│\u001b[0m \u001b[1;32mLiteAgent Completed\u001b[0m \u001b[32m│\u001b[0m\n", 399 | "\u001b[32m│\u001b[0m \u001b[37mName: \u001b[0m\u001b[32mCompany Researcher\u001b[0m \u001b[32m│\u001b[0m\n", 400 | "\u001b[32m│\u001b[0m \u001b[37mid: \u001b[0m\u001b[32m02995baa-5082-44d4-b6a7-d1f6d9174c2c\u001b[0m \u001b[32m│\u001b[0m\n", 401 | "\u001b[32m│\u001b[0m \u001b[37mrole: \u001b[0m\u001b[32mCompany Researcher\u001b[0m \u001b[32m│\u001b[0m\n", 402 | "\u001b[32m│\u001b[0m \u001b[37mgoal: \u001b[0m\u001b[32mFetch current information for a given company and return proper Markdown\u001b[0m \u001b[32m│\u001b[0m\n", 403 | "\u001b[32m│\u001b[0m \u001b[37mbackstory: \u001b[0m\u001b[32mSpecializes in searching with Google-grounded Gemini responses.\u001b[0m \u001b[32m│\u001b[0m\n", 404 | "\u001b[32m│\u001b[0m \u001b[37mtools: \u001b[0m\u001b[32m[]\u001b[0m \u001b[32m│\u001b[0m\n", 405 | "\u001b[32m│\u001b[0m \u001b[37mverbose: \u001b[0m\u001b[32mTrue\u001b[0m \u001b[32m│\u001b[0m\n", 406 | "\u001b[32m│\u001b[0m \u001b[37mTool Args: \u001b[0m \u001b[32m│\u001b[0m\n", 407 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 408 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 409 | "\u001b[32m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" 410 | ] 411 | }, 412 | "metadata": {}, 413 | "output_type": "display_data" 414 | }, 415 | { 416 | "data": { 417 | "text/html": [ 418 | "
\n",
419 |               "
\n" 420 | ], 421 | "text/plain": [ 422 | "\n" 423 | ] 424 | }, 425 | "metadata": {}, 426 | "output_type": "display_data" 427 | } 428 | ], 429 | "source": [ 430 | "from crewai import Agent\n", 431 | "\n", 432 | "gemini_with_search = GeminiWithGoogleSearch()\n", 433 | "\n", 434 | "researcher = Agent(\n", 435 | " role=\"Company Researcher\",\n", 436 | " goal=\"Fetch current information for a given company and return proper Markdown\",\n", 437 | " backstory=\"Specializes in searching with Google-grounded Gemini responses.\",\n", 438 | " llm=gemini_with_search,\n", 439 | " verbose=True,\n", 440 | ")\n", 441 | "\n", 442 | "output = researcher.kickoff(messages=\"Fundraising information for OpenRouter Inc.\")" 443 | ] 444 | }, 445 | { 446 | "cell_type": "markdown", 447 | "metadata": { 448 | "id": "sUVmcWdFNd1y" 449 | }, 450 | "source": [ 451 | "## Raw output from the agent" 452 | ] 453 | }, 454 | { 455 | "cell_type": "code", 456 | "execution_count": 15, 457 | "metadata": { 458 | "colab": { 459 | "base_uri": "https://localhost:8080/" 460 | }, 461 | "id": "zTefbfarNW7W", 462 | "outputId": "6b808bf2-eeb8-4e9b-9505-31ade21ed623" 463 | }, 464 | "outputs": [ 465 | { 466 | "data": { 467 | "text/plain": [ 468 | "LiteAgentOutput(raw=\"## OpenRouter Inc. Secures $40 Million in Funding Across Two Rounds\\n\\nOpenRouter Inc., a startup that provides a unified API for accessing over 400 large language models, has raised a total of $40.5 million in funding over two rounds. This places the company's valuation at approximately $500 million.\\n\\nThe company's latest funding was a **$28 million Series A round in April 2025, led by Menlo Ventures**. This followed a **$12.5 million seed round in February 2025, led by Andreessen Horowitz**. Other notable investors across both rounds include Sequoia Capital, Soma Capital, and angel investor Fred Ehrsam.\\n\\n### Funding Rounds at a Glance:\\n\\n| Date | Funding Round | Amount | Lead Investor |\\n|---|---|---|---|\\n| April 2025 | Series A | $28 million | Menlo Ventures |\\n| February 2025 | Seed | $12.5 million | Andreessen Horowitz |\\n\\nFounded in 2023 by Alex Atallah, co-founder of OpenSea, and Louis Vichy, OpenRouter aims to simplify the development of AI applications by providing a single point of access to a wide array of models from providers like OpenAI, Google, and Anthropic. Their platform is designed to help developers and enterprises seamlessly switch between different AI models without the need to rewrite code or manage multiple contracts.\\n\\nThe influx of capital will be used to accelerate product development, expand the number of supported AI models, and enhance the platform's enterprise capabilities. OpenRouter has seen significant traction, processing over 8.4 trillion tokens per month and managing an annualized inference spending that surpassed $100 million in April 2025. This represents a tenfold increase in six months. The company monetizes its service by taking a 5% commission on customer inference spending.\", pydantic=None, agent_role='Company Researcher', usage_metrics={'total_tokens': 791, 'prompt_tokens': 108, 'cached_prompt_tokens': 0, 'completion_tokens': 683, 'successful_requests': 1})" 469 | ] 470 | }, 471 | "execution_count": 15, 472 | "metadata": {}, 473 | "output_type": "execute_result" 474 | } 475 | ], 476 | "source": [ 477 | "output" 478 | ] 479 | }, 480 | { 481 | "cell_type": "markdown", 482 | "metadata": { 483 | "id": "rzuvxaXyNimu" 484 | }, 485 | "source": [ 486 | "## Rendering output nicely\n", 487 | "\n", 488 | "Gemini often returns markdown-style text. To display it cleanly inside\n", 489 | "a Jupyter notebook, we use `IPython.display.Markdown`.\n", 490 | "Since Gemini’s formatting can be inconsistent, we add a small normalizer\n", 491 | "to fix bullets, headings, and spacing before rendering." 492 | ] 493 | }, 494 | { 495 | "cell_type": "code", 496 | "execution_count": 17, 497 | "metadata": { 498 | "colab": { 499 | "base_uri": "https://localhost:8080/", 500 | "height": 244 501 | }, 502 | "id": "Le4pgMiXKwMB", 503 | "outputId": "79b5169b-5bbb-4683-be90-f3ba071c8f5f" 504 | }, 505 | "outputs": [ 506 | { 507 | "data": { 508 | "text/markdown": [ 509 | "## OpenRouter Inc. Secures $40 Million in Funding Across Two Rounds\n", 510 | "\n", 511 | "OpenRouter Inc., a startup that provides a unified API for accessing over 400 large language models, has raised a total of $40.5 million in funding over two rounds. This places the company's valuation at approximately $500 million.\n", 512 | "\n", 513 | "The company's latest funding was a **$28 million Series A round in April 2025, led by Menlo Ventures**. This followed a **$12.5 million seed round in February 2025, led by Andreessen Horowitz**. Other notable investors across both rounds include Sequoia Capital, Soma Capital, and angel investor Fred Ehrsam.\n", 514 | "\n", 515 | "### Funding Rounds at a Glance:\n", 516 | "\n", 517 | "| Date | Funding Round | Amount | Lead Investor |\n", 518 | "|---|---|---|---|\n", 519 | "| April 2025 | Series A | $28 million | Menlo Ventures |\n", 520 | "| February 2025 | Seed | $12.5 million | Andreessen Horowitz |\n", 521 | "\n", 522 | "Founded in 2023 by Alex Atallah, co-founder of OpenSea, and Louis Vichy, OpenRouter aims to simplify the development of AI applications by providing a single point of access to a wide array of models from providers like OpenAI, Google, and Anthropic. Their platform is designed to help developers and enterprises seamlessly switch between different AI models without the need to rewrite code or manage multiple contracts.\n", 523 | "\n", 524 | "The influx of capital will be used to accelerate product development, expand the number of supported AI models, and enhance the platform's enterprise capabilities. OpenRouter has seen significant traction, processing over 8.4 trillion tokens per month and managing an annualized inference spending that surpassed $100 million in April 2025. This represents a tenfold increase in six months. The company monetizes its service by taking a 5% commission on customer inference spending." 525 | ], 526 | "text/plain": [ 527 | "" 528 | ] 529 | }, 530 | "metadata": {}, 531 | "output_type": "display_data" 532 | } 533 | ], 534 | "source": [ 535 | "from IPython.display import display, Markdown\n", 536 | "display(Markdown(output.raw))" 537 | ] 538 | }, 539 | { 540 | "cell_type": "markdown", 541 | "metadata": {}, 542 | "source": [ 543 | "## Further Reading & Support\n", 544 | "\n", 545 | "📘 CrewAI Docs – Custom LLM Implementation:\n", 546 | "https://docs.crewai.com/how-to/custom-llm\n", 547 | "\n", 548 | "📘 CrewAI Docs – Agents & LLMs:\n", 549 | "https://docs.crewai.com/concepts/agents\n", 550 | "\n", 551 | "💬 CrewAI Community Forum (Q&A, discussions):\n", 552 | "https://community.crewai.com\n", 553 | "\n", 554 | "📘 Gemini API Docs – Grounding with Google Search:\n", 555 | "https://ai.google.dev/gemini-api/docs/grounding" 556 | ] 557 | } 558 | ], 559 | "metadata": { 560 | "colab": { 561 | "provenance": [] 562 | }, 563 | "kernelspec": { 564 | "display_name": ".venv", 565 | "language": "python", 566 | "name": "python3" 567 | }, 568 | "language_info": { 569 | "codemirror_mode": { 570 | "name": "ipython", 571 | "version": 3 572 | }, 573 | "file_extension": ".py", 574 | "mimetype": "text/x-python", 575 | "name": "python", 576 | "nbconvert_exporter": "python", 577 | "pygments_lexer": "ipython3", 578 | "version": "3.12.6" 579 | } 580 | }, 581 | "nbformat": 4, 582 | "nbformat_minor": 0 583 | } 584 | -------------------------------------------------------------------------------- /Guardrails/task_guardrails.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "id": "vh58zkJWdXaL" 7 | }, 8 | "source": [ 9 | "# **Introduction to Task Guardrails in CrewAI**\n", 10 | "\n", 11 | "This notebook will demonstrate using CrewAI Task Guardrails — a powerful way to add custom validation logic to your agent workflows.\n", 12 | "\n", 13 | "Just like bumpers in bowling, guardrails help your AI agents stay on track by validating the output of a task and deciding whether it needs to retry.\n", 14 | "\n", 15 | "We’ll show you how to:\n", 16 | "* Write a custom guardrail function\n", 17 | "* Attach it to a task\n", 18 | "* Automatically retry until the output meets your criteria\n", 19 | "\n", 20 | "Let’s get started! 🚀" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "metadata": { 26 | "id": "qOIyf22hegRt" 27 | }, 28 | "source": [ 29 | "## Setup: Imports and API Key\n", 30 | "Before we define our agent and guardrail logic, we import the required modules from CrewAI and initialize the LLM.\n", 31 | "\n", 32 | "We'll also use a search tool (**SerperDevTool**) and the **TaskOutput** object to handle validation logic." 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": 1, 38 | "metadata": { 39 | "collapsed": true, 40 | "id": "gSX3sW2rBqDi" 41 | }, 42 | "outputs": [ 43 | { 44 | "name": "stdout", 45 | "output_type": "stream", 46 | "text": [ 47 | "Note: you may need to restart the kernel to use updated packages.\n" 48 | ] 49 | } 50 | ], 51 | "source": [ 52 | "%uv pip install -U -q crewai crewai-tools" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": 2, 58 | "metadata": { 59 | "id": "cfyB1y_2eu5m" 60 | }, 61 | "outputs": [ 62 | { 63 | "name": "stderr", 64 | "output_type": "stream", 65 | "text": [ 66 | "/Users/tonykipkemboi/Workspace/crewAI-quickstarts/.venv/lib/python3.12/site-packages/pydantic/_internal/_config.py:323: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.11/migration/\n", 67 | " warnings.warn(DEPRECATION_MESSAGE, DeprecationWarning)\n" 68 | ] 69 | } 70 | ], 71 | "source": [ 72 | "from crewai import Agent, Task, LLM, Crew\n", 73 | "from typing import Tuple, Union, Dict, Any\n", 74 | "from crewai import TaskOutput\n", 75 | "from datetime import date\n", 76 | "from crewai_tools import SerperDevTool" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 3, 82 | "metadata": { 83 | "id": "2XBfhfbJU8-s" 84 | }, 85 | "outputs": [], 86 | "source": [ 87 | "# Filter out deprecation warnings\n", 88 | "import warnings\n", 89 | "warnings.filterwarnings(\"ignore\")\n", 90 | "warnings.filterwarnings(\"ignore\", category=SyntaxWarning, module=\"pysbd\")" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 5, 96 | "metadata": { 97 | "id": "hvF9pE31BwTx" 98 | }, 99 | "outputs": [ 100 | { 101 | "name": "stdout", 102 | "output_type": "stream", 103 | "text": [ 104 | "✅ API keys set successfully!\n" 105 | ] 106 | } 107 | ], 108 | "source": [ 109 | "import os\n", 110 | "\n", 111 | "SERPER_API_KEY = os.getenv('SERPER_API_KEY')\n", 112 | "OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')\n", 113 | "\n", 114 | "if SERPER_API_KEY and OPENAI_API_KEY:\n", 115 | " os.environ['SERPER_API_KEY'] = SERPER_API_KEY\n", 116 | " os.environ['OPENAI_API_KEY'] = OPENAI_API_KEY\n", 117 | " print('✅ API keys set successfully!')\n", 118 | "else:\n", 119 | " raise ValueError('Please enter both SERPER and OPENAI API keys')" 120 | ] 121 | }, 122 | { 123 | "cell_type": "markdown", 124 | "metadata": { 125 | "id": "iIVHahH3e89n" 126 | }, 127 | "source": [ 128 | "## Custom Guardrail Function\n", 129 | "Here’s where the magic happens!\n", 130 | "\n", 131 | "We're defining a custom validation function called **validate_blog_content**. This function checks the output of a task — in this case, we’re enforcing that the result is less than **{pick-your-word-count}** words.\n", 132 | "\n", 133 | "If it passes the check, the task is complete.\n", 134 | "If it fails, CrewAI will retry it (up to the number of retries you specify)." 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": 7, 140 | "metadata": { 141 | "id": "QuTqdqYje7Tg" 142 | }, 143 | "outputs": [], 144 | "source": [ 145 | "def validate_blog_content(result: TaskOutput) -> Tuple[bool, Any]:\n", 146 | " \"\"\"Validate blog content meets requirements.\"\"\"\n", 147 | " try:\n", 148 | " # Check word count\n", 149 | " try:\n", 150 | " word_count = len(result.raw.split())\n", 151 | " print(f\"Word count: {word_count}\")\n", 152 | " if word_count > 50:\n", 153 | " return (False, \"Blog content exceeds 50 words\")\n", 154 | " except Exception as wc_error:\n", 155 | " print(f\"Error during word count check: {wc_error}\")\n", 156 | " return (False, f\"Error during word count check: {wc_error}\")\n", 157 | "\n", 158 | "\n", 159 | " # Additional validation logic here\n", 160 | " return (True, result.raw.strip())\n", 161 | " except Exception as e:\n", 162 | " print(f\"Unexpected error during validation: {e}\")\n", 163 | " return (False, f\"Unexpected error during validation: {e}\")" 164 | ] 165 | }, 166 | { 167 | "cell_type": "markdown", 168 | "metadata": { 169 | "id": "JtA01oODgD4q" 170 | }, 171 | "source": [ 172 | "## Define your Crew (Agent + Task + Tools)\n", 173 | "Now we create a simple agent called \"**Blog Writer**\" whose goal is to generate blog content." 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": 8, 179 | "metadata": { 180 | "collapsed": true, 181 | "id": "_eE-FoH1BkdL" 182 | }, 183 | "outputs": [], 184 | "source": [ 185 | "# LLM to be used by the agent(s)\n", 186 | "llm = LLM(model=\"gpt-4o-mini\", api_key=OPENAI_API_KEY)\n", 187 | "\n", 188 | "blog_agent = Agent(\n", 189 | " role=\"Blog Writer\",\n", 190 | " goal=\"Write blog post\",\n", 191 | " backstory=\"An expert blog writer\",\n", 192 | " tools=[SerperDevTool()],\n", 193 | " llm=llm,\n", 194 | " verbose=True\n", 195 | ")\n", 196 | "\n", 197 | "blog_task = Task(\n", 198 | " description=\"Write a super DETAILED blog post about {prompt} for {year}\",\n", 199 | " expected_output=\"\"\"A properly structured blog post under 50 words.\n", 200 | " Blog format:\n", 201 | " # Title\n", 202 | " ## Subtitle\n", 203 | " Paragraphs...\n", 204 | " \"\"\",\n", 205 | " agent=blog_agent,\n", 206 | " markdown=True,\n", 207 | " guardrail=validate_blog_content, # Add the guardrail function\n", 208 | " max_retries=4 # Set the maximum number of retries\n", 209 | ")\n", 210 | "\n", 211 | "crew = Crew(\n", 212 | " agents=[blog_agent],\n", 213 | " tasks=[blog_task],\n", 214 | " verbose=True\n", 215 | ")" 216 | ] 217 | }, 218 | { 219 | "cell_type": "markdown", 220 | "metadata": { 221 | "id": "NTWprkOWfyjs" 222 | }, 223 | "source": [ 224 | "## Launch the Crew\n", 225 | "Finally, we bundle the agent and task into a **Crew**, pass in some inputs (*prompt* and *year*), and run it using **.kickoff()**." 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": 9, 231 | "metadata": { 232 | "id": "WOHsWzcrf5mr" 233 | }, 234 | "outputs": [ 235 | { 236 | "data": { 237 | "text/html": [ 238 | "
╭──────────────────────────────────────────── Crew Execution Started ─────────────────────────────────────────────╮\n",
239 |               "                                                                                                                 \n",
240 |               "  Crew Execution Started                                                                                         \n",
241 |               "  Name: crew                                                                                                     \n",
242 |               "  ID: 53c93fc0-e371-4f37-b56f-c30c73a7923d                                                                       \n",
243 |               "  Tool Args:                                                                                                     \n",
244 |               "                                                                                                                 \n",
245 |               "                                                                                                                 \n",
246 |               "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
247 |               "
\n" 248 | ], 249 | "text/plain": [ 250 | "\u001b[36m╭─\u001b[0m\u001b[36m───────────────────────────────────────────\u001b[0m\u001b[36m Crew Execution Started \u001b[0m\u001b[36m────────────────────────────────────────────\u001b[0m\u001b[36m─╮\u001b[0m\n", 251 | "\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n", 252 | "\u001b[36m│\u001b[0m \u001b[1;36mCrew Execution Started\u001b[0m \u001b[36m│\u001b[0m\n", 253 | "\u001b[36m│\u001b[0m \u001b[37mName: \u001b[0m\u001b[36mcrew\u001b[0m \u001b[36m│\u001b[0m\n", 254 | "\u001b[36m│\u001b[0m \u001b[37mID: \u001b[0m\u001b[36m53c93fc0-e371-4f37-b56f-c30c73a7923d\u001b[0m \u001b[36m│\u001b[0m\n", 255 | "\u001b[36m│\u001b[0m \u001b[37mTool Args: \u001b[0m \u001b[36m│\u001b[0m\n", 256 | "\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n", 257 | "\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n", 258 | "\u001b[36m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" 259 | ] 260 | }, 261 | "metadata": {}, 262 | "output_type": "display_data" 263 | }, 264 | { 265 | "data": { 266 | "text/html": [ 267 | "
\n",
268 |               "
\n" 269 | ], 270 | "text/plain": [ 271 | "\n" 272 | ] 273 | }, 274 | "metadata": {}, 275 | "output_type": "display_data" 276 | }, 277 | { 278 | "data": { 279 | "text/html": [ 280 | "
\n"
281 |             ],
282 |             "text/plain": []
283 |           },
284 |           "metadata": {},
285 |           "output_type": "display_data"
286 |         },
287 |         {
288 |           "data": {
289 |             "text/html": [
290 |               "
╭─────────────────────────────────────────────── 🤖 Agent Started ────────────────────────────────────────────────╮\n",
291 |               "                                                                                                                 \n",
292 |               "  Agent: Blog Writer                                                                                             \n",
293 |               "                                                                                                                 \n",
294 |               "  Task: Write a super DETAILED blog post about CrewAI for 2025                                                   \n",
295 |               "                                                                                                                 \n",
296 |               "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
297 |               "
\n" 298 | ], 299 | "text/plain": [ 300 | "\u001b[35m╭─\u001b[0m\u001b[35m──────────────────────────────────────────────\u001b[0m\u001b[35m 🤖 Agent Started \u001b[0m\u001b[35m───────────────────────────────────────────────\u001b[0m\u001b[35m─╮\u001b[0m\n", 301 | "\u001b[35m│\u001b[0m \u001b[35m│\u001b[0m\n", 302 | "\u001b[35m│\u001b[0m \u001b[37mAgent: \u001b[0m\u001b[1;92mBlog Writer\u001b[0m \u001b[35m│\u001b[0m\n", 303 | "\u001b[35m│\u001b[0m \u001b[35m│\u001b[0m\n", 304 | "\u001b[35m│\u001b[0m \u001b[37mTask: \u001b[0m\u001b[92mWrite a super DETAILED blog post about CrewAI for 2025\u001b[0m \u001b[35m│\u001b[0m\n", 305 | "\u001b[35m│\u001b[0m \u001b[35m│\u001b[0m\n", 306 | "\u001b[35m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" 307 | ] 308 | }, 309 | "metadata": {}, 310 | "output_type": "display_data" 311 | }, 312 | { 313 | "data": { 314 | "text/html": [ 315 | "
\n",
316 |               "
\n" 317 | ], 318 | "text/plain": [ 319 | "\n" 320 | ] 321 | }, 322 | "metadata": {}, 323 | "output_type": "display_data" 324 | }, 325 | { 326 | "data": { 327 | "text/html": [ 328 | "
\n"
329 |             ],
330 |             "text/plain": []
331 |           },
332 |           "metadata": {},
333 |           "output_type": "display_data"
334 |         },
335 |         {
336 |           "data": {
337 |             "text/html": [
338 |               "
╭──────────────────────────────────────────── 🔧 Agent Tool Execution ────────────────────────────────────────────╮\n",
339 |               "                                                                                                                 \n",
340 |               "  Agent: Blog Writer                                                                                             \n",
341 |               "                                                                                                                 \n",
342 |               "  Thought: Action: Search the internet with Serper                                                               \n",
343 |               "                                                                                                                 \n",
344 |               "  Using Tool: Search the internet with Serper                                                                    \n",
345 |               "                                                                                                                 \n",
346 |               "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
347 |               "
\n" 348 | ], 349 | "text/plain": [ 350 | "\u001b[35m╭─\u001b[0m\u001b[35m───────────────────────────────────────────\u001b[0m\u001b[35m 🔧 Agent Tool Execution \u001b[0m\u001b[35m───────────────────────────────────────────\u001b[0m\u001b[35m─╮\u001b[0m\n", 351 | "\u001b[35m│\u001b[0m \u001b[35m│\u001b[0m\n", 352 | "\u001b[35m│\u001b[0m \u001b[37mAgent: \u001b[0m\u001b[1;92mBlog Writer\u001b[0m \u001b[35m│\u001b[0m\n", 353 | "\u001b[35m│\u001b[0m \u001b[35m│\u001b[0m\n", 354 | "\u001b[35m│\u001b[0m \u001b[37mThought: \u001b[0m\u001b[92mAction: Search the internet with Serper\u001b[0m \u001b[35m│\u001b[0m\n", 355 | "\u001b[35m│\u001b[0m \u001b[35m│\u001b[0m\n", 356 | "\u001b[35m│\u001b[0m \u001b[37mUsing Tool: \u001b[0m\u001b[1;92mSearch the internet with Serper\u001b[0m \u001b[35m│\u001b[0m\n", 357 | "\u001b[35m│\u001b[0m \u001b[35m│\u001b[0m\n", 358 | "\u001b[35m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" 359 | ] 360 | }, 361 | "metadata": {}, 362 | "output_type": "display_data" 363 | }, 364 | { 365 | "data": { 366 | "text/html": [ 367 | "
╭────────────────────────────────────────────────── Tool Input ───────────────────────────────────────────────────╮\n",
368 |               "                                                                                                                 \n",
369 |               "  \"{\\\"search_query\\\": \\\"CrewAI 2025 features and updates\\\"}\"                                                     \n",
370 |               "                                                                                                                 \n",
371 |               "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
372 |               "
\n" 373 | ], 374 | "text/plain": [ 375 | "\u001b[34m╭─\u001b[0m\u001b[34m─────────────────────────────────────────────────\u001b[0m\u001b[34m Tool Input \u001b[0m\u001b[34m──────────────────────────────────────────────────\u001b[0m\u001b[34m─╮\u001b[0m\n", 376 | "\u001b[34m│\u001b[0m \u001b[34m│\u001b[0m\n", 377 | "\u001b[34m│\u001b[0m \u001b[38;2;230;219;116;49m\"{\\\"search_query\\\": \\\"CrewAI 2025 features and updates\\\"}\"\u001b[0m \u001b[34m│\u001b[0m\n", 378 | "\u001b[34m│\u001b[0m \u001b[34m│\u001b[0m\n", 379 | "\u001b[34m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" 380 | ] 381 | }, 382 | "metadata": {}, 383 | "output_type": "display_data" 384 | }, 385 | { 386 | "data": { 387 | "text/html": [ 388 | "
╭────────────────────────────────────────────────── Tool Output ──────────────────────────────────────────────────╮\n",
389 |               "                                                                                                                 \n",
390 |               "  {'searchParameters': {'q': 'CrewAI 2025 features and updates', 'type': 'search', 'num': 10, 'engine':          \n",
391 |               "  'google'}, 'organic': [{'title': 'CrewAI Review 2025: The Right Sales Tool for Your Business?', 'link':        \n",
392 |               "  'https://reply.io/blog/crew-ai-review/', 'snippet': 'Key features include:', 'position': 1}, {'title': 'How    \n",
393 |               "  CrewAI is evolving beyond orchestration to create the most ...', 'link':                                       \n",
394 |               "  'https://blog.crewai.com/how-crewai-is-evolving-beyond-orchestration-to-create-the-most-powerful-agentic-ai-p  \n",
395 |               "  latform/', 'snippet': 'CrewAI has added a number of features to not support agentic RAG, but to provide        \n",
396 |               "  developers with greater flexibility. ... CrewAI © 2025.', 'position': 2}, {'title': 'CrewAI Pricing,           \n",
397 |               "  Features, & Alternatives Explained (2025) - Lindy', 'link': 'https://www.lindy.ai/blog/crew-ai-pricing',       \n",
398 |               "  'snippet': 'As your needs grow, you can upgrade to a higher plan with more executions, deployed crews, and     \n",
399 |               "  onboarding support. Annual billing discounts.', 'position': 3}, {'title': 'CrewAI', 'link':                    \n",
400 |               "  'https://www.crewai.com/', 'snippet': 'Streamline workflows across industries with powerful AI agents. Build   \n",
401 |               "  and deploy automated workflows using any LLM and cloud platform. Request a Demo.', 'position': 4,              \n",
402 |               "  'sitelinks': [{'title': 'CrewAI', 'link': 'https://blog.crewai.com/'}, {'title': 'Multi Agent Systems and      \n",
403 |               "  how...', 'link': 'https://learn.crewai.com/'}, {'title': 'Open source', 'link':                                \n",
404 |               "  'https://www.crewai.com/open-source'}, {'title': 'Documentation', 'link': 'https://docs.crewai.com/'}]},       \n",
405 |               "  {'title': 'New Release - 0.126.0 - Announcements - CrewAI', 'link':                                            \n",
406 |               "  'https://community.crewai.com/t/new-release-0-126-0/6112', 'snippet': 'CrewAI v0.126.0 is out!                 \n",
407 |               "  :police_car_light: Core Improvements & Fixes • Added support for Python 3.13 • Fixed agent knowledge sources   \n",
408 |               "  issue.', 'position': 5}, {'title': 'CrewAI Review 2025: Is It Really Worth Your Money? - Lindy', 'link':       \n",
409 |               "  'https://www.lindy.ai/blog/crew-ai', 'snippet': 'CrewAI is an open-source tool that lets developers make AI    \n",
410 |               "  agents. Y...                                                                                                   \n",
411 |               "                                                                                                                 \n",
412 |               "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
413 |               "
\n" 414 | ], 415 | "text/plain": [ 416 | "\u001b[32m╭─\u001b[0m\u001b[32m─────────────────────────────────────────────────\u001b[0m\u001b[32m Tool Output \u001b[0m\u001b[32m─────────────────────────────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", 417 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 418 | "\u001b[32m│\u001b[0m \u001b[92m{'searchParameters': {'q': 'CrewAI 2025 features and updates', 'type': 'search', 'num': 10, 'engine': \u001b[0m \u001b[32m│\u001b[0m\n", 419 | "\u001b[32m│\u001b[0m \u001b[92m'google'}, 'organic': [{'title': 'CrewAI Review 2025: The Right Sales Tool for Your Business?', 'link': \u001b[0m \u001b[32m│\u001b[0m\n", 420 | "\u001b[32m│\u001b[0m \u001b[92m'https://reply.io/blog/crew-ai-review/', 'snippet': 'Key features include:', 'position': 1}, {'title': 'How \u001b[0m \u001b[32m│\u001b[0m\n", 421 | "\u001b[32m│\u001b[0m \u001b[92mCrewAI is evolving beyond orchestration to create the most ...', 'link': \u001b[0m \u001b[32m│\u001b[0m\n", 422 | "\u001b[32m│\u001b[0m \u001b[92m'https://blog.crewai.com/how-crewai-is-evolving-beyond-orchestration-to-create-the-most-powerful-agentic-ai-p\u001b[0m \u001b[32m│\u001b[0m\n", 423 | "\u001b[32m│\u001b[0m \u001b[92mlatform/', 'snippet': 'CrewAI has added a number of features to not support agentic RAG, but to provide \u001b[0m \u001b[32m│\u001b[0m\n", 424 | "\u001b[32m│\u001b[0m \u001b[92mdevelopers with greater flexibility. ... CrewAI © 2025.', 'position': 2}, {'title': 'CrewAI Pricing, \u001b[0m \u001b[32m│\u001b[0m\n", 425 | "\u001b[32m│\u001b[0m \u001b[92mFeatures, & Alternatives Explained (2025) - Lindy', 'link': 'https://www.lindy.ai/blog/crew-ai-pricing', \u001b[0m \u001b[32m│\u001b[0m\n", 426 | "\u001b[32m│\u001b[0m \u001b[92m'snippet': 'As your needs grow, you can upgrade to a higher plan with more executions, deployed crews, and \u001b[0m \u001b[32m│\u001b[0m\n", 427 | "\u001b[32m│\u001b[0m \u001b[92monboarding support. Annual billing discounts.', 'position': 3}, {'title': 'CrewAI', 'link': \u001b[0m \u001b[32m│\u001b[0m\n", 428 | "\u001b[32m│\u001b[0m \u001b[92m'https://www.crewai.com/', 'snippet': 'Streamline workflows across industries with powerful AI agents. Build \u001b[0m \u001b[32m│\u001b[0m\n", 429 | "\u001b[32m│\u001b[0m \u001b[92mand deploy automated workflows using any LLM and cloud platform. Request a Demo.', 'position': 4, \u001b[0m \u001b[32m│\u001b[0m\n", 430 | "\u001b[32m│\u001b[0m \u001b[92m'sitelinks': [{'title': 'CrewAI', 'link': 'https://blog.crewai.com/'}, {'title': 'Multi Agent Systems and \u001b[0m \u001b[32m│\u001b[0m\n", 431 | "\u001b[32m│\u001b[0m \u001b[92mhow...', 'link': 'https://learn.crewai.com/'}, {'title': 'Open source', 'link': \u001b[0m \u001b[32m│\u001b[0m\n", 432 | "\u001b[32m│\u001b[0m \u001b[92m'https://www.crewai.com/open-source'}, {'title': 'Documentation', 'link': 'https://docs.crewai.com/'}]}, \u001b[0m \u001b[32m│\u001b[0m\n", 433 | "\u001b[32m│\u001b[0m \u001b[92m{'title': 'New Release - 0.126.0 - Announcements - CrewAI', 'link': \u001b[0m \u001b[32m│\u001b[0m\n", 434 | "\u001b[32m│\u001b[0m \u001b[92m'https://community.crewai.com/t/new-release-0-126-0/6112', 'snippet': 'CrewAI v0.126.0 is out! \u001b[0m \u001b[32m│\u001b[0m\n", 435 | "\u001b[32m│\u001b[0m \u001b[92m:police_car_light: Core Improvements & Fixes • Added support for Python 3.13 • Fixed agent knowledge sources \u001b[0m \u001b[32m│\u001b[0m\n", 436 | "\u001b[32m│\u001b[0m \u001b[92missue.', 'position': 5}, {'title': 'CrewAI Review 2025: Is It Really Worth Your Money? - Lindy', 'link': \u001b[0m \u001b[32m│\u001b[0m\n", 437 | "\u001b[32m│\u001b[0m \u001b[92m'https://www.lindy.ai/blog/crew-ai', 'snippet': 'CrewAI is an open-source tool that lets developers make AI \u001b[0m \u001b[32m│\u001b[0m\n", 438 | "\u001b[32m│\u001b[0m \u001b[92magents. Y...\u001b[0m \u001b[32m│\u001b[0m\n", 439 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 440 | "\u001b[32m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" 441 | ] 442 | }, 443 | "metadata": {}, 444 | "output_type": "display_data" 445 | }, 446 | { 447 | "data": { 448 | "text/html": [ 449 | "
\n",
450 |               "
\n" 451 | ], 452 | "text/plain": [ 453 | "\n" 454 | ] 455 | }, 456 | "metadata": {}, 457 | "output_type": "display_data" 458 | }, 459 | { 460 | "data": { 461 | "text/html": [ 462 | "
\n"
463 |             ],
464 |             "text/plain": []
465 |           },
466 |           "metadata": {},
467 |           "output_type": "display_data"
468 |         },
469 |         {
470 |           "data": {
471 |             "text/html": [
472 |               "
╭───────────────────────────────────────────── ✅ Agent Final Answer ─────────────────────────────────────────────╮\n",
473 |               "                                                                                                                 \n",
474 |               "  Agent: Blog Writer                                                                                             \n",
475 |               "                                                                                                                 \n",
476 |               "  Final Answer:                                                                                                  \n",
477 |               "  # CrewAI in 2025                                                                                               \n",
478 |               "  ## The Future of Automated Workflows                                                                           \n",
479 |               "                                                                                                                 \n",
480 |               "  As **AI technologies continue to evolve**, CrewAI is at the forefront, enabling developers to create           \n",
481 |               "  intricate automated workflows.                                                                                 \n",
482 |               "                                                                                                                 \n",
483 |               "  Key features include:                                                                                          \n",
484 |               "  - Integration with leading LLMs                                                                                \n",
485 |               "  - Enhanced multi-agent collaboration                                                                           \n",
486 |               "  - Comprehensive support for Python                                                                             \n",
487 |               "                                                                                                                 \n",
488 |               "  Stay tuned for more updates!                                                                                   \n",
489 |               "                                                                                                                 \n",
490 |               "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
491 |               "
\n" 492 | ], 493 | "text/plain": [ 494 | "\u001b[32m╭─\u001b[0m\u001b[32m────────────────────────────────────────────\u001b[0m\u001b[32m ✅ Agent Final Answer \u001b[0m\u001b[32m────────────────────────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", 495 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 496 | "\u001b[32m│\u001b[0m \u001b[37mAgent: \u001b[0m\u001b[1;92mBlog Writer\u001b[0m \u001b[32m│\u001b[0m\n", 497 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 498 | "\u001b[32m│\u001b[0m \u001b[37mFinal Answer:\u001b[0m \u001b[32m│\u001b[0m\n", 499 | "\u001b[32m│\u001b[0m \u001b[92m# CrewAI in 2025\u001b[0m \u001b[32m│\u001b[0m\n", 500 | "\u001b[32m│\u001b[0m \u001b[92m## The Future of Automated Workflows\u001b[0m \u001b[32m│\u001b[0m\n", 501 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 502 | "\u001b[32m│\u001b[0m \u001b[92mAs **AI technologies continue to evolve**, CrewAI is at the forefront, enabling developers to create \u001b[0m \u001b[32m│\u001b[0m\n", 503 | "\u001b[32m│\u001b[0m \u001b[92mintricate automated workflows. \u001b[0m \u001b[32m│\u001b[0m\n", 504 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 505 | "\u001b[32m│\u001b[0m \u001b[92mKey features include:\u001b[0m \u001b[32m│\u001b[0m\n", 506 | "\u001b[32m│\u001b[0m \u001b[92m- Integration with leading LLMs\u001b[0m \u001b[32m│\u001b[0m\n", 507 | "\u001b[32m│\u001b[0m \u001b[92m- Enhanced multi-agent collaboration\u001b[0m \u001b[32m│\u001b[0m\n", 508 | "\u001b[32m│\u001b[0m \u001b[92m- Comprehensive support for Python \u001b[0m \u001b[32m│\u001b[0m\n", 509 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 510 | "\u001b[32m│\u001b[0m \u001b[92mStay tuned for more updates!\u001b[0m \u001b[32m│\u001b[0m\n", 511 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 512 | "\u001b[32m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" 513 | ] 514 | }, 515 | "metadata": {}, 516 | "output_type": "display_data" 517 | }, 518 | { 519 | "data": { 520 | "text/html": [ 521 | "
\n",
522 |               "
\n" 523 | ], 524 | "text/plain": [ 525 | "\n" 526 | ] 527 | }, 528 | "metadata": {}, 529 | "output_type": "display_data" 530 | }, 531 | { 532 | "data": { 533 | "text/html": [ 534 | "
╭─────────────────────────────────────────────── 🛡️ Guardrail Check ───────────────────────────────────────────────╮\n",
535 |               "                                                                                                                 \n",
536 |               "  Guardrail Evaluation Started                                                                                   \n",
537 |               "  Name: def validate_blog_content(result: TaskOutput) -> T...                                                    \n",
538 |               "  Status: 🔄 Evaluating                                                                                          \n",
539 |               "  Attempt: 1                                                                                                     \n",
540 |               "  Tool Args:                                                                                                     \n",
541 |               "                                                                                                                 \n",
542 |               "                                                                                                                 \n",
543 |               "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
544 |               "
\n" 545 | ], 546 | "text/plain": [ 547 | "\u001b[33m╭─\u001b[0m\u001b[33m──────────────────────────────────────────────\u001b[0m\u001b[33m 🛡️ Guardrail Check \u001b[0m\u001b[33m──────────────────────────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", 548 | "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", 549 | "\u001b[33m│\u001b[0m \u001b[1;33mGuardrail Evaluation Started\u001b[0m \u001b[33m│\u001b[0m\n", 550 | "\u001b[33m│\u001b[0m \u001b[37mName: \u001b[0m\u001b[33mdef validate_blog_content(result: TaskOutput) -> T...\u001b[0m \u001b[33m│\u001b[0m\n", 551 | "\u001b[33m│\u001b[0m \u001b[37mStatus: \u001b[0m\u001b[33m🔄 Evaluating\u001b[0m \u001b[33m│\u001b[0m\n", 552 | "\u001b[33m│\u001b[0m \u001b[37mAttempt: \u001b[0m\u001b[33m1\u001b[0m \u001b[33m│\u001b[0m\n", 553 | "\u001b[33m│\u001b[0m \u001b[37mTool Args: \u001b[0m \u001b[33m│\u001b[0m\n", 554 | "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", 555 | "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", 556 | "\u001b[33m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" 557 | ] 558 | }, 559 | "metadata": {}, 560 | "output_type": "display_data" 561 | }, 562 | { 563 | "data": { 564 | "text/html": [ 565 | "
\n",
566 |               "
\n" 567 | ], 568 | "text/plain": [ 569 | "\n" 570 | ] 571 | }, 572 | "metadata": {}, 573 | "output_type": "display_data" 574 | }, 575 | { 576 | "name": "stdout", 577 | "output_type": "stream", 578 | "text": [ 579 | "Word count: 50\n" 580 | ] 581 | }, 582 | { 583 | "data": { 584 | "text/html": [ 585 | "
╭────────────────────────────────────────────── 🛡️ Guardrail Success ──────────────────────────────────────────────╮\n",
586 |               "                                                                                                                 \n",
587 |               "  Guardrail Passed                                                                                               \n",
588 |               "  Name: Validation Successful                                                                                    \n",
589 |               "  Status: ✅ Validated                                                                                           \n",
590 |               "  Attempts: 1                                                                                                    \n",
591 |               "  Tool Args:                                                                                                     \n",
592 |               "                                                                                                                 \n",
593 |               "                                                                                                                 \n",
594 |               "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
595 |               "
\n" 596 | ], 597 | "text/plain": [ 598 | "\u001b[32m╭─\u001b[0m\u001b[32m─────────────────────────────────────────────\u001b[0m\u001b[32m 🛡️ Guardrail Success \u001b[0m\u001b[32m─────────────────────────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", 599 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 600 | "\u001b[32m│\u001b[0m \u001b[1;32mGuardrail Passed\u001b[0m \u001b[32m│\u001b[0m\n", 601 | "\u001b[32m│\u001b[0m \u001b[37mName: \u001b[0m\u001b[32mValidation Successful\u001b[0m \u001b[32m│\u001b[0m\n", 602 | "\u001b[32m│\u001b[0m \u001b[37mStatus: \u001b[0m\u001b[32m✅ Validated\u001b[0m \u001b[32m│\u001b[0m\n", 603 | "\u001b[32m│\u001b[0m \u001b[37mAttempts: \u001b[0m\u001b[32m1\u001b[0m \u001b[32m│\u001b[0m\n", 604 | "\u001b[32m│\u001b[0m \u001b[37mTool Args: \u001b[0m \u001b[32m│\u001b[0m\n", 605 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 606 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 607 | "\u001b[32m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" 608 | ] 609 | }, 610 | "metadata": {}, 611 | "output_type": "display_data" 612 | }, 613 | { 614 | "data": { 615 | "text/html": [ 616 | "
\n",
617 |               "
\n" 618 | ], 619 | "text/plain": [ 620 | "\n" 621 | ] 622 | }, 623 | "metadata": {}, 624 | "output_type": "display_data" 625 | }, 626 | { 627 | "data": { 628 | "text/html": [ 629 | "
\n"
630 |             ],
631 |             "text/plain": []
632 |           },
633 |           "metadata": {},
634 |           "output_type": "display_data"
635 |         },
636 |         {
637 |           "data": {
638 |             "text/html": [
639 |               "
╭──────────────────────────────────────────────── Task Completion ────────────────────────────────────────────────╮\n",
640 |               "                                                                                                                 \n",
641 |               "  Task Completed                                                                                                 \n",
642 |               "  Name: 3cd83abd-4d22-41f2-a4e8-8f732f2fd073                                                                     \n",
643 |               "  Agent: Blog Writer                                                                                             \n",
644 |               "  Tool Args:                                                                                                     \n",
645 |               "                                                                                                                 \n",
646 |               "                                                                                                                 \n",
647 |               "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
648 |               "
\n" 649 | ], 650 | "text/plain": [ 651 | "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────────────────────────────\u001b[0m\u001b[32m Task Completion \u001b[0m\u001b[32m───────────────────────────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", 652 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 653 | "\u001b[32m│\u001b[0m \u001b[1;32mTask Completed\u001b[0m \u001b[32m│\u001b[0m\n", 654 | "\u001b[32m│\u001b[0m \u001b[37mName: \u001b[0m\u001b[32m3cd83abd-4d22-41f2-a4e8-8f732f2fd073\u001b[0m \u001b[32m│\u001b[0m\n", 655 | "\u001b[32m│\u001b[0m \u001b[37mAgent: \u001b[0m\u001b[32mBlog Writer\u001b[0m \u001b[32m│\u001b[0m\n", 656 | "\u001b[32m│\u001b[0m \u001b[37mTool Args: \u001b[0m \u001b[32m│\u001b[0m\n", 657 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 658 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 659 | "\u001b[32m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" 660 | ] 661 | }, 662 | "metadata": {}, 663 | "output_type": "display_data" 664 | }, 665 | { 666 | "data": { 667 | "text/html": [ 668 | "
\n",
669 |               "
\n" 670 | ], 671 | "text/plain": [ 672 | "\n" 673 | ] 674 | }, 675 | "metadata": {}, 676 | "output_type": "display_data" 677 | }, 678 | { 679 | "data": { 680 | "text/html": [ 681 | "
╭──────────────────────────────────────────────── Crew Completion ────────────────────────────────────────────────╮\n",
682 |               "                                                                                                                 \n",
683 |               "  Crew Execution Completed                                                                                       \n",
684 |               "  Name: crew                                                                                                     \n",
685 |               "  ID: 53c93fc0-e371-4f37-b56f-c30c73a7923d                                                                       \n",
686 |               "  Tool Args:                                                                                                     \n",
687 |               "  Final Output: # CrewAI in 2025                                                                                 \n",
688 |               "  ## The Future of Automated Workflows                                                                           \n",
689 |               "                                                                                                                 \n",
690 |               "  As **AI technologies continue to evolve**, CrewAI is at the forefront, enabling developers to create           \n",
691 |               "  intricate automated workflows.                                                                                 \n",
692 |               "                                                                                                                 \n",
693 |               "  Key features include:                                                                                          \n",
694 |               "  - Integration with leading LLMs                                                                                \n",
695 |               "  - Enhanced multi-agent collaboration                                                                           \n",
696 |               "  - Comprehensive support for Python                                                                             \n",
697 |               "                                                                                                                 \n",
698 |               "  Stay tuned for more updates!                                                                                   \n",
699 |               "                                                                                                                 \n",
700 |               "                                                                                                                 \n",
701 |               "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
702 |               "
\n" 703 | ], 704 | "text/plain": [ 705 | "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────────────────────────────\u001b[0m\u001b[32m Crew Completion \u001b[0m\u001b[32m───────────────────────────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", 706 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 707 | "\u001b[32m│\u001b[0m \u001b[1;32mCrew Execution Completed\u001b[0m \u001b[32m│\u001b[0m\n", 708 | "\u001b[32m│\u001b[0m \u001b[37mName: \u001b[0m\u001b[32mcrew\u001b[0m \u001b[32m│\u001b[0m\n", 709 | "\u001b[32m│\u001b[0m \u001b[37mID: \u001b[0m\u001b[32m53c93fc0-e371-4f37-b56f-c30c73a7923d\u001b[0m \u001b[32m│\u001b[0m\n", 710 | "\u001b[32m│\u001b[0m \u001b[37mTool Args: \u001b[0m \u001b[32m│\u001b[0m\n", 711 | "\u001b[32m│\u001b[0m \u001b[37mFinal Output: # CrewAI in 2025\u001b[0m \u001b[32m│\u001b[0m\n", 712 | "\u001b[32m│\u001b[0m \u001b[37m## The Future of Automated Workflows\u001b[0m \u001b[32m│\u001b[0m\n", 713 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 714 | "\u001b[32m│\u001b[0m \u001b[37mAs **AI technologies continue to evolve**, CrewAI is at the forefront, enabling developers to create \u001b[0m \u001b[32m│\u001b[0m\n", 715 | "\u001b[32m│\u001b[0m \u001b[37mintricate automated workflows. \u001b[0m \u001b[32m│\u001b[0m\n", 716 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 717 | "\u001b[32m│\u001b[0m \u001b[37mKey features include:\u001b[0m \u001b[32m│\u001b[0m\n", 718 | "\u001b[32m│\u001b[0m \u001b[37m- Integration with leading LLMs\u001b[0m \u001b[32m│\u001b[0m\n", 719 | "\u001b[32m│\u001b[0m \u001b[37m- Enhanced multi-agent collaboration\u001b[0m \u001b[32m│\u001b[0m\n", 720 | "\u001b[32m│\u001b[0m \u001b[37m- Comprehensive support for Python \u001b[0m \u001b[32m│\u001b[0m\n", 721 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 722 | "\u001b[32m│\u001b[0m \u001b[37mStay tuned for more updates!\u001b[0m \u001b[32m│\u001b[0m\n", 723 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 724 | "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", 725 | "\u001b[32m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" 726 | ] 727 | }, 728 | "metadata": {}, 729 | "output_type": "display_data" 730 | }, 731 | { 732 | "data": { 733 | "text/html": [ 734 | "
\n",
735 |               "
\n" 736 | ], 737 | "text/plain": [ 738 | "\n" 739 | ] 740 | }, 741 | "metadata": {}, 742 | "output_type": "display_data" 743 | } 744 | ], 745 | "source": [ 746 | "results = crew.kickoff(\n", 747 | " inputs={\n", 748 | " \"prompt\": \"CrewAI\",\n", 749 | " \"year\": date.today().year\n", 750 | " }\n", 751 | ")" 752 | ] 753 | }, 754 | { 755 | "cell_type": "markdown", 756 | "metadata": { 757 | "id": "BshuwhDbfrrl" 758 | }, 759 | "source": [ 760 | "## Displaying the Result\n", 761 | "Once the Crew finishes executing, we display the final blog post using Markdown formatting:" 762 | ] 763 | }, 764 | { 765 | "cell_type": "code", 766 | "execution_count": 10, 767 | "metadata": { 768 | "id": "-mR7kBBBftlw" 769 | }, 770 | "outputs": [ 771 | { 772 | "data": { 773 | "text/markdown": [ 774 | "# CrewAI in 2025\n", 775 | "## The Future of Automated Workflows\n", 776 | "\n", 777 | "As **AI technologies continue to evolve**, CrewAI is at the forefront, enabling developers to create intricate automated workflows. \n", 778 | "\n", 779 | "Key features include:\n", 780 | "- Integration with leading LLMs\n", 781 | "- Enhanced multi-agent collaboration\n", 782 | "- Comprehensive support for Python \n", 783 | "\n", 784 | "Stay tuned for more updates!" 785 | ], 786 | "text/plain": [ 787 | "" 788 | ] 789 | }, 790 | "metadata": {}, 791 | "output_type": "display_data" 792 | } 793 | ], 794 | "source": [ 795 | "from IPython.display import display, Markdown\n", 796 | "display(Markdown(results.raw))" 797 | ] 798 | }, 799 | { 800 | "cell_type": "markdown", 801 | "metadata": { 802 | "id": "o28BkhFDiakJ" 803 | }, 804 | "source": [ 805 | "## Conclusion\n", 806 | "\n", 807 | "And that’s it! You’ve now seen how to:\n", 808 | "\n", 809 | "* Write and register a task guardrail in CrewAI\n", 810 | "* Validate custom output logic\n", 811 | "* Automatically rerun tasks that don’t meet your standards\n", 812 | "\n", 813 | "This makes your agents **more reliable**, **more controllable**, and **better suited to production use cases**.\n", 814 | "\n", 815 | "👉 [Learn more in the docs](https://docs.crewai.com/en/concepts/tasks#task-guardrails)" 816 | ] 817 | } 818 | ], 819 | "metadata": { 820 | "colab": { 821 | "provenance": [] 822 | }, 823 | "kernelspec": { 824 | "display_name": ".venv", 825 | "language": "python", 826 | "name": "python3" 827 | }, 828 | "language_info": { 829 | "codemirror_mode": { 830 | "name": "ipython", 831 | "version": 3 832 | }, 833 | "file_extension": ".py", 834 | "mimetype": "text/x-python", 835 | "name": "python", 836 | "nbconvert_exporter": "python", 837 | "pygments_lexer": "ipython3", 838 | "version": "3.12.9" 839 | } 840 | }, 841 | "nbformat": 4, 842 | "nbformat_minor": 0 843 | } 844 | --------------------------------------------------------------------------------