Compare commits

...

68 Commits

Author SHA1 Message Date
Greyson LaLonde
2544075062 Improve HITL human feedback prompt to prioritize human input 2025-08-11 17:13:20 -04:00
Lorenze Jay
251ae00b8b Lorenze/tracing-improvements-cleanup (#3291)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* feat: add tracing support to Crew and Flow classes

- Introduced a new `tracing` optional field in both the `Crew` and `Flow` classes to enable tracing functionality.
- Updated the initialization logic to conditionally set up the `TraceCollectionListener` based on the `tracing` flag or the `CREWAI_TRACING_ENABLED` environment variable.
- Removed the obsolete `interfaces.py` file related to tracing.
- Enhanced the `TraceCollectionListener` to accept a `tracing` parameter and adjusted its internal logic accordingly.
- Added tests to verify the correct setup of the trace listener when tracing is enabled.

This change improves the observability of the crew execution process and allows for better debugging and performance monitoring.

* fix flow name

* refactor: replace _send_batch method with finalize_batch calls in TraceCollectionListener

- Updated the TraceCollectionListener to use the batch_manager's finalize_batch method instead of the deprecated _send_batch method for handling trace events.
- This change improves the clarity of the code and ensures that batch finalization is consistently managed through the batch manager.
- Removed the obsolete _send_batch method to streamline the listener's functionality.

* removed comments

* refactor: enhance tracing functionality by introducing utility for tracing checks

- Added a new utility function `is_tracing_enabled` to streamline the logic for checking if tracing is enabled based on the `CREWAI_TRACING_ENABLED` environment variable.
- Updated the `Crew` and `Flow` classes to utilize this utility for improved readability and maintainability.
- Refactored the `TraceCollectionListener` to simplify tracing checks and ensure consistent behavior across components.
- Introduced a new module for tracing utilities to encapsulate related functions, enhancing code organization.

* refactor: remove unused imports from crew and flow modules

- Removed unnecessary `os` imports from both `crew.py` and `flow.py` files to enhance code cleanliness and maintainability.
2025-08-08 13:42:25 -07:00
Tony Kipkemboi
a221295394 WIP: docs updates (#3296) 2025-08-08 13:05:43 -07:00
Lucas Gomide
a92211f0ba fix: use correct endpoint to get auth/parameters on enterprise configuration (#3295)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
2025-08-08 10:56:44 -04:00
Lucas Gomide
f9481cf10d feat: add enterprise configure command (#3289)
* feat: add enterprise configure command

* refactor: renaming EnterpriseCommand to EnterpriseConfigureCommand
2025-08-08 08:50:01 -04:00
633WHU
915857541e feat: improve LLM message formatting performance (#3251)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* optimize: improve LLM message formatting performance

Replace inefficient copy+append operations with list concatenation
in _format_messages_for_provider method. This optimization reduces
memory allocation and improves performance for large conversation
histories.

**Changes:**
- Mistral models: Use list concatenation instead of copy() + append()
- Ollama models: Use list concatenation instead of copy() + append()
- Add comprehensive performance tests to verify improvements

**Performance impact:**
- Reduces memory allocations for large message lists
- Improves processing speed by 2-25% depending on message list size
- Maintains exact same functionality with better efficiency

cliu_whu@yeah.net

* remove useless comment

---------

Co-authored-by: chiliu <chiliu@paypal.com>
2025-08-07 09:07:47 -04:00
Lorenze Jay
7c162411b7 chore: update crewai to 0.157.0 and crewai-tools dependency to version 0.60.0 (#3281)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* chore: update crewai-tools dependency to version 0.60.0

- Updated the `pyproject.toml` and `uv.lock` files to reflect the new version of `crewai-tools`.
- This change ensures compatibility with the latest features and improvements in the tools package.

* chore: bump CrewAI version to 0.157.0

- Updated the version in `__init__.py` to reflect the new release.
- Adjusted dependency versions in `pyproject.toml` files for crew, flow, and tool templates to ensure compatibility with the latest features and improvements in CrewAI.
- This change maintains consistency across the project and prepares for upcoming enhancements.
2025-08-06 14:47:50 -07:00
Lorenze Jay
8f4a6cc61c Lorenze/tracing v1 (#3279)
* initial setup

* feat: enhance CrewKickoffCompletedEvent to include total token usage

- Added total_tokens attribute to CrewKickoffCompletedEvent for better tracking of token usage during crew execution.
- Updated Crew class to emit total token usage upon kickoff completion.
- Removed obsolete context handler and execution context tracker files to streamline event handling.

* cleanup

* remove print statements for loggers

* feat: add CrewAI base URL and improve logging in tracing

- Introduced `CREWAI_BASE_URL` constant for easy access to the CrewAI application URL.
- Replaced print statements with logging in the `TraceSender` class for better error tracking.
- Enhanced the `TraceBatchManager` to provide default values for flow names and removed unnecessary comments.
- Implemented singleton pattern in `TraceCollectionListener` to ensure a single instance is used.
- Added a new test case to verify that the trace listener correctly collects events during crew execution.

* clear

* fix: update datetime serialization in tracing interfaces

- Removed the 'Z' suffix from datetime serialization in TraceSender and TraceEvent to ensure consistent ISO format.
- Added new test cases to validate the functionality of the TraceBatchManager and event collection during crew execution.
- Introduced fixtures to clear event bus listeners before each test to maintain isolation.

* test: enhance tracing tests with mock authentication token

- Added a mock authentication token to the tracing tests to ensure proper setup and event collection.
- Updated test methods to include the mock token, improving isolation and reliability of tests related to the TraceListener and BatchManager.
- Ensured that the tests validate the correct behavior of event collection during crew execution.

* test: refactor tracing tests to improve mock usage

- Moved the mock authentication token patching inside the test class to enhance readability and maintainability.
- Updated test methods to remove unnecessary mock parameters, streamlining the test signatures.
- Ensured that the tests continue to validate the correct behavior of event collection during crew execution while improving isolation.

* test: refactor tracing tests for improved mock usage and consistency

- Moved mock authentication token patching into individual test methods for better clarity and maintainability.
- Corrected the backstory string in the `Agent` instantiation to fix a typo.
- Ensured that all tests validate the correct behavior of event collection during crew execution while enhancing isolation and readability.

* test: add new tracing test for disabled trace listener

- Introduced a new test case to verify that the trace listener does not make HTTP calls when tracing is disabled via environment variables.
- Enhanced existing tests by mocking PlusAPI HTTP calls to avoid authentication and network requests, improving test isolation and reliability.
- Updated the test setup to ensure proper initialization of the trace listener and its components during crew execution.

* refactor: update LLM class to utilize new completion function and improve cost calculation

- Replaced direct calls to `litellm.completion` with a new import for better clarity and maintainability.
- Introduced a new optional attribute `completion_cost` in the LLM class to track the cost of completions.
- Updated the handling of completion responses to ensure accurate cost calculations and improved error handling.
- Removed outdated test cassettes for gemini models to streamline test suite and avoid redundancy.
- Enhanced existing tests to reflect changes in the LLM class and ensure proper functionality.

* test: enhance tracing tests with additional request and response scenarios

- Added new test cases to validate the behavior of the trace listener and batch manager when handling 404 responses from the tracing API.
- Updated existing test cassettes to include detailed request and response structures, ensuring comprehensive coverage of edge cases.
- Improved mock setup to avoid unnecessary network calls and enhance test reliability.
- Ensured that the tests validate the correct behavior of event collection during crew execution, particularly in scenarios where the tracing service is unavailable.

* feat: enable conditional tracing based on environment variable

- Added support for enabling or disabling the trace listener based on the `CREWAI_TRACING_ENABLED` environment variable.
- Updated the `Crew` class to conditionally set up the trace listener only when tracing is enabled, improving performance and resource management.
- Refactored test cases to ensure proper cleanup of event bus listeners before and after each test, enhancing test reliability and isolation.
- Improved mock setup in tracing tests to validate the behavior of the trace listener when tracing is disabled.

* fix: downgrade litellm version from 1.74.9 to 1.74.3

- Updated the `pyproject.toml` and `uv.lock` files to reflect the change in the `litellm` dependency version.
- This downgrade addresses compatibility issues and ensures stability in the project environment.

* refactor: improve tracing test setup by moving mock authentication token patching

- Removed the module-level patch for the authentication token and implemented a fixture to mock the token for all tests in the class, enhancing test isolation and readability.
- Updated the event bus clearing logic to ensure original handlers are restored after tests, improving reliability of the test environment.
- This refactor streamlines the test setup and ensures consistent behavior across tracing tests.

* test: enhance tracing test setup with comprehensive mock authentication

- Expanded the mock authentication token patching to cover all instances where `get_auth_token` is used across different modules, ensuring consistent behavior in tests.
- Introduced a new fixture to reset tracing singleton instances between tests, improving test isolation and reliability.
- This update enhances the overall robustness of the tracing tests by ensuring that all necessary components are properly mocked and reset, leading to more reliable test outcomes.

* just drop the test for now

* refactor: comment out completion-related code in LLM and LLM event classes

- Commented out the `completion` and `completion_cost` imports and their usage in the `LLM` class to prevent potential issues during execution.
- Updated the `LLMCallCompletedEvent` class to comment out the `response_cost` attribute, ensuring consistency with the changes in the LLM class.
- This refactor aims to streamline the code and prepare for future updates without affecting current functionality.

* refactor: update LLM response handling in LiteAgent

- Commented out the `response_cost` attribute in the LLM response handling to align with recent refactoring in the LLM class.
- This change aims to maintain consistency in the codebase and prepare for future updates without affecting current functionality.

* refactor: remove commented-out response cost attributes in LLM and LiteAgent

- Commented out the `response_cost` attribute in both the `LiteAgent` and `LLM` classes to maintain consistency with recent refactoring efforts.
- This change aligns with previous updates aimed at streamlining the codebase and preparing for future enhancements without impacting current functionality.

* bring back litellm upgrade version
2025-08-06 14:05:14 -07:00
633WHU
7dc86dc79a perf: optimize string operations with partition() over split()[0] (#3255)
Replace inefficient split()[0] operations with partition()[0] for better performance
when extracting the first part of a string before a delimiter.

Key improvements:
• Agent role processing: 29% faster with partition()
• Model provider extraction: 16% faster
• Console formatting: Improved responsiveness
• Better readability and explicit intent

Changes:
- agent_utils.py: Use partition('\n')[0] for agent role extraction
- console_formatter.py: Optimize agent role processing in logging
- llm_utils.py: Improve model provider parsing
- llm.py: Optimize model name parsing

Performance impact: 15-30% improvement in string processing operations
that are frequently used in agent execution and console output.

cliu_whu@yeah.net

Co-authored-by: chiliu <chiliu@paypal.com>
2025-08-06 15:04:53 -04:00
Vidit Ostwal
7ce20cfcc6 Dropping User Memory (#3225)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
* Dropping User Memory

* Dropping checks for user memory

* changed memory.mdx documentation removed user memory.

* Flaky Test Case Maybe

* Drop memory_config

* Fixed test cases

* Fixed some test cases

* Changed docs

* Changed BR docs

* Docs fixing

* Fix minor doc

* Fix minor doc

* Fix minor doc

* Added fallback mechanism in Mem0
2025-08-06 13:08:10 -04:00
Mrunmay Shelar
1d9523c98f docs: add LangDB integration documentation (#3228)
docs: update LangDB links in observability documentation

- Removed references to the AI Gateway features in both English and Portuguese documentation.
- Updated the Model Catalog links to point to the new app.langdb.ai domain.
- Ensured consistency across both language versions of the documentation.
2025-08-06 11:13:58 -04:00
Lucas Gomide
9f1d7d1aa9 fix: allow persist Flow state with BaseModel entries (#3276)
Co-authored-by: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com>
2025-08-06 09:04:59 -04:00
Lucas Gomide
79b375f6fa build: bump LiteLLM to 1.74.9 (#3278)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-08-05 17:10:23 -04:00
Lucas Gomide
75752479c2 docs: add CLI config docs (#3275) 2025-08-05 15:24:34 -04:00
Lucas Gomide
477bc1f09e feat: add default value for crew.name (#3252)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Co-authored-by: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com>
2025-08-05 12:25:50 -04:00
Lucas Gomide
66567bdc2f Support Device authorization with Okta (#3271)
* feat: support oauth2 config for authentication

* refactor: improve OAuth2 settings management

The CLI now supports seamless integration with other authentication providers, since the client_id, issue, domain are now manage by the user

* feat: support okta Device Authorization flow

* chore: resolve linter issues

* test: fix tests

* test: adding tests for auth providers

* test: fix broken test

* refator: adding WorkOS paramenters as default settings auth

* chore: improve oauth2 attributes description

* refactor: simplify WorkOS getting values

* fix: ensure Auth0 parameters is set when overrinding default auth provider

* chore: remove TODO Auth0 no longer provides default values

---------

Co-authored-by: Heitor Carvalho <heitor.scz@gmail.com>
2025-08-05 12:16:21 -04:00
Lucas Gomide
0b31bbe957 fix: enable word wrapping for long input tool (#3274) 2025-08-05 11:05:38 -04:00
Lucas Gomide
246cf588cd docs: updating MCP docs with connect_timeout attribute (#3273) 2025-08-05 10:27:18 -04:00
Heitor Carvalho
88ed91561f feat: add crewai config command group and tests (#3206)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-07-31 10:38:51 -04:00
Lorenze Jay
9a347ad458 chore: update crewai-tools dependency to version 0.59.0 and bump CrewAI version to 0.152.0 (#3244)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
- Updated `crewai-tools` dependency from `0.58.0` to `0.59.0` in `pyproject.toml` and `uv.lock`.
- Bumped the version of the CrewAI library from `0.150.0` to `0.152.0` in `__init__.py`.
- Updated dependency versions in CLI templates for crew, flow, and tool projects to reflect the new CrewAI version.
2025-07-30 14:38:24 -07:00
Lucas Gomide
34c3075fdb fix: support to add memories to Mem0 with agent_id (#3217)
* fix: support to add memories to Mem0 with agent_id

* feat: removing memory_type checkings from Mem0Storage

* feat: ensure agent_id is always present while saving memory into Mem0

* fix: use OR operator when querying Mem0 memories with both user_id and agent_id
2025-07-30 11:56:46 -04:00
Vidit Ostwal
498e8dc6e8 Changed the import error to show missing module files (#2423)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
* Fix issue #2421: Handle missing google.genai dependency gracefully

Co-Authored-By: Joe Moura <joao@crewai.com>

* Fix import sorting in test file

Co-Authored-By: Joe Moura <joao@crewai.com>

* Fix import sorting with ruff

Co-Authored-By: Joe Moura <joao@crewai.com>

* Removed unwatned test case

* Added dynamic catching for all the embedder function

* Dropped the comment

* Added test case

* Fixed Linting Issue

* Flaky test case in 3.13

* Test Case fixed

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Joe Moura <joao@crewai.com>
Co-authored-by: Lucas Gomide <lucaslg200@gmail.com>
2025-07-30 10:01:17 -04:00
Lorenze Jay
cb522cf500 Enhance Flow class to support custom flow names (#3234)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
- Added an optional `name` attribute to the Flow class for better identification.
- Updated event emissions to utilize the new `name` attribute, ensuring accurate flow naming in events.
- Added tests to verify the correct flow name is set and emitted during flow execution.
2025-07-29 15:41:30 -07:00
Vini Brasil
017acc74f5 Add timezone to event timestamps (#3231)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Events were lacking timezone information, making them naive datetimes,
which can be ambiguous.
2025-07-28 17:09:06 -03:00
Greyson LaLonde
fab86d197a Refactor: Move RAG components to dedicated top-level module (#3222)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* Move RAG components to top-level module

- Create src/crewai/rag directory structure
- Move embeddings configurator from utilities to rag module
- Update imports across codebase and documentation
- Remove deprecated embedding files

* Remove empty knowledge/embedder directory
2025-07-25 10:55:31 -04:00
Vidit Ostwal
864e9bfb76 Changed the default value in Mem0 config (#3216)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* Changed the default value in Mem0 config

* Added regression test for this

* Fixed Linting issues
2025-07-24 13:20:18 -04:00
Lucas Gomide
d3b45d197c fix: remove crewai signup references, replaced by crewai login (#3213) 2025-07-24 07:47:35 -04:00
Manuka Yasas
579153b070 docs: fix incorrect model naming in Google Vertex AI documentation (#3189)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
- Change model format from "gemini/gemini-1.5-pro-latest" to "gemini-1.5-pro-latest"
  in Vertex AI section examples
- Update both English and Portuguese documentation files
- Fixes incorrect provider prefix usage for Vertex AI models
- Ensures consistency with Vertex AI provider requirements

Files changed:
- docs/en/concepts/llms.mdx (line 272)
- docs/pt-BR/concepts/llms.mdx (line 270)

Co-authored-by: Tony Kipkemboi <iamtonykipkemboi@gmail.com>
2025-07-23 16:58:57 -04:00
Lorenze Jay
b1fdcdfa6e chore: update dependencies and version in project files (#3212)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
- Updated `crewai-tools` dependency from `0.55.0` to `0.58.0` in `pyproject.toml` and `uv.lock`.
- Added new packages `anthropic`, `browserbase`, `playwright`, `pyee`, and `stagehand` with their respective versions in `uv.lock`.
- Bumped the version of the CrewAI library from `0.148.0` to `0.150.0` in `__init__.py`.
- Updated dependency versions in CLI templates for crew, flow, and tool projects to reflect the new CrewAI version.
2025-07-23 11:03:50 -07:00
Mike Plachta
18d76a270c docs: add SerperScrapeWebsiteTool documentation and reorganize SerperDevTool setup instructions (#3211) 2025-07-23 12:12:59 -04:00
Vidit Ostwal
30541239ad Changed Mem0 Storage v1.1 -> v2 (#2893)
* Changed v1.1 -> v2

* Fixed Test Cases:

* Fixed linting issues

* Changed docs

* Refractored the storage

* Fixed test cases

* Fixing run-time checks

* Fixed Test Case

* Updated docs and added test case for custom categories

* Add the TODO back

* Minor Changes

* Added output_format in search

* Minor changes

* Added output_format and version in both search and save

* Small change

* Minor bugs

* Fixed test cases

* Changed docs

---------

Co-authored-by: Lucas Gomide <lucaslg200@gmail.com>
2025-07-23 08:30:52 -04:00
Tony Kipkemboi
9a65573955 Feature/update docs (#3205)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* docs: add create_directory parameter

* docs: remove string guardrails to focus on function guardrails

* docs: remove get help from docs.json

* docs: update pt-BR docs.json changes
2025-07-22 13:55:27 -04:00
Lucas Gomide
27623a1d01 feat: remove duplicate print on LLM call error (#3183)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
By improving litellm handler error / outputs

Co-authored-by: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com>
2025-07-21 22:08:07 -04:00
João Moura
2593242234 Adding Support to adhoc tool calling using the internal LLM class (#3195)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
* Adding Support to adhoc tool calling using the internal LLM class

* fix type
2025-07-21 19:36:48 -03:00
Greyson LaLonde
2ab6c31544 chore: add deprecation notices to UserMemory (#3201)
- Mark UserMemory and UserMemoryItem for removal in v0.156.0 or 2025-08-04
- Update all references with deprecation warnings
- Users should migrate to ExternalMemory
2025-07-21 15:26:34 -04:00
Lucas Gomide
3c55c8a22a fix: append user message when last message is from assistent when using Ollama models (#3200)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Ollama doesn't supports last message to be 'assistant'
We can drop this commit after merging https://github.com/BerriAI/litellm/pull/10917
2025-07-21 13:30:40 -04:00
Ranuga Disansa
424433ff58 docs: Add Tavily Search & Extractor tools to Search-Research suite (#3146)
* docs: Add Tavily Search and Extractor tools documentation

* docs: Add Tavily Search and Extractor tools to the documentation

---------

Co-authored-by: Tony Kipkemboi <iamtonykipkemboi@gmail.com>
2025-07-21 12:01:29 -04:00
Lucas Gomide
2fd99503ed build: upgrade LiteLLM to 1.74.3 (#3199) 2025-07-21 09:58:47 -04:00
Vidit Ostwal
942014962e fixed save method, changed the test cases (#3187)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* fixed save method, changed the test cases

* Linting fixed
2025-07-18 15:10:26 -04:00
Lucas Gomide
2ab79a7dd5 feat: drop unsupported stop parameter for LLM models automatically (#3184) 2025-07-18 13:54:28 -04:00
Lucas Gomide
27c449c9c4 test: remove workaround related to SQLite without FTS5 (#3179)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
For more details check out [here](actions/runner-images#12576)
2025-07-18 09:37:15 -04:00
Vini Brasil
9737333ffd Use file lock around Chroma client initialization (#3181)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
This commit fixes a bug with concurrent processess and Chroma where
`table collections already exists` (and similar) were raised.

https://cookbook.chromadb.dev/core/system_constraints/
2025-07-17 11:50:45 -03:00
Lucas Gomide
bf248d5118 docs: fix neatlogs documentation (#3171)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-07-16 21:18:04 -04:00
Lorenze Jay
2490e8cd46 Update CrewAI version to 0.148.0 in project templates and dependencies (#3172)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
* Update CrewAI version to 0.148.0 in project templates and dependencies

* Update crewai-tools dependency to version 0.55.0 in pyproject.toml and uv.lock for improved functionality and performance.
2025-07-16 12:36:43 -07:00
Lucas Gomide
9b67e5a15f Emit events about Agent eval (#3168)
* feat: emit events abou Agent Eval

We are triggering events when an evaluation has started/completed/failed

* style: fix type checking issues
2025-07-16 13:18:59 -04:00
Lucas Gomide
6ebb6c9b63 Supporting eval single Agent/LiteAgent (#3167)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* refactor: rely on task completion event to evaluate agents

* feat: remove Crew dependency to evaluate agent

* feat: drop execution_context in AgentEvaluator

* chore: drop experimental Agent Eval feature from stable crew.test

* feat: support eval LiteAgent

* resolve linter issues
2025-07-15 09:22:41 -04:00
Lucas Gomide
53f674be60 chore: remove evaluation folder (#3159)
This folder was moved to `experimental` folder
2025-07-15 08:30:20 -04:00
Paras Sakarwal
11717a5213 docs: added integration with neatlogs (#3138)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-07-14 11:08:24 -04:00
Lucas Gomide
b6d699f764 Implement thread-safe AgentEvaluator (#3157)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
* refactor: implement thread-safe AgentEvaluator with hybrid state management

* chore: remove useless comments
2025-07-14 10:05:42 -04:00
Lucas Gomide
5b15061b87 test: add test helper to assert Agent Experiments (#3156) 2025-07-14 09:24:49 -04:00
Lucas Gomide
1b6b2b36d9 Introduce Evaluator Experiment (#3133)
* feat: add exchanged messages in LLMCallCompletedEvent

* feat: add GoalAlignment metric for Agent evaluation

* feat: add SemanticQuality metric for Agent evaluation

* feat: add Tool Metrics for Agent evaluation

* feat: add Reasoning Metrics for Agent evaluation, still in progress

* feat: add AgentEvaluator class

This class will evaluate Agent' results and report to user

* fix: do not evaluate Agent by default

This is a experimental feature we still need refine it further

* test: add Agent eval tests

* fix: render all feedback per iteration

* style: resolve linter issues

* style: fix mypy issues

* fix: allow messages be empty on LLMCallCompletedEvent

* feat: add Experiment evaluation framework with baseline comparison

* fix: reset evaluator for each experiement iteraction

* fix: fix track of new test cases

* chore: split Experimental evaluation classes

* refactor: remove unused method

* refactor: isolate Console print in a dedicated class

* fix: make crew required to run an experiment

* fix: use time-aware to define experiment result

* test: add tests for Evaluator Experiment

* style: fix linter issues

* fix: encode string before hashing

* style: resolve linter issues

* feat: add experimental folder for beta features (#3141)

* test: move tests to experimental folder
2025-07-14 09:06:45 -04:00
devin-ai-integration[bot]
3ada4053bd Fix #3149: Add missing create_directory parameter to Task class (#3150)
* Fix #3149: Add missing create_directory parameter to Task class

- Add create_directory field with default value True for backward compatibility
- Update _save_file method to respect create_directory parameter
- Add comprehensive tests covering all scenarios
- Maintain existing behavior when create_directory=True (default)

The create_directory parameter was documented but missing from implementation.
Users can now control directory creation behavior:
- create_directory=True (default): Creates directories if they don't exist
- create_directory=False: Raises RuntimeError if directory doesn't exist

Fixes issue where users got TypeError when trying to use the documented
create_directory parameter.

Co-Authored-By: Jo\u00E3o <joao@crewai.com>

* Fix lint: Remove unused import os from test_create_directory_true

- Removes F401 lint error: 'os' imported but unused
- All lint checks should now pass

Co-Authored-By: Jo\u00E3o <joao@crewai.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Jo\u00E3o <joao@crewai.com>
2025-07-14 08:15:41 -04:00
Vidit Ostwal
e7a5747c6b Comparing BaseLLM class instead of LLM (#3120)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* Compaing BaseLLM class instead of LLM

* Fixed test cases

* Fixed Linting Issues

* removed last line

---------

Co-authored-by: Lucas Gomide <lucaslg200@gmail.com>
2025-07-11 20:50:36 -04:00
Vidit Ostwal
eec1262d4f Fix agent knowledge (#2831)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
* Added add_sources()

* Fixed the agent knowledge querying

* Added test cases

* Fixed linting issue

* Fixed logic

* Seems like a falky test case

* Minor changes

* Added knowledge attriute to the crew documentation

* Flaky test

* fixed spaces

* Flaky Test Case

* Seems like a flaky test case

---------

Co-authored-by: Lucas Gomide <lucaslg200@gmail.com>
2025-07-11 13:52:26 -04:00
Tony Kipkemboi
c6caa763d7 docs: Add guardrail attribute documentation and examples (#3139)
- Document string-based guardrails in tasks
- Add guardrail examples to YAML configuration
- Fix Python code formatting in PT-BR CLI docs
2025-07-11 13:32:59 -04:00
Lucas Gomide
08fa3797ca Introducing Agent evaluation (#3130)
* feat: add exchanged messages in LLMCallCompletedEvent

* feat: add GoalAlignment metric for Agent evaluation

* feat: add SemanticQuality metric for Agent evaluation

* feat: add Tool Metrics for Agent evaluation

* feat: add Reasoning Metrics for Agent evaluation, still in progress

* feat: add AgentEvaluator class

This class will evaluate Agent' results and report to user

* fix: do not evaluate Agent by default

This is a experimental feature we still need refine it further

* test: add Agent eval tests

* fix: render all feedback per iteration

* style: resolve linter issues

* style: fix mypy issues

* fix: allow messages be empty on LLMCallCompletedEvent
2025-07-11 13:18:03 -04:00
Greyson LaLonde
bf8fa3232b Add SQLite FTS5 support to test workflow (#3140)
* Add SQLite FTS5 support to test workflow

* Add explanatory comment for SQLite FTS5 workaround
2025-07-11 12:01:25 -04:00
Heitor Carvalho
a6e60a5d42 fix: use production workos environment id (#3129)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-07-09 17:09:01 -04:00
Lorenze Jay
7b0f3aabd9 chore: update crewAI and dependencies to version 0.141.0 and 0.51.0 (#3128)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
- Bump crewAI version to 0.141.0 in __init__.py for alignment with updated dependencies.
- Update `crewai-tools` dependency version to 0.51.0 in pyproject.toml and related template files.
- Add new testing dependencies: pytest-split and pytest-xdist for improved test execution.
- Ensure compatibility with the latest package versions in uv.lock and template files.
2025-07-09 10:37:06 -07:00
Lucas Gomide
f071966951 docs: add docs about Agent.kickoff usage (#3121)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Co-authored-by: Tony Kipkemboi <iamtonykipkemboi@gmail.com>
2025-07-08 16:15:40 -04:00
Lucas Gomide
318310bb7a docs: add docs about Agent repository (#3122) 2025-07-08 15:56:08 -04:00
Greyson LaLonde
34a03f882c feat: add crew context tracking for LLM guardrail events (#3111)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Add crew context tracking using OpenTelemetry baggage for thread-safe propagation. Context is set during kickoff and cleaned up in finally block. Added thread safety tests with mocked agent execution.
2025-07-07 16:33:07 -04:00
Greyson LaLonde
a0fcc0c8d1 Speed up GitHub Actions tests with parallelization (#3107)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
- Add pytest-xdist and pytest-split to dev dependencies for parallel test execution
- Split tests into 8 parallel groups per Python version for better distribution
- Enable CPU-level parallelization with -n auto to maximize resource usage
- Add fail-fast strategy and maxfail=3 to stop early on failures
- Add job name to match branch protection rules
- Reduce test timeout from default to 30s for faster failure detection
- Remove redundant cache configuration
2025-07-03 21:08:00 -04:00
Lorenze Jay
748c25451c Lorenze/new version 0.140.0 (#3106)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* fix: clean up whitespace and update dependencies

* Removed unnecessary whitespace in multiple files for consistency.
* Updated `crewai-tools` dependency version to `0.49.0` in `pyproject.toml` and related template files.
* Bumped CrewAI version to `0.140.0` in `__init__.py` for alignment with updated dependencies.

* chore: update pyproject.toml to exclude documentation from build targets

* Added exclusions for the `docs` directory in both wheel and sdist build targets to streamline the build process and reduce unnecessary file inclusion.

* chore: update uv.lock for dependency resolution and Python version compatibility

* Incremented revision to 2.
* Updated resolution markers to include support for Python 3.13 and adjusted platform checks for better compatibility.
* Added new wheel URLs for zstandard version 0.23.0 to ensure availability across various platforms.

* chore: pin json-repair dependency version in pyproject.toml and uv.lock

* Updated json-repair dependency from a range to a specific version (0.25.2) for consistency and to avoid potential compatibility issues.
* Adjusted related entries in uv.lock to reflect the pinned version, ensuring alignment across project files.

* chore: pin agentops dependency version in pyproject.toml and uv.lock

* Updated agentops dependency from a range to a specific version (0.3.18) for consistency and to avoid potential compatibility issues.
* Adjusted related entries in uv.lock to reflect the pinned version, ensuring alignment across project files.

* test: enhance cache call assertions in crew tests

* Improved the test for cache hitting between agents by filtering mock calls to ensure they include the expected 'tool' and 'input' keywords.
* Added assertions to verify the number of cache calls and their expected arguments, enhancing the reliability of the test.
* Cleaned up whitespace and improved readability in various test cases for better maintainability.
2025-07-02 15:22:18 -07:00
Heitor Carvalho
a77dcdd419 feat: add multiple provider support (#3089)
* Remove `crewai signup` command, update docs

* Add `Settings.clear()` and clear settings before each login

* Add pyjwt

* Remove print statement from ToolCommand.login()

* Remove auth0 dependency

* Update docs
2025-07-02 16:44:47 -04:00
Greyson LaLonde
68f5bdf0d9 feat: add console logging for LLM guardrail events (#3105)
* feat: add console logging for memory events

* fix: emit guardrail events in correct order and handle exceptions

* fix: remove unreachable elif conditions in guardrail event listener

* fix: resolve mypy type errors in guardrail event handler
2025-07-02 16:19:22 -04:00
Irineu Brito
7f83947020 fix: correct code example language inconsistency in pt-BR docs (#3088)
* fix: correct code example language inconsistency in pt-BR docs

* fix: fix: fully standardize code example language and naming in pt-BR docs

* fix: fix: fully standardize code example language and naming in pt-BR docs fixed variables

* fix: fix: fully standardize code example language and naming in pt-BR docs fixed params

---------

Co-authored-by: Lucas Gomide <lucaslg200@gmail.com>
2025-07-02 12:18:32 -04:00
Lucas Gomide
ceb310bcde docs: add docs about Memory Events (#3104)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
2025-07-02 11:10:45 -04:00
234 changed files with 19624 additions and 4737 deletions

View File

@@ -260,7 +260,7 @@ def handle_success(self):
# Handle success case
pass
@listen("failure_path")
@listen("failure_path")
def handle_failure(self):
# Handle failure case
pass
@@ -288,7 +288,7 @@ class SelectiveFlow(Flow):
def critical_step(self):
# Only this method's state is persisted
self.state["important_data"] = "value"
@start()
def temporary_step(self):
# This method's state is not persisted
@@ -322,20 +322,20 @@ flow.plot("workflow_diagram") # Generates HTML visualization
class CyclicFlow(Flow):
max_iterations = 5
current_iteration = 0
@start("loop")
def process_iteration(self):
if self.current_iteration >= self.max_iterations:
return
# Process current iteration
self.current_iteration += 1
@router(process_iteration)
def check_continue(self):
if self.current_iteration < self.max_iterations:
return "loop" # Continue cycling
return "complete"
@listen("complete")
def finalize(self):
# Final processing
@@ -369,7 +369,7 @@ def risky_operation(self):
self.state["success"] = False
return None
@listen(risky_operation)
@listen(risky_operation)
def handle_result(self, result):
if self.state.get("success", False):
# Handle success case
@@ -390,7 +390,7 @@ class CrewOrchestrationFlow(Flow[WorkflowState]):
result = research_crew.crew().kickoff(inputs={"topic": self.state.research_topic})
self.state.research_results = result.raw
return result
@listen(research_phase)
def analysis_phase(self, research_results):
analysis_crew = AnalysisCrew()
@@ -400,13 +400,13 @@ class CrewOrchestrationFlow(Flow[WorkflowState]):
})
self.state.analysis_results = result.raw
return result
@router(analysis_phase)
def decide_next_action(self):
if self.state.analysis_results.confidence > 0.7:
return "generate_report"
return "additional_research"
@listen("generate_report")
def final_report(self):
reporting_crew = ReportingCrew()
@@ -439,7 +439,7 @@ class CrewOrchestrationFlow(Flow[WorkflowState]):
## CrewAI Version Compatibility:
- Stay updated with CrewAI releases for new features and bug fixes
- Test crew functionality when upgrading CrewAI versions
- Use version constraints in pyproject.toml (e.g., "crewai[tools]>=0.134.0,<1.0.0")
- Use version constraints in pyproject.toml (e.g., "crewai[tools]>=0.140.0,<1.0.0")
- Monitor deprecation warnings for future compatibility
## Code Examples and Implementation Patterns
@@ -464,22 +464,22 @@ class ResearchOutput(BaseModel):
@CrewBase
class ResearchCrew():
"""Advanced research crew with structured outputs and validation"""
agents: List[BaseAgent]
tasks: List[Task]
@before_kickoff
def setup_environment(self):
"""Initialize environment before crew execution"""
print("🚀 Setting up research environment...")
# Validate API keys, create directories, etc.
@after_kickoff
def cleanup_and_report(self, output):
"""Handle post-execution tasks"""
print(f"✅ Research completed. Generated {len(output.tasks_output)} task outputs")
print(f"📊 Token usage: {output.token_usage}")
@agent
def researcher(self) -> Agent:
return Agent(
@@ -490,7 +490,7 @@ class ResearchCrew():
max_iter=15,
max_execution_time=1800
)
@agent
def analyst(self) -> Agent:
return Agent(
@@ -499,7 +499,7 @@ class ResearchCrew():
verbose=True,
memory=True
)
@task
def research_task(self) -> Task:
return Task(
@@ -507,7 +507,7 @@ class ResearchCrew():
agent=self.researcher(),
output_pydantic=ResearchOutput
)
@task
def validation_task(self) -> Task:
return Task(
@@ -517,7 +517,7 @@ class ResearchCrew():
guardrail=self.validate_research_quality,
max_retries=3
)
def validate_research_quality(self, output) -> tuple[bool, str]:
"""Custom guardrail to ensure research quality"""
content = output.raw
@@ -526,7 +526,7 @@ class ResearchCrew():
if not any(keyword in content.lower() for keyword in ['conclusion', 'finding', 'result']):
return False, "Missing key analytical elements."
return True, content
@crew
def crew(self) -> Crew:
return Crew(
@@ -557,13 +557,13 @@ class RobustSearchTool(BaseTool):
name: str = "robust_search"
description: str = "Perform web search with retry logic and error handling"
args_schema: Type[BaseModel] = SearchInput
def __init__(self, api_key: Optional[str] = None, **kwargs):
super().__init__(**kwargs)
self.api_key = api_key or os.getenv("SEARCH_API_KEY")
self.rate_limit_delay = 1.0
self.last_request_time = 0
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=4, max=10)
@@ -575,43 +575,43 @@ class RobustSearchTool(BaseTool):
time_since_last = time.time() - self.last_request_time
if time_since_last < self.rate_limit_delay:
time.sleep(self.rate_limit_delay - time_since_last)
# Input validation
if not query or len(query.strip()) == 0:
return "Error: Empty search query provided"
if len(query) > 500:
return "Error: Search query too long (max 500 characters)"
# Perform search
results = self._perform_search(query, max_results, timeout)
self.last_request_time = time.time()
return self._format_results(results)
except requests.exceptions.Timeout:
return f"Search timed out after {timeout} seconds"
except requests.exceptions.RequestException as e:
return f"Search failed due to network error: {str(e)}"
except Exception as e:
return f"Unexpected error during search: {str(e)}"
def _perform_search(self, query: str, max_results: int, timeout: int) -> List[dict]:
"""Implement actual search logic here"""
# Your search API implementation
pass
def _format_results(self, results: List[dict]) -> str:
"""Format search results for LLM consumption"""
if not results:
return "No results found for the given query."
formatted = "Search Results:\n\n"
for i, result in enumerate(results[:10], 1):
formatted += f"{i}. {result.get('title', 'No title')}\n"
formatted += f" URL: {result.get('url', 'No URL')}\n"
formatted += f" Summary: {result.get('snippet', 'No summary')}\n\n"
return formatted
```
@@ -623,20 +623,20 @@ from crewai.memory.storage.mem0_storage import Mem0Storage
class AdvancedMemoryManager:
"""Enhanced memory management for CrewAI applications"""
def __init__(self, crew, config: dict = None):
self.crew = crew
self.config = config or {}
self.setup_memory_systems()
def setup_memory_systems(self):
"""Configure multiple memory systems"""
# Short-term memory for current session
self.short_term = ShortTermMemory()
# Long-term memory for cross-session persistence
self.long_term = LongTermMemory()
# External memory with Mem0 (if configured)
if self.config.get('use_external_memory'):
self.external = ExternalMemory.create_storage(
@@ -649,8 +649,8 @@ class AdvancedMemoryManager:
}
}
)
def save_with_context(self, content: str, memory_type: str = "short_term",
def save_with_context(self, content: str, memory_type: str = "short_term",
metadata: dict = None, agent: str = None):
"""Save content with enhanced metadata"""
enhanced_metadata = {
@@ -659,14 +659,14 @@ class AdvancedMemoryManager:
"crew_type": self.crew.__class__.__name__,
**(metadata or {})
}
if memory_type == "short_term":
self.short_term.save(content, enhanced_metadata, agent)
elif memory_type == "long_term":
self.long_term.save(content, enhanced_metadata, agent)
elif memory_type == "external" and hasattr(self, 'external'):
self.external.save(content, enhanced_metadata, agent)
def search_across_memories(self, query: str, limit: int = 5) -> dict:
"""Search across all memory systems"""
results = {
@@ -674,23 +674,23 @@ class AdvancedMemoryManager:
"long_term": [],
"external": []
}
# Search short-term memory
results["short_term"] = self.short_term.search(query, limit=limit)
# Search long-term memory
results["long_term"] = self.long_term.search(query, limit=limit)
# Search external memory (if available)
if hasattr(self, 'external'):
results["external"] = self.external.search(query, limit=limit)
return results
def cleanup_old_memories(self, days_threshold: int = 30):
"""Clean up old memories based on age"""
cutoff_time = time.time() - (days_threshold * 24 * 60 * 60)
# Implement cleanup logic based on timestamps in metadata
# This would vary based on your specific storage implementation
pass
@@ -719,12 +719,12 @@ class TaskMetrics:
class CrewMonitor:
"""Comprehensive monitoring for CrewAI applications"""
def __init__(self, crew_name: str, log_level: str = "INFO"):
self.crew_name = crew_name
self.metrics: List[TaskMetrics] = []
self.session_start = time.time()
# Setup logging
logging.basicConfig(
level=getattr(logging, log_level),
@@ -735,7 +735,7 @@ class CrewMonitor:
]
)
self.logger = logging.getLogger(f"CrewAI.{crew_name}")
def start_task_monitoring(self, task_name: str, agent_name: str) -> dict:
"""Start monitoring a task execution"""
context = {
@@ -743,16 +743,16 @@ class CrewMonitor:
"agent_name": agent_name,
"start_time": time.time()
}
self.logger.info(f"Task started: {task_name} by {agent_name}")
return context
def end_task_monitoring(self, context: dict, success: bool = True,
def end_task_monitoring(self, context: dict, success: bool = True,
tokens_used: int = 0, error: str = None):
"""End monitoring and record metrics"""
end_time = time.time()
duration = end_time - context["start_time"]
# Get memory usage (if psutil is available)
memory_usage = None
try:
@@ -761,7 +761,7 @@ class CrewMonitor:
memory_usage = process.memory_info().rss / 1024 / 1024 # MB
except ImportError:
pass
metrics = TaskMetrics(
task_name=context["task_name"],
agent_name=context["agent_name"],
@@ -773,29 +773,29 @@ class CrewMonitor:
error_message=error,
memory_usage_mb=memory_usage
)
self.metrics.append(metrics)
# Log the completion
status = "SUCCESS" if success else "FAILED"
self.logger.info(f"Task {status}: {context['task_name']} "
f"(Duration: {duration:.2f}s, Tokens: {tokens_used})")
if error:
self.logger.error(f"Task error: {error}")
def get_performance_summary(self) -> Dict[str, Any]:
"""Generate comprehensive performance summary"""
if not self.metrics:
return {"message": "No metrics recorded yet"}
successful_tasks = [m for m in self.metrics if m.success]
failed_tasks = [m for m in self.metrics if not m.success]
total_duration = sum(m.duration for m in self.metrics)
total_tokens = sum(m.tokens_used for m in self.metrics)
avg_duration = total_duration / len(self.metrics)
return {
"crew_name": self.crew_name,
"session_duration": time.time() - self.session_start,
@@ -811,7 +811,7 @@ class CrewMonitor:
"most_token_intensive": max(self.metrics, key=lambda x: x.tokens_used).task_name if self.metrics else None,
"common_errors": self._get_common_errors()
}
def _get_common_errors(self) -> Dict[str, int]:
"""Get frequency of common errors"""
error_counts = {}
@@ -819,20 +819,20 @@ class CrewMonitor:
if metric.error_message:
error_counts[metric.error_message] = error_counts.get(metric.error_message, 0) + 1
return dict(sorted(error_counts.items(), key=lambda x: x[1], reverse=True))
def export_metrics(self, filename: str = None) -> str:
"""Export metrics to JSON file"""
if not filename:
filename = f"crew_metrics_{self.crew_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
export_data = {
"summary": self.get_performance_summary(),
"detailed_metrics": [asdict(m) for m in self.metrics]
}
with open(filename, 'w') as f:
json.dump(export_data, f, indent=2, default=str)
self.logger.info(f"Metrics exported to {filename}")
return filename
@@ -847,10 +847,10 @@ def monitored_research_task(self) -> Task:
if context:
tokens = getattr(task_output, 'token_usage', {}).get('total', 0)
monitor.end_task_monitoring(context, success=True, tokens_used=tokens)
# Start monitoring would be called before task execution
# This is a simplified example - in practice you'd integrate this into the task execution flow
return Task(
config=self.tasks_config['research_task'],
agent=self.researcher(),
@@ -872,7 +872,7 @@ class ErrorSeverity(Enum):
class CrewError(Exception):
"""Base exception for CrewAI applications"""
def __init__(self, message: str, severity: ErrorSeverity = ErrorSeverity.MEDIUM,
def __init__(self, message: str, severity: ErrorSeverity = ErrorSeverity.MEDIUM,
context: dict = None):
super().__init__(message)
self.severity = severity
@@ -893,19 +893,19 @@ class ConfigurationError(CrewError):
class ErrorHandler:
"""Centralized error handling for CrewAI applications"""
def __init__(self, crew_name: str):
self.crew_name = crew_name
self.error_log: List[CrewError] = []
self.recovery_strategies: Dict[type, Callable] = {}
def register_recovery_strategy(self, error_type: type, strategy: Callable):
"""Register a recovery strategy for specific error types"""
self.recovery_strategies[error_type] = strategy
def handle_error(self, error: Exception, context: dict = None) -> Any:
"""Handle errors with appropriate recovery strategies"""
# Convert to CrewError if needed
if not isinstance(error, CrewError):
crew_error = CrewError(
@@ -915,11 +915,11 @@ class ErrorHandler:
)
else:
crew_error = error
# Log the error
self.error_log.append(crew_error)
self._log_error(crew_error)
# Apply recovery strategy if available
error_type = type(error)
if error_type in self.recovery_strategies:
@@ -931,21 +931,21 @@ class ErrorHandler:
ErrorSeverity.HIGH,
{"original_error": str(error), "recovery_error": str(recovery_error)}
))
# If critical, re-raise
if crew_error.severity == ErrorSeverity.CRITICAL:
raise crew_error
return None
def _log_error(self, error: CrewError):
"""Log error with appropriate level based on severity"""
logger = logging.getLogger(f"CrewAI.{self.crew_name}.ErrorHandler")
error_msg = f"[{error.severity.value.upper()}] {error}"
if error.context:
error_msg += f" | Context: {error.context}"
if error.severity in [ErrorSeverity.HIGH, ErrorSeverity.CRITICAL]:
logger.error(error_msg)
logger.error(f"Stack trace: {traceback.format_exc()}")
@@ -953,16 +953,16 @@ class ErrorHandler:
logger.warning(error_msg)
else:
logger.info(error_msg)
def get_error_summary(self) -> Dict[str, Any]:
"""Get summary of errors encountered"""
if not self.error_log:
return {"total_errors": 0}
severity_counts = {}
for error in self.error_log:
severity_counts[error.severity.value] = severity_counts.get(error.severity.value, 0) + 1
return {
"total_errors": len(self.error_log),
"severity_breakdown": severity_counts,
@@ -1004,7 +1004,7 @@ def robust_task(self) -> Task:
# Use fallback response
return "Task failed, using fallback response"
return wrapper
return Task(
config=self.tasks_config['research_task'],
agent=self.researcher()
@@ -1020,60 +1020,60 @@ from pydantic import BaseSettings, Field, validator
class Environment(str, Enum):
DEVELOPMENT = "development"
TESTING = "testing"
TESTING = "testing"
STAGING = "staging"
PRODUCTION = "production"
class CrewAISettings(BaseSettings):
"""Comprehensive settings management for CrewAI applications"""
# Environment
environment: Environment = Field(default=Environment.DEVELOPMENT)
debug: bool = Field(default=True)
# API Keys (loaded from environment)
openai_api_key: Optional[str] = Field(default=None, env="OPENAI_API_KEY")
anthropic_api_key: Optional[str] = Field(default=None, env="ANTHROPIC_API_KEY")
serper_api_key: Optional[str] = Field(default=None, env="SERPER_API_KEY")
mem0_api_key: Optional[str] = Field(default=None, env="MEM0_API_KEY")
# CrewAI Configuration
crew_max_rpm: int = Field(default=100)
crew_max_execution_time: int = Field(default=3600) # 1 hour
default_llm_model: str = Field(default="gpt-4")
fallback_llm_model: str = Field(default="gpt-3.5-turbo")
# Memory and Storage
crewai_storage_dir: str = Field(default="./storage", env="CREWAI_STORAGE_DIR")
memory_enabled: bool = Field(default=True)
memory_cleanup_interval: int = Field(default=86400) # 24 hours in seconds
# Performance
enable_caching: bool = Field(default=True)
max_retries: int = Field(default=3)
retry_delay: float = Field(default=1.0)
# Monitoring
enable_monitoring: bool = Field(default=True)
log_level: str = Field(default="INFO")
metrics_export_interval: int = Field(default=3600) # 1 hour
# Security
input_sanitization: bool = Field(default=True)
max_input_length: int = Field(default=10000)
allowed_file_types: list = Field(default=["txt", "md", "pdf", "docx"])
@validator('environment', pre=True)
def set_debug_based_on_env(cls, v):
return v
@validator('debug')
def set_debug_from_env(cls, v, values):
env = values.get('environment')
if env == Environment.PRODUCTION:
return False
return v
@validator('openai_api_key')
def validate_openai_key(cls, v):
if not v:
@@ -1081,15 +1081,15 @@ class CrewAISettings(BaseSettings):
if not v.startswith('sk-'):
raise ValueError("Invalid OpenAI API key format")
return v
@property
def is_production(self) -> bool:
return self.environment == Environment.PRODUCTION
@property
def is_development(self) -> bool:
return self.environment == Environment.DEVELOPMENT
def get_llm_config(self) -> Dict[str, Any]:
"""Get LLM configuration based on environment"""
config = {
@@ -1098,12 +1098,12 @@ class CrewAISettings(BaseSettings):
"max_tokens": 4000 if self.is_production else 2000,
"timeout": 60
}
if self.is_development:
config["model"] = self.fallback_llm_model
return config
def get_memory_config(self) -> Dict[str, Any]:
"""Get memory configuration"""
return {
@@ -1112,7 +1112,7 @@ class CrewAISettings(BaseSettings):
"cleanup_interval": self.memory_cleanup_interval,
"provider": "mem0" if self.mem0_api_key and self.is_production else "local"
}
class Config:
env_file = ".env"
env_file_encoding = 'utf-8'
@@ -1125,25 +1125,25 @@ settings = CrewAISettings()
@CrewBase
class ConfigurableCrew():
"""Crew that uses centralized configuration"""
def __init__(self):
self.settings = settings
self.validate_configuration()
def validate_configuration(self):
"""Validate configuration before crew execution"""
required_keys = [self.settings.openai_api_key]
if not all(required_keys):
raise ConfigurationError("Missing required API keys")
if not os.path.exists(self.settings.crewai_storage_dir):
os.makedirs(self.settings.crewai_storage_dir, exist_ok=True)
@agent
def adaptive_agent(self) -> Agent:
"""Agent that adapts to configuration"""
llm_config = self.settings.get_llm_config()
return Agent(
config=self.agents_config['researcher'],
llm=llm_config["model"],
@@ -1163,7 +1163,7 @@ from crewai.tasks.task_output import TaskOutput
class CrewAITestFramework:
"""Comprehensive testing framework for CrewAI applications"""
@staticmethod
def create_mock_agent(role: str = "test_agent", tools: list = None) -> Mock:
"""Create a mock agent for testing"""
@@ -1175,9 +1175,9 @@ class CrewAITestFramework:
mock_agent.llm = "gpt-3.5-turbo"
mock_agent.verbose = False
return mock_agent
@staticmethod
def create_mock_task_output(content: str, success: bool = True,
def create_mock_task_output(content: str, success: bool = True,
tokens: int = 100) -> TaskOutput:
"""Create a mock task output for testing"""
return TaskOutput(
@@ -1187,13 +1187,13 @@ class CrewAITestFramework:
pydantic=None,
json_dict=None
)
@staticmethod
def create_test_crew(agents: list = None, tasks: list = None) -> Crew:
"""Create a test crew with mock components"""
test_agents = agents or [CrewAITestFramework.create_mock_agent()]
test_tasks = tasks or []
return Crew(
agents=test_agents,
tasks=test_tasks,
@@ -1203,53 +1203,53 @@ class CrewAITestFramework:
# Example test cases
class TestResearchCrew:
"""Test cases for research crew functionality"""
def setup_method(self):
"""Setup test environment"""
self.framework = CrewAITestFramework()
self.mock_serper = Mock()
@patch('crewai_tools.SerperDevTool')
def test_agent_creation(self, mock_serper_tool):
"""Test agent creation with proper configuration"""
mock_serper_tool.return_value = self.mock_serper
crew = ResearchCrew()
researcher = crew.researcher()
assert researcher.role == "Senior Research Analyst"
assert len(researcher.tools) > 0
assert researcher.verbose is True
def test_task_validation(self):
"""Test task validation logic"""
crew = ResearchCrew()
# Test valid output
valid_output = self.framework.create_mock_task_output(
"This is a comprehensive research summary with conclusions and findings."
)
is_valid, message = crew.validate_research_quality(valid_output)
assert is_valid is True
# Test invalid output (too short)
invalid_output = self.framework.create_mock_task_output("Too short")
is_valid, message = crew.validate_research_quality(invalid_output)
assert is_valid is False
assert "brief" in message.lower()
@patch('requests.get')
def test_tool_error_handling(self, mock_requests):
"""Test tool error handling and recovery"""
# Simulate network error
mock_requests.side_effect = requests.exceptions.RequestException("Network error")
tool = RobustSearchTool()
result = tool._run("test query")
assert "network error" in result.lower()
assert "failed" in result.lower()
@pytest.mark.asyncio
async def test_crew_execution_flow(self):
"""Test complete crew execution with mocked dependencies"""
@@ -1257,18 +1257,18 @@ class TestResearchCrew:
mock_execute.return_value = self.framework.create_mock_task_output(
"Research completed successfully with findings and recommendations."
)
crew = ResearchCrew()
result = crew.crew().kickoff(inputs={"topic": "AI testing"})
assert result is not None
assert "successfully" in result.raw.lower()
def test_memory_integration(self):
"""Test memory system integration"""
crew = ResearchCrew()
memory_manager = AdvancedMemoryManager(crew)
# Test saving to memory
test_content = "Important research finding about AI"
memory_manager.save_with_context(
@@ -1277,34 +1277,34 @@ class TestResearchCrew:
metadata={"importance": "high"},
agent="researcher"
)
# Test searching memory
results = memory_manager.search_across_memories("AI research")
assert "short_term" in results
def test_error_handling_workflow(self):
"""Test error handling and recovery mechanisms"""
error_handler = ErrorHandler("test_crew")
# Test error registration and handling
test_error = TaskExecutionError("Test task failed", ErrorSeverity.MEDIUM)
result = error_handler.handle_error(test_error)
assert len(error_handler.error_log) == 1
assert error_handler.error_log[0].severity == ErrorSeverity.MEDIUM
def test_configuration_validation(self):
"""Test configuration validation"""
# Test with missing API key
with patch.dict(os.environ, {}, clear=True):
with pytest.raises(ValueError):
settings = CrewAISettings()
# Test with valid configuration
with patch.dict(os.environ, {"OPENAI_API_KEY": "sk-test-key"}):
settings = CrewAISettings()
assert settings.openai_api_key == "sk-test-key"
@pytest.mark.integration
def test_end_to_end_workflow(self):
"""Integration test for complete workflow"""
@@ -1315,41 +1315,41 @@ class TestResearchCrew:
# Performance testing
class TestCrewPerformance:
"""Performance tests for CrewAI applications"""
def test_memory_usage(self):
"""Test memory usage during crew execution"""
import psutil
import gc
process = psutil.Process()
initial_memory = process.memory_info().rss
# Create and run crew multiple times
for i in range(10):
crew = ResearchCrew()
# Simulate crew execution
del crew
gc.collect()
final_memory = process.memory_info().rss
memory_increase = final_memory - initial_memory
# Assert memory increase is reasonable (less than 100MB)
assert memory_increase < 100 * 1024 * 1024
def test_concurrent_execution(self):
"""Test concurrent crew execution"""
import concurrent.futures
def run_crew(crew_id):
crew = ResearchCrew()
# Simulate execution
return f"crew_{crew_id}_completed"
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
futures = [executor.submit(run_crew, i) for i in range(5)]
results = [future.result() for future in futures]
assert len(results) == 5
assert all("completed" in result for result in results)
@@ -1400,7 +1400,7 @@ class TestCrewPerformance:
### Development:
1. Always use .env files for sensitive configuration
2. Implement comprehensive error handling and logging
2. Implement comprehensive error handling and logging
3. Use structured outputs with Pydantic for reliability
4. Test crew functionality with different input scenarios
5. Follow CrewAI patterns and conventions consistently
@@ -1426,4 +1426,4 @@ class TestCrewPerformance:
5. Use async patterns for I/O-bound operations
6. Implement proper connection pooling and resource management
7. Profile and optimize critical paths
8. Plan for horizontal scaling when needed
8. Plan for horizontal scaling when needed

View File

@@ -7,14 +7,18 @@ permissions:
env:
OPENAI_API_KEY: fake-api-key
PYTHONUNBUFFERED: 1
jobs:
tests:
name: tests (${{ matrix.python-version }})
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: true
matrix:
python-version: ['3.10', '3.11', '3.12', '3.13']
group: [1, 2, 3, 4, 5, 6, 7, 8]
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -23,6 +27,9 @@ jobs:
uses: astral-sh/setup-uv@v3
with:
enable-cache: true
cache-dependency-glob: |
**/pyproject.toml
**/uv.lock
- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}
@@ -30,5 +37,14 @@ jobs:
- name: Install the project
run: uv sync --dev --all-extras
- name: Run tests
run: uv run pytest --block-network --timeout=60 -vv
- name: Run tests (group ${{ matrix.group }} of 8)
run: |
uv run pytest \
--block-network \
--timeout=30 \
-vv \
--splits 8 \
--group ${{ matrix.group }} \
--durations=10 \
-n auto \
--maxfail=3

3
.gitignore vendored
View File

@@ -26,4 +26,5 @@ test_flow.html
crewairules.mdc
plan.md
conceptual_plan.md
build_image
build_image
chromadb-*.lock

View File

@@ -9,12 +9,7 @@
},
"favicon": "/images/favicon.svg",
"contextual": {
"options": [
"copy",
"view",
"chatgpt",
"claude"
]
"options": ["copy", "view", "chatgpt", "claude"]
},
"navigation": {
"languages": [
@@ -37,11 +32,6 @@
"href": "https://chatgpt.com/g/g-qqTuUWsBY-crewai-assistant",
"icon": "robot"
},
{
"anchor": "Get Help",
"href": "mailto:support@crewai.com",
"icon": "headset"
},
{
"anchor": "Releases",
"href": "https://github.com/crewAIInc/crewAI/releases",
@@ -55,32 +45,22 @@
"groups": [
{
"group": "Get Started",
"pages": [
"en/introduction",
"en/installation",
"en/quickstart"
]
"pages": ["en/introduction", "en/installation", "en/quickstart"]
},
{
"group": "Guides",
"pages": [
{
"group": "Strategy",
"pages": [
"en/guides/concepts/evaluating-use-cases"
]
"pages": ["en/guides/concepts/evaluating-use-cases"]
},
{
"group": "Agents",
"pages": [
"en/guides/agents/crafting-effective-agents"
]
"pages": ["en/guides/agents/crafting-effective-agents"]
},
{
"group": "Crews",
"pages": [
"en/guides/crews/first-crew"
]
"pages": ["en/guides/crews/first-crew"]
},
{
"group": "Flows",
@@ -94,7 +74,6 @@
"pages": [
"en/guides/advanced/customizing-prompts",
"en/guides/advanced/fingerprinting"
]
}
]
@@ -149,7 +128,9 @@
"en/tools/file-document/jsonsearchtool",
"en/tools/file-document/csvsearchtool",
"en/tools/file-document/directorysearchtool",
"en/tools/file-document/directoryreadtool"
"en/tools/file-document/directoryreadtool",
"en/tools/file-document/ocrtool",
"en/tools/file-document/pdf-text-writing-tool"
]
},
{
@@ -167,7 +148,8 @@
"en/tools/web-scraping/stagehandtool",
"en/tools/web-scraping/firecrawlcrawlwebsitetool",
"en/tools/web-scraping/firecrawlscrapewebsitetool",
"en/tools/web-scraping/oxylabsscraperstool"
"en/tools/web-scraping/oxylabsscraperstool",
"en/tools/web-scraping/brightdata-tools"
]
},
{
@@ -182,7 +164,13 @@
"en/tools/search-research/websitesearchtool",
"en/tools/search-research/codedocssearchtool",
"en/tools/search-research/youtubechannelsearchtool",
"en/tools/search-research/youtubevideosearchtool"
"en/tools/search-research/youtubevideosearchtool",
"en/tools/search-research/tavilysearchtool",
"en/tools/search-research/tavilyextractortool",
"en/tools/search-research/arxivpapertool",
"en/tools/search-research/serpapi-googlesearchtool",
"en/tools/search-research/serpapi-googleshoppingtool",
"en/tools/search-research/databricks-query-tool"
]
},
{
@@ -194,7 +182,9 @@
"en/tools/database-data/snowflakesearchtool",
"en/tools/database-data/nl2sqltool",
"en/tools/database-data/qdrantvectorsearchtool",
"en/tools/database-data/weaviatevectorsearchtool"
"en/tools/database-data/weaviatevectorsearchtool",
"en/tools/database-data/mongodbvectorsearchtool",
"en/tools/database-data/singlestoresearchtool"
]
},
{
@@ -226,7 +216,8 @@
"en/tools/automation/overview",
"en/tools/automation/apifyactorstool",
"en/tools/automation/composiotool",
"en/tools/automation/multiontool"
"en/tools/automation/multiontool",
"en/tools/automation/zapieractionstool"
]
}
]
@@ -237,10 +228,12 @@
"en/observability/overview",
"en/observability/agentops",
"en/observability/arize-phoenix",
"en/observability/langdb",
"en/observability/langfuse",
"en/observability/langtrace",
"en/observability/maxim",
"en/observability/mlflow",
"en/observability/neatlogs",
"en/observability/openlit",
"en/observability/opik",
"en/observability/patronus-evaluation",
@@ -274,9 +267,7 @@
},
{
"group": "Telemetry",
"pages": [
"en/telemetry"
]
"pages": ["en/telemetry"]
}
]
},
@@ -285,9 +276,7 @@
"groups": [
{
"group": "Getting Started",
"pages": [
"en/enterprise/introduction"
]
"pages": ["en/enterprise/introduction"]
},
{
"group": "Features",
@@ -296,7 +285,8 @@
"en/enterprise/features/webhook-streaming",
"en/enterprise/features/traces",
"en/enterprise/features/hallucination-guardrail",
"en/enterprise/features/integrations"
"en/enterprise/features/integrations",
"en/enterprise/features/agent-repositories"
]
},
{
@@ -341,9 +331,7 @@
},
{
"group": "Resources",
"pages": [
"en/enterprise/resources/frequently-asked-questions"
]
"pages": ["en/enterprise/resources/frequently-asked-questions"]
}
]
},
@@ -352,9 +340,7 @@
"groups": [
{
"group": "Getting Started",
"pages": [
"en/api-reference/introduction"
]
"pages": ["en/api-reference/introduction"]
},
{
"group": "Endpoints",
@@ -364,16 +350,13 @@
},
{
"tab": "Examples",
"groups": [
"groups": [
{
"group": "Examples",
"pages": [
"en/examples/example"
]
"pages": ["en/examples/example"]
}
]
}
]
},
{
@@ -395,11 +378,6 @@
"href": "https://chatgpt.com/g/g-qqTuUWsBY-crewai-assistant",
"icon": "robot"
},
{
"anchor": "Obter Ajuda",
"href": "mailto:support@crewai.com",
"icon": "headset"
},
{
"anchor": "Lançamentos",
"href": "https://github.com/crewAIInc/crewAI/releases",
@@ -424,21 +402,15 @@
"pages": [
{
"group": "Estratégia",
"pages": [
"pt-BR/guides/concepts/evaluating-use-cases"
]
"pages": ["pt-BR/guides/concepts/evaluating-use-cases"]
},
{
"group": "Agentes",
"pages": [
"pt-BR/guides/agents/crafting-effective-agents"
]
"pages": ["pt-BR/guides/agents/crafting-effective-agents"]
},
{
"group": "Crews",
"pages": [
"pt-BR/guides/crews/first-crew"
]
"pages": ["pt-BR/guides/crews/first-crew"]
},
{
"group": "Flows",
@@ -594,6 +566,7 @@
"pt-BR/observability/overview",
"pt-BR/observability/agentops",
"pt-BR/observability/arize-phoenix",
"pt-BR/observability/langdb",
"pt-BR/observability/langfuse",
"pt-BR/observability/langtrace",
"pt-BR/observability/maxim",
@@ -631,9 +604,7 @@
},
{
"group": "Telemetria",
"pages": [
"pt-BR/telemetry"
]
"pages": ["pt-BR/telemetry"]
}
]
},
@@ -642,9 +613,7 @@
"groups": [
{
"group": "Começando",
"pages": [
"pt-BR/enterprise/introduction"
]
"pages": ["pt-BR/enterprise/introduction"]
},
{
"group": "Funcionalidades",
@@ -709,9 +678,7 @@
"groups": [
{
"group": "Começando",
"pages": [
"pt-BR/api-reference/introduction"
]
"pages": ["pt-BR/api-reference/introduction"]
},
{
"group": "Endpoints",
@@ -721,16 +688,13 @@
},
{
"tab": "Exemplos",
"groups": [
"groups": [
{
"group": "Exemplos",
"pages": [
"pt-BR/examples/example"
]
"pages": ["pt-BR/examples/example"]
}
]
}
]
}
]
@@ -774,7 +738,7 @@
"destination": "/en/introduction"
},
{
"source": "/installation",
"source": "/installation",
"destination": "/en/installation"
},
{

View File

@@ -526,6 +526,103 @@ agent = Agent(
The context window management feature works automatically in the background. You don't need to call any special functions - just set `respect_context_window` to your preferred behavior and CrewAI handles the rest!
</Note>
## Direct Agent Interaction with `kickoff()`
Agents can be used directly without going through a task or crew workflow using the `kickoff()` method. This provides a simpler way to interact with an agent when you don't need the full crew orchestration capabilities.
### How `kickoff()` Works
The `kickoff()` method allows you to send messages directly to an agent and get a response, similar to how you would interact with an LLM but with all the agent's capabilities (tools, reasoning, etc.).
```python Code
from crewai import Agent
from crewai_tools import SerperDevTool
# Create an agent
researcher = Agent(
role="AI Technology Researcher",
goal="Research the latest AI developments",
tools=[SerperDevTool()],
verbose=True
)
# Use kickoff() to interact directly with the agent
result = researcher.kickoff("What are the latest developments in language models?")
# Access the raw response
print(result.raw)
```
### Parameters and Return Values
| Parameter | Type | Description |
| :---------------- | :---------------------------------- | :------------------------------------------------------------------------ |
| `messages` | `Union[str, List[Dict[str, str]]]` | Either a string query or a list of message dictionaries with role/content |
| `response_format` | `Optional[Type[Any]]` | Optional Pydantic model for structured output |
The method returns a `LiteAgentOutput` object with the following properties:
- `raw`: String containing the raw output text
- `pydantic`: Parsed Pydantic model (if a `response_format` was provided)
- `agent_role`: Role of the agent that produced the output
- `usage_metrics`: Token usage metrics for the execution
### Structured Output
You can get structured output by providing a Pydantic model as the `response_format`:
```python Code
from pydantic import BaseModel
from typing import List
class ResearchFindings(BaseModel):
main_points: List[str]
key_technologies: List[str]
future_predictions: str
# Get structured output
result = researcher.kickoff(
"Summarize the latest developments in AI for 2025",
response_format=ResearchFindings
)
# Access structured data
print(result.pydantic.main_points)
print(result.pydantic.future_predictions)
```
### Multiple Messages
You can also provide a conversation history as a list of message dictionaries:
```python Code
messages = [
{"role": "user", "content": "I need information about large language models"},
{"role": "assistant", "content": "I'd be happy to help with that! What specifically would you like to know?"},
{"role": "user", "content": "What are the latest developments in 2025?"}
]
result = researcher.kickoff(messages)
```
### Async Support
An asynchronous version is available via `kickoff_async()` with the same parameters:
```python Code
import asyncio
async def main():
result = await researcher.kickoff_async("What are the latest developments in AI?")
print(result.raw)
asyncio.run(main())
```
<Note>
The `kickoff()` method uses a `LiteAgent` internally, which provides a simpler execution flow while preserving all of the agent's configuration (role, goal, backstory, tools, etc.).
</Note>
## Important Considerations and Best Practices
### Security and Code Execution

View File

@@ -4,6 +4,8 @@ description: Learn how to use the CrewAI CLI to interact with CrewAI.
icon: terminal
---
<Warning>Since release 0.140.0, CrewAI Enterprise started a process of migrating their login provider. As such, the authentication flow via CLI was updated. Users that use Google to login, or that created their account after July 3rd, 2025 will be unable to log in with older versions of the `crewai` library.</Warning>
## Overview
The CrewAI CLI provides a set of commands to interact with CrewAI, allowing you to create, train, run, and manage crews & flows.
@@ -86,7 +88,7 @@ crewai replay [OPTIONS]
- `-t, --task_id TEXT`: Replay the crew from this task ID, including all subsequent tasks
Example:
```shell Terminal
```shell Terminal
crewai replay -t task_123456
```
@@ -132,7 +134,7 @@ crewai test [OPTIONS]
- `-m, --model TEXT`: LLM Model to run the tests on the Crew (default: "gpt-4o-mini")
Example:
```shell Terminal
```shell Terminal
crewai test -n 5 -m gpt-3.5-turbo
```
@@ -149,7 +151,7 @@ Starting from version 0.103.0, the `crewai run` command can be used to run both
</Note>
<Note>
Make sure to run these commands from the directory where your CrewAI project is set up.
Make sure to run these commands from the directory where your CrewAI project is set up.
Some commands may require additional configuration or setup within your project structure.
</Note>
@@ -186,10 +188,7 @@ def crew(self) -> Crew:
Deploy the crew or flow to [CrewAI Enterprise](https://app.crewai.com).
- **Authentication**: You need to be authenticated to deploy to CrewAI Enterprise.
```shell Terminal
crewai signup
```
If you already have an account, you can login with:
You can login or create an account with:
```shell Terminal
crewai login
```
@@ -236,7 +235,7 @@ You must be authenticated to CrewAI Enterprise to use these organization managem
- **Deploy the Crew**: Once you are authenticated, you can deploy your crew or flow to CrewAI Enterprise.
```shell Terminal
crewai deploy push
```
```
- Initiates the deployment process on the CrewAI Enterprise platform.
- Upon successful initiation, it will output the Deployment created successfully! message along with the Deployment Name and a unique Deployment ID (UUID).
@@ -310,3 +309,82 @@ When you select a provider, the CLI will prompt you to enter the Key name and th
See the following link for each provider's key name:
* [LiteLLM Providers](https://docs.litellm.ai/docs/providers)
### 12. Configuration Management
Manage CLI configuration settings for CrewAI.
```shell Terminal
crewai config [COMMAND] [OPTIONS]
```
#### Commands:
- `list`: Display all CLI configuration parameters
```shell Terminal
crewai config list
```
- `set`: Set a CLI configuration parameter
```shell Terminal
crewai config set <key> <value>
```
- `reset`: Reset all CLI configuration parameters to default values
```shell Terminal
crewai config reset
```
#### Available Configuration Parameters
- `enterprise_base_url`: Base URL of the CrewAI Enterprise instance
- `oauth2_provider`: OAuth2 provider used for authentication (e.g., workos, okta, auth0)
- `oauth2_audience`: OAuth2 audience value, typically used to identify the target API or resource
- `oauth2_client_id`: OAuth2 client ID issued by the provider, used during authentication requests
- `oauth2_domain`: OAuth2 provider's domain (e.g., your-org.auth0.com) used for issuing tokens
#### Examples
Display current configuration:
```shell Terminal
crewai config list
```
Example output:
```
CrewAI CLI Configuration
┏━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Setting ┃ Value ┃ Description ┃
┡━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ enterprise_base_url│ https://app.crewai.com │ Base URL of the CrewAI Enterprise instance │
│ org_name │ Not set │ Name of the currently active organization │
│ org_uuid │ Not set │ UUID of the currently active organization │
│ oauth2_provider │ workos │ OAuth2 provider used for authentication (e.g., workos, okta, auth0). │
│ oauth2_audience │ client_01YYY │ OAuth2 audience value, typically used to identify the target API or resource. │
│ oauth2_client_id │ client_01XXX │ OAuth2 client ID issued by the provider, used during authentication requests. │
│ oauth2_domain │ login.crewai.com │ OAuth2 provider's domain (e.g., your-org.auth0.com) used for issuing tokens. │
```
Set the enterprise base URL:
```shell Terminal
crewai config set enterprise_base_url https://my-enterprise.crewai.com
```
Set OAuth2 provider:
```shell Terminal
crewai config set oauth2_provider auth0
```
Set OAuth2 domain:
```shell Terminal
crewai config set oauth2_domain my-company.auth0.com
```
Reset all configuration to defaults:
```shell Terminal
crewai config reset
```
<Note>
Configuration settings are stored in `~/.config/crewai/settings.json`. Some settings like organization name and UUID are read-only and managed through authentication and organization commands. Tool repository related settings are hidden and cannot be set directly by users.
</Note>

View File

@@ -20,8 +20,7 @@ A crew in crewAI represents a collaborative group of agents working together to
| **Function Calling LLM** _(optional)_ | `function_calling_llm` | If passed, the crew will use this LLM to do function calling for tools for all agents in the crew. Each agent can have its own LLM, which overrides the crew's LLM for function calling. |
| **Config** _(optional)_ | `config` | Optional configuration settings for the crew, in `Json` or `Dict[str, Any]` format. |
| **Max RPM** _(optional)_ | `max_rpm` | Maximum requests per minute the crew adheres to during execution. Defaults to `None`. |
| **Memory** _(optional)_ | `memory` | Utilized for storing execution memories (short-term, long-term, entity memory). |
| **Memory Config** _(optional)_ | `memory_config` | Configuration for the memory provider to be used by the crew. |
| **Memory** _(optional)_ | `memory` | Utilized for storing execution memories (short-term, long-term, entity memory). | |
| **Cache** _(optional)_ | `cache` | Specifies whether to use a cache for storing the results of tools' execution. Defaults to `True`. |
| **Embedder** _(optional)_ | `embedder` | Configuration for the embedder to be used by the crew. Mostly used by memory for now. Default is `{"provider": "openai"}`. |
| **Step Callback** _(optional)_ | `step_callback` | A function that is called after each step of every agent. This can be used to log the agent's actions or to perform other operations; it won't override the agent-specific `step_callback`. |
@@ -32,6 +31,7 @@ A crew in crewAI represents a collaborative group of agents working together to
| **Prompt File** _(optional)_ | `prompt_file` | Path to the prompt JSON file to be used for the crew. |
| **Planning** *(optional)* | `planning` | Adds planning ability to the Crew. When activated before each Crew iteration, all Crew data is sent to an AgentPlanner that will plan the tasks and this plan will be added to each task description. |
| **Planning LLM** *(optional)* | `planning_llm` | The language model used by the AgentPlanner in a planning process. |
| **Knowledge Sources** _(optional)_ | `knowledge_sources` | Knowledge sources available at the crew level, accessible to all the agents. |
<Tip>
**Crew Max RPM**: The `max_rpm` attribute sets the maximum number of requests per minute the crew can perform to avoid rate limits and will override individual agents' `max_rpm` settings if you set it.

View File

@@ -255,6 +255,17 @@ CrewAI provides a wide range of events that you can listen for:
- **LLMCallFailedEvent**: Emitted when an LLM call fails
- **LLMStreamChunkEvent**: Emitted for each chunk received during streaming LLM responses
### Memory Events
- **MemoryQueryStartedEvent**: Emitted when a memory query is started. Contains the query, limit, and optional score threshold.
- **MemoryQueryCompletedEvent**: Emitted when a memory query is completed successfully. Contains the query, results, limit, score threshold, and query execution time.
- **MemoryQueryFailedEvent**: Emitted when a memory query fails. Contains the query, limit, score threshold, and error message.
- **MemorySaveStartedEvent**: Emitted when a memory save operation is started. Contains the value to be saved, metadata, and optional agent role.
- **MemorySaveCompletedEvent**: Emitted when a memory save operation is completed successfully. Contains the saved value, metadata, agent role, and save execution time.
- **MemorySaveFailedEvent**: Emitted when a memory save operation fails. Contains the value, metadata, agent role, and error message.
- **MemoryRetrievalStartedEvent**: Emitted when memory retrieval for a task prompt starts. Contains the optional task ID.
- **MemoryRetrievalCompletedEvent**: Emitted when memory retrieval for a task prompt completes successfully. Contains the task ID, memory content, and retrieval execution time.
## Event Handler Structure
Each event handler receives two parameters:

View File

@@ -270,7 +270,7 @@ In this section, you'll find detailed examples that help you select, configure,
from crewai import LLM
llm = LLM(
model="gemini/gemini-1.5-pro-latest",
model="gemini-1.5-pro-latest", # or vertex_ai/gemini-1.5-pro-latest
temperature=0.7,
vertex_credentials=vertex_credentials_json
)

View File

@@ -9,8 +9,7 @@ icon: database
The CrewAI framework provides a sophisticated memory system designed to significantly enhance AI agent capabilities. CrewAI offers **three distinct memory approaches** that serve different use cases:
1. **Basic Memory System** - Built-in short-term, long-term, and entity memory
2. **User Memory** - User-specific memory with Mem0 integration (legacy approach)
3. **External Memory** - Standalone external memory providers (new approach)
2. **External Memory** - Standalone external memory providers
## Memory System Components
@@ -19,7 +18,7 @@ The CrewAI framework provides a sophisticated memory system designed to signific
| **Short-Term Memory**| Temporarily stores recent interactions and outcomes using `RAG`, enabling agents to recall and utilize information relevant to their current context during the current executions.|
| **Long-Term Memory** | Preserves valuable insights and learnings from past executions, allowing agents to build and refine their knowledge over time. |
| **Entity Memory** | Captures and organizes information about entities (people, places, concepts) encountered during tasks, facilitating deeper understanding and relationship mapping. Uses `RAG` for storing entity information. |
| **Contextual Memory**| Maintains the context of interactions by combining `ShortTermMemory`, `LongTermMemory`, and `EntityMemory`, aiding in the coherence and relevance of agent responses over a sequence of tasks or a conversation. |
| **Contextual Memory**| Maintains the context of interactions by combining `ShortTermMemory`, `LongTermMemory`, `ExternalMemory` and `EntityMemory`, aiding in the coherence and relevance of agent responses over a sequence of tasks or a conversation. |
## 1. Basic Memory System (Recommended)
@@ -62,7 +61,7 @@ By default, CrewAI uses the `appdirs` library to determine storage locations fol
```
~/Library/Application Support/CrewAI/{project_name}/
├── knowledge/ # Knowledge base ChromaDB files
├── short_term_memory/ # Short-term memory ChromaDB files
├── short_term_memory/ # Short-term memory ChromaDB files
├── long_term_memory/ # Long-term memory ChromaDB files
├── entities/ # Entity memory ChromaDB files
└── long_term_memory_storage.db # SQLite database
@@ -202,7 +201,7 @@ crew = Crew(
tasks=[task],
memory=True,
embedder={
"provider": "anthropic", # Match your LLM provider
"provider": "anthropic", # Match your LLM provider
"config": {
"api_key": "your-anthropic-key",
"model": "text-embedding-3-small"
@@ -252,7 +251,7 @@ chroma_path = os.path.join(storage_path, "knowledge")
if os.path.exists(chroma_path):
client = chromadb.PersistentClient(path=chroma_path)
collections = client.list_collections()
print("ChromaDB Collections:")
for collection in collections:
print(f" - {collection.name}: {collection.count()} documents")
@@ -269,7 +268,7 @@ crew = Crew(agents=[...], tasks=[...], memory=True)
# Reset specific memory types
crew.reset_memories(command_type='short') # Short-term memory
crew.reset_memories(command_type='long') # Long-term memory
crew.reset_memories(command_type='long') # Long-term memory
crew.reset_memories(command_type='entity') # Entity memory
crew.reset_memories(command_type='knowledge') # Knowledge storage
```
@@ -596,7 +595,7 @@ providers_to_test = [
{
"name": "Ollama",
"config": {
"provider": "ollama",
"provider": "ollama",
"config": {"model": "mxbai-embed-large"}
}
}
@@ -604,7 +603,7 @@ providers_to_test = [
for provider in providers_to_test:
print(f"\nTesting {provider['name']} embeddings...")
# Create crew with specific embedder
crew = Crew(
agents=[...],
@@ -612,7 +611,7 @@ for provider in providers_to_test:
memory=True,
embedder=provider['config']
)
# Run your test and measure performance
result = crew.kickoff()
print(f"{provider['name']} completed successfully")
@@ -623,7 +622,7 @@ for provider in providers_to_test:
**Model not found errors:**
```python
# Verify model availability
from crewai.utilities.embedding_configurator import EmbeddingConfigurator
from crewai.rag.embeddings.configurator import EmbeddingConfigurator
configurator = EmbeddingConfigurator()
try:
@@ -655,17 +654,17 @@ import time
def test_embedding_performance(embedder_config, test_text="This is a test document"):
start_time = time.time()
crew = Crew(
agents=[...],
tasks=[...],
memory=True,
embedder=embedder_config
)
# Simulate memory operation
crew.kickoff()
end_time = time.time()
return end_time - start_time
@@ -676,7 +675,7 @@ openai_time = test_embedding_performance({
})
ollama_time = test_embedding_performance({
"provider": "ollama",
"provider": "ollama",
"config": {"model": "mxbai-embed-large"}
})
@@ -684,67 +683,18 @@ print(f"OpenAI: {openai_time:.2f}s")
print(f"Ollama: {ollama_time:.2f}s")
```
## 2. User Memory with Mem0 (Legacy)
## 2. External Memory
External Memory provides a standalone memory system that operates independently from the crew's built-in memory. This is ideal for specialized memory providers or cross-application memory sharing.
<Warning>
**Legacy Approach**: While fully functional, this approach is considered legacy. For new projects requiring user-specific memory, consider using External Memory instead.
</Warning>
User Memory integrates with [Mem0](https://mem0.ai/) to provide user-specific memory that persists across sessions and integrates with the crew's contextual memory system.
### Prerequisites
```bash
pip install mem0ai
```
### Mem0 Cloud Configuration
### Basic External Memory with Mem0
```python
import os
from crewai import Crew, Process
from crewai import Agent, Crew, Process, Task
from crewai.memory.external.external_memory import ExternalMemory
# Set your Mem0 API key
os.environ["MEM0_API_KEY"] = "m0-your-api-key"
crew = Crew(
agents=[...],
tasks=[...],
memory=True, # Required for contextual memory integration
memory_config={
"provider": "mem0",
"config": {"user_id": "john"},
"user_memory": {} # Required - triggers user memory initialization
},
process=Process.sequential,
verbose=True
)
```
### Advanced Mem0 Configuration
```python
crew = Crew(
agents=[...],
tasks=[...],
memory=True,
memory_config={
"provider": "mem0",
"config": {
"user_id": "john",
"org_id": "my_org_id", # Optional
"project_id": "my_project_id", # Optional
"api_key": "custom-api-key" # Optional - overrides env var
},
"user_memory": {}
}
)
```
### Local Mem0 Configuration
```python
crew = Crew(
agents=[...],
tasks=[...],
memory=True,
memory_config={
# Create external memory instance with local Mem0 Configuration
external_memory = ExternalMemory(
embedder_config={
"provider": "mem0",
"config": {
"user_id": "john",
@@ -761,37 +711,60 @@ crew = Crew(
"provider": "openai",
"config": {"api_key": "your-api-key", "model": "text-embedding-3-small"}
}
}
},
"infer": True # Optional defaults to True
},
"user_memory": {}
}
)
```
## 3. External Memory (New Approach)
External Memory provides a standalone memory system that operates independently from the crew's built-in memory. This is ideal for specialized memory providers or cross-application memory sharing.
### Basic External Memory with Mem0
```python
import os
from crewai import Agent, Crew, Process, Task
from crewai.memory.external.external_memory import ExternalMemory
os.environ["MEM0_API_KEY"] = "your-api-key"
# Create external memory instance
external_memory = ExternalMemory(
embedder_config={
"provider": "mem0",
"config": {"user_id": "U-123"}
}
)
crew = Crew(
agents=[...],
tasks=[...],
external_memory=external_memory, # Separate from basic memory
external_memory=external_memory, # Separate from basic memory
process=Process.sequential,
verbose=True
)
```
### Advanced External Memory with Mem0 Client
When using Mem0 Client, you can customize the memory configuration further, by using parameters like 'includes', 'excludes', 'custom_categories', 'infer' and 'run_id' (this is only for short-term memory).
You can find more details in the [Mem0 documentation](https://docs.mem0.ai/).
```python
import os
from crewai import Agent, Crew, Process, Task
from crewai.memory.external.external_memory import ExternalMemory
new_categories = [
{"lifestyle_management_concerns": "Tracks daily routines, habits, hobbies and interests including cooking, time management and work-life balance"},
{"seeking_structure": "Documents goals around creating routines, schedules, and organized systems in various life areas"},
{"personal_information": "Basic information about the user including name, preferences, and personality traits"}
]
os.environ["MEM0_API_KEY"] = "your-api-key"
# Create external memory instance with Mem0 Client
external_memory = ExternalMemory(
embedder_config={
"provider": "mem0",
"config": {
"user_id": "john",
"org_id": "my_org_id", # Optional
"project_id": "my_project_id", # Optional
"api_key": "custom-api-key" # Optional - overrides env var
"run_id": "my_run_id", # Optional - for short-term memory
"includes": "include1", # Optional
"excludes": "exclude1", # Optional
"infer": True # Optional defaults to True
"custom_categories": new_categories # Optional - custom categories for user memory
},
}
)
crew = Crew(
agents=[...],
tasks=[...],
external_memory=external_memory, # Separate from basic memory
process=Process.sequential,
verbose=True
)
@@ -808,8 +781,8 @@ class CustomStorage(Storage):
def save(self, value, metadata=None, agent=None):
self.memories.append({
"value": value,
"metadata": metadata,
"value": value,
"metadata": metadata,
"agent": agent
})
@@ -830,17 +803,18 @@ crew = Crew(
)
```
## Memory System Comparison
## 🧠 Memory System Comparison
| **Category** | **Feature** | **Basic Memory** | **External Memory** |
|---------------------|------------------------|-----------------------------|------------------------------|
| **Ease of Use** | Setup Complexity | Simple | Moderate |
| | Integration | Built-in (contextual) | Standalone |
| **Persistence** | Storage | Local files | Custom / Mem0 |
| | Cross-session Support | ✅ | ✅ |
| **Personalization** | User-specific Memory | ❌ | ✅ |
| | Custom Providers | Limited | Any provider |
| **Use Case Fit** | Recommended For | Most general use cases | Specialized / custom needs |
| Feature | Basic Memory | User Memory (Legacy) | External Memory |
|---------|-------------|---------------------|----------------|
| **Setup Complexity** | Simple | Medium | Medium |
| **Integration** | Built-in contextual | Contextual + User-specific | Standalone |
| **Storage** | Local files | Mem0 Cloud/Local | Custom/Mem0 |
| **Cross-session** | ✅ | ✅ | ✅ |
| **User-specific** | ❌ | ✅ | ✅ |
| **Custom providers** | Limited | Mem0 only | Any provider |
| **Recommended for** | Most use cases | Legacy projects | Specialized needs |
## Supported Embedding Providers
@@ -986,7 +960,201 @@ crew = Crew(
- 🫡 **Enhanced Personalization:** Memory enables agents to remember user preferences and historical interactions, leading to personalized experiences.
- 🧠 **Improved Problem Solving:** Access to a rich memory store aids agents in making more informed decisions, drawing on past learnings and contextual insights.
## Memory Events
CrewAI's event system provides powerful insights into memory operations. By leveraging memory events, you can monitor, debug, and optimize your memory system's performance and behavior.
### Available Memory Events
CrewAI emits the following memory-related events:
| Event | Description | Key Properties |
| :---- | :---------- | :------------- |
| **MemoryQueryStartedEvent** | Emitted when a memory query begins | `query`, `limit`, `score_threshold` |
| **MemoryQueryCompletedEvent** | Emitted when a memory query completes successfully | `query`, `results`, `limit`, `score_threshold`, `query_time_ms` |
| **MemoryQueryFailedEvent** | Emitted when a memory query fails | `query`, `limit`, `score_threshold`, `error` |
| **MemorySaveStartedEvent** | Emitted when a memory save operation begins | `value`, `metadata`, `agent_role` |
| **MemorySaveCompletedEvent** | Emitted when a memory save operation completes successfully | `value`, `metadata`, `agent_role`, `save_time_ms` |
| **MemorySaveFailedEvent** | Emitted when a memory save operation fails | `value`, `metadata`, `agent_role`, `error` |
| **MemoryRetrievalStartedEvent** | Emitted when memory retrieval for a task prompt starts | `task_id` |
| **MemoryRetrievalCompletedEvent** | Emitted when memory retrieval completes successfully | `task_id`, `memory_content`, `retrieval_time_ms` |
### Practical Applications
#### 1. Memory Performance Monitoring
Track memory operation timing to optimize your application:
```python
from crewai.utilities.events.base_event_listener import BaseEventListener
from crewai.utilities.events import (
MemoryQueryCompletedEvent,
MemorySaveCompletedEvent
)
import time
class MemoryPerformanceMonitor(BaseEventListener):
def __init__(self):
super().__init__()
self.query_times = []
self.save_times = []
def setup_listeners(self, crewai_event_bus):
@crewai_event_bus.on(MemoryQueryCompletedEvent)
def on_memory_query_completed(source, event: MemoryQueryCompletedEvent):
self.query_times.append(event.query_time_ms)
print(f"Memory query completed in {event.query_time_ms:.2f}ms. Query: '{event.query}'")
print(f"Average query time: {sum(self.query_times)/len(self.query_times):.2f}ms")
@crewai_event_bus.on(MemorySaveCompletedEvent)
def on_memory_save_completed(source, event: MemorySaveCompletedEvent):
self.save_times.append(event.save_time_ms)
print(f"Memory save completed in {event.save_time_ms:.2f}ms")
print(f"Average save time: {sum(self.save_times)/len(self.save_times):.2f}ms")
# Create an instance of your listener
memory_monitor = MemoryPerformanceMonitor()
```
#### 2. Memory Content Logging
Log memory operations for debugging and insights:
```python
from crewai.utilities.events.base_event_listener import BaseEventListener
from crewai.utilities.events import (
MemorySaveStartedEvent,
MemoryQueryStartedEvent,
MemoryRetrievalCompletedEvent
)
import logging
# Configure logging
logger = logging.getLogger('memory_events')
class MemoryLogger(BaseEventListener):
def setup_listeners(self, crewai_event_bus):
@crewai_event_bus.on(MemorySaveStartedEvent)
def on_memory_save_started(source, event: MemorySaveStartedEvent):
if event.agent_role:
logger.info(f"Agent '{event.agent_role}' saving memory: {event.value[:50]}...")
else:
logger.info(f"Saving memory: {event.value[:50]}...")
@crewai_event_bus.on(MemoryQueryStartedEvent)
def on_memory_query_started(source, event: MemoryQueryStartedEvent):
logger.info(f"Memory query started: '{event.query}' (limit: {event.limit})")
@crewai_event_bus.on(MemoryRetrievalCompletedEvent)
def on_memory_retrieval_completed(source, event: MemoryRetrievalCompletedEvent):
if event.task_id:
logger.info(f"Memory retrieved for task {event.task_id} in {event.retrieval_time_ms:.2f}ms")
else:
logger.info(f"Memory retrieved in {event.retrieval_time_ms:.2f}ms")
logger.debug(f"Memory content: {event.memory_content}")
# Create an instance of your listener
memory_logger = MemoryLogger()
```
#### 3. Error Tracking and Notifications
Capture and respond to memory errors:
```python
from crewai.utilities.events.base_event_listener import BaseEventListener
from crewai.utilities.events import (
MemorySaveFailedEvent,
MemoryQueryFailedEvent
)
import logging
from typing import Optional
# Configure logging
logger = logging.getLogger('memory_errors')
class MemoryErrorTracker(BaseEventListener):
def __init__(self, notify_email: Optional[str] = None):
super().__init__()
self.notify_email = notify_email
self.error_count = 0
def setup_listeners(self, crewai_event_bus):
@crewai_event_bus.on(MemorySaveFailedEvent)
def on_memory_save_failed(source, event: MemorySaveFailedEvent):
self.error_count += 1
agent_info = f"Agent '{event.agent_role}'" if event.agent_role else "Unknown agent"
error_message = f"Memory save failed: {event.error}. {agent_info}"
logger.error(error_message)
if self.notify_email and self.error_count % 5 == 0:
self._send_notification(error_message)
@crewai_event_bus.on(MemoryQueryFailedEvent)
def on_memory_query_failed(source, event: MemoryQueryFailedEvent):
self.error_count += 1
error_message = f"Memory query failed: {event.error}. Query: '{event.query}'"
logger.error(error_message)
if self.notify_email and self.error_count % 5 == 0:
self._send_notification(error_message)
def _send_notification(self, message):
# Implement your notification system (email, Slack, etc.)
print(f"[NOTIFICATION] Would send to {self.notify_email}: {message}")
# Create an instance of your listener
error_tracker = MemoryErrorTracker(notify_email="admin@example.com")
```
### Integrating with Analytics Platforms
Memory events can be forwarded to analytics and monitoring platforms to track performance metrics, detect anomalies, and visualize memory usage patterns:
```python
from crewai.utilities.events.base_event_listener import BaseEventListener
from crewai.utilities.events import (
MemoryQueryCompletedEvent,
MemorySaveCompletedEvent
)
class MemoryAnalyticsForwarder(BaseEventListener):
def __init__(self, analytics_client):
super().__init__()
self.client = analytics_client
def setup_listeners(self, crewai_event_bus):
@crewai_event_bus.on(MemoryQueryCompletedEvent)
def on_memory_query_completed(source, event: MemoryQueryCompletedEvent):
# Forward query metrics to analytics platform
self.client.track_metric({
"event_type": "memory_query",
"query": event.query,
"duration_ms": event.query_time_ms,
"result_count": len(event.results) if hasattr(event.results, "__len__") else 0,
"timestamp": event.timestamp
})
@crewai_event_bus.on(MemorySaveCompletedEvent)
def on_memory_save_completed(source, event: MemorySaveCompletedEvent):
# Forward save metrics to analytics platform
self.client.track_metric({
"event_type": "memory_save",
"agent_role": event.agent_role,
"duration_ms": event.save_time_ms,
"timestamp": event.timestamp
})
```
### Best Practices for Memory Event Listeners
1. **Keep handlers lightweight**: Avoid complex processing in event handlers to prevent performance impacts
2. **Use appropriate logging levels**: Use INFO for normal operations, DEBUG for details, ERROR for issues
3. **Batch metrics when possible**: Accumulate metrics before sending to external systems
4. **Handle exceptions gracefully**: Ensure your event handlers don't crash due to unexpected data
5. **Consider memory consumption**: Be mindful of storing large amounts of event data
## Conclusion
Integrating CrewAI's memory system into your projects is straightforward. By leveraging the provided memory components and configurations,
Integrating CrewAI's memory system into your projects is straightforward. By leveraging the provided memory components and configurations,
you can quickly empower your agents with the ability to remember, reason, and learn from their interactions, unlocking new levels of intelligence and capability.

View File

@@ -54,9 +54,11 @@ crew = Crew(
| **Markdown** _(optional)_ | `markdown` | `Optional[bool]` | Whether the task should instruct the agent to return the final answer formatted in Markdown. Defaults to False. |
| **Config** _(optional)_ | `config` | `Optional[Dict[str, Any]]` | Task-specific configuration parameters. |
| **Output File** _(optional)_ | `output_file` | `Optional[str]` | File path for storing the task output. |
| **Create Directory** _(optional)_ | `create_directory` | `Optional[bool]` | Whether to create the directory for output_file if it doesn't exist. Defaults to True. |
| **Output JSON** _(optional)_ | `output_json` | `Optional[Type[BaseModel]]` | A Pydantic model to structure the JSON output. |
| **Output Pydantic** _(optional)_ | `output_pydantic` | `Optional[Type[BaseModel]]` | A Pydantic model for task output. |
| **Callback** _(optional)_ | `callback` | `Optional[Any]` | Function/object to be executed after task completion. |
| **Guardrail** _(optional)_ | `guardrail` | `Optional[Callable]` | Function to validate task output before proceeding to next task. |
## Creating Tasks
@@ -332,9 +334,11 @@ Task guardrails provide a way to validate and transform task outputs before they
are passed to the next task. This feature helps ensure data quality and provides
feedback to agents when their output doesn't meet specific criteria.
### Using Task Guardrails
Guardrails are implemented as Python functions that contain custom validation logic, giving you complete control over the validation process and ensuring reliable, deterministic results.
To add a guardrail to a task, provide a validation function through the `guardrail` parameter:
### Function-Based Guardrails
To add a function-based guardrail to a task, provide a validation function through the `guardrail` parameter:
```python Code
from typing import Tuple, Union, Dict, Any
@@ -372,9 +376,7 @@ blog_task = Task(
- On success: it returns a tuple of `(bool, Any)`. For example: `(True, validated_result)`
- On Failure: it returns a tuple of `(bool, str)`. For example: `(False, "Error message explain the failure")`
### LLMGuardrail
The `LLMGuardrail` class offers a robust mechanism for validating task outputs.
### Error Handling Best Practices
@@ -798,184 +800,91 @@ While creating and executing tasks, certain validation mechanisms are in place t
These validations help in maintaining the consistency and reliability of task executions within the crewAI framework.
## Task Guardrails
Task guardrails provide a powerful way to validate, transform, or filter task outputs before they are passed to the next task. Guardrails are optional functions that execute before the next task starts, allowing you to ensure that task outputs meet specific requirements or formats.
### Basic Usage
#### Define your own logic to validate
```python Code
from typing import Tuple, Union
from crewai import Task
def validate_json_output(result: str) -> Tuple[bool, Union[dict, str]]:
"""Validate that the output is valid JSON."""
try:
json_data = json.loads(result)
return (True, json_data)
except json.JSONDecodeError:
return (False, "Output must be valid JSON")
task = Task(
description="Generate JSON data",
expected_output="Valid JSON object",
guardrail=validate_json_output
)
```
#### Leverage a no-code approach for validation
```python Code
from crewai import Task
task = Task(
description="Generate JSON data",
expected_output="Valid JSON object",
guardrail="Ensure the response is a valid JSON object"
)
```
#### Using YAML
```yaml
research_task:
...
guardrail: make sure each bullet contains a minimum of 100 words
...
```
```python Code
@CrewBase
class InternalCrew:
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
...
@task
def research_task(self):
return Task(config=self.tasks_config["research_task"]) # type: ignore[index]
...
```
#### Use custom models for code generation
```python Code
from crewai import Task
from crewai.llm import LLM
task = Task(
description="Generate JSON data",
expected_output="Valid JSON object",
guardrail=LLMGuardrail(
description="Ensure the response is a valid JSON object",
llm=LLM(model="gpt-4o-mini"),
)
)
```
### How Guardrails Work
1. **Optional Attribute**: Guardrails are an optional attribute at the task level, allowing you to add validation only where needed.
2. **Execution Timing**: The guardrail function is executed before the next task starts, ensuring valid data flow between tasks.
3. **Return Format**: Guardrails must return a tuple of `(success, data)`:
- If `success` is `True`, `data` is the validated/transformed result
- If `success` is `False`, `data` is the error message
4. **Result Routing**:
- On success (`True`), the result is automatically passed to the next task
- On failure (`False`), the error is sent back to the agent to generate a new answer
### Common Use Cases
#### Data Format Validation
```python Code
def validate_email_format(result: str) -> Tuple[bool, Union[str, str]]:
"""Ensure the output contains a valid email address."""
import re
email_pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$'
if re.match(email_pattern, result.strip()):
return (True, result.strip())
return (False, "Output must be a valid email address")
```
#### Content Filtering
```python Code
def filter_sensitive_info(result: str) -> Tuple[bool, Union[str, str]]:
"""Remove or validate sensitive information."""
sensitive_patterns = ['SSN:', 'password:', 'secret:']
for pattern in sensitive_patterns:
if pattern.lower() in result.lower():
return (False, f"Output contains sensitive information ({pattern})")
return (True, result)
```
#### Data Transformation
```python Code
def normalize_phone_number(result: str) -> Tuple[bool, Union[str, str]]:
"""Ensure phone numbers are in a consistent format."""
import re
digits = re.sub(r'\D', '', result)
if len(digits) == 10:
formatted = f"({digits[:3]}) {digits[3:6]}-{digits[6:]}"
return (True, formatted)
return (False, "Output must be a 10-digit phone number")
```
### Advanced Features
#### Chaining Multiple Validations
```python Code
def chain_validations(*validators):
"""Chain multiple validators together."""
def combined_validator(result):
for validator in validators:
success, data = validator(result)
if not success:
return (False, data)
result = data
return (True, result)
return combined_validator
# Usage
task = Task(
description="Get user contact info",
expected_output="Email and phone",
guardrail=chain_validations(
validate_email_format,
filter_sensitive_info
)
)
```
#### Custom Retry Logic
```python Code
task = Task(
description="Generate data",
expected_output="Valid data",
guardrail=validate_data,
max_retries=5 # Override default retry limit
)
```
## Creating Directories when Saving Files
You can now specify if a task should create directories when saving its output to a file. This is particularly useful for organizing outputs and ensuring that file paths are correctly structured.
The `create_directory` parameter controls whether CrewAI should automatically create directories when saving task outputs to files. This feature is particularly useful for organizing outputs and ensuring that file paths are correctly structured, especially when working with complex project hierarchies.
### Default Behavior
By default, `create_directory=True`, which means CrewAI will automatically create any missing directories in the output file path:
```python Code
# ...
save_output_task = Task(
description='Save the summarized AI news to a file',
expected_output='File saved successfully',
agent=research_agent,
tools=[file_save_tool],
output_file='outputs/ai_news_summary.txt',
create_directory=True
# Default behavior - directories are created automatically
report_task = Task(
description='Generate a comprehensive market analysis report',
expected_output='A detailed market analysis with charts and insights',
agent=analyst_agent,
output_file='reports/2025/market_analysis.md', # Creates 'reports/2025/' if it doesn't exist
markdown=True
)
```
#...
### Disabling Directory Creation
If you want to prevent automatic directory creation and ensure that the directory already exists, set `create_directory=False`:
```python Code
# Strict mode - directory must already exist
strict_output_task = Task(
description='Save critical data that requires existing infrastructure',
expected_output='Data saved to pre-configured location',
agent=data_agent,
output_file='secure/vault/critical_data.json',
create_directory=False # Will raise RuntimeError if 'secure/vault/' doesn't exist
)
```
### YAML Configuration
You can also configure this behavior in your YAML task definitions:
```yaml tasks.yaml
analysis_task:
description: >
Generate quarterly financial analysis
expected_output: >
A comprehensive financial report with quarterly insights
agent: financial_analyst
output_file: reports/quarterly/q4_2024_analysis.pdf
create_directory: true # Automatically create 'reports/quarterly/' directory
audit_task:
description: >
Perform compliance audit and save to existing audit directory
expected_output: >
A compliance audit report
agent: auditor
output_file: audit/compliance_report.md
create_directory: false # Directory must already exist
```
### Use Cases
**Automatic Directory Creation (`create_directory=True`):**
- Development and prototyping environments
- Dynamic report generation with date-based folders
- Automated workflows where directory structure may vary
- Multi-tenant applications with user-specific folders
**Manual Directory Management (`create_directory=False`):**
- Production environments with strict file system controls
- Security-sensitive applications where directories must be pre-configured
- Systems with specific permission requirements
- Compliance environments where directory creation is audited
### Error Handling
When `create_directory=False` and the directory doesn't exist, CrewAI will raise a `RuntimeError`:
```python Code
try:
result = crew.kickoff()
except RuntimeError as e:
# Handle missing directory error
print(f"Directory creation failed: {e}")
# Create directory manually or use fallback location
```
Check out the video below to see how to use structured outputs in CrewAI:

View File

@@ -0,0 +1,155 @@
---
title: 'Agent Repositories'
description: 'Learn how to use Agent Repositories to share and reuse your agents across teams and projects'
icon: 'database'
---
Agent Repositories allow enterprise users to store, share, and reuse agent definitions across teams and projects. This feature enables organizations to maintain a centralized library of standardized agents, promoting consistency and reducing duplication of effort.
## Benefits of Agent Repositories
- **Standardization**: Maintain consistent agent definitions across your organization
- **Reusability**: Create an agent once and use it in multiple crews and projects
- **Governance**: Implement organization-wide policies for agent configurations
- **Collaboration**: Enable teams to share and build upon each other's work
## Using Agent Repositories
### Prerequisites
1. You must have an account at CrewAI, try the [free plan](https://app.crewai.com).
2. You need to be authenticated using the CrewAI CLI.
3. If you have more than one organization, make sure you are switched to the correct organization using the CLI command:
```bash
crewai org switch <org_id>
```
### Creating and Managing Agents in Repositories
To create and manage agents in repositories,Enterprise Dashboard.
### Loading Agents from Repositories
You can load agents from repositories in your code using the `from_repository` parameter:
```python
from crewai import Agent
# Create an agent by loading it from a repository
# The agent is loaded with all its predefined configurations
researcher = Agent(
from_repository="market-research-agent"
)
```
### Overriding Repository Settings
You can override specific settings from the repository by providing them in the configuration:
```python
researcher = Agent(
from_repository="market-research-agent",
goal="Research the latest trends in AI development", # Override the repository goal
verbose=True # Add a setting not in the repository
)
```
### Example: Creating a Crew with Repository Agents
```python
from crewai import Crew, Agent, Task
# Load agents from repositories
researcher = Agent(
from_repository="market-research-agent"
)
writer = Agent(
from_repository="content-writer-agent"
)
# Create tasks
research_task = Task(
description="Research the latest trends in AI",
agent=researcher
)
writing_task = Task(
description="Write a comprehensive report based on the research",
agent=writer
)
# Create the crew
crew = Crew(
agents=[researcher, writer],
tasks=[research_task, writing_task],
verbose=True
)
# Run the crew
result = crew.kickoff()
```
### Example: Using `kickoff()` with Repository Agents
You can also use repository agents directly with the `kickoff()` method for simpler interactions:
```python
from crewai import Agent
from pydantic import BaseModel
from typing import List
# Define a structured output format
class MarketAnalysis(BaseModel):
key_trends: List[str]
opportunities: List[str]
recommendation: str
# Load an agent from repository
analyst = Agent(
from_repository="market-analyst-agent",
verbose=True
)
# Get a free-form response
result = analyst.kickoff("Analyze the AI market in 2025")
print(result.raw) # Access the raw response
# Get structured output
structured_result = analyst.kickoff(
"Provide a structured analysis of the AI market in 2025",
response_format=MarketAnalysis
)
# Access structured data
print(f"Key Trends: {structured_result.pydantic.key_trends}")
print(f"Recommendation: {structured_result.pydantic.recommendation}")
```
## Best Practices
1. **Naming Convention**: Use clear, descriptive names for your repository agents
2. **Documentation**: Include comprehensive descriptions for each agent
3. **Tool Management**: Ensure that tools referenced by repository agents are available in your environment
4. **Access Control**: Manage permissions to ensure only authorized team members can modify repository agents
## Organization Management
To switch between organizations or see your current organization, use the CrewAI CLI:
```bash
# View current organization
crewai org current
# Switch to a different organization
crewai org switch <org_id>
# List all available organizations
crewai org list
```
<Note>
When loading agents from repositories, you must be authenticated and switched to the correct organization. If you receive errors, check your authentication status and organization settings using the CLI commands above.
</Note>

View File

@@ -41,11 +41,8 @@ The CLI provides the fastest way to deploy locally developed crews to the Enterp
First, you need to authenticate your CLI with the CrewAI Enterprise platform:
```bash
# If you already have a CrewAI Enterprise account
# If you already have a CrewAI Enterprise account, or want to create one:
crewai login
# If you're creating a new account
crewai signup
```
When you run either command, the CLI will:

View File

@@ -44,6 +44,19 @@ The `MCPServerAdapter` class from `crewai-tools` is the primary way to connect t
Using a Python context manager (`with` statement) is the **recommended approach** for `MCPServerAdapter`. It automatically handles starting and stopping the connection to the MCP server.
## Connection Configuration
The `MCPServerAdapter` supports several configuration options to customize the connection behavior:
- **`connect_timeout`** (optional): Maximum time in seconds to wait for establishing a connection to the MCP server. Defaults to 30 seconds if not specified. This is particularly useful for remote servers that may have variable response times.
```python
# Example with custom connection timeout
with MCPServerAdapter(server_params, connect_timeout=60) as tools:
# Connection will timeout after 60 seconds if not established
pass
```
```python
from crewai import Agent
from crewai_tools import MCPServerAdapter
@@ -70,7 +83,7 @@ server_params = {
}
# Example usage (uncomment and adapt once server_params is set):
with MCPServerAdapter(server_params) as mcp_tools:
with MCPServerAdapter(server_params, connect_timeout=60) as mcp_tools:
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
my_agent = Agent(
@@ -95,7 +108,7 @@ There are two ways to filter tools:
### Accessing a specific tool using dictionary-style indexing.
```python
with MCPServerAdapter(server_params) as mcp_tools:
with MCPServerAdapter(server_params, connect_timeout=60) as mcp_tools:
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
my_agent = Agent(
@@ -112,7 +125,7 @@ with MCPServerAdapter(server_params) as mcp_tools:
### Pass a list of tool names to the `MCPServerAdapter` constructor.
```python
with MCPServerAdapter(server_params, "tool_name") as mcp_tools:
with MCPServerAdapter(server_params, "tool_name", connect_timeout=60) as mcp_tools:
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
my_agent = Agent(

View File

@@ -0,0 +1,286 @@
---
title: LangDB Integration
description: Govern, secure, and optimize your CrewAI workflows with LangDB AI Gateway—access 350+ models, automatic routing, cost optimization, and full observability.
icon: database
---
# Introduction
[LangDB AI Gateway](https://langdb.ai) provides OpenAI-compatible APIs to connect with multiple Large Language Models and serves as an observability platform that makes it effortless to trace CrewAI workflows end-to-end while providing access to 350+ language models. With a single `init()` call, all agent interactions, task executions, and LLM calls are captured, providing comprehensive observability and production-ready AI infrastructure for your applications.
<Frame caption="LangDB CrewAI Trace Example">
<img src="/images/langdb-1.png" alt="LangDB CrewAI trace example" />
</Frame>
**Checkout:** [View the live trace example](https://app.langdb.ai/sharing/threads/3becbfed-a1be-ae84-ea3c-4942867a3e22)
## Features
### AI Gateway Capabilities
- **Access to 350+ LLMs**: Connect to all major language models through a single integration
- **Virtual Models**: Create custom model configurations with specific parameters and routing rules
- **Virtual MCP**: Enable compatibility and integration with MCP (Model Context Protocol) systems for enhanced agent communication
- **Guardrails**: Implement safety measures and compliance controls for agent behavior
### Observability & Tracing
- **Automatic Tracing**: Single `init()` call captures all CrewAI interactions
- **End-to-End Visibility**: Monitor agent workflows from start to finish
- **Tool Usage Tracking**: Track which tools agents use and their outcomes
- **Model Call Monitoring**: Detailed insights into LLM interactions
- **Performance Analytics**: Monitor latency, token usage, and costs
- **Debugging Support**: Step-through execution for troubleshooting
- **Real-time Monitoring**: Live traces and metrics dashboard
## Setup Instructions
<Steps>
<Step title="Install LangDB">
Install the LangDB client with CrewAI feature flag:
```bash
pip install 'pylangdb[crewai]'
```
</Step>
<Step title="Set Environment Variables">
Configure your LangDB credentials:
```bash
export LANGDB_API_KEY="<your_langdb_api_key>"
export LANGDB_PROJECT_ID="<your_langdb_project_id>"
export LANGDB_API_BASE_URL='https://api.us-east-1.langdb.ai'
```
</Step>
<Step title="Initialize Tracing">
Import and initialize LangDB before configuring your CrewAI code:
```python
from pylangdb.crewai import init
# Initialize LangDB
init()
```
</Step>
<Step title="Configure CrewAI with LangDB">
Set up your LLM with LangDB headers:
```python
from crewai import Agent, Task, Crew, LLM
import os
# Configure LLM with LangDB headers
llm = LLM(
model="openai/gpt-4o", # Replace with the model you want to use
api_key=os.getenv("LANGDB_API_KEY"),
base_url=os.getenv("LANGDB_API_BASE_URL"),
extra_headers={"x-project-id": os.getenv("LANGDB_PROJECT_ID")}
)
```
</Step>
</Steps>
## Quick Start Example
Here's a simple example to get you started with LangDB and CrewAI:
```python
import os
from pylangdb.crewai import init
from crewai import Agent, Task, Crew, LLM
# Initialize LangDB before any CrewAI imports
init()
def create_llm(model):
return LLM(
model=model,
api_key=os.environ.get("LANGDB_API_KEY"),
base_url=os.environ.get("LANGDB_API_BASE_URL"),
extra_headers={"x-project-id": os.environ.get("LANGDB_PROJECT_ID")}
)
# Define your agent
researcher = Agent(
role="Research Specialist",
goal="Research topics thoroughly",
backstory="Expert researcher with skills in finding information",
llm=create_llm("openai/gpt-4o"), # Replace with the model you want to use
verbose=True
)
# Create a task
task = Task(
description="Research the given topic and provide a comprehensive summary",
agent=researcher,
expected_output="Detailed research summary with key findings"
)
# Create and run the crew
crew = Crew(agents=[researcher], tasks=[task])
result = crew.kickoff()
print(result)
```
## Complete Example: Research and Planning Agent
This comprehensive example demonstrates a multi-agent workflow with research and planning capabilities.
### Prerequisites
```bash
pip install crewai 'pylangdb[crewai]' crewai_tools setuptools python-dotenv
```
### Environment Setup
```bash
# LangDB credentials
export LANGDB_API_KEY="<your_langdb_api_key>"
export LANGDB_PROJECT_ID="<your_langdb_project_id>"
export LANGDB_API_BASE_URL='https://api.us-east-1.langdb.ai'
# Additional API keys (optional)
export SERPER_API_KEY="<your_serper_api_key>" # For web search capabilities
```
### Complete Implementation
```python
#!/usr/bin/env python3
import os
import sys
from pylangdb.crewai import init
init() # Initialize LangDB before any CrewAI imports
from dotenv import load_dotenv
from crewai import Agent, Task, Crew, Process, LLM
from crewai_tools import SerperDevTool
load_dotenv()
def create_llm(model):
return LLM(
model=model,
api_key=os.environ.get("LANGDB_API_KEY"),
base_url=os.environ.get("LANGDB_API_BASE_URL"),
extra_headers={"x-project-id": os.environ.get("LANGDB_PROJECT_ID")}
)
class ResearchPlanningCrew:
def researcher(self) -> Agent:
return Agent(
role="Research Specialist",
goal="Research topics thoroughly and compile comprehensive information",
backstory="Expert researcher with skills in finding and analyzing information from various sources",
tools=[SerperDevTool()],
llm=create_llm("openai/gpt-4o"),
verbose=True
)
def planner(self) -> Agent:
return Agent(
role="Strategic Planner",
goal="Create actionable plans based on research findings",
backstory="Strategic planner who breaks down complex challenges into executable plans",
reasoning=True,
max_reasoning_attempts=3,
llm=create_llm("openai/anthropic/claude-3.7-sonnet"),
verbose=True
)
def research_task(self) -> Task:
return Task(
description="Research the topic thoroughly and compile comprehensive information",
agent=self.researcher(),
expected_output="Comprehensive research report with key findings and insights"
)
def planning_task(self) -> Task:
return Task(
description="Create a strategic plan based on the research findings",
agent=self.planner(),
expected_output="Strategic execution plan with phases, goals, and actionable steps",
context=[self.research_task()]
)
def crew(self) -> Crew:
return Crew(
agents=[self.researcher(), self.planner()],
tasks=[self.research_task(), self.planning_task()],
verbose=True,
process=Process.sequential
)
def main():
topic = sys.argv[1] if len(sys.argv) > 1 else "Artificial Intelligence in Healthcare"
crew_instance = ResearchPlanningCrew()
# Update task descriptions with the specific topic
crew_instance.research_task().description = f"Research {topic} thoroughly and compile comprehensive information"
crew_instance.planning_task().description = f"Create a strategic plan for {topic} based on the research findings"
result = crew_instance.crew().kickoff()
print(result)
if __name__ == "__main__":
main()
```
### Running the Example
```bash
python main.py "Sustainable Energy Solutions"
```
## Viewing Traces in LangDB
After running your CrewAI application, you can view detailed traces in the LangDB dashboard:
<Frame caption="LangDB Trace Dashboard">
<img src="/images/langdb-2.png" alt="LangDB trace dashboard showing CrewAI workflow" />
</Frame>
### What You'll See
- **Agent Interactions**: Complete flow of agent conversations and task handoffs
- **Tool Usage**: Which tools were called, their inputs, and outputs
- **Model Calls**: Detailed LLM interactions with prompts image.pngand responses
- **Performance Metrics**: Latency, token usage, and cost tracking
- **Execution Timeline**: Step-by-step view of the entire workflow
## Troubleshooting
### Common Issues
- **No traces appearing**: Ensure `init()` is called before any CrewAI imports
- **Authentication errors**: Verify your LangDB API key and project ID
## Resources
<CardGroup cols={3}>
<Card title="LangDB Documentation" icon="book" href="https://docs.langdb.ai">
Official LangDB documentation and guides
</Card>
<Card title="LangDB Guides" icon="graduation-cap" href="https://docs.langdb.ai/guides">
Step-by-step tutorials for building AI agents
</Card>
<Card title="GitHub Examples" icon="github" href="https://github.com/langdb/langdb-samples/tree/main/examples/crewai" >
Complete CrewAI integration examples
</Card>
<Card title="LangDB Dashboard" icon="chart-line" href="https://app.langdb.ai">
Access your traces and analytics
</Card>
<Card title="Model Catalog" icon="list" href="https://app.langdb.ai/models">
Browse 350+ available language models
</Card>
<Card title="Enterprise Features" icon="building" href="https://docs.langdb.ai/enterprise">
Self-hosted options and enterprise capabilities
</Card>
</CardGroup>
## Next Steps
This guide covered the basics of integrating LangDB AI Gateway with CrewAI. To further enhance your AI workflows, explore:
- **Virtual Models**: Create custom model configurations with routing strategies
- **Guardrails & Safety**: Implement content filtering and compliance controls
- **Production Deployment**: Configure fallbacks, retries, and load balancing
For more advanced features and use cases, visit the [LangDB Documentation](https://docs.langdb.ai) or explore the [Model Catalog](https://app.langdb.ai/models) to discover all available models.

View File

@@ -0,0 +1,134 @@
---
title: Neatlogs Integration
description: Understand, debug, and share your CrewAI agent runs
icon: magnifying-glass-chart
---
# Introduction
Neatlogs helps you **see what your agent did**, **why**, and **share it**.
It captures every step: thoughts, tool calls, responses, evaluations. No raw logs. Just clear, structured traces. Great for debugging and collaboration.
## Why use Neatlogs?
CrewAI agents use multiple tools and reasoning steps. When something goes wrong, you need context — not just errors.
Neatlogs lets you:
- Follow the full decision path
- Add feedback directly on steps
- Chat with the trace using AI assistant
- Share runs publicly for feedback
- Turn insights into tasks
All in one place.
Manage your traces effortlessly
![Traces](/images/neatlogs-1.png)
![Trace Response](/images/neatlogs-2.png)
The best UX to view a CrewAI trace. Post comments anywhere you want. Use AI to debug.
![Trace Details](/images/neatlogs-3.png)
![Ai Chat Bot With A Trace](/images/neatlogs-4.png)
![Comments Drawer](/images/neatlogs-5.png)
## Core Features
- **Trace Viewer**: Track thoughts, tools, and decisions in sequence
- **Inline Comments**: Tag teammates on any trace step
- **Feedback & Evaluation**: Mark outputs as correct or incorrect
- **Error Highlighting**: Automatic flagging of API/tool failures
- **Task Conversion**: Convert comments into assigned tasks
- **Ask the Trace (AI)**: Chat with your trace using Neatlogs AI bot
- **Public Sharing**: Publish trace links to your community
## Quick Setup with CrewAI
<Steps>
<Step title="Sign Up & Get API Key">
Visit [neatlogs.com](https://neatlogs.com/?utm_source=crewAI-docs), create a project, copy the API key.
</Step>
<Step title="Install SDK">
```bash
pip install neatlogs
```
(Latest version 0.8.0, Python 3.8+; MIT license)
</Step>
<Step title="Initialize Neatlogs">
Before starting Crew agents, add:
```python
import neatlogs
neatlogs.init("YOUR_PROJECT_API_KEY")
```
Agents run as usual. Neatlogs captures everything automatically.
</Step>
</Steps>
## Under the Hood
According to GitHub, Neatlogs:
- Captures thoughts, tool calls, responses, errors, and token stats
- Supports AI-powered task generation and robust evaluation workflows
All with just two lines of code.
## Watch It Work
### 🔍 Full Demo (4min)
<iframe
width="100%"
height="315"
src="https://www.youtube.com/embed/8KDme9T2I7Q?si=b8oHteaBwFNs_Duk"
title="YouTube video player"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
></iframe>
### ⚙️ CrewAI Integration (30s)
<iframe
className="w-full aspect-video rounded-xl"
src="https://www.loom.com/embed/9c78b552af43452bb3e4783cb8d91230?sid=e9d7d370-a91a-49b0-809e-2f375d9e801d"
title="Loom video player"
frameBorder="0"
allowFullScreen
></iframe>
## Links & Support
- 📘 [Neatlogs Docs](https://docs.neatlogs.com/)
- 🔐 [Dashboard & API Key](https://app.neatlogs.com/)
- 🐦 [Follow on Twitter](https://twitter.com/neatlogs)
- 📧 Contact: hello@neatlogs.com
- 🛠 [GitHub SDK](https://github.com/NeatLogs/neatlogs)
## TL;DR
With just:
```bash
pip install neatlogs
import neatlogs
neatlogs.init("YOUR_API_KEY")
You can now capture, understand, share, and act on your CrewAI agent runs in seconds.
No setup overhead. Full trace transparency. Full team collaboration.
```

View File

@@ -25,6 +25,10 @@ Observability is crucial for understanding how your CrewAI agents perform, ident
Session replays, metrics, and monitoring for agent development and production.
</Card>
<Card title="LangDB" icon="database" href="/en/observability/langdb">
End-to-end tracing for CrewAI workflows with automatic agent interaction capture.
</Card>
<Card title="OpenLIT" icon="magnifying-glass-chart" href="/en/observability/openlit">
OpenTelemetry-native monitoring with cost tracking and performance analytics.
</Card>

View File

@@ -35,7 +35,7 @@ os.environ['OTEL_SDK_DISABLED'] = 'true'
### Data Explanation:
| Defaulted | Data | Reason and Specifics |
|-----------|-------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|
|:----------|:------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------|
| Yes | CrewAI and Python Version | Tracks software versions. Example: CrewAI v1.2.3, Python 3.8.10. No personal data. |
| Yes | Crew Metadata | Includes: randomly generated key and ID, process type (e.g., 'sequential', 'parallel'), boolean flag for memory usage (true/false), count of tasks, count of agents. All non-personal. |
| Yes | Agent Data | Includes: randomly generated key and ID, role name (should not include personal info), boolean settings (verbose, delegation enabled, code execution allowed), max iterations, max RPM, max retry limit, LLM info (see LLM Attributes), list of tool names (should not include personal info). No personal data. |

View File

@@ -20,6 +20,10 @@ These tools enable your agents to automate workflows, integrate with external pl
<Card title="Multion Tool" icon="window-restore" href="/en/tools/automation/multiontool">
Automate browser interactions and web-based workflows.
</Card>
<Card title="Zapier Actions Adapter" icon="bolt" href="/en/tools/automation/zapieractionstool">
Expose Zapier Actions as CrewAI tools for automation across thousands of apps.
</Card>
</CardGroup>
## **Common Use Cases**

View File

@@ -0,0 +1,58 @@
---
title: Zapier Actions Tool
description: The `ZapierActionsAdapter` exposes Zapier actions as CrewAI tools for automation.
icon: bolt
---
# `ZapierActionsAdapter`
## Description
Use the Zapier adapter to list and call Zapier actions as CrewAI tools. This enables agents to trigger automations across thousands of apps.
## Installation
This adapter is included with `crewai-tools`. No extra install required.
## Environment Variables
- `ZAPIER_API_KEY` (required): Zapier API key. Get one from the Zapier Actions dashboard at https://actions.zapier.com/ (create an account, then generate an API key). You can also pass `zapier_api_key` directly when constructing the adapter.
## Example
```python Code
from crewai import Agent, Task, Crew
from crewai_tools.adapters.zapier_adapter import ZapierActionsAdapter
adapter = ZapierActionsAdapter(api_key="your_zapier_api_key")
tools = adapter.tools()
agent = Agent(
role="Automator",
goal="Execute Zapier actions",
backstory="Automation specialist",
tools=tools,
verbose=True,
)
task = Task(
description="Create a new Google Sheet and add a row using Zapier actions",
expected_output="Confirmation with created resource IDs",
agent=agent,
)
crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
```
## Notes & limits
- The adapter lists available actions for your key and creates `BaseTool` wrappers dynamically.
- Handle actionspecific required fields in your task instructions or tool call.
- Rate limits depend on your Zapier plan; see the Zapier Actions docs.
## Notes
- The adapter fetches available actions and generates `BaseTool` wrappers dynamically.

View File

@@ -0,0 +1,168 @@
---
title: MongoDB Vector Search Tool
description: The `MongoDBVectorSearchTool` performs vector search on MongoDB Atlas with optional indexing helpers.
icon: "leaf"
---
# `MongoDBVectorSearchTool`
## Description
Perform vector similarity queries on MongoDB Atlas collections. Supports index creation helpers and bulk insert of embedded texts.
MongoDB Atlas supports native vector search. Learn more:
https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-overview/
## Installation
Install with the MongoDB extra:
```shell
pip install crewai-tools[mongodb]
```
or
```shell
uv add crewai-tools --extra mongodb
```
## Parameters
### Initialization
- `connection_string` (str, required)
- `database_name` (str, required)
- `collection_name` (str, required)
- `vector_index_name` (str, default `vector_index`)
- `text_key` (str, default `text`)
- `embedding_key` (str, default `embedding`)
- `dimensions` (int, default `1536`)
### Run Parameters
- `query` (str, required): Natural language query to embed and search.
## Quick start
```python Code
from crewai_tools import MongoDBVectorSearchTool
tool = MongoDBVectorSearchTool(
connection_string="mongodb+srv://...",
database_name="mydb",
collection_name="docs",
)
print(tool.run(query="how to create vector index"))
```
## Index creation helpers
Use `create_vector_search_index(...)` to provision an Atlas Vector Search index with the correct dimensions and similarity.
## Common issues
- Authentication failures: ensure your Atlas IP Access List allows your runner and the connection string includes credentials.
- Index not found: create the vector index first; name must match `vector_index_name`.
- Dimensions mismatch: align embedding model dimensions with `dimensions`.
## More examples
### Basic initialization
```python Code
from crewai_tools import MongoDBVectorSearchTool
tool = MongoDBVectorSearchTool(
database_name="example_database",
collection_name="example_collection",
connection_string="<your_mongodb_connection_string>",
)
```
### Custom query configuration
```python Code
from crewai_tools import MongoDBVectorSearchConfig, MongoDBVectorSearchTool
query_config = MongoDBVectorSearchConfig(limit=10, oversampling_factor=2)
tool = MongoDBVectorSearchTool(
database_name="example_database",
collection_name="example_collection",
connection_string="<your_mongodb_connection_string>",
query_config=query_config,
vector_index_name="my_vector_index",
)
rag_agent = Agent(
name="rag_agent",
role="You are a helpful assistant that can answer questions with the help of the MongoDBVectorSearchTool.",
goal="...",
backstory="...",
tools=[tool],
)
```
### Preloading the database and creating the index
```python Code
import os
from crewai_tools import MongoDBVectorSearchTool
tool = MongoDBVectorSearchTool(
database_name="example_database",
collection_name="example_collection",
connection_string="<your_mongodb_connection_string>",
)
# Load text content from a local folder and add to MongoDB
texts = []
for fname in os.listdir("knowledge"):
path = os.path.join("knowledge", fname)
if os.path.isfile(path):
with open(path, "r", encoding="utf-8") as f:
texts.append(f.read())
tool.add_texts(texts)
# Create the Atlas Vector Search index (e.g., 3072 dims for text-embedding-3-large)
tool.create_vector_search_index(dimensions=3072)
```
## Example
```python Code
from crewai import Agent, Task, Crew
from crewai_tools import MongoDBVectorSearchTool
tool = MongoDBVectorSearchTool(
connection_string="mongodb+srv://...",
database_name="mydb",
collection_name="docs",
)
agent = Agent(
role="RAG Agent",
goal="Answer using MongoDB vector search",
backstory="Knowledge retrieval specialist",
tools=[tool],
verbose=True,
)
task = Task(
description="Find relevant content for 'indexing guidance'",
expected_output="A concise answer citing the most relevant matches",
agent=agent,
)
crew = Crew(
agents=[agent],
tasks=[task],
verbose=True,
)
result = crew.kickoff()
```

View File

@@ -32,6 +32,14 @@ These tools enable your agents to interact with various database systems, from t
<Card title="Weaviate Vector Search" icon="network-wired" href="/en/tools/database-data/weaviatevectorsearchtool">
Perform semantic search with Weaviate vector database.
</Card>
<Card title="MongoDB Vector Search" icon="leaf" href="/en/tools/database-data/mongodbvectorsearchtool">
Vector similarity search on MongoDB Atlas with indexing helpers.
</Card>
<Card title="SingleStore Search" icon="database" href="/en/tools/database-data/singlestoresearchtool">
Safe SELECT/SHOW queries on SingleStore with pooling and validation.
</Card>
</CardGroup>
## **Common Use Cases**

View File

@@ -0,0 +1,61 @@
---
title: SingleStore Search Tool
description: The `SingleStoreSearchTool` safely executes SELECT/SHOW queries on SingleStore with pooling.
icon: circle
---
# `SingleStoreSearchTool`
## Description
Execute readonly queries (`SELECT`/`SHOW`) against SingleStore with connection pooling and input validation.
## Installation
```shell
uv add crewai-tools[singlestore]
```
## Environment Variables
Variables like `SINGLESTOREDB_HOST`, `SINGLESTOREDB_USER`, `SINGLESTOREDB_PASSWORD`, etc., can be used, or `SINGLESTOREDB_URL` as a single DSN.
Generate the API key from the SingleStore dashboard, [docs here](https://docs.singlestore.com/cloud/reference/management-api/#generate-an-api-key).
## Example
```python Code
from crewai import Agent, Task, Crew
from crewai_tools import SingleStoreSearchTool
tool = SingleStoreSearchTool(
tables=["products"],
host="host",
user="user",
password="pass",
database="db",
)
agent = Agent(
role="Analyst",
goal="Query SingleStore",
tools=[tool],
verbose=True,
)
task = Task(
description="List 5 products",
expected_output="5 rows as JSON/text",
agent=agent,
)
crew = Crew(
agents=[agent],
tasks=[task],
verbose=True,
)
result = crew.kickoff()
```

View File

@@ -0,0 +1,89 @@
---
title: OCR Tool
description: The `OCRTool` extracts text from local images or image URLs using an LLM with vision.
icon: image
---
# `OCRTool`
## Description
Extract text from images (local path or URL). Uses a visioncapable LLM via CrewAIs LLM interface.
## Installation
No extra install beyond `crewai-tools`. Ensure your selected LLM supports vision.
## Parameters
### Run Parameters
- `image_path_url` (str, required): Local image path or HTTP(S) URL.
## Examples
### Direct usage
```python Code
from crewai_tools import OCRTool
print(OCRTool().run(image_path_url="/tmp/receipt.png"))
```
### With an agent
```python Code
from crewai import Agent, Task, Crew
from crewai_tools import OCRTool
ocr = OCRTool()
agent = Agent(
role="OCR",
goal="Extract text",
tools=[ocr],
)
task = Task(
description="Extract text from https://example.com/invoice.jpg",
expected_output="All detected text in plain text",
agent=agent,
)
crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
```
## Notes
- Ensure the selected LLM supports image inputs.
- For large images, consider downscaling to reduce token usage.
- You can pass a specific LLM instance to the tool (e.g., `LLM(model="gpt-4o")`) if needed, matching the README guidance.
## Example
```python Code
from crewai import Agent, Task, Crew
from crewai_tools import OCRTool
tool = OCRTool()
agent = Agent(
role="OCR Specialist",
goal="Extract text from images",
backstory="Visionenabled analyst",
tools=[tool],
verbose=True,
)
task = Task(
description="Extract text from https://example.com/receipt.png",
expected_output="All detected text in plain text",
agent=agent,
)
crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
```

View File

@@ -52,6 +52,14 @@ These tools enable your agents to work with various file formats and document ty
<Card title="Directory Read Tool" icon="folder" href="/en/tools/file-document/directoryreadtool">
Read and list directory contents, file structures, and metadata.
</Card>
<Card title="OCR Tool" icon="image" href="/en/tools/file-document/ocrtool">
Extract text from images (local files or URLs) using a visioncapable LLM.
</Card>
<Card title="PDF Text Writing Tool" icon="file-pdf" href="/en/tools/file-document/pdf-text-writing-tool">
Write text at specific coordinates in PDFs, with optional custom fonts.
</Card>
</CardGroup>
## **Common Use Cases**

View File

@@ -0,0 +1,76 @@
---
title: PDF Text Writing Tool
description: The `PDFTextWritingTool` writes text to specific positions in a PDF, supporting custom fonts.
icon: file-pdf
---
# `PDFTextWritingTool`
## Description
Write text at precise coordinates on a PDF page, optionally embedding a custom TrueType font.
## Parameters
### Run Parameters
- `pdf_path` (str, required): Path to the input PDF.
- `text` (str, required): Text to add.
- `position` (tuple[int, int], required): `(x, y)` coordinates.
- `font_size` (int, default `12`)
- `font_color` (str, default `"0 0 0 rg"`)
- `font_name` (str, default `"F1"`)
- `font_file` (str, optional): Path to `.ttf` file.
- `page_number` (int, default `0`)
## Example
```python Code
from crewai import Agent, Task, Crew
from crewai_tools import PDFTextWritingTool
tool = PDFTextWritingTool()
agent = Agent(
role="PDF Editor",
goal="Annotate PDFs",
backstory="Documentation specialist",
tools=[tool],
verbose=True,
)
task = Task(
description="Write 'CONFIDENTIAL' at (72, 720) on page 1 of ./sample.pdf",
expected_output="Confirmation message",
agent=agent,
)
crew = Crew(
agents=[agent],
tasks=[task],
verbose=True,
)
result = crew.kickoff()
```
### Direct usage
```python Code
from crewai_tools import PDFTextWritingTool
PDFTextWritingTool().run(
pdf_path="./input.pdf",
text="CONFIDENTIAL",
position=(72, 720),
font_size=18,
page_number=0,
)
```
## Tips
- Coordinate origin is the bottomleft corner.
- If using a custom font (`font_file`), ensure it is a valid `.ttf`.

View File

@@ -0,0 +1,112 @@
---
title: Arxiv Paper Tool
description: The `ArxivPaperTool` searches arXiv for papers matching a query and optionally downloads PDFs.
icon: box-archive
---
# `ArxivPaperTool`
## Description
The `ArxivPaperTool` queries the arXiv API for academic papers and returns compact, readable results. It can also optionally download PDFs to disk.
## Installation
This tool has no special installation beyond `crewai-tools`.
```shell
uv add crewai-tools
```
No API key is required. This tool uses the public arXiv Atom API.
## Steps to Get Started
1. Initialize the tool.
2. Provide a `search_query` (e.g., "transformer neural network").
3. Optionally set `max_results` (1100) and enable PDF downloads in the constructor.
## Example
```python Code
from crewai import Agent, Task, Crew
from crewai_tools import ArxivPaperTool
tool = ArxivPaperTool(
download_pdfs=False,
save_dir="./arxiv_pdfs",
use_title_as_filename=True,
)
agent = Agent(
role="Researcher",
goal="Find relevant arXiv papers",
backstory="Expert at literature discovery",
tools=[tool],
verbose=True,
)
task = Task(
description="Search arXiv for 'transformer neural network' and list top 5 results.",
expected_output="A concise list of 5 relevant papers with titles, links, and summaries.",
agent=agent,
)
crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
```
### Direct usage (without Agent)
```python Code
from crewai_tools import ArxivPaperTool
tool = ArxivPaperTool(
download_pdfs=True,
save_dir="./arxiv_pdfs",
)
print(tool.run(search_query="mixture of experts", max_results=3))
```
## Parameters
### Initialization Parameters
- `download_pdfs` (bool, default `False`): Whether to download PDFs.
- `save_dir` (str, default `./arxiv_pdfs`): Directory to save PDFs.
- `use_title_as_filename` (bool, default `False`): Use paper titles for filenames.
### Run Parameters
- `search_query` (str, required): The arXiv search query.
- `max_results` (int, default `5`, range 1100): Number of results.
## Output format
The tool returns a humanreadable list of papers with:
- Title
- Link (abs page)
- Snippet/summary (truncated)
When `download_pdfs=True`, PDFs are saved to disk and the summary mentions saved files.
## Usage Notes
- The tool returns formatted text with key metadata and links.
- When `download_pdfs=True`, PDFs will be stored in `save_dir`.
## Troubleshooting
- If you receive a network timeout, retry or reduce `max_results`.
- Invalid XML errors indicate an arXiv response parse issue; try a simpler query.
- File system errors (e.g., permission denied) may occur when saving PDFs; ensure `save_dir` is writable.
## Related links
- arXiv API docs: https://info.arxiv.org/help/api/index.html
## Error Handling
- Network issues, invalid XML, and OS errors are handled with informative messages.

View File

@@ -23,7 +23,7 @@ pip install 'crewai[tools]'
To effectively use the `BraveSearchTool`, follow these steps:
1. **Package Installation**: Confirm that the `crewai[tools]` package is installed in your Python environment.
2. **API Key Acquisition**: Acquire a Brave Search API key by registering at [Brave Search API](https://api.search.brave.com/app/keys).
2. **API Key Acquisition**: Acquire a Brave Search API key at https://api.search.brave.com/app/keys (sign in to generate a key).
3. **Environment Configuration**: Store your obtained API key in an environment variable named `BRAVE_API_KEY` to facilitate its use by the tool.
## Example

View File

@@ -0,0 +1,80 @@
---
title: Databricks SQL Query Tool
description: The `DatabricksQueryTool` executes SQL queries against Databricks workspace tables.
icon: trowel-bricks
---
# `DatabricksQueryTool`
## Description
Run SQL against Databricks workspace tables with either CLI profile or direct host/token authentication.
## Installation
```shell
uv add crewai-tools[databricks-sdk]
```
## Environment Variables
- `DATABRICKS_CONFIG_PROFILE` or (`DATABRICKS_HOST` + `DATABRICKS_TOKEN`)
Create a personal access token and find host details in the Databricks workspace under User Settings → Developer.
Docs: https://docs.databricks.com/en/dev-tools/auth/pat.html
## Example
```python Code
from crewai import Agent, Task, Crew
from crewai_tools import DatabricksQueryTool
tool = DatabricksQueryTool(
default_catalog="main",
default_schema="default",
)
agent = Agent(
role="Data Analyst",
goal="Query Databricks",
tools=[tool],
verbose=True,
)
task = Task(
description="SELECT * FROM my_table LIMIT 10",
expected_output="10 rows",
agent=agent,
)
crew = Crew(
agents=[agent],
tasks=[task],
verbose=True,
)
result = crew.kickoff()
print(result)
```
## Parameters
- `query` (required): SQL query to execute
- `catalog` (optional): Override default catalog
- `db_schema` (optional): Override default schema
- `warehouse_id` (optional): Override default SQL warehouse
- `row_limit` (optional): Maximum rows to return (default: 1000)
## Defaults on initialization
- `default_catalog`
- `default_schema`
- `default_warehouse_id`
### Error handling & tips
- Authentication errors: verify `DATABRICKS_HOST` begins with `https://` and token is valid.
- Permissions: ensure your SQL warehouse and schema are accessible by your token.
- Limits: longrunning queries should be avoided in agent loops; add filters/limits.

View File

@@ -24,6 +24,8 @@ pip install 'crewai[tools]'
This command installs the necessary package to run the GithubSearchTool along with any other tools included in the crewai_tools package.
Get a GitHub Personal Access Token at https://github.com/settings/tokens (Developer settings → Finegrained tokens or classic tokens).
## Example
Heres how you can use the GithubSearchTool to perform semantic searches within a GitHub repository:

View File

@@ -44,6 +44,26 @@ These tools enable your agents to search the web, research topics, and find info
<Card title="YouTube Video Search" icon="play" href="/en/tools/search-research/youtubevideosearchtool">
Find and analyze YouTube videos by topic, keyword, or criteria.
</Card>
<Card title="Tavily Search Tool" icon="magnifying-glass" href="/en/tools/search-research/tavilysearchtool">
Comprehensive web search using Tavily's AI-powered search API.
</Card>
<Card title="Tavily Extractor Tool" icon="file-text" href="/en/tools/search-research/tavilyextractortool">
Extract structured content from web pages using the Tavily API.
</Card>
<Card title="Arxiv Paper Tool" icon="box-archive" href="/en/tools/search-research/arxivpapertool">
Search arXiv and optionally download PDFs.
</Card>
<Card title="SerpApi Google Search" icon="search" href="/en/tools/search-research/serpapi-googlesearchtool">
Google search via SerpApi with structured results.
</Card>
<Card title="SerpApi Google Shopping" icon="cart-shopping" href="/en/tools/search-research/serpapi-googleshoppingtool">
Google Shopping queries via SerpApi.
</Card>
</CardGroup>
## **Common Use Cases**
@@ -55,17 +75,19 @@ These tools enable your agents to search the web, research topics, and find info
- **Academic Research**: Find scholarly articles and technical papers
```python
from crewai_tools import SerperDevTool, GitHubSearchTool, YoutubeVideoSearchTool
from crewai_tools import SerperDevTool, GitHubSearchTool, YoutubeVideoSearchTool, TavilySearchTool, TavilyExtractorTool
# Create research tools
web_search = SerperDevTool()
code_search = GitHubSearchTool()
video_research = YoutubeVideoSearchTool()
tavily_search = TavilySearchTool()
content_extractor = TavilyExtractorTool()
# Add to your agent
agent = Agent(
role="Research Analyst",
tools=[web_search, code_search, video_research],
tools=[web_search, code_search, video_research, tavily_search, content_extractor],
goal="Gather comprehensive information on any topic"
)
```

View File

@@ -0,0 +1,65 @@
---
title: SerpApi Google Search Tool
description: The `SerpApiGoogleSearchTool` performs Google searches using the SerpApi service.
icon: google
---
# `SerpApiGoogleSearchTool`
## Description
Use the `SerpApiGoogleSearchTool` to run Google searches with SerpApi and retrieve structured results. Requires a SerpApi API key.
## Installation
```shell
uv add crewai-tools[serpapi]
```
## Environment Variables
- `SERPAPI_API_KEY` (required): API key for SerpApi. Create one at https://serpapi.com/ (free tier available).
## Example
```python Code
from crewai import Agent, Task, Crew
from crewai_tools import SerpApiGoogleSearchTool
tool = SerpApiGoogleSearchTool()
agent = Agent(
role="Researcher",
goal="Answer questions using Google search",
backstory="Search specialist",
tools=[tool],
verbose=True,
)
task = Task(
description="Search for the latest CrewAI releases",
expected_output="A concise list of relevant results with titles and links",
agent=agent,
)
crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
```
## Notes
- Set `SERPAPI_API_KEY` in the environment. Create a key at https://serpapi.com/
- See also Google Shopping via SerpApi: `/en/tools/search-research/serpapi-googleshoppingtool`
## Parameters
### Run Parameters
- `search_query` (str, required): The Google query.
- `location` (str, optional): Geographic location parameter.
## Notes
- This tool wraps SerpApi and returns structured search results.

View File

@@ -0,0 +1,61 @@
---
title: SerpApi Google Shopping Tool
description: The `SerpApiGoogleShoppingTool` searches Google Shopping results using SerpApi.
icon: cart-shopping
---
# `SerpApiGoogleShoppingTool`
## Description
Leverage `SerpApiGoogleShoppingTool` to query Google Shopping via SerpApi and retrieve product-oriented results.
## Installation
```shell
uv add crewai-tools[serpapi]
```
## Environment Variables
- `SERPAPI_API_KEY` (required): API key for SerpApi. Create one at https://serpapi.com/ (free tier available).
## Example
```python Code
from crewai import Agent, Task, Crew
from crewai_tools import SerpApiGoogleShoppingTool
tool = SerpApiGoogleShoppingTool()
agent = Agent(
role="Shopping Researcher",
goal="Find relevant products",
backstory="Expert in product search",
tools=[tool],
verbose=True,
)
task = Task(
description="Search Google Shopping for 'wireless noise-canceling headphones'",
expected_output="Top relevant products with titles and links",
agent=agent,
)
crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
```
## Notes
- Set `SERPAPI_API_KEY` in the environment. Create a key at https://serpapi.com/
- See also Google Web Search via SerpApi: `/en/tools/search-research/serpapi-googlesearchtool`
## Parameters
### Run Parameters
- `search_query` (str, required): Product search query.
- `location` (str, optional): Geographic location parameter.

View File

@@ -6,10 +6,6 @@ icon: google
# `SerperDevTool`
<Note>
We are still working on improving tools, so there might be unexpected behavior or changes in the future.
</Note>
## Description
This tool is designed to perform a semantic search for a specified query from a text's content across the internet. It utilizes the [serper.dev](https://serper.dev) API
@@ -17,6 +13,12 @@ to fetch and display the most relevant search results based on the query provide
## Installation
To effectively use the `SerperDevTool`, follow these steps:
1. **Package Installation**: Confirm that the `crewai[tools]` package is installed in your Python environment.
2. **API Key Acquisition**: Acquire a `serper.dev` API key at https://serper.dev/ (free tier available).
3. **Environment Configuration**: Store your obtained API key in an environment variable named `SERPER_API_KEY` to facilitate its use by the tool.
To incorporate this tool into your project, follow the installation instructions below:
```shell
@@ -34,14 +36,6 @@ from crewai_tools import SerperDevTool
tool = SerperDevTool()
```
## Steps to Get Started
To effectively use the `SerperDevTool`, follow these steps:
1. **Package Installation**: Confirm that the `crewai[tools]` package is installed in your Python environment.
2. **API Key Acquisition**: Acquire a `serper.dev` API key by registering for a free account at `serper.dev`.
3. **Environment Configuration**: Store your obtained API key in an environment variable named `SERPER_API_KEY` to facilitate its use by the tool.
## Parameters
The `SerperDevTool` comes with several parameters that will be passed to the API :

View File

@@ -0,0 +1,139 @@
---
title: "Tavily Extractor Tool"
description: "Extract structured content from web pages using the Tavily API"
icon: square-poll-horizontal
---
The `TavilyExtractorTool` allows CrewAI agents to extract structured content from web pages using the Tavily API. It can process single URLs or lists of URLs and provides options for controlling the extraction depth and including images.
## Installation
To use the `TavilyExtractorTool`, you need to install the `tavily-python` library:
```shell
pip install 'crewai[tools]' tavily-python
```
You also need to set your Tavily API key as an environment variable:
```bash
export TAVILY_API_KEY='your-tavily-api-key'
```
## Example Usage
Here's how to initialize and use the `TavilyExtractorTool` within a CrewAI agent:
```python
import os
from crewai import Agent, Task, Crew
from crewai_tools import TavilyExtractorTool
# Ensure TAVILY_API_KEY is set in your environment
# os.environ["TAVILY_API_KEY"] = "YOUR_API_KEY"
# Initialize the tool
tavily_tool = TavilyExtractorTool()
# Create an agent that uses the tool
extractor_agent = Agent(
role='Web Content Extractor',
goal='Extract key information from specified web pages',
backstory='You are an expert at extracting relevant content from websites using the Tavily API.',
tools=[tavily_tool],
verbose=True
)
# Define a task for the agent
extract_task = Task(
description='Extract the main content from the URL https://example.com using basic extraction depth.',
expected_output='A JSON string containing the extracted content from the URL.',
agent=extractor_agent
)
# Create and run the crew
crew = Crew(
agents=[extractor_agent],
tasks=[extract_task],
verbose=2
)
result = crew.kickoff()
print(result)
```
## Configuration Options
The `TavilyExtractorTool` accepts the following arguments:
- `urls` (Union[List[str], str]): **Required**. A single URL string or a list of URL strings to extract data from.
- `include_images` (Optional[bool]): Whether to include images in the extraction results. Defaults to `False`.
- `extract_depth` (Literal["basic", "advanced"]): The depth of extraction. Use `"basic"` for faster, surface-level extraction or `"advanced"` for more comprehensive extraction. Defaults to `"basic"`.
- `timeout` (int): The maximum time in seconds to wait for the extraction request to complete. Defaults to `60`.
## Advanced Usage
### Multiple URLs with Advanced Extraction
```python
# Example with multiple URLs and advanced extraction
multi_extract_task = Task(
description='Extract content from https://example.com and https://anotherexample.org using advanced extraction.',
expected_output='A JSON string containing the extracted content from both URLs.',
agent=extractor_agent
)
# Configure the tool with custom parameters
custom_extractor = TavilyExtractorTool(
extract_depth='advanced',
include_images=True,
timeout=120
)
agent_with_custom_tool = Agent(
role="Advanced Content Extractor",
goal="Extract comprehensive content with images",
tools=[custom_extractor]
)
```
### Tool Parameters
You can customize the tool's behavior by setting parameters during initialization:
```python
# Initialize with custom configuration
extractor_tool = TavilyExtractorTool(
extract_depth='advanced', # More comprehensive extraction
include_images=True, # Include image results
timeout=90 # Custom timeout
)
```
## Features
- **Single or Multiple URLs**: Extract content from one URL or process multiple URLs in a single request
- **Configurable Depth**: Choose between basic (fast) and advanced (comprehensive) extraction modes
- **Image Support**: Optionally include images in the extraction results
- **Structured Output**: Returns well-formatted JSON containing the extracted content
- **Error Handling**: Robust handling of network timeouts and extraction errors
## Response Format
The tool returns a JSON string representing the structured data extracted from the provided URL(s). The exact structure depends on the content of the pages and the `extract_depth` used.
Common response elements include:
- **Title**: The page title
- **Content**: Main text content of the page
- **Images**: Image URLs and metadata (when `include_images=True`)
- **Metadata**: Additional page information like author, description, etc.
## Use Cases
- **Content Analysis**: Extract and analyze content from competitor websites
- **Research**: Gather structured data from multiple sources for analysis
- **Content Migration**: Extract content from existing websites for migration
- **Monitoring**: Regular extraction of content for change detection
- **Data Collection**: Systematic extraction of information from web sources
Refer to the [Tavily API documentation](https://docs.tavily.com/docs/tavily-api/python-sdk#extract) for detailed information about the response structure and available options.

View File

@@ -0,0 +1,124 @@
---
title: "Tavily Search Tool"
description: "Perform comprehensive web searches using the Tavily Search API"
icon: "magnifying-glass"
---
The `TavilySearchTool` provides an interface to the Tavily Search API, enabling CrewAI agents to perform comprehensive web searches. It allows for specifying search depth, topics, time ranges, included/excluded domains, and whether to include direct answers, raw content, or images in the results.
## Installation
To use the `TavilySearchTool`, you need to install the `tavily-python` library:
```shell
pip install 'crewai[tools]' tavily-python
```
## Environment Variables
Ensure your Tavily API key is set as an environment variable:
```bash
export TAVILY_API_KEY='your_tavily_api_key'
```
Get an API key at https://app.tavily.com/ (sign up, then create a key).
## Example Usage
Here's how to initialize and use the `TavilySearchTool` within a CrewAI agent:
```python
import os
from crewai import Agent, Task, Crew
from crewai_tools import TavilySearchTool
# Ensure the TAVILY_API_KEY environment variable is set
# os.environ["TAVILY_API_KEY"] = "YOUR_TAVILY_API_KEY"
# Initialize the tool
tavily_tool = TavilySearchTool()
# Create an agent that uses the tool
researcher = Agent(
role='Market Researcher',
goal='Find information about the latest AI trends',
backstory='An expert market researcher specializing in technology.',
tools=[tavily_tool],
verbose=True
)
# Create a task for the agent
research_task = Task(
description='Search for the top 3 AI trends in 2024.',
expected_output='A JSON report summarizing the top 3 AI trends found.',
agent=researcher
)
# Form the crew and kick it off
crew = Crew(
agents=[researcher],
tasks=[research_task],
verbose=2
)
result = crew.kickoff()
print(result)
```
## Configuration Options
The `TavilySearchTool` accepts the following arguments during initialization or when calling the `run` method:
- `query` (str): **Required**. The search query string.
- `search_depth` (Literal["basic", "advanced"], optional): The depth of the search. Defaults to `"basic"`.
- `topic` (Literal["general", "news", "finance"], optional): The topic to focus the search on. Defaults to `"general"`.
- `time_range` (Literal["day", "week", "month", "year"], optional): The time range for the search. Defaults to `None`.
- `days` (int, optional): The number of days to search back. Relevant if `time_range` is not set. Defaults to `7`.
- `max_results` (int, optional): The maximum number of search results to return. Defaults to `5`.
- `include_domains` (Sequence[str], optional): A list of domains to prioritize in the search. Defaults to `None`.
- `exclude_domains` (Sequence[str], optional): A list of domains to exclude from the search. Defaults to `None`.
- `include_answer` (Union[bool, Literal["basic", "advanced"]], optional): Whether to include a direct answer synthesized from the search results. Defaults to `False`.
- `include_raw_content` (bool, optional): Whether to include the raw HTML content of the searched pages. Defaults to `False`.
- `include_images` (bool, optional): Whether to include image results. Defaults to `False`.
- `timeout` (int, optional): The request timeout in seconds. Defaults to `60`.
## Advanced Usage
You can configure the tool with custom parameters:
```python
# Example: Initialize with specific parameters
custom_tavily_tool = TavilySearchTool(
search_depth='advanced',
max_results=10,
include_answer=True
)
# The agent will use these defaults
agent_with_custom_tool = Agent(
role="Advanced Researcher",
goal="Conduct detailed research with comprehensive results",
tools=[custom_tavily_tool]
)
```
## Features
- **Comprehensive Search**: Access to Tavily's powerful search index
- **Configurable Depth**: Choose between basic and advanced search modes
- **Topic Filtering**: Focus searches on general, news, or finance topics
- **Time Range Control**: Limit results to specific time periods
- **Domain Control**: Include or exclude specific domains
- **Direct Answers**: Get synthesized answers from search results
- **Content Filtering**: Prevent context window issues with automatic content truncation
## Response Format
The tool returns search results as a JSON string containing:
- Search results with titles, URLs, and content snippets
- Optional direct answers to queries
- Optional image results
- Optional raw HTML content (when enabled)
Content for each result is automatically truncated to prevent context window issues while maintaining the most relevant information.

View File

@@ -0,0 +1,111 @@
---
title: Bright Data Tools
description: Bright Data integrations for SERP search, Web Unlocker scraping, and Dataset API.
icon: spider
---
# Bright Data Tools
This set of tools integrates Bright Data services for web extraction.
## Installation
```shell
uv add crewai-tools requests aiohttp
```
## Environment Variables
- `BRIGHT_DATA_API_KEY` (required)
- `BRIGHT_DATA_ZONE` (for SERP/Web Unlocker)
Create credentials at https://brightdata.com/ (sign up, then create an API token and zone).
See their docs: https://developers.brightdata.com/
## Included Tools
- `BrightDataSearchTool`: SERP search (Google/Bing/Yandex) with geo/language/device options.
- `BrightDataWebUnlockerTool`: Scrape pages with anti-bot bypass and rendering.
- `BrightDataDatasetTool`: Run Dataset API jobs and fetch results.
## Examples
### SERP Search
```python Code
from crewai_tools import BrightDataSearchTool
tool = BrightDataSearchTool(
query="CrewAI",
country="us",
)
print(tool.run())
```
### Web Unlocker
```python Code
from crewai_tools import BrightDataWebUnlockerTool
tool = BrightDataWebUnlockerTool(
url="https://example.com",
format="markdown",
)
print(tool.run(url="https://example.com"))
```
### Dataset API
```python Code
from crewai_tools import BrightDataDatasetTool
tool = BrightDataDatasetTool(
dataset_type="ecommerce",
url="https://example.com/product",
)
print(tool.run())
```
## Troubleshooting
- 401/403: verify `BRIGHT_DATA_API_KEY` and `BRIGHT_DATA_ZONE`.
- Empty/blocked content: enable rendering or try a different zone.
## Example
```python Code
from crewai import Agent, Task, Crew
from crewai_tools import BrightDataSearchTool
tool = BrightDataSearchTool(
query="CrewAI",
country="us",
)
agent = Agent(
role="Web Researcher",
goal="Search with Bright Data",
backstory="Finds reliable results",
tools=[tool],
verbose=True,
)
task = Task(
description="Search for CrewAI and summarize top results",
expected_output="Short summary with links",
agent=agent,
)
crew = Crew(
agents=[agent],
tasks=[task],
verbose=True,
)
result = crew.kickoff()
```

View File

@@ -60,6 +60,10 @@ These tools enable your agents to interact with the web, extract data from websi
<Card title="Oxylabs Scraper Tool" icon="globe" href="/en/tools/web-scraping/oxylabsscraperstool">
Access web data at scale with Oxylabs.
</Card>
<Card title="Bright Data Tools" icon="spider" href="/en/tools/web-scraping/brightdata-tools">
SERP search, Web Unlocker, and Dataset API integrations.
</Card>
</CardGroup>
## **Common Use Cases**

View File

@@ -0,0 +1,100 @@
---
title: Serper Scrape Website
description: The `SerperScrapeWebsiteTool` is designed to scrape websites and extract clean, readable content using Serper's scraping API.
icon: globe
---
# `SerperScrapeWebsiteTool`
## Description
This tool is designed to scrape website content and extract clean, readable text from any website URL. It utilizes the [serper.dev](https://serper.dev) scraping API to fetch and process web pages, optionally including markdown formatting for better structure and readability.
## Installation
To effectively use the `SerperScrapeWebsiteTool`, follow these steps:
1. **Package Installation**: Confirm that the `crewai[tools]` package is installed in your Python environment.
2. **API Key Acquisition**: Acquire a `serper.dev` API key by registering for an account at `serper.dev`.
3. **Environment Configuration**: Store your obtained API key in an environment variable named `SERPER_API_KEY` to facilitate its use by the tool.
To incorporate this tool into your project, follow the installation instructions below:
```shell
pip install 'crewai[tools]'
```
## Example
The following example demonstrates how to initialize the tool and scrape a website:
```python Code
from crewai_tools import SerperScrapeWebsiteTool
# Initialize the tool for website scraping capabilities
tool = SerperScrapeWebsiteTool()
# Scrape a website with markdown formatting
result = tool.run(url="https://example.com", include_markdown=True)
```
## Arguments
The `SerperScrapeWebsiteTool` accepts the following arguments:
- **url**: Required. The URL of the website to scrape.
- **include_markdown**: Optional. Whether to include markdown formatting in the scraped content. Defaults to `True`.
## Example with Parameters
Here is an example demonstrating how to use the tool with different parameters:
```python Code
from crewai_tools import SerperScrapeWebsiteTool
tool = SerperScrapeWebsiteTool()
# Scrape with markdown formatting (default)
markdown_result = tool.run(
url="https://docs.crewai.com",
include_markdown=True
)
# Scrape without markdown formatting for plain text
plain_result = tool.run(
url="https://docs.crewai.com",
include_markdown=False
)
print("Markdown formatted content:")
print(markdown_result)
print("\nPlain text content:")
print(plain_result)
```
## Use Cases
The `SerperScrapeWebsiteTool` is particularly useful for:
- **Content Analysis**: Extract and analyze website content for research purposes
- **Data Collection**: Gather structured information from web pages
- **Documentation Processing**: Convert web-based documentation into readable formats
- **Competitive Analysis**: Scrape competitor websites for market research
- **Content Migration**: Extract content from existing websites for migration purposes
## Error Handling
The tool includes comprehensive error handling for:
- **Network Issues**: Handles connection timeouts and network errors gracefully
- **API Errors**: Provides detailed error messages for API-related issues
- **Invalid URLs**: Validates and reports issues with malformed URLs
- **Authentication**: Clear error messages for missing or invalid API keys
## Security Considerations
- Always store your `SERPER_API_KEY` in environment variables, never hardcode it in your source code
- Be mindful of rate limits imposed by the Serper API
- Respect robots.txt and website terms of service when scraping content
- Consider implementing delays between requests for large-scale scraping operations

BIN
docs/images/langdb-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

BIN
docs/images/langdb-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
docs/images/neatlogs-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

BIN
docs/images/neatlogs-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 KiB

BIN
docs/images/neatlogs-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 KiB

BIN
docs/images/neatlogs-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

BIN
docs/images/neatlogs-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

View File

@@ -149,34 +149,33 @@ from crewai_tools import SerperDevTool
# Crie um agente com todos os parâmetros disponíveis
agent = Agent(
role="Senior Data Scientist",
goal="Analyze and interpret complex datasets to provide actionable insights",
backstory="With over 10 years of experience in data science and machine learning, "
"you excel at finding patterns in complex datasets.",
llm="gpt-4", # Default: OPENAI_MODEL_NAME or "gpt-4"
function_calling_llm=None, # Optional: Separate LLM for tool calling
verbose=False, # Default: False
allow_delegation=False, # Default: False
max_iter=20, # Default: 20 iterations
max_rpm=None, # Optional: Rate limit for API calls
max_execution_time=None, # Optional: Maximum execution time in seconds
max_retry_limit=2, # Default: 2 retries on error
allow_code_execution=False, # Default: False
code_execution_mode="safe", # Default: "safe" (options: "safe", "unsafe")
respect_context_window=True, # Default: True
use_system_prompt=True, # Default: True
multimodal=False, # Default: False
inject_date=False, # Default: False
date_format="%Y-%m-%d", # Default: ISO format
reasoning=False, # Default: False
max_reasoning_attempts=None, # Default: None
tools=[SerperDevTool()], # Optional: List of tools
knowledge_sources=None, # Optional: List of knowledge sources
embedder=None, # Optional: Custom embedder configuration
system_template=None, # Optional: Custom system prompt template
prompt_template=None, # Optional: Custom prompt template
response_template=None, # Optional: Custom response template
step_callback=None, # Optional: Callback function for monitoring
role="Cientista de Dados Sênior",
goal="Analisar e interpretar conjuntos de dados complexos para fornecer insights acionáveis",
backstory="Com mais de 10 anos de experiência em ciência de dados e aprendizado de máquina, você é especialista em encontrar padrões em grandes volumes de dados.",
llm="gpt-4", # Padrão: OPENAI_MODEL_NAME ou "gpt-4"
function_calling_llm=None, # Opcional: LLM separado para chamadas de ferramentas
verbose=False, # Padrão: False
allow_delegation=False, # Padrão: False
max_iter=20, # Padrão: 20 iterações
max_rpm=None, # Opcional: Limite de requisições por minuto
max_execution_time=None, # Opcional: Tempo máximo de execução em segundos
max_retry_limit=2, # Padrão: 2 tentativas em caso de erro
allow_code_execution=False, # Padrão: False
code_execution_mode="safe", # Padrão: "safe" (opções: "safe", "unsafe")
respect_context_window=True, # Padrão: True
use_system_prompt=True, # Padrão: True
multimodal=False, # Padrão: False
inject_date=False, # Padrão: False
date_format="%Y-%m-%d", # Padrão: formato ISO
reasoning=False, # Padrão: False
max_reasoning_attempts=None, # Padrão: None
tools=[SerperDevTool()], # Opcional: Lista de ferramentas
knowledge_sources=None, # Opcional: Lista de fontes de conhecimento
embedder=None, # Opcional: Configuração de embedder customizado
system_template=None, # Opcional: Template de prompt de sistema
prompt_template=None, # Opcional: Template de prompt customizado
response_template=None, # Opcional: Template de resposta customizado
step_callback=None, # Opcional: Função de callback para monitoramento
)
```
@@ -185,65 +184,62 @@ Vamos detalhar algumas combinações de parâmetros-chave para casos de uso comu
#### Agente de Pesquisa Básico
```python Code
research_agent = Agent(
role="Research Analyst",
goal="Find and summarize information about specific topics",
backstory="You are an experienced researcher with attention to detail",
role="Analista de Pesquisa",
goal="Encontrar e resumir informações sobre tópicos específicos",
backstory="Você é um pesquisador experiente com atenção aos detalhes",
tools=[SerperDevTool()],
verbose=True # Enable logging for debugging
verbose=True # Ativa logs para depuração
)
```
#### Agente de Desenvolvimento de Código
```python Code
dev_agent = Agent(
role="Senior Python Developer",
goal="Write and debug Python code",
backstory="Expert Python developer with 10 years of experience",
role="Desenvolvedor Python Sênior",
goal="Escrever e depurar códigos Python",
backstory="Desenvolvedor Python especialista com 10 anos de experiência",
allow_code_execution=True,
code_execution_mode="safe", # Uses Docker for safety
max_execution_time=300, # 5-minute timeout
max_retry_limit=3 # More retries for complex code tasks
code_execution_mode="safe", # Usa Docker para segurança
max_execution_time=300, # Limite de 5 minutos
max_retry_limit=3 # Mais tentativas para tarefas complexas
)
```
#### Agente de Análise de Longa Duração
```python Code
analysis_agent = Agent(
role="Data Analyst",
goal="Perform deep analysis of large datasets",
backstory="Specialized in big data analysis and pattern recognition",
role="Analista de Dados",
goal="Realizar análise aprofundada de grandes conjuntos de dados",
backstory="Especialista em análise de big data e reconhecimento de padrões",
memory=True,
respect_context_window=True,
max_rpm=10, # Limit API calls
function_calling_llm="gpt-4o-mini" # Cheaper model for tool calls
max_rpm=10, # Limite de requisições por minuto
function_calling_llm="gpt-4o-mini" # Modelo mais econômico para chamadas de ferramentas
)
```
#### Agente com Template Personalizado
```python Code
custom_agent = Agent(
role="Customer Service Representative",
goal="Assist customers with their inquiries",
backstory="Experienced in customer support with a focus on satisfaction",
system_template="""<|start_header_id|>system<|end_header_id|>
{{ .System }}<|eot_id|>""",
prompt_template="""<|start_header_id|>user<|end_header_id|>
{{ .Prompt }}<|eot_id|>""",
response_template="""<|start_header_id|>assistant<|end_header_id|>
{{ .Response }}<|eot_id|>""",
role="Atendente de Suporte ao Cliente",
goal="Auxiliar clientes com suas dúvidas e solicitações",
backstory="Experiente em atendimento ao cliente com foco em satisfação",
system_template="""<|start_header_id|>system<|end_header_id|>\n {{ .System }}<|eot_id|>""",
prompt_template="""<|start_header_id|>user<|end_header_id|>\n {{ .Prompt }}<|eot_id|>""",
response_template="""<|start_header_id|>assistant<|end_header_id|>\n {{ .Response }}<|eot_id|>""",
)
```
#### Agente Ciente de Data, com Raciocínio
```python Code
strategic_agent = Agent(
role="Market Analyst",
goal="Track market movements with precise date references and strategic planning",
backstory="Expert in time-sensitive financial analysis and strategic reporting",
inject_date=True, # Automatically inject current date into tasks
date_format="%B %d, %Y", # Format as "May 21, 2025"
reasoning=True, # Enable strategic planning
max_reasoning_attempts=2, # Limit planning iterations
role="Analista de Mercado",
goal="Acompanhar movimentos do mercado com referências de datas precisas e planejamento estratégico",
backstory="Especialista em análise financeira sensível ao tempo e relatórios estratégicos",
inject_date=True, # Injeta automaticamente a data atual nas tarefas
date_format="%d de %B de %Y", # Exemplo: "21 de maio de 2025"
reasoning=True, # Ativa planejamento estratégico
max_reasoning_attempts=2, # Limite de iterações de planejamento
verbose=True
)
```
@@ -251,12 +247,12 @@ strategic_agent = Agent(
#### Agente de Raciocínio
```python Code
reasoning_agent = Agent(
role="Strategic Planner",
goal="Analyze complex problems and create detailed execution plans",
backstory="Expert strategic planner who methodically breaks down complex challenges",
reasoning=True, # Enable reasoning and planning
max_reasoning_attempts=3, # Limit reasoning attempts
max_iter=30, # Allow more iterations for complex planning
role="Planejador Estratégico",
goal="Analisar problemas complexos e criar planos de execução detalhados",
backstory="Especialista em planejamento estratégico que desmembra desafios complexos metodicamente",
reasoning=True, # Ativa raciocínio e planejamento
max_reasoning_attempts=3, # Limite de tentativas de raciocínio
max_iter=30, # Permite mais iterações para planejamento complexo
verbose=True
)
```
@@ -264,10 +260,10 @@ reasoning_agent = Agent(
#### Agente Multimodal
```python Code
multimodal_agent = Agent(
role="Visual Content Analyst",
goal="Analyze and process both text and visual content",
backstory="Specialized in multimodal analysis combining text and image understanding",
multimodal=True, # Enable multimodal capabilities
role="Analista de Conteúdo Visual",
goal="Analisar e processar tanto conteúdo textual quanto visual",
backstory="Especialista em análise multimodal combinando compreensão de texto e imagem",
multimodal=True, # Ativa capacidades multimodais
verbose=True
)
```
@@ -336,8 +332,8 @@ wiki_tool = WikipediaTools()
# Adicionar ferramentas ao agente
researcher = Agent(
role="AI Technology Researcher",
goal="Research the latest AI developments",
role="Pesquisador de Tecnologia em IA",
goal="Pesquisar os últimos avanços em IA",
tools=[search_tool, wiki_tool],
verbose=True
)
@@ -351,9 +347,9 @@ Agentes podem manter a memória de suas interações e usar contexto de tarefas
from crewai import Agent
analyst = Agent(
role="Data Analyst",
goal="Analyze and remember complex data patterns",
memory=True, # Enable memory
role="Analista de Dados",
goal="Analisar e memorizar padrões complexos de dados",
memory=True, # Ativa memória
verbose=True
)
```
@@ -380,10 +376,10 @@ Esta é a **configuração padrão e recomendada** para a maioria dos casos. Qua
```python Code
# Agente com gerenciamento automático de contexto (padrão)
smart_agent = Agent(
role="Research Analyst",
goal="Analyze large documents and datasets",
backstory="Expert at processing extensive information",
respect_context_window=True, # 🔑 Default: auto-handle context limits
role="Analista de Pesquisa",
goal="Analisar grandes documentos e conjuntos de dados",
backstory="Especialista em processar informações extensas",
respect_context_window=True, # 🔑 Padrão: gerencia limites de contexto automaticamente
verbose=True
)
```

View File

@@ -3,6 +3,7 @@ title: CLI
description: Aprenda a usar o CLI do CrewAI para interagir com o CrewAI.
icon: terminal
---
<Warning>A partir da versão 0.140.0, a plataforma CrewAI Enterprise iniciou um processo de migração de seu provedor de login. Como resultado, o fluxo de autenticação via CLI foi atualizado. Usuários que utlizam o Google para fazer login, ou que criaram conta após 3 de julho de 2025 não poderão fazer login com versões anteriores da biblioteca `crewai`.</Warning>
## Visão Geral
@@ -75,6 +76,22 @@ Exemplo:
crewai train -n 10 -f my_training_data.pkl
```
```python
# Exemplo de uso programático do comando train
n_iterations = 2
inputs = {"topic": "Treinamento CrewAI"}
filename = "seu_modelo.pkl"
try:
SuaCrew().crew().train(
n_iterations=n_iterations,
inputs=inputs,
filename=filename
)
except Exception as e:
raise Exception(f"Ocorreu um erro ao treinar a crew: {e}")
```
### 4. Replay
Reexecute a execução do crew a partir de uma tarefa específica.
@@ -86,7 +103,7 @@ crewai replay [OPTIONS]
- `-t, --task_id TEXT`: Reexecuta o crew a partir deste task ID, incluindo todas as tarefas subsequentes
Exemplo:
```shell Terminal
```shell Terminal
crewai replay -t task_123456
```
@@ -132,7 +149,7 @@ crewai test [OPTIONS]
- `-m, --model TEXT`: Modelo LLM para executar os testes no Crew (padrão: "gpt-4o-mini")
Exemplo:
```shell Terminal
```shell Terminal
crewai test -n 5 -m gpt-3.5-turbo
```
@@ -186,10 +203,7 @@ def crew(self) -> Crew:
Implemente o crew ou flow no [CrewAI Enterprise](https://app.crewai.com).
- **Autenticação**: Você precisa estar autenticado para implementar no CrewAI Enterprise.
```shell Terminal
crewai signup
```
Caso já tenha uma conta, você pode fazer login com:
Você pode fazer login ou criar uma conta com:
```shell Terminal
crewai login
```
@@ -236,7 +250,7 @@ Você deve estar autenticado no CrewAI Enterprise para usar estes comandos de ge
- **Implantar o Crew**: Depois de autenticado, você pode implantar seu crew ou flow no CrewAI Enterprise.
```shell Terminal
crewai deploy push
```
```
- Inicia o processo de deployment na plataforma CrewAI Enterprise.
- Após a iniciação bem-sucedida, será exibida a mensagem Deployment created successfully! juntamente com o Nome do Deployment e um Deployment ID (UUID) único.
@@ -309,4 +323,83 @@ Ao escolher um provedor, o CLI solicitará que você informe o nome da chave e a
Veja o seguinte link para o nome de chave de cada provedor:
* [LiteLLM Providers](https://docs.litellm.ai/docs/providers)
* [LiteLLM Providers](https://docs.litellm.ai/docs/providers)
### 12. Gerenciamento de Configuração
Gerencie as configurações do CLI para CrewAI.
```shell Terminal
crewai config [COMANDO] [OPÇÕES]
```
#### Comandos:
- `list`: Exibir todos os parâmetros de configuração do CLI
```shell Terminal
crewai config list
```
- `set`: Definir um parâmetro de configuração do CLI
```shell Terminal
crewai config set <chave> <valor>
```
- `reset`: Redefinir todos os parâmetros de configuração do CLI para valores padrão
```shell Terminal
crewai config reset
```
#### Parâmetros de Configuração Disponíveis
- `enterprise_base_url`: URL base da instância CrewAI Enterprise
- `oauth2_provider`: Provedor OAuth2 usado para autenticação (ex: workos, okta, auth0)
- `oauth2_audience`: Valor de audiência OAuth2, tipicamente usado para identificar a API ou recurso de destino
- `oauth2_client_id`: ID do cliente OAuth2 emitido pelo provedor, usado durante solicitações de autenticação
- `oauth2_domain`: Domínio do provedor OAuth2 (ex: sua-org.auth0.com) usado para emissão de tokens
#### Exemplos
Exibir configuração atual:
```shell Terminal
crewai config list
```
Exemplo de saída:
```
CrewAI CLI Configuration
┏━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Setting ┃ Value ┃ Description ┃
┡━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ enterprise_base_url│ https://app.crewai.com │ Base URL of the CrewAI Enterprise instance │
│ org_name │ Not set │ Name of the currently active organization │
│ org_uuid │ Not set │ UUID of the currently active organization │
│ oauth2_provider │ workos │ OAuth2 provider used for authentication (e.g., workos, okta, auth0). │
│ oauth2_audience │ client_01YYY │ OAuth2 audience value, typically used to identify the target API or resource. │
│ oauth2_client_id │ client_01XXX │ OAuth2 client ID issued by the provider, used during authentication requests. │
│ oauth2_domain │ login.crewai.com │ OAuth2 provider's domain (e.g., your-org.auth0.com) used for issuing tokens. │
```
Definir a URL base do enterprise:
```shell Terminal
crewai config set enterprise_base_url https://minha-empresa.crewai.com
```
Definir provedor OAuth2:
```shell Terminal
crewai config set oauth2_provider auth0
```
Definir domínio OAuth2:
```shell Terminal
crewai config set oauth2_domain minha-empresa.auth0.com
```
Redefinir todas as configurações para padrões:
```shell Terminal
crewai config reset
```
<Note>
As configurações são armazenadas em `~/.config/crewai/settings.json`. Algumas configurações como nome da organização e UUID são somente leitura e gerenciadas através de comandos de autenticação e organização. Configurações relacionadas ao repositório de ferramentas são ocultas e não podem ser definidas diretamente pelo usuário.
</Note>

View File

@@ -15,18 +15,18 @@ from crewai import Agent, Crew, Task
# Enable collaboration for agents
researcher = Agent(
role="Research Specialist",
goal="Conduct thorough research on any topic",
backstory="Expert researcher with access to various sources",
allow_delegation=True, # 🔑 Key setting for collaboration
role="Especialista em Pesquisa",
goal="Realizar pesquisas aprofundadas sobre qualquer tema",
backstory="Pesquisador especialista com acesso a diversas fontes",
allow_delegation=True, # 🔑 Configuração chave para colaboração
verbose=True
)
writer = Agent(
role="Content Writer",
goal="Create engaging content based on research",
backstory="Skilled writer who transforms research into compelling content",
allow_delegation=True, # 🔑 Enables asking questions to other agents
role="Redator de Conteúdo",
goal="Criar conteúdo envolvente com base em pesquisas",
backstory="Redator habilidoso que transforma pesquisas em conteúdo atraente",
allow_delegation=True, # 🔑 Permite fazer perguntas a outros agentes
verbose=True
)
@@ -67,19 +67,17 @@ from crewai import Agent, Crew, Task, Process
# Create collaborative agents
researcher = Agent(
role="Research Specialist",
goal="Find accurate, up-to-date information on any topic",
backstory="""You're a meticulous researcher with expertise in finding
reliable sources and fact-checking information across various domains.""",
role="Especialista em Pesquisa",
goal="Realizar pesquisas aprofundadas sobre qualquer tema",
backstory="Pesquisador especialista com acesso a diversas fontes",
allow_delegation=True,
verbose=True
)
writer = Agent(
role="Content Writer",
goal="Create engaging, well-structured content",
backstory="""You're a skilled content writer who excels at transforming
research into compelling, readable content for different audiences.""",
role="Redator de Conteúdo",
goal="Criar conteúdo envolvente com base em pesquisas",
backstory="Redator habilidoso que transforma pesquisas em conteúdo atraente",
allow_delegation=True,
verbose=True
)
@@ -95,17 +93,17 @@ editor = Agent(
# Create a task that encourages collaboration
article_task = Task(
description="""Write a comprehensive 1000-word article about 'The Future of AI in Healthcare'.
The article should include:
- Current AI applications in healthcare
- Emerging trends and technologies
- Potential challenges and ethical considerations
- Expert predictions for the next 5 years
Collaborate with your teammates to ensure accuracy and quality.""",
expected_output="A well-researched, engaging 1000-word article with proper structure and citations",
agent=writer # Writer leads, but can delegate research to researcher
description="""Escreva um artigo abrangente de 1000 palavras sobre 'O Futuro da IA na Saúde'.
O artigo deve incluir:
- Aplicações atuais de IA na saúde
- Tendências e tecnologias emergentes
- Desafios potenciais e considerações éticas
- Previsões de especialistas para os próximos 5 anos
Colabore com seus colegas para garantir precisão e qualidade.""",
expected_output="Um artigo bem pesquisado, envolvente, com 1000 palavras, estrutura adequada e citações",
agent=writer # O redator lidera, mas pode delegar pesquisa ao pesquisador
)
# Create collaborative crew
@@ -124,37 +122,37 @@ result = crew.kickoff()
### Padrão 1: Pesquisa → Redação → Edição
```python
research_task = Task(
description="Research the latest developments in quantum computing",
expected_output="Comprehensive research summary with key findings and sources",
description="Pesquise os últimos avanços em computação quântica",
expected_output="Resumo abrangente da pesquisa com principais descobertas e fontes",
agent=researcher
)
writing_task = Task(
description="Write an article based on the research findings",
expected_output="Engaging 800-word article about quantum computing",
description="Escreva um artigo com base nos achados da pesquisa",
expected_output="Artigo envolvente de 800 palavras sobre computação quântica",
agent=writer,
context=[research_task] # Gets research output as context
context=[research_task] # Recebe a saída da pesquisa como contexto
)
editing_task = Task(
description="Edit and polish the article for publication",
expected_output="Publication-ready article with improved clarity and flow",
description="Edite e revise o artigo para publicação",
expected_output="Artigo pronto para publicação, com clareza e fluidez aprimoradas",
agent=editor,
context=[writing_task] # Gets article draft as context
context=[writing_task] # Recebe o rascunho do artigo como contexto
)
```
### Padrão 2: Tarefa Única Colaborativa
```python
collaborative_task = Task(
description="""Create a marketing strategy for a new AI product.
Writer: Focus on messaging and content strategy
Researcher: Provide market analysis and competitor insights
Work together to create a comprehensive strategy.""",
expected_output="Complete marketing strategy with research backing",
agent=writer # Lead agent, but can delegate to researcher
description="""Crie uma estratégia de marketing para um novo produto de IA.
Redator: Foque em mensagens e estratégia de conteúdo
Pesquisador: Forneça análise de mercado e insights de concorrentes
Trabalhem juntos para criar uma estratégia abrangente.""",
expected_output="Estratégia de marketing completa com embasamento em pesquisa",
agent=writer # Agente líder, mas pode delegar ao pesquisador
)
```
@@ -167,35 +165,35 @@ from crewai import Agent, Crew, Task, Process
# Manager agent coordinates the team
manager = Agent(
role="Project Manager",
goal="Coordinate team efforts and ensure project success",
backstory="Experienced project manager skilled at delegation and quality control",
role="Gerente de Projetos",
goal="Coordenar esforços da equipe e garantir o sucesso do projeto",
backstory="Gerente de projetos experiente, habilidoso em delegação e controle de qualidade",
allow_delegation=True,
verbose=True
)
# Specialist agents
researcher = Agent(
role="Researcher",
goal="Provide accurate research and analysis",
backstory="Expert researcher with deep analytical skills",
allow_delegation=False, # Specialists focus on their expertise
role="Pesquisador",
goal="Fornecer pesquisa e análise precisas",
backstory="Pesquisador especialista com habilidades analíticas profundas",
allow_delegation=False, # Especialistas focam em sua expertise
verbose=True
)
writer = Agent(
role="Writer",
goal="Create compelling content",
backstory="Skilled writer who creates engaging content",
role="Redator",
goal="Criar conteúdo envolvente",
backstory="Redator habilidoso que cria conteúdo atraente",
allow_delegation=False,
verbose=True
)
# Manager-led task
project_task = Task(
description="Create a comprehensive market analysis report with recommendations",
expected_output="Executive summary, detailed analysis, and strategic recommendations",
agent=manager # Manager will delegate to specialists
description="Crie um relatório de análise de mercado completo com recomendações",
expected_output="Resumo executivo, análise detalhada e recomendações estratégicas",
agent=manager # O gerente delega para especialistas
)
# Hierarchical crew

View File

@@ -20,8 +20,7 @@ Uma crew no crewAI representa um grupo colaborativo de agentes trabalhando em co
| **Function Calling LLM** _(opcional)_ | `function_calling_llm` | Se definido, a crew utilizará este LLM para invocar funções das ferramentas para todos os agentes da crew. Cada agente pode ter seu próprio LLM, que substitui o LLM da crew para chamadas de função. |
| **Config** _(opcional)_ | `config` | Configurações opcionais para a crew, no formato `Json` ou `Dict[str, Any]`. |
| **Max RPM** _(opcional)_ | `max_rpm` | Número máximo de requisições por minuto que a crew respeita durante a execução. O padrão é `None`. |
| **Memory** _(opcional)_ | `memory` | Utilizada para armazenar memórias de execução (curto prazo, longo prazo, memória de entidade). |
| **Memory Config** _(opcional)_ | `memory_config` | Configuração para o provedor de memória a ser utilizada pela crew. |
| **Memory** _(opcional)_ | `memory` | Utilizada para armazenar memórias de execução (curto prazo, longo prazo, memória de entidade). | |
| **Cache** _(opcional)_ | `cache` | Especifica se deve usar cache para armazenar os resultados da execução de ferramentas. O padrão é `True`. |
| **Embedder** _(opcional)_ | `embedder` | Configuração do embedder a ser utilizado pela crew. Atualmente mais usado por memory. O padrão é `{"provider": "openai"}`. |
| **Step Callback** _(opcional)_ | `step_callback` | Uma função chamada após cada etapa de cada agente. Pode ser usada para registrar as ações do agente ou executar outras operações; não sobrescreve o `step_callback` específico do agente. |
@@ -153,32 +152,32 @@ from crewai_tools import YourCustomTool
class YourCrewName:
def agent_one(self) -> Agent:
return Agent(
role="Data Analyst",
goal="Analyze data trends in the market",
backstory="An experienced data analyst with a background in economics",
role="Analista de Dados",
goal="Analisar tendências de dados no mercado brasileiro",
backstory="Analista experiente com formação em economia",
verbose=True,
tools=[YourCustomTool()]
)
def agent_two(self) -> Agent:
return Agent(
role="Market Researcher",
goal="Gather information on market dynamics",
backstory="A diligent researcher with a keen eye for detail",
role="Pesquisador de Mercado",
goal="Coletar informações sobre a dinâmica do mercado nacional",
backstory="Pesquisador dedicado com olhar atento aos detalhes",
verbose=True
)
def task_one(self) -> Task:
return Task(
description="Collect recent market data and identify trends.",
expected_output="A report summarizing key trends in the market.",
description="Coletar dados recentes do mercado brasileiro e identificar tendências.",
expected_output="Um relatório resumido com as principais tendências do mercado.",
agent=self.agent_one()
)
def task_two(self) -> Task:
return Task(
description="Research factors affecting market dynamics.",
expected_output="An analysis of factors influencing the market.",
description="Pesquisar fatores que afetam a dinâmica do mercado nacional.",
expected_output="Uma análise dos fatores que influenciam o mercado.",
agent=self.agent_two()
)

View File

@@ -51,24 +51,24 @@ from crewai.utilities.events import (
)
from crewai.utilities.events.base_event_listener import BaseEventListener
class MyCustomListener(BaseEventListener):
class MeuListenerPersonalizado(BaseEventListener):
def __init__(self):
super().__init__()
def setup_listeners(self, crewai_event_bus):
@crewai_event_bus.on(CrewKickoffStartedEvent)
def on_crew_started(source, event):
print(f"Crew '{event.crew_name}' has started execution!")
def ao_iniciar_crew(source, event):
print(f"Crew '{event.crew_name}' iniciou a execução!")
@crewai_event_bus.on(CrewKickoffCompletedEvent)
def on_crew_completed(source, event):
print(f"Crew '{event.crew_name}' has completed execution!")
print(f"Output: {event.output}")
def ao_finalizar_crew(source, event):
print(f"Crew '{event.crew_name}' finalizou a execução!")
print(f"Saída: {event.output}")
@crewai_event_bus.on(AgentExecutionCompletedEvent)
def on_agent_execution_completed(source, event):
print(f"Agent '{event.agent.role}' completed task")
print(f"Output: {event.output}")
def ao_finalizar_execucao_agente(source, event):
print(f"Agente '{event.agent.role}' concluiu a tarefa")
print(f"Saída: {event.output}")
```
## Registrando Corretamente Seu Listener

View File

@@ -486,8 +486,9 @@ Existem duas formas de executar um flow:
Você pode executar um flow programaticamente criando uma instância da sua classe de flow e chamando o método `kickoff()`:
```python
flow = ExampleFlow()
result = flow.kickoff()
# Exemplo de execução de flow em português
flow = ExemploFlow()
resultado = flow.kickoff()
```
### Usando a CLI

View File

@@ -39,17 +39,17 @@ llm = LLM(model="gpt-4o-mini", temperature=0)
# Create an agent with the knowledge store
agent = Agent(
role="About User",
goal="You know everything about the user.",
backstory="You are a master at understanding people and their preferences.",
role="Sobre o Usuário",
goal="Você sabe tudo sobre o usuário.",
backstory="Você é mestre em entender pessoas e suas preferências.",
verbose=True,
allow_delegation=False,
llm=llm,
)
task = Task(
description="Answer the following questions about the user: {question}",
expected_output="An answer to the question.",
description="Responda às seguintes perguntas sobre o usuário: {question}",
expected_output="Uma resposta para a pergunta.",
agent=agent,
)
@@ -87,17 +87,17 @@ llm = LLM(model="gpt-4o-mini", temperature=0)
# Create an agent with the knowledge store
agent = Agent(
role="About papers",
goal="You know everything about the papers.",
backstory="You are a master at understanding papers and their content.",
role="Sobre artigos",
goal="Você sabe tudo sobre os artigos.",
backstory="Você é mestre em entender artigos e seus conteúdos.",
verbose=True,
allow_delegation=False,
llm=llm,
)
task = Task(
description="Answer the following questions about the papers: {question}",
expected_output="An answer to the question.",
description="Responda às seguintes perguntas sobre os artigos: {question}",
expected_output="Uma resposta para a pergunta.",
agent=agent,
)
@@ -201,16 +201,16 @@ specialist_knowledge = StringKnowledgeSource(
)
specialist_agent = Agent(
role="Technical Specialist",
goal="Provide technical expertise",
backstory="Expert in specialized technical domains",
knowledge_sources=[specialist_knowledge] # Agent-specific knowledge
role="Especialista Técnico",
goal="Fornecer expertise técnica",
backstory="Especialista em domínios técnicos especializados",
knowledge_sources=[specialist_knowledge] # Conhecimento específico do agente
)
task = Task(
description="Answer technical questions",
description="Responda perguntas técnicas",
agent=specialist_agent,
expected_output="Technical answer"
expected_output="Resposta técnica"
)
# No crew-level knowledge required
@@ -240,7 +240,7 @@ Cada nível de knowledge usa coleções de armazenamento independentes:
```python
# Agent knowledge storage
agent_collection_name = agent.role # e.g., "Technical Specialist"
agent_collection_name = agent.role # e.g., "Especialista Técnico"
# Crew knowledge storage
crew_collection_name = "crew"
@@ -248,7 +248,7 @@ crew_collection_name = "crew"
# Both stored in same ChromaDB instance but different collections
# Path: ~/.local/share/CrewAI/{project}/knowledge/
# ├── crew/ # Crew knowledge collection
# ├── Technical Specialist/ # Agent knowledge collection
# ├── Especialista Técnico/ # Agent knowledge collection
# └── Another Agent Role/ # Another agent's collection
```
@@ -265,7 +265,7 @@ agent_knowledge = StringKnowledgeSource(
)
agent = Agent(
role="Specialist",
role="Especialista",
goal="Use specialized knowledge",
backstory="Expert with specific knowledge",
knowledge_sources=[agent_knowledge],
@@ -299,10 +299,10 @@ specialist_knowledge = StringKnowledgeSource(
)
specialist = Agent(
role="Technical Specialist",
goal="Provide technical expertise",
backstory="Technical expert",
knowledge_sources=[specialist_knowledge] # Agent-specific
role="Especialista Técnico",
goal="Fornecer expertise técnica",
backstory="Especialista em domínios técnicos especializados",
knowledge_sources=[specialist_knowledge] # Conhecimento específico do agente
)
generalist = Agent(

View File

@@ -78,15 +78,15 @@ Existem diferentes locais no código do CrewAI onde você pode especificar o mod
# Configuração avançada com parâmetros detalhados
llm = LLM(
model="model-id-here", # gpt-4o, gemini-2.0-flash, anthropic/claude...
temperature=0.7, # Mais alto para saídas criativas
timeout=120, # Segundos para aguardar resposta
max_tokens=4000, # Comprimento máximo da resposta
top_p=0.9, # Parâmetro de amostragem nucleus
frequency_penalty=0.1 , # Reduz repetição
presence_penalty=0.1, # Incentiva diversidade de tópicos
response_format={"type": "json"}, # Para respostas estruturadas
seed=42 # Para resultados reproduzíveis
model="openai/gpt-4",
temperature=0.8,
max_tokens=150,
top_p=0.9,
frequency_penalty=0.1,
presence_penalty=0.1,
response_format={"type":"json"},
stop=["FIM"],
seed=42
)
```
@@ -127,13 +127,13 @@ Nesta seção, você encontrará exemplos detalhados que ajudam a selecionar, co
from crewai import LLM
llm = LLM(
model="openai/gpt-4", # chamar modelo por provider/model_name
model="openai/gpt-4",
temperature=0.8,
max_tokens=150,
top_p=0.9,
frequency_penalty=0.1,
presence_penalty=0.1,
stop=["END"],
stop=["FIM"],
seed=42
)
```
@@ -169,7 +169,7 @@ Nesta seção, você encontrará exemplos detalhados que ajudam a selecionar, co
llm = LLM(
model="meta_llama/Llama-4-Scout-17B-16E-Instruct-FP8",
temperature=0.8,
stop=["END"],
stop=["FIM"],
seed=42
)
```
@@ -268,7 +268,7 @@ Nesta seção, você encontrará exemplos detalhados que ajudam a selecionar, co
from crewai import LLM
llm = LLM(
model="gemini/gemini-1.5-pro-latest",
model="gemini-1.5-pro-latest", # or vertex_ai/gemini-1.5-pro-latest
temperature=0.7,
vertex_credentials=vertex_credentials_json
)

View File

@@ -9,8 +9,7 @@ icon: database
O framework CrewAI oferece um sistema de memória sofisticado projetado para aprimorar significativamente as capacidades dos agentes de IA. O CrewAI disponibiliza **três abordagens distintas de memória** que atendem a diferentes casos de uso:
1. **Sistema Básico de Memória** - Memória de curto prazo, longo prazo e de entidades integradas
2. **Memória de Usuário** - Memória específica do usuário com integração ao Mem0 (abordagem legada)
3. **Memória Externa** - Provedores de memória externos autônomos (nova abordagem)
2. **Memória Externa** - Provedores de memória externos autônomos
## Componentes do Sistema de Memória
@@ -19,7 +18,7 @@ O framework CrewAI oferece um sistema de memória sofisticado projetado para apr
| **Memória de Curto Prazo** | Armazena temporariamente interações e resultados recentes usando `RAG`, permitindo que os agentes recordem e utilizem informações relevantes ao contexto atual durante as execuções. |
| **Memória de Longo Prazo** | Preserva informações valiosas e aprendizados de execuções passadas, permitindo que os agentes construam e refinem seu conhecimento ao longo do tempo. |
| **Memória de Entidades** | Captura e organiza informações sobre entidades (pessoas, lugares, conceitos) encontradas durante tarefas, facilitando um entendimento mais profundo e o mapeamento de relacionamentos. Utiliza `RAG` para armazenar informações de entidades. |
| **Memória Contextual** | Mantém o contexto das interações combinando `ShortTermMemory`, `LongTermMemory` e `EntityMemory`, auxiliando na coerência e relevância das respostas dos agentes ao longo de uma sequência de tarefas ou conversas. |
| **Memória Contextual** | Mantém o contexto das interações combinando `ShortTermMemory`, `LongTermMemory` , `ExternalMemory` e `EntityMemory`, auxiliando na coerência e relevância das respostas dos agentes ao longo de uma sequência de tarefas ou conversas. |
## 1. Sistema Básico de Memória (Recomendado)
@@ -623,7 +622,7 @@ for provider in providers_to_test:
**Erros de modelo não encontrado:**
```python
# Verifique disponibilidade do modelo
from crewai.utilities.embedding_configurator import EmbeddingConfigurator
from crewai.rag.embeddings.configurator import EmbeddingConfigurator
configurator = EmbeddingConfigurator()
try:
@@ -684,67 +683,19 @@ print(f"OpenAI: {openai_time:.2f}s")
print(f"Ollama: {ollama_time:.2f}s")
```
## 2. Memória de Usuário com Mem0 (Legado)
## 2. Memória Externa
<Warning>
**Abordagem Legada**: Embora totalmente funcional, esta abordagem é considerada legada. Para novos projetos que exijam memória específica do usuário, considere usar Memória Externa.
</Warning>
A Memória Externa fornece um sistema de memória autônomo que opera independentemente da memória interna da crew. Isso é ideal para provedores de memória especializados ou compartilhamento de memória entre aplicações.
A Memória de Usuário se integra com o [Mem0](https://mem0.ai/) para fornecer memória específica do usuário que persiste entre sessões e se integra ao sistema de memória contextual da crew.
### Pré-requisitos
```bash
pip install mem0ai
```
### Configuração Mem0 na Nuvem
### Memória Externa Básica com Mem0
```python
import os
from crewai import Crew, Process
from crewai import Agent, Crew, Process, Task
from crewai.memory.external.external_memory import ExternalMemory
# Defina sua chave de API do Mem0
os.environ["MEM0_API_KEY"] = "m0-your-api-key"
crew = Crew(
agents=[...],
tasks=[...],
memory=True, # Necessário para integração com a memória contextual
memory_config={
"provider": "mem0",
"config": {"user_id": "john"},
"user_memory": {} # Obrigatório - inicializa a memória de usuário
},
process=Process.sequential,
verbose=True
)
```
### Configuração Avançada Mem0
```python
crew = Crew(
agents=[...],
tasks=[...],
memory=True,
memory_config={
"provider": "mem0",
"config": {
"user_id": "john",
"org_id": "my_org_id", # Opcional
"project_id": "my_project_id", # Opcional
"api_key": "custom-api-key" # Opcional - sobrescreve variável de ambiente
},
"user_memory": {}
}
)
```
### Configuração Mem0 Local
```python
crew = Crew(
agents=[...],
tasks=[...],
memory=True,
memory_config={
# Create external memory instance with local Mem0 Configuration
external_memory = ExternalMemory(
embedder_config={
"provider": "mem0",
"config": {
"user_id": "john",
@@ -761,37 +712,60 @@ crew = Crew(
"provider": "openai",
"config": {"api_key": "your-api-key", "model": "text-embedding-3-small"}
}
}
},
"infer": True # Optional defaults to True
},
"user_memory": {}
}
)
```
## 3. Memória Externa (Nova Abordagem)
A Memória Externa fornece um sistema de memória autônomo que opera independentemente da memória interna da crew. Isso é ideal para provedores de memória especializados ou compartilhamento de memória entre aplicações.
### Memória Externa Básica com Mem0
```python
import os
from crewai import Agent, Crew, Process, Task
from crewai.memory.external.external_memory import ExternalMemory
os.environ["MEM0_API_KEY"] = "your-api-key"
# Criar instância de memória externa
external_memory = ExternalMemory(
embedder_config={
"provider": "mem0",
"config": {"user_id": "U-123"}
}
)
crew = Crew(
agents=[...],
tasks=[...],
external_memory=external_memory, # Independente da memória básica
external_memory=external_memory, # Separate from basic memory
process=Process.sequential,
verbose=True
)
```
### Memória Externa Avançada com o Cliente Mem0
Ao usar o Cliente Mem0, você pode personalizar ainda mais a configuração de memória usando parâmetros como "includes", "excludes", "custom_categories", "infer" e "run_id" (apenas para memória de curto prazo).
Você pode encontrar mais detalhes na [documentação do Mem0](https://docs.mem0.ai/).
```python
import os
from crewai import Agent, Crew, Process, Task
from crewai.memory.external.external_memory import ExternalMemory
new_categories = [
{"lifestyle_management_concerns": "Tracks daily routines, habits, hobbies and interests including cooking, time management and work-life balance"},
{"seeking_structure": "Documents goals around creating routines, schedules, and organized systems in various life areas"},
{"personal_information": "Basic information about the user including name, preferences, and personality traits"}
]
os.environ["MEM0_API_KEY"] = "your-api-key"
# Create external memory instance with Mem0 Client
external_memory = ExternalMemory(
embedder_config={
"provider": "mem0",
"config": {
"user_id": "john",
"org_id": "my_org_id", # Optional
"project_id": "my_project_id", # Optional
"api_key": "custom-api-key" # Optional - overrides env var
"run_id": "my_run_id", # Optional - for short-term memory
"includes": "include1", # Optional
"excludes": "exclude1", # Optional
"infer": True # Optional defaults to True
"custom_categories": new_categories # Optional - custom categories for user memory
},
}
)
crew = Crew(
agents=[...],
tasks=[...],
external_memory=external_memory, # Separate from basic memory
process=Process.sequential,
verbose=True
)
@@ -830,17 +804,18 @@ crew = Crew(
)
```
## Comparação dos Sistemas de Memória
## 🧠 Comparação dos Sistemas de Memória
| **Categoria** | **Recurso** | **Memória Básica** | **Memória Externa** |
|------------------------|-------------------------------|-------------------------------|----------------------------------|
| **Facilidade de Uso** | Complexidade de Setup | Simples | Média |
| | Integração | Contextual integrada | Autônoma |
| **Persistência** | Armazenamento | Arquivos locais | Customizada / Mem0 |
| | Multi-sessão | ✅ | ✅ |
| **Personalização** | Especificidade do Usuário | ❌ | ✅ |
| | Provedores Customizados | Limitado | Qualquer provedor |
| **Aplicação Recomendada** | Recomendado para | Maioria dos casos | Necessidades especializadas |
| Recurso | Memória Básica | Memória de Usuário (Legado) | Memória Externa |
|---------|---------------|-----------------------------|----------------|
| **Complexidade de Setup** | Simples | Média | Média |
| **Integração** | Contextual integrada | Contextual + específica do usuário | Autônoma |
| **Armazenamento** | Arquivos locais | Mem0 Cloud/Local | Customizada/Mem0 |
| **Multi-sessão** | ✅ | ✅ | ✅ |
| **Especificidade do Usuário** | ❌ | ✅ | ✅ |
| **Provedores Customizados** | Limitado | Apenas Mem0 | Qualquer provedor |
| **Recomendado para** | Maioria dos casos | Projetos legados | Necessidades especializadas |
## Provedores de Embedding Suportados
@@ -989,4 +964,4 @@ crew = Crew(
## Conclusão
Integrar o sistema de memória do CrewAI em seus projetos é simples. Ao aproveitar os componentes e configurações oferecidos,
você rapidamente capacita seus agentes a lembrar, raciocinar e aprender com suas interações, desbloqueando novos níveis de inteligência e capacidade.
você rapidamente capacita seus agentes a lembrar, raciocinar e aprender com suas interações, desbloqueando novos níveis de inteligência e capacidade.

View File

@@ -17,7 +17,7 @@ Começar a usar o recurso de planejamento é muito simples, o único passo neces
from crewai import Crew, Agent, Task, Process
# Monte sua crew com capacidades de planejamento
my_crew = Crew(
minha_crew = Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,

View File

@@ -28,23 +28,23 @@ from crewai import Crew, Process
# Exemplo: Criando uma crew com processo sequencial
crew = Crew(
agents=my_agents,
tasks=my_tasks,
agents=meus_agentes,
tasks=minhas_tarefas,
process=Process.sequential
)
# Exemplo: Criando uma crew com processo hierárquico
# Certifique-se de fornecer um manager_llm ou manager_agent
crew = Crew(
agents=my_agents,
tasks=my_tasks,
agents=meus_agentes,
tasks=minhas_tarefas,
process=Process.hierarchical,
manager_llm="gpt-4o"
# ou
# manager_agent=my_manager_agent
# manager_agent=meu_agente_gerente
)
```
**Nota:** Certifique-se de que `my_agents` e `my_tasks` estejam definidos antes de criar o objeto `Crew`, e para o processo hierárquico, é necessário também fornecer o `manager_llm` ou `manager_agent`.
**Nota:** Certifique-se de que `meus_agentes` e `minhas_tarefas` estejam definidos antes de criar o objeto `Crew`, e para o processo hierárquico, é necessário também fornecer o `manager_llm` ou `manager_agent`.
## Processo Sequencial

View File

@@ -15,12 +15,12 @@ Para habilitar o reasoning para um agente, basta definir `reasoning=True` ao cri
```python
from crewai import Agent
agent = Agent(
role="Data Analyst",
goal="Analyze complex datasets and provide insights",
backstory="You are an experienced data analyst with expertise in finding patterns in complex data.",
reasoning=True, # Enable reasoning
max_reasoning_attempts=3 # Optional: Set a maximum number of reasoning attempts
analista = Agent(
role="Analista de Dados",
goal="Analisar dados e fornecer insights",
backstory="Você é um analista de dados especialista.",
reasoning=True,
max_reasoning_attempts=3 # Opcional: Defina um limite de tentativas de reasoning
)
```
@@ -53,23 +53,23 @@ Aqui está um exemplo completo:
from crewai import Agent, Task, Crew
# Create an agent with reasoning enabled
analyst = Agent(
role="Data Analyst",
goal="Analyze data and provide insights",
backstory="You are an expert data analyst.",
analista = Agent(
role="Analista de Dados",
goal="Analisar dados e fornecer insights",
backstory="Você é um analista de dados especialista.",
reasoning=True,
max_reasoning_attempts=3 # Optional: Set a limit on reasoning attempts
max_reasoning_attempts=3 # Opcional: Defina um limite de tentativas de reasoning
)
# Create a task
analysis_task = Task(
description="Analyze the provided sales data and identify key trends.",
expected_output="A report highlighting the top 3 sales trends.",
agent=analyst
description="Analise os dados de vendas fornecidos e identifique as principais tendências.",
expected_output="Um relatório destacando as 3 principais tendências de vendas.",
agent=analista
)
# Create a crew and run the task
crew = Crew(agents=[analyst], tasks=[analysis_task])
crew = Crew(agents=[analista], tasks=[analysis_task])
result = crew.kickoff()
print(result)
@@ -90,16 +90,16 @@ logging.basicConfig(level=logging.INFO)
# Create an agent with reasoning enabled
agent = Agent(
role="Data Analyst",
goal="Analyze data and provide insights",
role="Analista de Dados",
goal="Analisar dados e fornecer insights",
reasoning=True,
max_reasoning_attempts=3
)
# Create a task
task = Task(
description="Analyze the provided sales data and identify key trends.",
expected_output="A report highlighting the top 3 sales trends.",
description="Analise os dados de vendas fornecidos e identifique as principais tendências.",
expected_output="Um relatório destacando as 3 principais tendências de vendas.",
agent=agent
)
@@ -113,7 +113,7 @@ result = agent.execute_task(task)
Veja um exemplo de como pode ser um plano de reasoning para uma tarefa de análise de dados:
```
Task: Analyze the provided sales data and identify key trends.
Task: Analise os dados de vendas fornecidos e identifique as principais tendências.
Reasoning Plan:
I'll analyze the sales data to identify the top 3 trends.

View File

@@ -54,9 +54,11 @@ crew = Crew(
| **Markdown** _(opcional)_ | `markdown` | `Optional[bool]` | Se a tarefa deve instruir o agente a retornar a resposta final formatada em Markdown. O padrão é False. |
| **Config** _(opcional)_ | `config` | `Optional[Dict[str, Any]]` | Parâmetros de configuração específicos da tarefa. |
| **Arquivo de Saída** _(opcional)_| `output_file` | `Optional[str]` | Caminho do arquivo para armazenar a saída da tarefa. |
| **Criar Diretório** _(opcional)_ | `create_directory` | `Optional[bool]` | Se deve criar o diretório para output_file caso não exista. O padrão é True. |
| **Saída JSON** _(opcional)_ | `output_json` | `Optional[Type[BaseModel]]` | Um modelo Pydantic para estruturar a saída em JSON. |
| **Output Pydantic** _(opcional)_ | `output_pydantic` | `Optional[Type[BaseModel]]` | Um modelo Pydantic para a saída da tarefa. |
| **Callback** _(opcional)_ | `callback` | `Optional[Any]` | Função/objeto a ser executado após a conclusão da tarefa. |
| **Guardrail** _(opcional)_ | `guardrail` | `Optional[Callable]` | Função para validar a saída da tarefa antes de prosseguir para a próxima tarefa. |
## Criando Tarefas
@@ -330,9 +332,11 @@ analysis_task = Task(
Guardrails (trilhas de proteção) de tarefas fornecem uma maneira de validar e transformar as saídas das tarefas antes que elas sejam passadas para a próxima tarefa. Esse recurso assegura a qualidade dos dados e oferece feedback aos agentes quando sua saída não atende a critérios específicos.
### Usando Guardrails em Tarefas
Guardrails são implementados como funções Python que contêm lógica de validação customizada, proporcionando controle total sobre o processo de validação e garantindo resultados confiáveis e determinísticos.
Para adicionar um guardrail a uma tarefa, forneça uma função de validação por meio do parâmetro `guardrail`:
### Guardrails Baseados em Função
Para adicionar um guardrail baseado em função a uma tarefa, forneça uma função de validação por meio do parâmetro `guardrail`:
```python Code
from typing import Tuple, Union, Dict, Any
@@ -370,9 +374,7 @@ blog_task = Task(
- Em caso de sucesso: retorna uma tupla `(True, resultado_validado)`
- Em caso de falha: retorna uma tupla `(False, "mensagem de erro explicando a falha")`
### LLMGuardrail
A classe `LLMGuardrail` oferece um mecanismo robusto para validação das saídas das tarefas.
### Melhores Práticas de Tratamento de Erros
@@ -386,7 +388,7 @@ def validate_with_context(result: TaskOutput) -> Tuple[bool, Any]:
validated_data = perform_validation(result)
return (True, validated_data)
except ValidationError as e:
return (False, f"VALIDATION_ERROR: {str(e)}")
return (False, f"ERRO_DE_VALIDACAO: {str(e)}")
except Exception as e:
return (False, str(e))
```
@@ -823,26 +825,7 @@ task = Task(
)
```
#### Use uma abordagem no-code para validação
```python Code
from crewai import Task
task = Task(
description="Gerar dados em JSON",
expected_output="Objeto JSON válido",
guardrail="Garanta que a resposta é um objeto JSON válido"
)
```
#### Usando YAML
```yaml
research_task:
...
guardrail: garanta que cada bullet tenha no mínimo 100 palavras
...
```
```python Code
@CrewBase
@@ -958,21 +941,87 @@ task = Task(
## Criando Diretórios ao Salvar Arquivos
Agora é possível especificar se uma tarefa deve criar diretórios ao salvar sua saída em arquivo. Isso é útil para organizar outputs e garantir que os caminhos estejam corretos.
O parâmetro `create_directory` controla se o CrewAI deve criar automaticamente diretórios ao salvar saídas de tarefas em arquivos. Este recurso é particularmente útil para organizar outputs e garantir que os caminhos de arquivos estejam estruturados corretamente, especialmente ao trabalhar com hierarquias de projetos complexas.
### Comportamento Padrão
Por padrão, `create_directory=True`, o que significa que o CrewAI criará automaticamente qualquer diretório ausente no caminho do arquivo de saída:
```python Code
# ...
save_output_task = Task(
description='Salve o resumo das notícias de IA em um arquivo',
expected_output='Arquivo salvo com sucesso',
agent=research_agent,
tools=[file_save_tool],
output_file='outputs/ai_news_summary.txt',
create_directory=True
# Comportamento padrão - diretórios são criados automaticamente
report_task = Task(
description='Gerar um relatório abrangente de análise de mercado',
expected_output='Uma análise detalhada de mercado com gráficos e insights',
agent=analyst_agent,
output_file='reports/2025/market_analysis.md', # Cria 'reports/2025/' se não existir
markdown=True
)
```
#...
### Desabilitando a Criação de Diretórios
Se você quiser evitar a criação automática de diretórios e garantir que o diretório já exista, defina `create_directory=False`:
```python Code
# Modo estrito - o diretório já deve existir
strict_output_task = Task(
description='Salvar dados críticos que requerem infraestrutura existente',
expected_output='Dados salvos em localização pré-configurada',
agent=data_agent,
output_file='secure/vault/critical_data.json',
create_directory=False # Gerará RuntimeError se 'secure/vault/' não existir
)
```
### Configuração YAML
Você também pode configurar este comportamento em suas definições de tarefas YAML:
```yaml tasks.yaml
analysis_task:
description: >
Gerar análise financeira trimestral
expected_output: >
Um relatório financeiro abrangente com insights trimestrais
agent: financial_analyst
output_file: reports/quarterly/q4_2024_analysis.pdf
create_directory: true # Criar automaticamente o diretório 'reports/quarterly/'
audit_task:
description: >
Realizar auditoria de conformidade e salvar no diretório de auditoria existente
expected_output: >
Um relatório de auditoria de conformidade
agent: auditor
output_file: audit/compliance_report.md
create_directory: false # O diretório já deve existir
```
### Casos de Uso
**Criação Automática de Diretórios (`create_directory=True`):**
- Ambientes de desenvolvimento e prototipagem
- Geração dinâmica de relatórios com pastas baseadas em datas
- Fluxos de trabalho automatizados onde a estrutura de diretórios pode variar
- Aplicações multi-tenant com pastas específicas do usuário
**Gerenciamento Manual de Diretórios (`create_directory=False`):**
- Ambientes de produção com controles rígidos do sistema de arquivos
- Aplicações sensíveis à segurança onde diretórios devem ser pré-configurados
- Sistemas com requisitos específicos de permissão
- Ambientes de conformidade onde a criação de diretórios é auditada
### Tratamento de Erros
Quando `create_directory=False` e o diretório não existe, o CrewAI gerará um `RuntimeError`:
```python Code
try:
result = crew.kickoff()
except RuntimeError as e:
# Tratar erro de diretório ausente
print(f"Falha na criação do diretório: {e}")
# Criar diretório manualmente ou usar local alternativo
```
Veja o vídeo abaixo para aprender como utilizar saídas estruturadas no CrewAI:

View File

@@ -67,17 +67,17 @@ web_rag_tool = WebsiteSearchTool()
# Criar agentes
researcher = Agent(
role='Market Research Analyst',
goal='Provide up-to-date market analysis of the AI industry',
backstory='An expert analyst with a keen eye for market trends.',
role='Analista de Mercado',
goal='Fornecer análise de mercado atualizada da indústria de IA',
backstory='Analista especialista com olhar atento para tendências de mercado.',
tools=[search_tool, web_rag_tool],
verbose=True
)
writer = Agent(
role='Content Writer',
goal='Craft engaging blog posts about the AI industry',
backstory='A skilled writer with a passion for technology.',
role='Redator de Conteúdo',
goal='Criar posts de blog envolventes sobre a indústria de IA',
backstory='Redator habilidoso com paixão por tecnologia.',
tools=[docs_tool, file_tool],
verbose=True
)

View File

@@ -36,19 +36,18 @@ Para treinar sua crew de forma programática, siga estes passos:
3. Execute o comando de treinamento dentro de um bloco try-except para tratar possíveis erros.
```python Code
n_iterations = 2
inputs = {"topic": "CrewAI Training"}
filename = "your_model.pkl"
n_iteracoes = 2
entradas = {"topic": "Treinamento CrewAI"}
nome_arquivo = "seu_modelo.pkl"
try:
YourCrewName_Crew().crew().train(
n_iterations=n_iterations,
inputs=inputs,
filename=filename
SuaCrew().crew().train(
n_iterations=n_iteracoes,
inputs=entradas,
filename=nome_arquivo
)
except Exception as e:
raise Exception(f"An error occurred while training the crew: {e}")
raise Exception(f"Ocorreu um erro ao treinar a crew: {e}")
```
### Pontos Importantes

View File

@@ -26,13 +26,13 @@ from crewai.tasks.hallucination_guardrail import HallucinationGuardrail
from crewai import LLM
# Uso básico - utiliza o expected_output da tarefa como contexto
guardrail = HallucinationGuardrail(
protecao = HallucinationGuardrail(
llm=LLM(model="gpt-4o-mini")
)
# Com contexto de referência explícito
context_guardrail = HallucinationGuardrail(
context="AI helps with various tasks including analysis and generation.",
protecao_com_contexto = HallucinationGuardrail(
context="IA ajuda em várias tarefas, incluindo análise e geração.",
llm=LLM(model="gpt-4o-mini")
)
```
@@ -43,11 +43,11 @@ context_guardrail = HallucinationGuardrail(
from crewai import Task
# Crie sua tarefa com a proteção
task = Task(
description="Write a summary about AI capabilities",
expected_output="A factual summary based on the provided context",
agent=my_agent,
guardrail=guardrail # Adiciona a proteção para validar a saída
minha_tarefa = Task(
description="Escreva um resumo sobre as capacidades da IA",
expected_output="Um resumo factual baseado no contexto fornecido",
agent=meu_agente,
guardrail=protecao # Adiciona a proteção para validar a saída
)
```
@@ -59,8 +59,8 @@ Para validação mais rigorosa, é possível definir um limiar de fidelidade per
```python
# Proteção rigorosa exigindo alta pontuação de fidelidade
strict_guardrail = HallucinationGuardrail(
context="Quantum computing uses qubits that exist in superposition states.",
protecao_rigorosa = HallucinationGuardrail(
context="Computação quântica utiliza qubits que existem em estados de superposição.",
llm=LLM(model="gpt-4o-mini"),
threshold=8.0 # Requer pontuação >= 8 para validar
)
@@ -72,10 +72,10 @@ Se sua tarefa utiliza ferramentas, você pode incluir as respostas das ferrament
```python
# Proteção com contexto de resposta da ferramenta
weather_guardrail = HallucinationGuardrail(
context="Current weather information for the requested location",
protecao_clima = HallucinationGuardrail(
context="Informações meteorológicas atuais para o local solicitado",
llm=LLM(model="gpt-4o-mini"),
tool_response="Weather API returned: Temperature 22°C, Humidity 65%, Clear skies"
tool_response="API do Clima retornou: Temperatura 22°C, Umidade 65%, Céu limpo"
)
```
@@ -123,15 +123,15 @@ Quando uma proteção é adicionada à tarefa, ela valida automaticamente a saí
```python
# Fluxo de validação de saída da tarefa
task_output = agent.execute_task(task)
validation_result = guardrail(task_output)
task_output = meu_agente.execute_task(minha_tarefa)
resultado_validacao = protecao(task_output)
if validation_result.valid:
if resultado_validacao.valid:
# Tarefa concluída com sucesso
return task_output
else:
# Tarefa falha com feedback de validação
raise ValidationError(validation_result.feedback)
raise ValidationError(resultado_validacao.feedback)
```
### Rastreamento de Eventos
@@ -151,10 +151,10 @@ A proteção se integra ao sistema de eventos do CrewAI para fornecer observabil
Inclua todas as informações factuais relevantes nas quais a IA deve basear sua saída:
```python
context = """
Company XYZ was founded in 2020 and specializes in renewable energy solutions.
They have 150 employees and generated $50M revenue in 2023.
Their main products include solar panels and wind turbines.
contexto = """
Empresa XYZ foi fundada em 2020 e é especializada em soluções de energia renovável.
Possui 150 funcionários e faturou R$ 50 milhões em 2023.
Seus principais produtos incluem painéis solares e turbinas eólicas.
"""
```
</Step>
@@ -164,10 +164,10 @@ A proteção se integra ao sistema de eventos do CrewAI para fornecer observabil
```python
# Bom: Contexto focado
context = "The current weather in New York is 18°C with light rain."
contexto = "O clima atual em Nova York é 18°C com chuva leve."
# Evite: Informações irrelevantes
context = "The weather is 18°C. The city has 8 million people. Traffic is heavy."
contexto = "The weather is 18°C. The city has 8 million people. Traffic is heavy."
```
</Step>

View File

@@ -84,31 +84,31 @@ from crewai import Agent, Task, Crew
from crewai_tools import CrewaiEnterpriseTools
# Obtenha ferramentas enterprise (a ferramenta Gmail será incluída)
enterprise_tools = CrewaiEnterpriseTools(
enterprise_token="your_enterprise_token"
ferramentas_enterprise = CrewaiEnterpriseTools(
enterprise_token="seu_token_enterprise"
)
# imprima as ferramentas
print(enterprise_tools)
printf(ferramentas_enterprise)
# Crie um agente com capacidades do Gmail
email_agent = Agent(
role="Email Manager",
goal="Manage and organize email communications",
backstory="An AI assistant specialized in email management and communication.",
tools=enterprise_tools
agente_email = Agent(
role="Gerente de E-mails",
goal="Gerenciar e organizar comunicações por e-mail",
backstory="Um assistente de IA especializado em gestão de e-mails e comunicação.",
tools=ferramentas_enterprise
)
# Tarefa para enviar um e-mail
email_task = Task(
description="Draft and send a follow-up email to john@example.com about the project update",
agent=email_agent,
expected_output="Confirmation that email was sent successfully"
tarefa_email = Task(
description="Redigir e enviar um e-mail de acompanhamento para john@example.com sobre a atualização do projeto",
agent=agente_email,
expected_output="Confirmação de que o e-mail foi enviado com sucesso"
)
# Execute a tarefa
crew = Crew(
agents=[email_agent],
tasks=[email_task]
agents=[agente_email],
tasks=[tarefa_email]
)
# Execute o crew
@@ -125,23 +125,23 @@ enterprise_tools = CrewaiEnterpriseTools(
)
gmail_tool = enterprise_tools["gmail_find_email"]
gmail_agent = Agent(
role="Gmail Manager",
goal="Manage gmail communications and notifications",
backstory="An AI assistant that helps coordinate gmail communications.",
agente_gmail = Agent(
role="Gerente do Gmail",
goal="Gerenciar comunicações e notificações do gmail",
backstory="Um assistente de IA que ajuda a coordenar comunicações no gmail.",
tools=[gmail_tool]
)
notification_task = Task(
description="Find the email from john@example.com",
agent=gmail_agent,
expected_output="Email found from john@example.com"
tarefa_notificacao = Task(
description="Encontrar o e-mail de john@example.com",
agent=agente_gmail,
expected_output="E-mail encontrado de john@example.com"
)
# Execute a tarefa
crew = Crew(
agents=[slack_agent],
tasks=[notification_task]
agents=[agente_gmail],
tasks=[tarefa_notificacao]
)
```

View File

@@ -30,7 +30,7 @@ Antes de usar o Repositório de Ferramentas, certifique-se de que você possui:
Para instalar uma ferramenta:
```bash
crewai tool install <tool-name>
crewai tool install <nome-da-ferramenta>
```
Isso instala a ferramenta e a adiciona ao `pyproject.toml`.
@@ -40,7 +40,7 @@ Isso instala a ferramenta e a adiciona ao `pyproject.toml`.
Para criar um novo projeto de ferramenta:
```bash
crewai tool create <tool-name>
crewai tool create <nome-da-ferramenta>
```
Isso gera um projeto de ferramenta estruturado localmente.
@@ -76,7 +76,7 @@ Para atualizar uma ferramenta publicada:
3. Faça o commit das alterações e publique
```bash
git commit -m "Update version to 0.1.1"
git commit -m "Atualizar versão para 0.1.1"
crewai tool publish
```

View File

@@ -12,16 +12,17 @@ O Enterprise Event Streaming permite que você receba atualizações em tempo re
Ao utilizar a API Kickoff, inclua um objeto `webhooks` em sua requisição, por exemplo:
# Exemplo de uso da API Kickoff com webhooks
```json
{
"inputs": {"foo": "bar"},
"webhooks": {
"events": ["crew_kickoff_started", "llm_call_started"],
"url": "https://your.endpoint/webhook",
"url": "https://seu.endpoint/webhook",
"realtime": false,
"authentication": {
"strategy": "bearer",
"token": "my-secret-token"
"token": "meu-token-secreto"
}
}
}
@@ -33,19 +34,20 @@ Se `realtime` estiver definido como `true`, cada evento será entregue individua
Cada webhook envia uma lista de eventos:
# Exemplo de evento enviado pelo webhook
```json
{
"events": [
{
"id": "event-id",
"execution_id": "crew-run-id",
"id": "id-do-evento",
"execution_id": "id-da-execucao-do-crew",
"timestamp": "2025-02-16T10:58:44.965Z",
"type": "llm_call_started",
"data": {
"model": "gpt-4",
"messages": [
{"role": "system", "content": "You are an assistant."},
{"role": "user", "content": "Summarize this article."}
{"role": "system", "content": "Você é um assistente."},
{"role": "user", "content": "Resuma este artigo."}
]
}
}

View File

@@ -41,11 +41,8 @@ A CLI fornece a maneira mais rápida de implantar crews desenvolvidos localmente
Primeiro, você precisa autenticar sua CLI com a plataforma CrewAI Enterprise:
```bash
# Se já possui uma conta CrewAI Enterprise
# Se já possui uma conta CrewAI Enterprise, ou deseja criar uma:
crewai login
# Se vai criar uma nova conta
crewai signup
```
Ao executar qualquer um dos comandos, a CLI irá:

View File

@@ -16,17 +16,17 @@ from crewai import CrewBase
from crewai.project import before_kickoff
@CrewBase
class MyCrew:
class MinhaEquipe:
@before_kickoff
def prepare_data(self, inputs):
# Preprocess or modify inputs
inputs['processed'] = True
return inputs
def preparar_dados(self, entradas):
# Pré-processa ou modifica as entradas
entradas['processado'] = True
return entradas
#...
```
Neste exemplo, a função prepare_data modifica as entradas adicionando um novo par chave-valor indicando que as entradas foram processadas.
Neste exemplo, a função preparar_dados modifica as entradas adicionando um novo par chave-valor indicando que as entradas foram processadas.
## Hook Depois do Kickoff
@@ -39,17 +39,17 @@ from crewai import CrewBase
from crewai.project import after_kickoff
@CrewBase
class MyCrew:
class MinhaEquipe:
@after_kickoff
def log_results(self, result):
# Log or modify the results
print("Crew execution completed with result:", result)
return result
def registrar_resultados(self, resultado):
# Registra ou modifica os resultados
print("Execução da equipe concluída com resultado:", resultado)
return resultado
# ...
```
Na função `log_results`, os resultados da execução da crew são simplesmente impressos. Você pode estender isso para realizar operações mais complexas, como enviar notificações ou integrar com outros serviços.
Na função `registrar_resultados`, os resultados da execução da crew são simplesmente impressos. Você pode estender isso para realizar operações mais complexas, como enviar notificações ou integrar com outros serviços.
## Utilizando Ambos os Hooks

View File

@@ -77,9 +77,9 @@ search_tool = SerperDevTool()
# Inicialize o agente com opções avançadas
agent = Agent(
role='Research Analyst',
goal='Provide up-to-date market analysis',
backstory='An expert analyst with a keen eye for market trends.',
role='Analista de Pesquisa',
goal='Fornecer análises de mercado atualizadas',
backstory='Um analista especialista com olhar atento para tendências de mercado.',
tools=[search_tool],
memory=True, # Ativa memória
verbose=True,
@@ -98,14 +98,9 @@ eficiência dentro do ecossistema CrewAI. Se necessário, a delegação pode ser
```python Code
agent = Agent(
role='Content Writer',
goal='Write engaging content on market trends',
backstory='A seasoned writer with expertise in market analysis.',
role='Redator de Conteúdo',
goal='Escrever conteúdo envolvente sobre tendências de mercado',
backstory='Um redator experiente com expertise em análise de mercado.',
allow_delegation=True # Habilitando delegação
)
```
## Conclusão
Personalizar agentes no CrewAI definindo seus papéis, objetivos, histórias e ferramentas, juntamente com opções avançadas como personalização de modelo de linguagem, memória, ajustes de performance e preferências de delegação,
proporciona uma equipe de IA sofisticada e preparada para enfrentar desafios complexos.
```

View File

@@ -45,17 +45,17 @@ from crewai import Crew, Agent, Task
# Create an agent with code execution enabled
coding_agent = Agent(
role="Python Data Analyst",
goal="Analyze data and provide insights using Python",
backstory="You are an experienced data analyst with strong Python skills.",
role="Analista de Dados Python",
goal="Analisar dados e fornecer insights usando Python",
backstory="Você é um analista de dados experiente com fortes habilidades em Python.",
allow_code_execution=True
)
# Create a task that requires code execution
data_analysis_task = Task(
description="Analyze the given dataset and calculate the average age of participants. Ages: {ages}",
description="Analise o conjunto de dados fornecido e calcule a idade média dos participantes. Idades: {ages}",
agent=coding_agent,
expected_output="The average age of the participants."
expected_output="A idade média dos participantes."
)
# Create a crew and add the task
@@ -83,23 +83,23 @@ from crewai import Crew, Agent, Task
# Create an agent with code execution enabled
coding_agent = Agent(
role="Python Data Analyst",
goal="Analyze data and provide insights using Python",
backstory="You are an experienced data analyst with strong Python skills.",
role="Analista de Dados Python",
goal="Analisar dados e fornecer insights usando Python",
backstory="Você é um analista de dados experiente com fortes habilidades em Python.",
allow_code_execution=True
)
# Create tasks that require code execution
task_1 = Task(
description="Analyze the first dataset and calculate the average age of participants. Ages: {ages}",
description="Analise o primeiro conjunto de dados e calcule a idade média dos participantes. Idades: {ages}",
agent=coding_agent,
expected_output="The average age of the participants."
expected_output="A idade média dos participantes."
)
task_2 = Task(
description="Analyze the second dataset and calculate the average age of participants. Ages: {ages}",
description="Analise o segundo conjunto de dados e calcule a idade média dos participantes. Idades: {ages}",
agent=coding_agent,
expected_output="The average age of the participants."
expected_output="A idade média dos participantes."
)
# Create two crews and add tasks

View File

@@ -43,11 +43,11 @@ try:
with MCPServerAdapter(server_params_list) as aggregated_tools:
print(f"Available aggregated tools: {[tool.name for tool in aggregated_tools]}")
multi_server_agent = Agent(
role="Versatile Assistant",
goal="Utilize tools from local Stdio, remote SSE, and remote HTTP MCP servers.",
backstory="An AI agent capable of leveraging a diverse set of tools from multiple sources.",
tools=aggregated_tools, # All tools are available here
agente_multiservidor = Agent(
role="Assistente Versátil",
goal="Utilizar ferramentas de servidores MCP locais Stdio, remotos SSE e remotos HTTP.",
backstory="Um agente de IA capaz de aproveitar um conjunto diversificado de ferramentas de múltiplas fontes.",
tools=aggregated_tools, # Todas as ferramentas estão disponíveis aqui
verbose=True,
)

View File

@@ -44,6 +44,19 @@ A classe `MCPServerAdapter` da `crewai-tools` é a principal forma de conectar-s
O uso de um gerenciador de contexto Python (`with`) é a **abordagem recomendada** para o `MCPServerAdapter`. Ele lida automaticamente com a abertura e o fechamento da conexão com o servidor MCP.
## Configuração de Conexão
O `MCPServerAdapter` suporta várias opções de configuração para personalizar o comportamento da conexão:
- **`connect_timeout`** (opcional): Tempo máximo em segundos para aguardar o estabelecimento de uma conexão com o servidor MCP. O padrão é 30 segundos se não especificado. Isso é particularmente útil para servidores remotos que podem ter tempos de resposta variáveis.
```python
# Exemplo com timeout personalizado para conexão
with MCPServerAdapter(server_params, connect_timeout=60) as tools:
# A conexão terá timeout após 60 segundos se não estabelecida
pass
```
```python
from crewai import Agent
from crewai_tools import MCPServerAdapter
@@ -70,13 +83,13 @@ server_params = {
}
# Exemplo de uso (descomente e adapte após definir server_params):
with MCPServerAdapter(server_params) as mcp_tools:
with MCPServerAdapter(server_params, connect_timeout=60) as mcp_tools:
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
my_agent = Agent(
role="MCP Tool User",
goal="Utilize tools from an MCP server.",
backstory="I can connect to MCP servers and use their tools.",
meu_agente = Agent(
role="Usuário de Ferramentas MCP",
goal="Utilizar ferramentas de um servidor MCP.",
backstory="Posso conectar a servidores MCP e usar suas ferramentas.",
tools=mcp_tools, # Passe as ferramentas carregadas para o seu agente
reasoning=True,
verbose=True
@@ -88,13 +101,13 @@ Este padrão geral mostra como integrar ferramentas. Para exemplos específicos
## Filtrando Ferramentas
```python
with MCPServerAdapter(server_params) as mcp_tools:
with MCPServerAdapter(server_params, connect_timeout=60) as mcp_tools:
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
my_agent = Agent(
role="MCP Tool User",
goal="Utilize tools from an MCP server.",
backstory="I can connect to MCP servers and use their tools.",
meu_agente = Agent(
role="Usuário de Ferramentas MCP",
goal="Utilizar ferramentas de um servidor MCP.",
backstory="Posso conectar a servidores MCP e usar suas ferramentas.",
tools=mcp_tools["tool_name"], # Passe as ferramentas filtradas para o seu agente
reasoning=True,
verbose=True

View File

@@ -37,24 +37,24 @@ try:
print(f"Available tools from SSE MCP server: {[tool.name for tool in tools]}")
# Example: Using a tool from the SSE MCP server
sse_agent = Agent(
role="Remote Service User",
goal="Utilize a tool provided by a remote SSE MCP server.",
backstory="An AI agent that connects to external services via SSE.",
agente_sse = Agent(
role="Usuário de Serviço Remoto",
goal="Utilizar uma ferramenta fornecida por um servidor MCP remoto via SSE.",
backstory="Um agente de IA que conecta a serviços externos via SSE.",
tools=tools,
reasoning=True,
verbose=True,
)
sse_task = Task(
description="Fetch real-time stock updates for 'AAPL' using an SSE tool.",
expected_output="The latest stock price for AAPL.",
agent=sse_agent,
description="Buscar atualizações em tempo real das ações 'AAPL' usando uma ferramenta SSE.",
expected_output="O preço mais recente da ação AAPL.",
agent=agente_sse,
markdown=True
)
sse_crew = Crew(
agents=[sse_agent],
agents=[agente_sse],
tasks=[sse_task],
verbose=True,
process=Process.sequential
@@ -101,16 +101,16 @@ try:
print(f"Available tools (manual SSE): {[tool.name for tool in tools]}")
manual_sse_agent = Agent(
role="Remote Data Analyst",
goal="Analyze data fetched from a remote SSE MCP server using manual connection management.",
backstory="An AI skilled in handling SSE connections explicitly.",
role="Analista Remoto de Dados",
goal="Analisar dados obtidos de um servidor MCP remoto SSE usando gerenciamento manual de conexão.",
backstory="Um agente de IA especializado em gerenciar conexões SSE explicitamente.",
tools=tools,
verbose=True
)
analysis_task = Task(
description="Fetch and analyze the latest user activity trends from the SSE server.",
expected_output="A summary report of user activity trends.",
description="Buscar e analisar as tendências mais recentes de atividade de usuários do servidor SSE.",
expected_output="Um relatório resumido das tendências de atividade dos usuários.",
agent=manual_sse_agent
)

View File

@@ -38,24 +38,24 @@ with MCPServerAdapter(server_params) as tools:
print(f"Available tools from Stdio MCP server: {[tool.name for tool in tools]}")
# Exemplo: Usando as ferramentas do servidor MCP Stdio em um Agente CrewAI
research_agent = Agent(
role="Local Data Processor",
goal="Process data using a local Stdio-based tool.",
backstory="An AI that leverages local scripts via MCP for specialized tasks.",
pesquisador_local = Agent(
role="Processador Local de Dados",
goal="Processar dados usando uma ferramenta local baseada em Stdio.",
backstory="Uma IA que utiliza scripts locais via MCP para tarefas especializadas.",
tools=tools,
reasoning=True,
verbose=True,
)
processing_task = Task(
description="Process the input data file 'data.txt' and summarize its contents.",
expected_output="A summary of the processed data.",
agent=research_agent,
description="Processar o arquivo de dados de entrada 'data.txt' e resumir seu conteúdo.",
expected_output="Um resumo dos dados processados.",
agent=pesquisador_local,
markdown=True
)
data_crew = Crew(
agents=[research_agent],
agents=[pesquisador_local],
tasks=[processing_task],
verbose=True,
process=Process.sequential
@@ -95,16 +95,16 @@ try:
# Exemplo: Usando as ferramentas com sua configuração de Agent, Task, Crew
manual_agent = Agent(
role="Local Task Executor",
goal="Execute a specific local task using a manually managed Stdio tool.",
backstory="An AI proficient in controlling local processes via MCP.",
role="Executor Local de Tarefas",
goal="Executar uma tarefa local específica usando uma ferramenta Stdio gerenciada manualmente.",
backstory="Uma IA proficiente em controlar processos locais via MCP.",
tools=tools,
verbose=True
)
manual_task = Task(
description="Execute the 'perform_analysis' command via the Stdio tool.",
expected_output="Results of the analysis.",
description="Executar o comando 'perform_analysis' via ferramenta Stdio.",
expected_output="Resultados da análise.",
agent=manual_agent
)

View File

@@ -35,22 +35,22 @@ try:
with MCPServerAdapter(server_params) as tools:
print(f"Available tools from Streamable HTTP MCP server: {[tool.name for tool in tools]}")
http_agent = Agent(
role="HTTP Service Integrator",
goal="Utilize tools from a remote MCP server via Streamable HTTP.",
backstory="An AI agent adept at interacting with complex web services.",
agente_http = Agent(
role="Integrador de Serviços HTTP",
goal="Utilizar ferramentas de um servidor MCP remoto via Streamable HTTP.",
backstory="Um agente de IA especializado em interagir com serviços web complexos.",
tools=tools,
verbose=True,
)
http_task = Task(
description="Perform a complex data query using a tool from the Streamable HTTP server.",
expected_output="The result of the complex data query.",
agent=http_agent,
description="Realizar uma consulta de dados complexa usando uma ferramenta do servidor Streamable HTTP.",
expected_output="O resultado da consulta de dados complexa.",
agent=agente_http,
)
http_crew = Crew(
agents=[http_agent],
agents=[agente_http],
tasks=[http_task],
verbose=True,
process=Process.sequential
@@ -91,16 +91,16 @@ try:
print(f"Available tools (manual Streamable HTTP): {[tool.name for tool in tools]}")
manual_http_agent = Agent(
role="Advanced Web Service User",
goal="Interact with an MCP server using manually managed Streamable HTTP connections.",
backstory="An AI specialist in fine-tuning HTTP-based service integrations.",
role="Usuário Avançado de Serviços Web",
goal="Interagir com um servidor MCP usando conexões HTTP Streamable gerenciadas manualmente.",
backstory="Um especialista em IA em ajustar integrações baseadas em HTTP.",
tools=tools,
verbose=True
)
data_processing_task = Task(
description="Submit data for processing and retrieve results via Streamable HTTP.",
expected_output="Processed data or confirmation.",
description="Enviar dados para processamento e recuperar resultados via Streamable HTTP.",
expected_output="Dados processados ou confirmação.",
agent=manual_http_agent
)

View File

@@ -78,47 +78,40 @@ CrewAIInstrumentor().instrument(skip_dep_check=True, tracer_provider=tracer_prov
search_tool = SerperDevTool()
# Defina seus agentes com papéis e objetivos
researcher = Agent(
role="Senior Research Analyst",
goal="Uncover cutting-edge developments in AI and data science",
backstory="""You work at a leading tech think tank.
Your expertise lies in identifying emerging trends.
You have a knack for dissecting complex data and presenting actionable insights.""",
pesquisador = Agent(
role="Analista Sênior de Pesquisa",
goal="Descobrir os avanços mais recentes em IA e ciência de dados",
backstory="""
Você trabalha em um importante think tank de tecnologia. Sua especialidade é identificar tendências emergentes. Você tem habilidade para dissecar dados complexos e apresentar insights acionáveis.
""",
verbose=True,
allow_delegation=False,
# You can pass an optional llm attribute specifying what model you wanna use.
# llm=ChatOpenAI(model_name="gpt-3.5", temperature=0.7),
tools=[search_tool],
)
writer = Agent(
role="Tech Content Strategist",
goal="Craft compelling content on tech advancements",
backstory="""You are a renowned Content Strategist, known for your insightful and engaging articles.
You transform complex concepts into compelling narratives.""",
role="Estrategista de Conteúdo Técnico",
goal="Criar conteúdo envolvente sobre avanços tecnológicos",
backstory="Você é um Estrategista de Conteúdo renomado, conhecido por seus artigos perspicazes e envolventes. Você transforma conceitos complexos em narrativas atraentes.",
verbose=True,
allow_delegation=True,
)
# Crie tarefas para seus agentes
task1 = Task(
description="""Conduct a comprehensive analysis of the latest advancements in AI in 2024.
Identify key trends, breakthrough technologies, and potential industry impacts.""",
expected_output="Full analysis report in bullet points",
agent=researcher,
description="Realize uma análise abrangente dos avanços mais recentes em IA em 2024. Identifique tendências-chave, tecnologias inovadoras e impactos potenciais na indústria.",
expected_output="Relatório analítico completo em tópicos",
agent=pesquisador,
)
task2 = Task(
description="""Using the insights provided, develop an engaging blog
post that highlights the most significant AI advancements.
Your post should be informative yet accessible, catering to a tech-savvy audience.
Make it sound cool, avoid complex words so it doesn't sound like AI.""",
expected_output="Full blog post of at least 4 paragraphs",
description="Utilizando os insights fornecidos, desenvolva um blog envolvente destacando os avanços mais significativos em IA. O post deve ser informativo e acessível, voltado para um público técnico. Dê um tom interessante, evite palavras complexas para não soar como IA.",
expected_output="Post de blog completo com pelo menos 4 parágrafos",
agent=writer,
)
# Instancie seu crew com um processo sequencial
crew = Crew(
agents=[researcher, writer], tasks=[task1, task2], verbose=1, process=Process.sequential
agents=[pesquisador, writer], tasks=[task1, task2], verbose=1, process=Process.sequential
)
# Coloque seu crew para trabalhar!

View File

@@ -0,0 +1,286 @@
---
title: Integração LangDB
description: Governe, proteja e otimize seus fluxos de trabalho CrewAI com LangDB AI Gateway—acesse mais de 350 modelos, roteamento automático, otimização de custos e observabilidade completa.
icon: database
---
# Introdução
[LangDB AI Gateway](https://langdb.ai) fornece APIs compatíveis com OpenAI para conectar com múltiplos Modelos de Linguagem Grandes e serve como uma plataforma de observabilidade que torna effortless rastrear fluxos de trabalho CrewAI de ponta a ponta, proporcionando acesso a mais de 350 modelos de linguagem. Com uma única chamada `init()`, todas as interações de agentes, execuções de tarefas e chamadas LLM são capturadas, fornecendo observabilidade abrangente e infraestrutura de IA pronta para produção para suas aplicações.
<Frame caption="Exemplo de Rastreamento CrewAI LangDB">
<img src="/images/langdb-1.png" alt="Exemplo de rastreamento CrewAI LangDB" />
</Frame>
**Confira:** [Ver o exemplo de trace ao vivo](https://app.langdb.ai/sharing/threads/3becbfed-a1be-ae84-ea3c-4942867a3e22)
## Recursos
### Capacidades do AI Gateway
- **Acesso a mais de 350 LLMs**: Conecte-se a todos os principais modelos de linguagem através de uma única integração
- **Modelos Virtuais**: Crie configurações de modelo personalizadas com parâmetros específicos e regras de roteamento
- **MCP Virtual**: Habilite compatibilidade e integração com sistemas MCP (Model Context Protocol) para comunicação aprimorada de agentes
- **Guardrails**: Implemente medidas de segurança e controles de conformidade para comportamento de agentes
### Observabilidade e Rastreamento
- **Rastreamento Automático**: Uma única chamada `init()` captura todas as interações CrewAI
- **Visibilidade Ponta a Ponta**: Monitore fluxos de trabalho de agentes do início ao fim
- **Rastreamento de Uso de Ferramentas**: Rastreie quais ferramentas os agentes usam e seus resultados
- **Monitoramento de Chamadas de Modelo**: Insights detalhados sobre interações LLM
- **Análise de Performance**: Monitore latência, uso de tokens e custos
- **Suporte a Depuração**: Execução passo a passo para solução de problemas
- **Monitoramento em Tempo Real**: Dashboard de traces e métricas ao vivo
## Instruções de Configuração
<Steps>
<Step title="Instalar LangDB">
Instale o cliente LangDB com flag de recurso CrewAI:
```bash
pip install 'pylangdb[crewai]'
```
</Step>
<Step title="Definir Variáveis de Ambiente">
Configure suas credenciais LangDB:
```bash
export LANGDB_API_KEY="<sua_chave_api_langdb>"
export LANGDB_PROJECT_ID="<seu_id_projeto_langdb>"
export LANGDB_API_BASE_URL='https://api.us-east-1.langdb.ai'
```
</Step>
<Step title="Inicializar Rastreamento">
Importe e inicialize LangDB antes de configurar seu código CrewAI:
```python
from pylangdb.crewai import init
# Inicializar LangDB
init()
```
</Step>
<Step title="Configurar CrewAI com LangDB">
Configure seu LLM com cabeçalhos LangDB:
```python
from crewai import Agent, Task, Crew, LLM
import os
# Configurar LLM com cabeçalhos LangDB
llm = LLM(
model="openai/gpt-4o", # Substitua pelo modelo que você quer usar
api_key=os.getenv("LANGDB_API_KEY"),
base_url=os.getenv("LANGDB_API_BASE_URL"),
extra_headers={"x-project-id": os.getenv("LANGDB_PROJECT_ID")}
)
```
</Step>
</Steps>
## Exemplo de Início Rápido
Aqui está um exemplo simples para começar com LangDB e CrewAI:
```python
import os
from pylangdb.crewai import init
from crewai import Agent, Task, Crew, LLM
# Inicializar LangDB antes de qualquer importação CrewAI
init()
def create_llm(model):
return LLM(
model=model,
api_key=os.environ.get("LANGDB_API_KEY"),
base_url=os.environ.get("LANGDB_API_BASE_URL"),
extra_headers={"x-project-id": os.environ.get("LANGDB_PROJECT_ID")}
)
# Defina seu agente
researcher = Agent(
role="Especialista em Pesquisa",
goal="Pesquisar tópicos minuciosamente",
backstory="Pesquisador especialista com habilidades em encontrar informações",
llm=create_llm("openai/gpt-4o"), # Substitua pelo modelo que você quer usar
verbose=True
)
# Criar uma tarefa
task = Task(
description="Pesquise o tópico dado e forneça um resumo abrangente",
agent=researcher,
expected_output="Resumo de pesquisa detalhado com principais descobertas"
)
# Criar e executar a equipe
crew = Crew(agents=[researcher], tasks=[task])
result = crew.kickoff()
print(result)
```
## Exemplo Completo: Agente de Pesquisa e Planejamento
Este exemplo abrangente demonstra um fluxo de trabalho multi-agente com capacidades de pesquisa e planejamento.
### Pré-requisitos
```bash
pip install crewai 'pylangdb[crewai]' crewai_tools setuptools python-dotenv
```
### Configuração do Ambiente
```bash
# Credenciais LangDB
export LANGDB_API_KEY="<sua_chave_api_langdb>"
export LANGDB_PROJECT_ID="<seu_id_projeto_langdb>"
export LANGDB_API_BASE_URL='https://api.us-east-1.langdb.ai'
# Chaves API adicionais (opcional)
export SERPER_API_KEY="<sua_chave_api_serper>" # Para capacidades de busca na web
```
### Implementação Completa
```python
#!/usr/bin/env python3
import os
import sys
from pylangdb.crewai import init
init() # Inicializar LangDB antes de qualquer importação CrewAI
from dotenv import load_dotenv
from crewai import Agent, Task, Crew, Process, LLM
from crewai_tools import SerperDevTool
load_dotenv()
def create_llm(model):
return LLM(
model=model,
api_key=os.environ.get("LANGDB_API_KEY"),
base_url=os.environ.get("LANGDB_API_BASE_URL"),
extra_headers={"x-project-id": os.environ.get("LANGDB_PROJECT_ID")}
)
class ResearchPlanningCrew:
def researcher(self) -> Agent:
return Agent(
role="Especialista em Pesquisa",
goal="Pesquisar tópicos minuciosamente e compilar informações abrangentes",
backstory="Pesquisador especialista com habilidades em encontrar e analisar informações de várias fontes",
tools=[SerperDevTool()],
llm=create_llm("openai/gpt-4o"),
verbose=True
)
def planner(self) -> Agent:
return Agent(
role="Planejador Estratégico",
goal="Criar planos acionáveis baseados em descobertas de pesquisa",
backstory="Planejador estratégico que divide desafios complexos em planos executáveis",
reasoning=True,
max_reasoning_attempts=3,
llm=create_llm("openai/anthropic/claude-3.7-sonnet"),
verbose=True
)
def research_task(self) -> Task:
return Task(
description="Pesquise o tópico minuciosamente e compile informações abrangentes",
agent=self.researcher(),
expected_output="Relatório de pesquisa abrangente com principais descobertas e insights"
)
def planning_task(self) -> Task:
return Task(
description="Crie um plano estratégico baseado nas descobertas da pesquisa",
agent=self.planner(),
expected_output="Plano de execução estratégica com fases, objetivos e etapas acionáveis",
context=[self.research_task()]
)
def crew(self) -> Crew:
return Crew(
agents=[self.researcher(), self.planner()],
tasks=[self.research_task(), self.planning_task()],
verbose=True,
process=Process.sequential
)
def main():
topic = sys.argv[1] if len(sys.argv) > 1 else "Inteligência Artificial na Saúde"
crew_instance = ResearchPlanningCrew()
# Atualizar descrições de tarefas com o tópico específico
crew_instance.research_task().description = f"Pesquise {topic} minuciosamente e compile informações abrangentes"
crew_instance.planning_task().description = f"Crie um plano estratégico para {topic} baseado nas descobertas da pesquisa"
result = crew_instance.crew().kickoff()
print(result)
if __name__ == "__main__":
main()
```
### Executando o Exemplo
```bash
python main.py "Soluções de Energia Sustentável"
```
## Visualizando Traces no LangDB
Após executar sua aplicação CrewAI, você pode visualizar traces detalhados no dashboard LangDB:
<Frame caption="Dashboard de Trace LangDB">
<img src="/images/langdb-2.png" alt="Dashboard de trace LangDB mostrando fluxo de trabalho CrewAI" />
</Frame>
### O Que Você Verá
- **Interações de Agentes**: Fluxo completo de conversas de agentes e transferências de tarefas
- **Uso de Ferramentas**: Quais ferramentas foram chamadas, suas entradas e saídas
- **Chamadas de Modelo**: Interações LLM detalhadas com prompts e respostas
- **Métricas de Performance**: Rastreamento de latência, uso de tokens e custos
- **Linha do Tempo de Execução**: Visualização passo a passo de todo o fluxo de trabalho
## Solução de Problemas
### Problemas Comuns
- **Nenhum trace aparecendo**: Certifique-se de que `init()` seja chamado antes de qualquer importação CrewAI
- **Erros de autenticação**: Verifique sua chave API LangDB e ID do projeto
## Recursos
<CardGroup cols={3}>
<Card title="Documentação LangDB" icon="book" href="https://docs.langdb.ai">
Documentação oficial e guias LangDB
</Card>
<Card title="Guias LangDB" icon="graduation-cap" href="https://docs.langdb.ai/guides">
Tutoriais passo a passo para construir agentes de IA
</Card>
<Card title="Exemplos GitHub" icon="github" href="https://github.com/langdb/langdb-samples/tree/main/examples/crewai" >
Exemplos completos de integração CrewAI
</Card>
<Card title="Dashboard LangDB" icon="chart-line" href="https://app.langdb.ai">
Acesse seus traces e análises
</Card>
<Card title="Catálogo de Modelos" icon="list" href="https://app.langdb.ai/models">
Navegue por mais de 350 modelos de linguagem disponíveis
</Card>
<Card title="Recursos Enterprise" icon="building" href="https://docs.langdb.ai/enterprise">
Opções auto-hospedadas e capacidades empresariais
</Card>
</CardGroup>
## Próximos Passos
Este guia cobriu o básico da integração do LangDB AI Gateway com CrewAI. Para aprimorar ainda mais seus fluxos de trabalho de IA, explore:
- **Modelos Virtuais**: Crie configurações de modelo personalizadas com estratégias de roteamento
- **Guardrails e Segurança**: Implemente filtragem de conteúdo e controles de conformidade
- **Implantação em Produção**: Configure fallbacks, tentativas e balanceamento de carga
Para recursos mais avançados e casos de uso, visite a [Documentação LangDB](https://docs.langdb.ai) ou explore o [Catálogo de Modelos](https://app.langdb.ai/models) para descobrir todos os modelos disponíveis.

View File

@@ -76,20 +76,20 @@ from crewai_tools import (
web_rag_tool = WebsiteSearchTool()
writer = Agent(
role="Writer",
goal="Você torna a matemática envolvente e compreensível para crianças pequenas através de poesias",
backstory="Você é especialista em escrever haicais mas não sabe nada de matemática.",
tools=[web_rag_tool],
)
escritor = Agent(
role="Escritor",
goal="Você torna a matemática envolvente e compreensível para crianças pequenas através de poesias",
backstory="Você é especialista em escrever haicais mas não sabe nada de matemática.",
tools=[web_rag_tool],
)
task = Task(description=("O que é {multiplicação}?"),
expected_output=("Componha um haicai que inclua a resposta."),
agent=writer)
tarefa = Task(description=("O que é {multiplicação}?"),
expected_output=("Componha um haicai que inclua a resposta."),
agent=escritor)
crew = Crew(
agents=[writer],
tasks=[task],
equipe = Crew(
agents=[escritor],
tasks=[tarefa],
share_crew=False
)
```

View File

@@ -35,7 +35,7 @@ Essa integração permite o registro de hiperparâmetros, o monitoramento de reg
```python
from langtrace_python_sdk import langtrace
langtrace.init(api_key='<LANGTRACE_API_KEY>')
langtrace.init(api_key='<SUA_CHAVE_LANGTRACE>')
# Agora importe os módulos do CrewAI
from crewai import Agent, Task, Crew

View File

@@ -73,26 +73,24 @@ instrument_crewai(logger)
### 4. Crie e execute sua aplicação CrewAI normalmente
```python
# Crie seu agente
researcher = Agent(
role='Senior Research Analyst',
goal='Uncover cutting-edge developments in AI',
backstory="You are an expert researcher at a tech think tank...",
pesquisador = Agent(
role='Pesquisador Sênior',
goal='Descobrir os avanços mais recentes em IA',
backstory="Você é um pesquisador especialista em um think tank de tecnologia...",
verbose=True,
llm=llm
)
# Defina a tarefa
research_task = Task(
description="Research the latest AI advancements...",
description="Pesquise os avanços mais recentes em IA...",
expected_output="",
agent=researcher
agent=pesquisador
)
# Configure e execute a crew
crew = Crew(
agents=[researcher],
agents=[pesquisador],
tasks=[research_task],
verbose=True
)

View File

@@ -70,22 +70,19 @@ O tracing fornece uma forma de registrar os inputs, outputs e metadados associad
class TripAgents:
def city_selection_agent(self):
return Agent(
role="City Selection Expert",
goal="Select the best city based on weather, season, and prices",
backstory="An expert in analyzing travel data to pick ideal destinations",
tools=[
search_tool,
],
especialista_cidades = Agent(
role="Especialista em Seleção de Cidades",
goal="Selecionar a melhor cidade com base no clima, estação e preços",
backstory="Especialista em analisar dados de viagem para escolher destinos ideais",
tools=[search_tool],
verbose=True,
)
def local_expert(self):
return Agent(
role="Local Expert at this city",
goal="Provide the BEST insights about the selected city",
backstory="""A knowledgeable local guide with extensive information
about the city, it's attractions and customs""",
especialista_local = Agent(
role="Especialista Local nesta cidade",
goal="Fornecer as MELHORES informações sobre a cidade selecionada",
backstory="Um guia local experiente com amplo conhecimento sobre a cidade, suas atrações e costumes",
tools=[search_tool],
verbose=True,
)
@@ -96,53 +93,36 @@ O tracing fornece uma forma de registrar os inputs, outputs e metadados associad
return Task(
description=dedent(
f"""
Analyze and select the best city for the trip based
on specific criteria such as weather patterns, seasonal
events, and travel costs. This task involves comparing
multiple cities, considering factors like current weather
conditions, upcoming cultural or seasonal events, and
overall travel expenses.
Your final answer must be a detailed
report on the chosen city, and everything you found out
about it, including the actual flight costs, weather
forecast and attractions.
Analise e selecione a melhor cidade para a viagem com base em critérios específicos como padrões climáticos, eventos sazonais e custos de viagem. Esta tarefa envolve comparar várias cidades, considerando fatores como condições climáticas atuais, eventos culturais ou sazonais e despesas gerais de viagem.
Sua resposta final deve ser um relatório detalhado sobre a cidade escolhida e tudo o que você descobriu sobre ela, incluindo custos reais de voo, previsão do tempo e atrações.
Traveling from: {origin}
City Options: {cities}
Trip Date: {range}
Traveler Interests: {interests}
Saindo de: {origin}
Opções de cidades: {cities}
Data da viagem: {range}
Interesses do viajante: {interests}
"""
),
agent=agent,
expected_output="Detailed report on the chosen city including flight costs, weather forecast, and attractions",
expected_output="Relatório detalhado sobre a cidade escolhida incluindo custos de voo, previsão do tempo e atrações",
)
def gather_task(self, agent, origin, interests, range):
return Task(
description=dedent(
f"""
As a local expert on this city you must compile an
in-depth guide for someone traveling there and wanting
to have THE BEST trip ever!
Gather information about key attractions, local customs,
special events, and daily activity recommendations.
Find the best spots to go to, the kind of place only a
local would know.
This guide should provide a thorough overview of what
the city has to offer, including hidden gems, cultural
hotspots, must-visit landmarks, weather forecasts, and
high level costs.
The final answer must be a comprehensive city guide,
rich in cultural insights and practical tips,
tailored to enhance the travel experience.
Como especialista local nesta cidade, você deve compilar um guia aprofundado para alguém que está viajando para lá e quer ter a MELHOR viagem possível!
Reúna informações sobre principais atrações, costumes locais, eventos especiais e recomendações de atividades diárias.
Encontre os melhores lugares para ir, aqueles que só um local conhece.
Este guia deve fornecer uma visão abrangente do que a cidade tem a oferecer, incluindo joias escondidas, pontos culturais, marcos imperdíveis, previsão do tempo e custos gerais.
A resposta final deve ser um guia completo da cidade, rico em insights culturais e dicas práticas, adaptado para aprimorar a experiência de viagem.
Trip Date: {range}
Traveling from: {origin}
Traveler Interests: {interests}
Data da viagem: {range}
Saindo de: {origin}
Interesses do viajante: {interests}
"""
),
agent=agent,
expected_output="Comprehensive city guide including hidden gems, cultural hotspots, and practical travel tips",
expected_output="Guia completo da cidade incluindo joias escondidas, pontos culturais e dicas práticas",
)
@@ -189,7 +169,7 @@ O tracing fornece uma forma de registrar os inputs, outputs e metadados associad
trip_crew = TripCrew("California", "Tokyo", "Dec 12 - Dec 20", "sports")
result = trip_crew.run()
print(result)
print("Resultado da equipe:", result)
```
Consulte a [Documentação de Tracing do MLflow](https://mlflow.org/docs/latest/llms/tracing/index.html) para mais configurações e casos de uso.
</Step>

View File

@@ -69,10 +69,10 @@ Essa configuração permite acompanhar hiperparâmetros e monitorar problemas de
openlit.init(disable_metrics=True)
# Definir seus agentes
researcher = Agent(
role="Researcher",
goal="Conduct thorough research and analysis on AI and AI agents",
backstory="You're an expert researcher, specialized in technology, software engineering, AI, and startups. You work as a freelancer and are currently researching for a new client.",
pesquisador = Agent(
role="Pesquisador",
goal="Realizar pesquisas e análises aprofundadas sobre IA e agentes de IA",
backstory="Você é um pesquisador especialista em tecnologia, engenharia de software, IA e startups. Trabalha como freelancer e está atualmente pesquisando para um novo cliente.",
allow_delegation=False,
llm='command-r'
)
@@ -80,24 +80,24 @@ Essa configuração permite acompanhar hiperparâmetros e monitorar problemas de
# Definir sua task
task = Task(
description="Generate a list of 5 interesting ideas for an article, then write one captivating paragraph for each idea that showcases the potential of a full article on this topic. Return the list of ideas with their paragraphs and your notes.",
expected_output="5 bullet points, each with a paragraph and accompanying notes.",
description="Gere uma lista com 5 ideias interessantes para um artigo e escreva um parágrafo cativante para cada ideia, mostrando o potencial de um artigo completo sobre o tema. Retorne a lista de ideias com seus parágrafos e suas anotações.",
expected_output="5 tópicos, cada um com um parágrafo e notas complementares.",
)
# Definir o agente gerente
manager = Agent(
role="Project Manager",
goal="Efficiently manage the crew and ensure high-quality task completion",
backstory="You're an experienced project manager, skilled in overseeing complex projects and guiding teams to success. Your role is to coordinate the efforts of the crew members, ensuring that each task is completed on time and to the highest standard.",
gerente = Agent(
role="Gerente de Projeto",
goal="Gerenciar eficientemente a equipe e garantir a conclusão de tarefas de alta qualidade",
backstory="Você é um gerente de projetos experiente, habilidoso em supervisionar projetos complexos e guiar equipes para o sucesso. Sua função é coordenar os esforços dos membros da equipe, garantindo que cada tarefa seja concluída no prazo e com o mais alto padrão.",
allow_delegation=True,
llm='command-r'
)
# Instanciar sua crew com um manager personalizado
crew = Crew(
agents=[researcher],
agents=[pesquisador],
tasks=[task],
manager_agent=manager,
manager_agent=gerente,
process=Process.hierarchical,
)
@@ -132,18 +132,18 @@ Essa configuração permite acompanhar hiperparâmetros e monitorar problemas de
# Criar um agente com execução de código habilitada
coding_agent = Agent(
role="Python Data Analyst",
goal="Analyze data and provide insights using Python",
backstory="You are an experienced data analyst with strong Python skills.",
role="Analista de Dados Python",
goal="Analisar dados e fornecer insights usando Python",
backstory="Você é um analista de dados experiente com fortes habilidades em Python.",
allow_code_execution=True,
llm="command-r"
)
# Criar uma task que exige execução de código
data_analysis_task = Task(
description="Analyze the given dataset and calculate the average age of participants. Ages: {ages}",
description="Analise o conjunto de dados fornecido e calcule a idade média dos participantes. Idades: {ages}",
agent=coding_agent,
expected_output="5 bullet points, each with a paragraph and accompanying notes.",
expected_output="5 tópicos, cada um com um parágrafo e notas complementares.",
)
# Criar uma crew e adicionar a task

View File

@@ -58,43 +58,43 @@ Neste guia, utilizaremos o exemplo de início rápido da CrewAI.
from crewai import Agent, Crew, Task, Process
class YourCrewName:
def agent_one(self) -> Agent:
class NomeDaEquipe:
def agente_um(self) -> Agent:
return Agent(
role="Data Analyst",
goal="Analyze data trends in the market",
backstory="An experienced data analyst with a background in economics",
role="Analista de Dados",
goal="Analisar tendências de dados no mercado",
backstory="Analista de dados experiente com formação em economia",
verbose=True,
)
def agent_two(self) -> Agent:
def agente_dois(self) -> Agent:
return Agent(
role="Market Researcher",
goal="Gather information on market dynamics",
backstory="A diligent researcher with a keen eye for detail",
role="Pesquisador de Mercado",
goal="Coletar informações sobre a dinâmica do mercado",
backstory="Pesquisador dedicado com olhar atento para detalhes",
verbose=True,
)
def task_one(self) -> Task:
def tarefa_um(self) -> Task:
return Task(
name="Collect Data Task",
description="Collect recent market data and identify trends.",
expected_output="A report summarizing key trends in the market.",
agent=self.agent_one(),
name="Tarefa de Coleta de Dados",
description="Coletar dados recentes do mercado e identificar tendências.",
expected_output="Um relatório resumindo as principais tendências do mercado.",
agent=self.agente_um(),
)
def task_two(self) -> Task:
def tarefa_dois(self) -> Task:
return Task(
name="Market Research Task",
description="Research factors affecting market dynamics.",
expected_output="An analysis of factors influencing the market.",
agent=self.agent_two(),
name="Tarefa de Pesquisa de Mercado",
description="Pesquisar fatores que afetam a dinâmica do mercado.",
expected_output="Uma análise dos fatores que influenciam o mercado.",
agent=self.agente_dois(),
)
def crew(self) -> Crew:
def equipe(self) -> Crew:
return Crew(
agents=[self.agent_one(), self.agent_two()],
tasks=[self.task_one(), self.task_two()],
agents=[self.agente_um(), self.agente_dois()],
tasks=[self.tarefa_um(), self.tarefa_dois()],
process=Process.sequential,
verbose=True,
)
@@ -108,7 +108,7 @@ Neste guia, utilizaremos o exemplo de início rápido da CrewAI.
track_crewai(project_name="crewai-integration-demo")
my_crew = YourCrewName().crew()
my_crew = NomeDaEquipe().equipe()
result = my_crew.kickoff()
print(result)

View File

@@ -25,6 +25,10 @@ A observabilidade é fundamental para entender como seus agentes CrewAI estão d
Replays de sessões, métricas e monitoramento para desenvolvimento e produção de agentes.
</Card>
<Card title="LangDB" icon="database" href="/pt-BR/observability/langdb">
Rastreamento ponta a ponta para fluxos de trabalho CrewAI com captura automática de interações de agentes.
</Card>
<Card title="OpenLIT" icon="magnifying-glass-chart" href="/pt-BR/observability/openlit">
Monitoramento nativo OpenTelemetry com rastreamento de custos e análises de desempenho.
</Card>

View File

@@ -64,17 +64,17 @@ patronus_eval_tool = PatronusEvalTool()
# Define an agent that uses the tool
coding_agent = Agent(
role="Coding Agent",
goal="Generate high quality code and verify that the output is code",
backstory="An experienced coder who can generate high quality python code.",
role="Agente de Programação",
goal="Gerar código de alta qualidade e verificar se a saída é código",
backstory="Um programador experiente que pode gerar código Python de alta qualidade.",
tools=[patronus_eval_tool],
verbose=True,
)
# Example task to generate and evaluate code
generate_code_task = Task(
description="Create a simple program to generate the first N numbers in the Fibonacci sequence. Select the most appropriate evaluator and criteria for evaluating your output.",
expected_output="Program that generates the first N numbers in the Fibonacci sequence.",
description="Crie um programa simples para gerar os N primeiros números da sequência de Fibonacci. Selecione o avaliador e os critérios mais apropriados para avaliar sua saída.",
expected_output="Programa que gera os N primeiros números da sequência de Fibonacci.",
agent=coding_agent,
)
@@ -98,17 +98,17 @@ patronus_eval_tool = PatronusPredefinedCriteriaEvalTool(
# Define an agent that uses the tool
coding_agent = Agent(
role="Coding Agent",
goal="Generate high quality code",
backstory="An experienced coder who can generate high quality python code.",
role="Agente de Programação",
goal="Gerar código de alta qualidade",
backstory="Um programador experiente que pode gerar código Python de alta qualidade.",
tools=[patronus_eval_tool],
verbose=True,
)
# Example task to generate code
generate_code_task = Task(
description="Create a simple program to generate the first N numbers in the Fibonacci sequence.",
expected_output="Program that generates the first N numbers in the Fibonacci sequence.",
description="Crie um programa simples para gerar os N primeiros números da sequência de Fibonacci.",
expected_output="Programa que gera os N primeiros números da sequência de Fibonacci.",
agent=coding_agent,
)
@@ -149,17 +149,17 @@ patronus_eval_tool = PatronusLocalEvaluatorTool(
# Define an agent that uses the tool
coding_agent = Agent(
role="Coding Agent",
goal="Generate high quality code",
backstory="An experienced coder who can generate high quality python code.",
role="Agente de Programação",
goal="Gerar código de alta qualidade",
backstory="Um programador experiente que pode gerar código Python de alta qualidade.",
tools=[patronus_eval_tool],
verbose=True,
)
# Example task to generate code
generate_code_task = Task(
description="Create a simple program to generate the first N numbers in the Fibonacci sequence.",
expected_output="Program that generates the first N numbers in the Fibonacci sequence.",
description="Crie um programa simples para gerar os N primeiros números da sequência de Fibonacci.",
expected_output="Programa que gera os N primeiros números da sequência de Fibonacci.",
agent=coding_agent,
)

View File

@@ -50,48 +50,48 @@ O Weave captura automaticamente rastreamentos (traces) de suas aplicações Crew
llm = LLM(model="gpt-4o", temperature=0)
# Crie os agentes
researcher = Agent(
role='Research Analyst',
goal='Find and analyze the best investment opportunities',
backstory='Expert in financial analysis and market research',
pesquisador = Agent(
role='Analista de Pesquisa',
goal='Encontrar e analisar as melhores oportunidades de investimento',
backstory='Especialista em análise financeira e pesquisa de mercado',
llm=llm,
verbose=True,
allow_delegation=False,
)
writer = Agent(
role='Report Writer',
goal='Write clear and concise investment reports',
backstory='Experienced in creating detailed financial reports',
redator = Agent(
role='Redator de Relatórios',
goal='Escrever relatórios de investimento claros e concisos',
backstory='Experiente na criação de relatórios financeiros detalhados',
llm=llm,
verbose=True,
allow_delegation=False,
)
# Crie as tarefas
research_task = Task(
description='Deep research on the {topic}',
expected_output='Comprehensive market data including key players, market size, and growth trends.',
agent=researcher
pesquisa = Task(
description='Pesquisa aprofundada sobre o {tema}',
expected_output='Dados de mercado abrangentes incluindo principais players, tamanho de mercado e tendências de crescimento.',
agent=pesquisador
)
writing_task = Task(
description='Write a detailed report based on the research',
expected_output='The report should be easy to read and understand. Use bullet points where applicable.',
agent=writer
redacao = Task(
description='Escreva um relatório detalhado com base na pesquisa',
expected_output='O relatório deve ser fácil de ler e entender. Use tópicos quando aplicável.',
agent=redator
)
# Crie o crew
crew = Crew(
agents=[researcher, writer],
tasks=[research_task, writing_task],
equipe = Crew(
agents=[pesquisador, redator],
tasks=[pesquisa, redacao],
verbose=True,
process=Process.sequential,
)
# Execute o crew
result = crew.kickoff(inputs={"topic": "AI in material science"})
print(result)
resultado = equipe.kickoff(inputs={"tema": "IA em ciência dos materiais"})
print(resultado)
```
</Step>
<Step title="Visualize rastreamentos no Weave">

View File

@@ -39,23 +39,19 @@ Siga os passos abaixo para começar a tripular! 🚣‍♂️
# src/latest_ai_development/config/agents.yaml
researcher:
role: >
{topic} Senior Data Researcher
Pesquisador Sênior de Dados em {topic}
goal: >
Uncover cutting-edge developments in {topic}
Descobrir os avanços mais recentes em {topic}
backstory: >
You're a seasoned researcher with a knack for uncovering the latest
developments in {topic}. Known for your ability to find the most relevant
information and present it in a clear and concise manner.
Você é um pesquisador experiente com talento para descobrir os últimos avanços em {topic}. Conhecido por sua habilidade em encontrar as informações mais relevantes e apresentá-las de forma clara e concisa.
reporting_analyst:
role: >
{topic} Reporting Analyst
Analista de Relatórios em {topic}
goal: >
Create detailed reports based on {topic} data analysis and research findings
Criar relatórios detalhados com base na análise de dados e descobertas de pesquisa em {topic}
backstory: >
You're a meticulous analyst with a keen eye for detail. You're known for
your ability to turn complex data into clear and concise reports, making
it easy for others to understand and act on the information you provide.
Você é um analista meticuloso com um olhar atento aos detalhes. É conhecido por sua capacidade de transformar dados complexos em relatórios claros e concisos, facilitando o entendimento e a tomada de decisão por parte dos outros.
```
</Step>
<Step title="Modifique seu arquivo `tasks.yaml`">
@@ -63,20 +59,19 @@ Siga os passos abaixo para começar a tripular! 🚣‍♂️
# src/latest_ai_development/config/tasks.yaml
research_task:
description: >
Conduct a thorough research about {topic}
Make sure you find any interesting and relevant information given
the current year is 2025.
Realize uma pesquisa aprofundada sobre {topic}.
Certifique-se de encontrar informações interessantes e relevantes considerando que o ano atual é 2025.
expected_output: >
A list with 10 bullet points of the most relevant information about {topic}
Uma lista com 10 tópicos dos dados mais relevantes sobre {topic}
agent: researcher
reporting_task:
description: >
Review the context you got and expand each topic into a full section for a report.
Make sure the report is detailed and contains any and all relevant information.
Revise o contexto obtido e expanda cada tópico em uma seção completa para um relatório.
Certifique-se de que o relatório seja detalhado e contenha todas as informações relevantes.
expected_output: >
A fully fledge reports with the mains topics, each with a full section of information.
Formatted as markdown without '```'
Um relatório completo com os principais tópicos, cada um com uma seção detalhada de informações.
Formate como markdown sem usar '```'
agent: reporting_analyst
output_file: report.md
```
@@ -122,15 +117,15 @@ Siga os passos abaixo para começar a tripular! 🚣‍♂️
def reporting_task(self) -> Task:
return Task(
config=self.tasks_config['reporting_task'], # type: ignore[index]
output_file='output/report.md' # This is the file that will be contain the final report.
output_file='output/report.md' # Este é o arquivo que conterá o relatório final.
)
@crew
def crew(self) -> Crew:
"""Creates the LatestAiDevelopment crew"""
return Crew(
agents=self.agents, # Automatically created by the @agent decorator
tasks=self.tasks, # Automatically created by the @task decorator
agents=self.agents, # Criado automaticamente pelo decorador @agent
tasks=self.tasks, # Criado automaticamente pelo decorador @task
process=Process.sequential,
verbose=True,
)
@@ -229,7 +224,7 @@ Siga os passos abaixo para começar a tripular! 🚣‍♂️
<CodeGroup>
```markdown output/report.md
# Comprehensive Report on the Rise and Impact of AI Agents in 2025
# Relatório Abrangente sobre a Ascensão e o Impacto dos Agentes de IA em 2025
## 1. Introduction to AI Agents
In 2025, Artificial Intelligence (AI) agents are at the forefront of innovation across various industries. As intelligent systems that can perform tasks typically requiring human cognition, AI agents are paving the way for significant advancements in operational efficiency, decision-making, and overall productivity within sectors like Human Resources (HR) and Finance. This report aims to detail the rise of AI agents, their frameworks, applications, and potential implications on the workforce.

View File

@@ -35,78 +35,18 @@ from crewai_tools import LinkupSearchTool
from crewai import Agent
import os
# Initialize the tool with your API key
linkup_tool = LinkupSearchTool(api_key=os.getenv("LINKUP_API_KEY"))
# Inicialize a ferramenta com sua chave de API
linkup_ferramenta = LinkupSearchTool(api_key=os.getenv("LINKUP_API_KEY"))
# Define an agent that uses the tool
# Defina um agente que usa a ferramenta
@agent
def researcher(self) -> Agent:
def pesquisador(self) -> Agent:
'''
This agent uses the LinkupSearchTool to retrieve contextual information
from the Linkup API.
Este agente usa o LinkupSearchTool para recuperar informações contextuais
da API do Linkup.
'''
return Agent(
config=self.agents_config["researcher"],
tools=[linkup_tool]
config=self.agentes_config["pesquisador"],
tools=[linkup_ferramenta]
)
```
## Parâmetros
O `LinkupSearchTool` aceita os seguintes parâmetros:
### Parâmetros do Construtor
- **api_key**: Obrigatório. Sua chave de API do Linkup.
### Parâmetros de Execução
- **query**: Obrigatório. O termo ou frase de busca.
- **depth**: Opcional. A profundidade da busca. O padrão é "standard".
- **output_type**: Opcional. O tipo de saída. O padrão é "searchResults".
## Uso Avançado
Você pode personalizar os parâmetros de busca para resultados mais específicos:
```python Code
# Perform a search with custom parameters
results = linkup_tool.run(
query="Women Nobel Prize Physics",
depth="deep",
output_type="searchResults"
)
```
## Formato de Retorno
A ferramenta retorna resultados no seguinte formato:
```json
{
"success": true,
"results": [
{
"name": "Result Title",
"url": "https://example.com/result",
"content": "Content of the result..."
},
// Additional results...
]
}
```
Se ocorrer um erro, a resposta será:
```json
{
"success": false,
"error": "Error message"
}
```
## Tratamento de Erros
A ferramenta lida com erros de API de forma amigável e fornece feedback estruturado. Se a requisição à API falhar, a ferramenta retornará um dicionário com `success: false` e uma mensagem de erro.
## Conclusão
O `LinkupSearchTool` oferece uma forma integrada de incorporar as capacidades de busca de informações contextuais do Linkup aos seus agentes CrewAI. Ao utilizar esta ferramenta, os agentes podem acessar informações relevantes e atualizadas para aprimorar sua tomada de decisão e execução de tarefas.
```

View File

@@ -11,7 +11,7 @@ dependencies = [
# Core Dependencies
"pydantic>=2.4.2",
"openai>=1.13.3",
"litellm==1.72.6",
"litellm==1.74.9",
"instructor>=1.3.3",
# Text Processing
"pdfplumber>=0.11.4",
@@ -27,18 +27,19 @@ dependencies = [
"openpyxl>=3.1.5",
"pyvis>=0.3.2",
# Authentication and Security
"auth0-python>=4.7.1",
"python-dotenv>=1.0.0",
"pyjwt>=2.9.0",
# Configuration and Utils
"click>=8.1.7",
"appdirs>=1.4.4",
"jsonref>=1.1.0",
"json-repair>=0.25.2",
"json-repair==0.25.2",
"uv>=0.4.25",
"tomli-w>=1.1.0",
"tomli>=2.0.2",
"blinker>=1.9.0",
"json5>=0.10.0",
"portalocker==2.7.0",
]
[project.urls]
@@ -47,11 +48,11 @@ Documentation = "https://docs.crewai.com"
Repository = "https://github.com/crewAIInc/crewAI"
[project.optional-dependencies]
tools = ["crewai-tools~=0.48.0"]
tools = ["crewai-tools~=0.60.0"]
embeddings = [
"tiktoken~=0.8.0"
]
agentops = ["agentops>=0.3.0"]
agentops = ["agentops==0.3.18"]
pdfplumber = [
"pdfplumber>=0.11.4",
]
@@ -83,6 +84,8 @@ dev-dependencies = [
"pytest-recording>=0.13.2",
"pytest-randomly>=3.16.0",
"pytest-timeout>=2.3.1",
"pytest-xdist>=3.6.1",
"pytest-split>=0.9.0",
]
[project.scripts]
@@ -123,3 +126,15 @@ path = "src/crewai/__init__.py"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
exclude = [
"docs/**",
"docs/",
]
[tool.hatch.build.targets.sdist]
exclude = [
"docs/**",
"docs/",
]

View File

@@ -28,19 +28,19 @@ _telemetry_submitted = False
def _track_install():
"""Track package installation/first-use via Scarf analytics."""
global _telemetry_submitted
if _telemetry_submitted or Telemetry._is_telemetry_disabled():
return
try:
pixel_url = "https://api.scarf.sh/v2/packages/CrewAI/crewai/docs/00f2dad1-8334-4a39-934e-003b2e1146db"
req = urllib.request.Request(pixel_url)
req.add_header('User-Agent', f'CrewAI-Python/{__version__}')
with urllib.request.urlopen(req, timeout=2): # nosec B310
_telemetry_submitted = True
except Exception:
pass
@@ -54,7 +54,7 @@ def _track_install_async():
_track_install_async()
__version__ = "0.134.0"
__version__ = "0.157.0"
__all__ = [
"Agent",
"Crew",

View File

@@ -210,7 +210,6 @@ class Agent(BaseAgent):
sources=self.knowledge_sources,
embedder=self.embedder,
collection_name=self.role,
storage=self.knowledge_storage or None,
)
self.knowledge.add_sources()
except (TypeError, ValueError) as e:
@@ -223,11 +222,9 @@ class Agent(BaseAgent):
memory_attributes = [
"memory",
"memory_config",
"_short_term_memory",
"_long_term_memory",
"_entity_memory",
"_user_memory",
"_external_memory",
]
@@ -317,11 +314,9 @@ class Agent(BaseAgent):
start_time = time.time()
contextual_memory = ContextualMemory(
self.crew.memory_config,
self.crew._short_term_memory,
self.crew._long_term_memory,
self.crew._entity_memory,
self.crew._user_memory,
self.crew._external_memory,
)
memory = contextual_memory.build_context_for_task(task, context)
@@ -341,7 +336,8 @@ class Agent(BaseAgent):
self.knowledge_config.model_dump() if self.knowledge_config else {}
)
if self.knowledge:
if self.knowledge or (self.crew and self.crew.knowledge):
crewai_event_bus.emit(
self,
event=KnowledgeRetrievalStartedEvent(
@@ -353,25 +349,28 @@ class Agent(BaseAgent):
task_prompt
)
if self.knowledge_search_query:
agent_knowledge_snippets = self.knowledge.query(
[self.knowledge_search_query], **knowledge_config
)
if agent_knowledge_snippets:
self.agent_knowledge_context = extract_knowledge_context(
agent_knowledge_snippets
)
if self.agent_knowledge_context:
task_prompt += self.agent_knowledge_context
if self.crew:
knowledge_snippets = self.crew.query_knowledge(
# Quering agent specific knowledge
if self.knowledge:
agent_knowledge_snippets = self.knowledge.query(
[self.knowledge_search_query], **knowledge_config
)
if knowledge_snippets:
self.crew_knowledge_context = extract_knowledge_context(
knowledge_snippets
if agent_knowledge_snippets:
self.agent_knowledge_context = extract_knowledge_context(
agent_knowledge_snippets
)
if self.crew_knowledge_context:
task_prompt += self.crew_knowledge_context
if self.agent_knowledge_context:
task_prompt += self.agent_knowledge_context
# Quering crew specific knowledge
knowledge_snippets = self.crew.query_knowledge(
[self.knowledge_search_query], **knowledge_config
)
if knowledge_snippets:
self.crew_knowledge_context = extract_knowledge_context(
knowledge_snippets
)
if self.crew_knowledge_context:
task_prompt += self.crew_knowledge_context
crewai_event_bus.emit(
self,

View File

@@ -120,11 +120,8 @@ class CrewAgentExecutor(CrewAgentExecutorMixin):
raise
except Exception as e:
handle_unknown_error(self._printer, e)
if e.__class__.__module__.startswith("litellm"):
# Do not retry on litellm errors
raise e
else:
raise e
raise
if self.ask_for_human_input:
formatted_answer = self._handle_human_feedback(formatted_answer)

View File

@@ -1,4 +1,6 @@
ALGORITHMS = ["RS256"]
#TODO: The AUTH0 constants should be removed after WorkOS migration is completed
AUTH0_DOMAIN = "crewai.us.auth0.com"
AUTH0_CLIENT_ID = "DEVC5Fw6NlRoSzmDCcOhVq85EfLBjKa8"
AUTH0_AUDIENCE = "https://crewai.us.auth0.com/api/v2/"

View File

@@ -1,41 +1,92 @@
import time
import webbrowser
from typing import Any, Dict
from typing import Any, Dict, Optional
import requests
from rich.console import Console
from pydantic import BaseModel, Field
from .constants import AUTH0_AUDIENCE, AUTH0_CLIENT_ID, AUTH0_DOMAIN
from .utils import TokenManager, validate_token
from .utils import TokenManager, validate_jwt_token
from urllib.parse import quote
from crewai.cli.plus_api import PlusAPI
from crewai.cli.config import Settings
from crewai.cli.authentication.constants import (
AUTH0_AUDIENCE,
AUTH0_CLIENT_ID,
AUTH0_DOMAIN,
)
console = Console()
class AuthenticationCommand:
DEVICE_CODE_URL = f"https://{AUTH0_DOMAIN}/oauth/device/code"
TOKEN_URL = f"https://{AUTH0_DOMAIN}/oauth/token"
class Oauth2Settings(BaseModel):
provider: str = Field(description="OAuth2 provider used for authentication (e.g., workos, okta, auth0).")
client_id: str = Field(description="OAuth2 client ID issued by the provider, used during authentication requests.")
domain: str = Field(description="OAuth2 provider's domain (e.g., your-org.auth0.com) used for issuing tokens.")
audience: Optional[str] = Field(description="OAuth2 audience value, typically used to identify the target API or resource.", default=None)
@classmethod
def from_settings(cls):
settings = Settings()
return cls(
provider=settings.oauth2_provider,
domain=settings.oauth2_domain,
client_id=settings.oauth2_client_id,
audience=settings.oauth2_audience,
)
class ProviderFactory:
@classmethod
def from_settings(cls, settings: Optional[Oauth2Settings] = None):
settings = settings or Oauth2Settings.from_settings()
import importlib
module = importlib.import_module(f"crewai.cli.authentication.providers.{settings.provider.lower()}")
provider = getattr(module, f"{settings.provider.capitalize()}Provider")
return provider(settings)
class AuthenticationCommand:
def __init__(self):
self.token_manager = TokenManager()
self.oauth2_provider = ProviderFactory.from_settings()
def signup(self) -> None:
def login(self) -> None:
"""Sign up to CrewAI+"""
console.print("Signing Up to CrewAI+ \n", style="bold blue")
console.print("Signing in to CrewAI Enterprise...\n", style="bold blue")
# TODO: WORKOS - Next line and conditional are temporary until migration to WorkOS is complete.
user_provider = self._determine_user_provider()
if user_provider == "auth0":
settings = Oauth2Settings(
provider="auth0",
client_id=AUTH0_CLIENT_ID,
domain=AUTH0_DOMAIN,
audience=AUTH0_AUDIENCE
)
self.oauth2_provider = ProviderFactory.from_settings(settings)
# End of temporary code.
device_code_data = self._get_device_code()
self._display_auth_instructions(device_code_data)
return self._poll_for_token(device_code_data)
def _get_device_code(self) -> Dict[str, Any]:
def _get_device_code(
self
) -> Dict[str, Any]:
"""Get the device code to authenticate the user."""
device_code_payload = {
"client_id": AUTH0_CLIENT_ID,
"client_id": self.oauth2_provider.get_client_id(),
"scope": "openid",
"audience": AUTH0_AUDIENCE,
"audience": self.oauth2_provider.get_audience(),
}
response = requests.post(
url=self.DEVICE_CODE_URL, data=device_code_payload, timeout=20
url=self.oauth2_provider.get_authorize_url(), data=device_code_payload, timeout=20
)
response.raise_for_status()
return response.json()
@@ -46,38 +97,33 @@ class AuthenticationCommand:
console.print("2. Enter the following code: ", device_code_data["user_code"])
webbrowser.open(device_code_data["verification_uri_complete"])
def _poll_for_token(self, device_code_data: Dict[str, Any]) -> None:
"""Poll the server for the token."""
def _poll_for_token(
self, device_code_data: Dict[str, Any]
) -> None:
"""Polls the server for the token until it is received, or max attempts are reached."""
token_payload = {
"grant_type": "urn:ietf:params:oauth:grant-type:device_code",
"device_code": device_code_data["device_code"],
"client_id": AUTH0_CLIENT_ID,
"client_id": self.oauth2_provider.get_client_id(),
}
console.print("\nWaiting for authentication... ", style="bold blue", end="")
attempts = 0
while True and attempts < 5:
response = requests.post(self.TOKEN_URL, data=token_payload, timeout=30)
while True and attempts < 10:
response = requests.post(self.oauth2_provider.get_token_url(), data=token_payload, timeout=30)
token_data = response.json()
if response.status_code == 200:
validate_token(token_data["id_token"])
expires_in = 360000 # Token expiration time in seconds
self.token_manager.save_tokens(token_data["access_token"], expires_in)
self._validate_and_save_token(token_data)
try:
from crewai.cli.tools.main import ToolCommand
ToolCommand().login()
except Exception:
console.print(
"\n[bold yellow]Warning:[/bold yellow] Authentication with the Tool Repository failed.",
style="yellow",
)
console.print(
"Other features will work normally, but you may experience limitations "
"with downloading and publishing tools."
"\nRun [bold]crewai login[/bold] to try logging in again.\n",
style="yellow",
)
console.print(
"Success!",
style="bold green",
)
self._login_to_tool_repository()
console.print(
"\n[bold green]Welcome to CrewAI Enterprise![/bold green]\n"
@@ -93,3 +139,83 @@ class AuthenticationCommand:
console.print(
"Timeout: Failed to get the token. Please try again.", style="bold red"
)
def _validate_and_save_token(self, token_data: Dict[str, Any]) -> None:
"""Validates the JWT token and saves the token to the token manager."""
jwt_token = token_data["access_token"]
issuer = self.oauth2_provider.get_issuer()
jwt_token_data = {
"jwt_token": jwt_token,
"jwks_url": self.oauth2_provider.get_jwks_url(),
"issuer": issuer,
"audience": self.oauth2_provider.get_audience(),
}
decoded_token = validate_jwt_token(**jwt_token_data)
expires_at = decoded_token.get("exp", 0)
self.token_manager.save_tokens(jwt_token, expires_at)
def _login_to_tool_repository(self) -> None:
"""Login to the tool repository."""
from crewai.cli.tools.main import ToolCommand
try:
console.print(
"Now logging you in to the Tool Repository... ",
style="bold blue",
end="",
)
ToolCommand().login()
console.print(
"Success!\n",
style="bold green",
)
settings = Settings()
console.print(
f"You are authenticated to the tool repository as [bold cyan]'{settings.org_name}'[/bold cyan] ({settings.org_uuid})",
style="green",
)
except Exception:
console.print(
"\n[bold yellow]Warning:[/bold yellow] Authentication with the Tool Repository failed.",
style="yellow",
)
console.print(
"Other features will work normally, but you may experience limitations "
"with downloading and publishing tools."
"\nRun [bold]crewai login[/bold] to try logging in again.\n",
style="yellow",
)
# TODO: WORKOS - This method is temporary until migration to WorkOS is complete.
def _determine_user_provider(self) -> str:
"""Determine which provider to use for authentication."""
console.print(
"Enter your CrewAI Enterprise account email: ", style="bold blue", end=""
)
email = input()
email_encoded = quote(email)
# It's not correct to call this method directly, but it's temporary until migration is complete.
response = PlusAPI("")._make_request(
"GET", f"/crewai_plus/api/v1/me/provider?email={email_encoded}"
)
if response.status_code == 200:
if response.json().get("provider") == "auth0":
return "auth0"
else:
return "workos"
else:
console.print(
"Error: Failed to authenticate with crewai enterprise. Ensure that you are using the latest crewai version and please try again. If the problem persists, contact support@crewai.com.",
style="red",
)
raise SystemExit

View File

@@ -0,0 +1,26 @@
from crewai.cli.authentication.providers.base_provider import BaseProvider
class Auth0Provider(BaseProvider):
def get_authorize_url(self) -> str:
return f"https://{self._get_domain()}/oauth/device/code"
def get_token_url(self) -> str:
return f"https://{self._get_domain()}/oauth/token"
def get_jwks_url(self) -> str:
return f"https://{self._get_domain()}/.well-known/jwks.json"
def get_issuer(self) -> str:
return f"https://{self._get_domain()}/"
def get_audience(self) -> str:
assert self.settings.audience is not None, "Audience is required"
return self.settings.audience
def get_client_id(self) -> str:
assert self.settings.client_id is not None, "Client ID is required"
return self.settings.client_id
def _get_domain(self) -> str:
assert self.settings.domain is not None, "Domain is required"
return self.settings.domain

View File

@@ -0,0 +1,30 @@
from abc import ABC, abstractmethod
from crewai.cli.authentication.main import Oauth2Settings
class BaseProvider(ABC):
def __init__(self, settings: Oauth2Settings):
self.settings = settings
@abstractmethod
def get_authorize_url(self) -> str:
...
@abstractmethod
def get_token_url(self) -> str:
...
@abstractmethod
def get_jwks_url(self) -> str:
...
@abstractmethod
def get_issuer(self) -> str:
...
@abstractmethod
def get_audience(self) -> str:
...
@abstractmethod
def get_client_id(self) -> str:
...

View File

@@ -0,0 +1,22 @@
from crewai.cli.authentication.providers.base_provider import BaseProvider
class OktaProvider(BaseProvider):
def get_authorize_url(self) -> str:
return f"https://{self.settings.domain}/oauth2/default/v1/device/authorize"
def get_token_url(self) -> str:
return f"https://{self.settings.domain}/oauth2/default/v1/token"
def get_jwks_url(self) -> str:
return f"https://{self.settings.domain}/oauth2/default/v1/keys"
def get_issuer(self) -> str:
return f"https://{self.settings.domain}/oauth2/default"
def get_audience(self) -> str:
assert self.settings.audience is not None
return self.settings.audience
def get_client_id(self) -> str:
assert self.settings.client_id is not None
return self.settings.client_id

View File

@@ -0,0 +1,25 @@
from crewai.cli.authentication.providers.base_provider import BaseProvider
class WorkosProvider(BaseProvider):
def get_authorize_url(self) -> str:
return f"https://{self._get_domain()}/oauth2/device_authorization"
def get_token_url(self) -> str:
return f"https://{self._get_domain()}/oauth2/token"
def get_jwks_url(self) -> str:
return f"https://{self._get_domain()}/oauth2/jwks"
def get_issuer(self) -> str:
return f"https://{self._get_domain()}"
def get_audience(self) -> str:
return self.settings.audience or ""
def get_client_id(self) -> str:
assert self.settings.client_id is not None, "Client ID is required"
return self.settings.client_id
def _get_domain(self) -> str:
assert self.settings.domain is not None, "Domain is required"
return self.settings.domain

View File

@@ -1,32 +1,72 @@
import json
import os
import sys
from datetime import datetime, timedelta
from datetime import datetime
from pathlib import Path
from typing import Optional
from auth0.authentication.token_verifier import (
AsymmetricSignatureVerifier,
TokenVerifier,
)
import jwt
from jwt import PyJWKClient
from cryptography.fernet import Fernet
from .constants import AUTH0_CLIENT_ID, AUTH0_DOMAIN
def validate_token(id_token: str) -> None:
def validate_jwt_token(
jwt_token: str, jwks_url: str, issuer: str, audience: str
) -> dict:
"""
Verify the token and its precedence
:param id_token:
Verify the token's signature and claims using PyJWT.
:param jwt_token: The JWT (JWS) string to validate.
:param jwks_url: The URL of the JWKS endpoint.
:param issuer: The expected issuer of the token.
:param audience: The expected audience of the token.
:return: The decoded token.
:raises Exception: If the token is invalid for any reason (e.g., signature mismatch,
expired, incorrect issuer/audience, JWKS fetching error,
missing required claims).
"""
jwks_url = f"https://{AUTH0_DOMAIN}/.well-known/jwks.json"
issuer = f"https://{AUTH0_DOMAIN}/"
signature_verifier = AsymmetricSignatureVerifier(jwks_url)
token_verifier = TokenVerifier(
signature_verifier=signature_verifier, issuer=issuer, audience=AUTH0_CLIENT_ID
)
token_verifier.verify(id_token)
decoded_token = None
try:
jwk_client = PyJWKClient(jwks_url)
signing_key = jwk_client.get_signing_key_from_jwt(jwt_token)
_unverified_decoded_token = jwt.decode(
jwt_token, options={"verify_signature": False}
)
decoded_token = jwt.decode(
jwt_token,
signing_key.key,
algorithms=["RS256"],
audience=audience,
issuer=issuer,
options={
"verify_signature": True,
"verify_exp": True,
"verify_nbf": True,
"verify_iat": True,
"require": ["exp", "iat", "iss", "aud", "sub"],
},
)
return decoded_token
except jwt.ExpiredSignatureError:
raise Exception("Token has expired.")
except jwt.InvalidAudienceError:
actual_audience = _unverified_decoded_token.get("aud", "[no audience found]")
raise Exception(
f"Invalid token audience. Got: '{actual_audience}'. Expected: '{audience}'"
)
except jwt.InvalidIssuerError:
actual_issuer = _unverified_decoded_token.get("iss", "[no issuer found]")
raise Exception(
f"Invalid token issuer. Got: '{actual_issuer}'. Expected: '{issuer}'"
)
except jwt.MissingRequiredClaimError as e:
raise Exception(f"Token is missing required claims: {str(e)}")
except jwt.exceptions.PyJWKClientError as e:
raise Exception(f"JWKS or key processing error: {str(e)}")
except jwt.InvalidTokenError as e:
raise Exception(f"Invalid token: {str(e)}")
class TokenManager:
@@ -56,14 +96,14 @@ class TokenManager:
self.save_secure_file(key_filename, new_key)
return new_key
def save_tokens(self, access_token: str, expires_in: int) -> None:
def save_tokens(self, access_token: str, expires_at: int) -> None:
"""
Save the access token and its expiration time.
:param access_token: The access token to save.
:param expires_in: The expiration time of the access token in seconds.
:param expires_at: The UNIX timestamp of the expiration time.
"""
expiration_time = datetime.now() + timedelta(seconds=expires_in)
expiration_time = datetime.fromtimestamp(expires_at)
data = {
"access_token": access_token,
"expiration": expiration_time.isoformat(),

View File

@@ -2,7 +2,8 @@ from importlib.metadata import version as get_version
from typing import Optional
import click
from crewai.cli.config import Settings
from crewai.cli.settings.main import SettingsCommand
from crewai.cli.add_crew_to_flow import add_crew_to_flow
from crewai.cli.create_crew import create_crew
from crewai.cli.create_flow import create_flow
@@ -13,6 +14,7 @@ from crewai.memory.storage.kickoff_task_outputs_storage import (
from .authentication.main import AuthenticationCommand
from .deploy.main import DeployCommand
from .enterprise.main import EnterpriseConfigureCommand
from .evaluate_crew import evaluate_crew
from .install_crew import install_crew
from .kickoff_flow import kickoff_flow
@@ -138,8 +140,12 @@ def log_tasks_outputs() -> None:
@click.option("-s", "--short", is_flag=True, help="Reset SHORT TERM memory")
@click.option("-e", "--entities", is_flag=True, help="Reset ENTITIES memory")
@click.option("-kn", "--knowledge", is_flag=True, help="Reset KNOWLEDGE storage")
@click.option("-akn", "--agent-knowledge", is_flag=True, help="Reset AGENT KNOWLEDGE storage")
@click.option("-k","--kickoff-outputs",is_flag=True,help="Reset LATEST KICKOFF TASK OUTPUTS")
@click.option(
"-akn", "--agent-knowledge", is_flag=True, help="Reset AGENT KNOWLEDGE storage"
)
@click.option(
"-k", "--kickoff-outputs", is_flag=True, help="Reset LATEST KICKOFF TASK OUTPUTS"
)
@click.option("-a", "--all", is_flag=True, help="Reset ALL memories")
def reset_memories(
long: bool,
@@ -154,13 +160,23 @@ def reset_memories(
Reset the crew memories (long, short, entity, latest_crew_kickoff_ouputs, knowledge, agent_knowledge). This will delete all the data saved.
"""
try:
memory_types = [long, short, entities, knowledge, agent_knowledge, kickoff_outputs, all]
memory_types = [
long,
short,
entities,
knowledge,
agent_knowledge,
kickoff_outputs,
all,
]
if not any(memory_types):
click.echo(
"Please specify at least one memory type to reset using the appropriate flags."
)
return
reset_memories_command(long, short, entities, knowledge, agent_knowledge, kickoff_outputs, all)
reset_memories_command(
long, short, entities, knowledge, agent_knowledge, kickoff_outputs, all
)
except Exception as e:
click.echo(f"An error occurred while resetting memories: {e}", err=True)
@@ -210,16 +226,11 @@ def update():
update_crew()
@crewai.command()
def signup():
"""Sign Up/Login to CrewAI+."""
AuthenticationCommand().signup()
@crewai.command()
def login():
"""Sign Up/Login to CrewAI+."""
AuthenticationCommand().signup()
"""Sign Up/Login to CrewAI Enterprise."""
Settings().clear_user_settings()
AuthenticationCommand().login()
# DEPLOY CREWAI+ COMMANDS
@@ -360,8 +371,8 @@ def org():
pass
@org.command()
def list():
@org.command("list")
def org_list():
"""List available organizations."""
org_command = OrganizationCommand()
org_command.list()
@@ -382,5 +393,48 @@ def current():
org_command.current()
@crewai.group()
def enterprise():
"""Enterprise Configuration commands."""
pass
@enterprise.command("configure")
@click.argument("enterprise_url")
def enterprise_configure(enterprise_url: str):
"""Configure CrewAI Enterprise OAuth2 settings from the provided Enterprise URL."""
enterprise_command = EnterpriseConfigureCommand()
enterprise_command.configure(enterprise_url)
@crewai.group()
def config():
"""CLI Configuration commands."""
pass
@config.command("list")
def config_list():
"""List all CLI configuration parameters."""
config_command = SettingsCommand()
config_command.list()
@config.command("set")
@click.argument("key")
@click.argument("value")
def config_set(key: str, value: str):
"""Set a CLI configuration parameter."""
config_command = SettingsCommand()
config_command.set(key, value)
@config.command("reset")
def config_reset():
"""Reset all CLI configuration parameters to default values."""
config_command = SettingsCommand()
config_command.reset_all_settings()
if __name__ == "__main__":
crewai()

View File

@@ -26,7 +26,7 @@ class PlusAPIMixin:
"Please sign up/login to CrewAI+ before using the CLI.",
style="bold red",
)
console.print("Run 'crewai signup' to sign up/login.", style="bold green")
console.print("Run 'crewai login' to sign up/login.", style="bold green")
raise SystemExit
def _validate_response(self, response: requests.Response) -> None:

Some files were not shown because too many files have changed in this diff Show More