feat: adopt directory-based docs versioning with Edge channel

Switch docs.crewai.com from navigation-only versioning (every version
selector entry rendered the same docs/<lang>/* source files) to
Mintlify's directory-based versioning so each version selector entry
renders its own snapshot. Add an "Edge" channel under docs/edge/<lang>/*
that always reflects main HEAD for unreleased work, eliminating
pre-release leakage onto frozen release labels. External links to
canonical /<lang>/* URLs are preserved via wildcard redirects that
always land on the current default version.

Layout:
- docs/edge/<lang>/*         rolling source (you edit here)
- docs/edge/enterprise-api.*.yaml
- docs/v<X.Y.Z>/<lang>/*     frozen, immutable snapshots
- docs/v<X.Y.Z>/enterprise-api.*.yaml
- docs/images/               shared, append-only
- docs/docs.json             nav + redirects

URLs follow the Mintlify-idiomatic shape: /edge/<lang>/<page> for
Edge, /v<X.Y.Z>/<lang>/<page> for every frozen snapshot. The wildcard
redirects /<lang>/:slug* -> /<default>/<lang>/:slug* keep stale links
working, and every freeze rewrites them (plus all per-section/per-page
redirects) so destinations always resolve to the current default
without depending on a second redirect hop.

Release flow integration (devtools release):
- New module crewai_devtools.docs_versioning.freeze() materialises
  docs/v<X.Y.Z>/ from docs/edge/, rewrites openapi: refs inside the
  snapshot, inserts the version into every language block in
  docs.json, and refreshes all redirect destinations.
- _update_docs_and_create_pr() in cli.py now calls that freeze during
  Phase 2 of devtools release. Edge changelogs are updated first (so
  the snapshot freeze picks them up), then the snapshot is staged
  alongside docs.json, branched as docs/freeze-v<X.Y.Z>, and the PR
  is titled [docs-freeze] docs: snapshot and changelog for v<X.Y.Z>
  — the title prefix the new CI guard reads.
- The PR still gates tag, GitHub release, PyPI publish, and the
  enterprise release as before; no new PRs are added.
- Pre-releases (1.X.YaN, 1.X.YbN, ...) skip the snapshot — they ride
  Edge — and the docs PR title omits the [docs-freeze] prefix.
- docs_check (AI-generated docs scaffolding) writes to
  docs/edge/<lang>/* so newly-generated unreleased docs land in Edge
  and never accidentally touch a frozen snapshot.

Migration scripts (one-shot):
- scripts/docs/freeze_historical_versions.py reconstructs all 16
  historical snapshots (v1.10.0 .. v1.14.7) from git tags via
  git archive | tar, rewriting openapi: MDX refs so each snapshot
  reads its own enterprise-api YAML rather than the live one.
- scripts/docs/prefix_version_paths.py one-shot-migrates docs.json:
  rewrites every page path in 16 versioned blocks to point under
  docs/v<X.Y.Z>/, inserts a new Edge entry per language, tags
  v1.14.7 as Latest (default), prunes pages whose target file
  doesn't exist in the snapshot (e.g. docs/ar/ didn't exist before
  v1.12.0), and writes the wildcard + per-section redirects.
- scripts/docs/freeze_current_edge.py is now a thin CLI wrapper
  around docs_versioning.freeze for manual one-off freezes (e.g.
  retroactively snapshotting a forgotten release).

CI guards (.github/workflows/docs-snapshots.yml):
- Frozen snapshots under docs/v[0-9]*/ are immutable; only PRs whose
  title contains [docs-freeze] (i.e. release-cut PRs generated by
  devtools release or the manual wrapper) may modify them.
- Images under docs/images/ are append-only since snapshots share a
  single image directory. Deleting or renaming an image breaks every
  historical snapshot that still references it.

Restored docs/images/crewai-otel-export.png from PR #3673; it was
deleted in PR #4908 but v1.10.0 / v1.10.1 snapshots still reference
it. Restoring instead of editing the snapshots preserves historical
rendering fidelity and validates the new append-only rule
retroactively.

Tests:
- lib/devtools/tests/test_docs_versioning.py covers the freeze: file
  copy, openapi rewrite, version insertion, default demotion, redirect
  upserts, per-section redirect rewriting, idempotency, and invalid
  inputs.

Verified locally with mintlify broken-links: 0 broken links across
the full site (Edge + 16 frozen versions, 4 locales).

AGENTS.md (repo root) is the contributor guide for the new model;
RELEASING.md is the release-cut runbook; README's Contribution
section links to both.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Lucas Gomide
2026-06-17 09:33:56 -03:00
parent 7bb9bc7e1a
commit 93dafe2637
15793 changed files with 3237032 additions and 16873 deletions

View File

@@ -0,0 +1,61 @@
---
title: Hooks Antes e Depois do Kickoff
description: Aprenda a usar hooks antes e depois do kickoff em CrewAI
mode: "wide"
---
O CrewAI fornece hooks que permitem executar código antes e depois do kickoff de uma crew. Esses hooks são úteis para pré-processar entradas ou pós-processar resultados.
## Hook Antes do Kickoff
O hook antes do kickoff é executado antes da crew iniciar suas tarefas. Ele recebe o dicionário de entradas e pode modificá-lo antes de passá-lo para a crew. Você pode usar esse hook para configurar seu ambiente, carregar dados necessários ou pré-processar suas entradas. Isso é útil em cenários onde os dados de entrada podem precisar de enriquecimento ou validação antes de serem processados pela crew.
Aqui está um exemplo de como definir uma função antes do kickoff em seu `crew.py`:
```python
from crewai import CrewBase
from crewai.project import before_kickoff
@CrewBase
class MinhaEquipe:
@before_kickoff
def preparar_dados(self, entradas):
# Pré-processa ou modifica as entradas
entradas['processado'] = True
return entradas
#...
```
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
O hook depois do kickoff é executado após a crew completar suas tarefas. Ele recebe o objeto de resultado, que contém as saídas da execução da crew. Este hook é ideal para pós-processar resultados, como log, transformação de dados ou análise adicional.
Veja como você pode definir uma função depois do kickoff em seu `crew.py`:
```python
from crewai import CrewBase
from crewai.project import after_kickoff
@CrewBase
class MinhaEquipe:
@after_kickoff
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 `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
Ambos os hooks podem ser usados juntos para oferecer um processo completo de preparação e finalização na execução da sua crew. Eles são particularmente úteis para manter uma arquitetura de código limpa, separando responsabilidades e melhorando a modularidade das suas implementações com CrewAI.
## Conclusão
Os hooks antes e depois do kickoff em CrewAI oferecem formas poderosas de interagir com o ciclo de vida da execução de uma crew. Ao entender e utilizar esses hooks, você pode aumentar significativamente a robustez e flexibilidade dos seus agentes de IA.

View File

@@ -0,0 +1,442 @@
---
title: Traga seu próprio agente
description: Aprenda como trazer seus próprios agentes que funcionam dentro de uma Crew.
icon: robots
mode: "wide"
---
Interoperabilidade é um conceito fundamental no CrewAI. Este guia mostrará como trazer seus próprios agentes para funcionar dentro de uma Crew.
## Guia de Adaptação para trazer seus próprios agentes (Agentes Langgraph, Agentes OpenAI, etc...)
Requeremos 3 adaptadores para tornar qualquer agente de diferentes frameworks compatível com uma crew.
1. BaseAgentAdapter
2. BaseToolAdapter
3. BaseConverter
## BaseAgentAdapter
Esta classe abstrata define a interface comum e a funcionalidade que todos
os adaptadores de agente devem implementar. Ela estende BaseAgent para manter compatibilidade
com o framework CrewAI, ao mesmo tempo em que adiciona requisitos específicos do adaptador.
Métodos obrigatórios:
1. `def configure_tools`
2. `def configure_structured_output`
## Criando seu próprio Adaptador
Para integrar um agente de um framework diferente (por exemplo, LangGraph, Autogen, OpenAI Assistants) ao CrewAI, você precisa criar um adaptador customizado herdando de `BaseAgentAdapter`. Esse adaptador atua como uma camada de compatibilidade, traduzindo entre as interfaces do CrewAI e os requisitos específicos do seu agente externo.
Veja como implementar seu adaptador customizado:
1. **Herdar de `BaseAgentAdapter`**:
```python
from crewai.agents.agent_adapters.base_agent_adapter import BaseAgentAdapter
from crewai.tools import BaseTool
from typing import List, Optional, Any, Dict
class MyCustomAgentAdapter(BaseAgentAdapter):
# ... detalhes da implementação ...
```
2. **Implementar `__init__`**:
O construtor deve chamar o construtor da classe pai `super().__init__(**kwargs)` e executar qualquer inicialização específica do seu agente externo. Você pode usar o dicionário opcional `agent_config` passado durante a inicialização do `Agent` do CrewAI para configurar seu adaptador e o agente subjacente.
```python
def __init__(self, agent_config: Optional[Dict[str, Any]] = None, **kwargs: Any):
super().__init__(agent_config=agent_config, **kwargs)
# Inicialize seu agente externo aqui, possivelmente usando agent_config
# Exemplo: self.external_agent = initialize_my_agent(agent_config)
print(f"Inicializando MyCustomAgentAdapter com config: {agent_config}")
```
3. **Implementar `configure_tools`**:
Este método abstrato é crucial. Ele recebe uma lista de instâncias de `BaseTool` do CrewAI. Sua implementação deve converter ou adaptar essas ferramentas para o formato esperado pelo seu framework de agente externo. Isso pode envolver encapsulamento, extração de atributos específicos ou registro delas na instância do agente externo.
```python
def configure_tools(self, tools: Optional[List[BaseTool]] = None) -> None:
if tools:
adapted_tools = []
for tool in tools:
# Adapte o CrewAI BaseTool para o formato que seu agente espera
# Exemplo: adapted_tool = adapt_to_my_framework(tool)
# adapted_tools.append(adapted_tool)
pass # Substitua pela sua lógica real de adaptação
# Configure o agente externo com as ferramentas adaptadas
# Exemplo: self.external_agent.set_tools(adapted_tools)
print(f"Configurando ferramentas para MyCustomAgentAdapter: {adapted_tools}") # Placeholder
else:
# Caso nenhum ferramenta seja fornecida
# Exemplo: self.external_agent.set_tools([])
print("Nenhuma ferramenta fornecida para MyCustomAgentAdapter.")
```
4. **Implementar `configure_structured_output`**:
Esse método é chamado quando o `Agent` do CrewAI é configurado com requisitos de saída estruturada (por exemplo, `output_json` ou `output_pydantic`). Seu adaptador precisa garantir que o agente externo esteja configurado para cumprir esses requisitos. Isso pode envolver definir parâmetros específicos no agente externo ou garantir que seu modelo subjacente suporte o formato solicitado. Se o agente externo não suportar saída estruturada de forma compatível com as expectativas do CrewAI, talvez seja necessário lidar com a conversão ou lançar um erro apropriado.
```python
def configure_structured_output(self, structured_output: Any) -> None:
# Configure seu agente externo para produzir saída no formato especificado
# Exemplo: self.external_agent.set_output_format(structured_output)
self.adapted_structured_output = True # Sinaliza que a saída estruturada foi tratada
print(f"Configurando saída estruturada para MyCustomAgentAdapter: {structured_output}")
```
Implementando esses métodos, seu `MyCustomAgentAdapter` permitirá que sua implementação personalizada de agente funcione corretamente dentro de uma crew do CrewAI, interagindo com tarefas e ferramentas de forma transparente. Lembre-se de substituir os comentários e prints de exemplo pela sua lógica real de adaptação específica do framework externo que está integrando.
## Implementação de BaseToolAdapter
A classe `BaseToolAdapter` é responsável por converter os objetos nativos `BaseTool` do CrewAI em um formato que o seu framework de agente externo possa entender e utilizar. Diferentes frameworks de agentes (como LangGraph, OpenAI Assistants, etc.) possuem suas próprias formas de definir e tratar ferramentas, e o `BaseToolAdapter` age como tradutor.
Veja como implementar seu adaptador de ferramentas personalizado:
1. **Herdar de `BaseToolAdapter`**:
```python
from crewai.agents.agent_adapters.base_tool_adapter import BaseToolAdapter
from crewai.tools import BaseTool
from typing import List, Any
class MyCustomToolAdapter(BaseToolAdapter):
# ... detalhes da implementação ...
```
2. **Implementar `configure_tools`**:
Este é o método abstrato principal que você deve implementar. Ele recebe uma lista de instâncias de `BaseTool` fornecidas ao agente. Sua tarefa é iterar por essa lista, adaptar cada `BaseTool` para o formato esperado pelo seu framework externo e armazenar as ferramentas convertidas na lista `self.converted_tools` (inicializada no construtor da classe base).
```python
def configure_tools(self, tools: List[BaseTool]) -> None:
"""Configura e converte ferramentas do CrewAI para a implementação específica."""
self.converted_tools = [] # Reseta caso seja chamado múltiplas vezes
for tool in tools:
# Sanitizar o nome da ferramenta se necessário pelo framework alvo
sanitized_name = self.sanitize_tool_name(tool.name)
# --- Sua lógica de conversão aqui ---
# Exemplo: Converter BaseTool para formato de dicionário para LangGraph
# converted_tool = {
# "name": sanitized_name,
# "description": tool.description,
# "parameters": tool.args_schema.schema() if tool.args_schema else {},
# # Adicione outros campos específicos do framework
# }
# Exemplo: Converter BaseTool para definição de função OpenAI
# converted_tool = {
# "type": "function",
# "function": {
# "name": sanitized_name,
# "description": tool.description,
# "parameters": tool.args_schema.schema() if tool.args_schema else {"type": "object", "properties": {}},
# }
# }
# --- Substitua os exemplos acima pela sua adaptação real ---
converted_tool = self.adapt_tool_to_my_framework(tool, sanitized_name) # Placeholder
self.converted_tools.append(converted_tool)
print(f"Ferramenta '{tool.name}' adaptada para '{sanitized_name}' em MyCustomToolAdapter") # Placeholder
print(f"MyCustomToolAdapter terminou de configurar ferramentas: {len(self.converted_tools)} adaptadas.") # Placeholder
# --- Método auxiliar para adaptação (Exemplo) ---
def adapt_tool_to_my_framework(self, tool: BaseTool, sanitized_name: str) -> Any:
# Substitua pela lógica real para converter um CrewAI BaseTool
# para o formato necessário do framework de agente externo específico.
# Isso pode variar bastante de acordo com o framework.
adapted_representation = {
"framework_specific_name": sanitized_name,
"framework_specific_description": tool.description,
"inputs": tool.args_schema.schema() if tool.args_schema else None,
"implementation_reference": tool.run # Ou conforme o framework precisa chamar
}
# Certifique-se também que a ferramenta funcione tanto síncrona quanto assincronamente
async def async_tool_wrapper(*args, **kwargs):
output = tool.run(*args, **kwargs)
if inspect.isawaitable(output):
return await output
else:
return output
adapted_tool = MyFrameworkTool(
name=sanitized_name,
description=tool.description,
inputs=tool.args_schema.schema() if tool.args_schema else None,
implementation_reference=async_tool_wrapper
)
return adapted_representation
```
3. **Utilizando o Adaptador**:
Normalmente, você instanciaria seu `MyCustomToolAdapter` dentro do método `configure_tools` do seu `MyCustomAgentAdapter` e o usaria para processar as ferramentas antes de configurar o agente externo.
```python
# Dentro de MyCustomAgentAdapter.configure_tools
def configure_tools(self, tools: Optional[List[BaseTool]] = None) -> None:
if tools:
tool_adapter = MyCustomToolAdapter() # Instancia seu adaptador de ferramenta
tool_adapter.configure_tools(tools) # Converte as ferramentas
adapted_tools = tool_adapter.tools() # Obtém as ferramentas convertidas
# Agora configure seu agente externo com as ferramentas adaptadas
# Exemplo: self.external_agent.set_tools(adapted_tools)
print(f"Configurando agente externo com ferramentas adaptadas: {adapted_tools}") # Placeholder
else:
# Caso sem ferramentas
print("Nenhuma ferramenta fornecida para MyCustomAgentAdapter.")
```
Ao criar um `BaseToolAdapter`, você desacopla a lógica de conversão de ferramenta da adaptação de agente, tornando a integração mais limpa e modular. Lembre-se de substituir os exemplos de placeholder pela lógica de conversão real exigida pelo seu framework externo específico.
## BaseConverter
O `BaseConverterAdapter` desempenha um papel crucial quando uma `Task` do CrewAI exige que um agente retorne sua saída final em um formato estruturado específico, como JSON ou um modelo Pydantic. Ele faz a ponte entre os requisitos de saída estruturada do CrewAI e as capacidades do seu agente externo.
Suas responsabilidades principais são:
1. **Configurar o Agente para Saída Estruturada:** Com base nos requisitos da `Task` (`output_json` ou `output_pydantic`), ele instrui o `BaseAgentAdapter` associado (e indiretamente, o agente externo) sobre qual formato é esperado.
2. **Apriorar o Prompt do Sistema:** Ele modifica o prompt do sistema do agente para incluir instruções claras sobre *como* gerar a saída na estrutura exigida.
3. **Pós-processamento do Resultado:** Pega a saída bruta do agente e tenta fazer parsing, validar e formatar conforme a estrutura requerida, retornando por fim uma representação em string (por exemplo, uma string JSON).
Veja como implementar seu adaptador de conversão customizado:
1. **Herdar de `BaseConverterAdapter`**:
```python
from crewai.agents.agent_adapters.base_converter_adapter import BaseConverterAdapter
# Supondo que o seu MyCustomAgentAdapter foi definido
# from .my_custom_agent_adapter import MyCustomAgentAdapter
from crewai.task import Task
from typing import Any
class MyCustomConverterAdapter(BaseConverterAdapter):
# Armazena o tipo de saída esperado (ex: 'json', 'pydantic', 'text')
_output_type: str = 'text'
_output_schema: Any = None # Armazena o schema JSON ou modelo Pydantic
# ... detalhes da implementação ...
```
2. **Implementar `__init__`**:
O construtor deve aceitar a instância correspondente de `agent_adapter` com a qual irá trabalhar.
```python
def __init__(self, agent_adapter: Any): # Use um type hint específico para seu AgentAdapter
self.agent_adapter = agent_adapter
print(f"Inicializando MyCustomConverterAdapter para o adaptador de agente: {type(agent_adapter).__name__}")
```
3. **Implementar `configure_structured_output`**:
Esse método recebe o objeto `Task` do CrewAI. Você precisa checar os atributos `output_json` e `output_pydantic` da task para determinar a estrutura de saída exigida. Armazene essa informação (por exemplo, em `_output_type` e `_output_schema`) e, potencialmente, chame métodos de configuração no seu `self.agent_adapter` se o agente externo necessitar de um ajuste específico para saída estruturada (algo que pode já ter sido parcialmente feito no `configure_structured_output` do adaptador de agente).
```python
def configure_structured_output(self, task: Task) -> None:
"""Configura a saída estruturada esperada baseada na task."""
if task.output_pydantic:
self._output_type = 'pydantic'
self._output_schema = task.output_pydantic
print(f"Converter: Configurado para saída Pydantic: {self._output_schema.__name__}")
elif task.output_json:
self._output_type = 'json'
self._output_schema = task.output_json
print(f"Converter: Configurado para saída JSON com schema: {self._output_schema}")
else:
self._output_type = 'text'
self._output_schema = None
print("Converter: Configurado para saída de texto padrão.")
# Opcionalmente, informe o agent_adapter se necessário
# self.agent_adapter.set_output_mode(self._output_type, self._output_schema)
```
4. **Implementar `enhance_system_prompt`**:
Este método recebe o prompt base do sistema do agente e deve anexar instruções adaptadas para o `_output_type` e `_output_schema` atualmente configurados. O objetivo é guiar o LLM que alimenta o agente a produzir saída no formato correto.
```python
def enhance_system_prompt(self, base_prompt: str) -> str:
"""Aprimore o prompt do sistema com instruções de saída estruturada."""
if self._output_type == 'text':
return base_prompt # Nenhum aprimoramento necessário para texto puro
instructions = "\n\nSua resposta final DEVE estar formatada como "
if self._output_type == 'json':
schema_str = json.dumps(self._output_schema, indent=2)
instructions += f"um objeto JSON conforme o seguinte schema:\n```json\n{schema_str}\n```"
elif self._output_type == 'pydantic':
schema_str = json.dumps(self._output_schema.model_json_schema(), indent=2)
instructions += f"um objeto JSON conforme o modelo Pydantic '{self._output_schema.__name__}' com o seguinte schema:\n```json\n{schema_str}\n```"
instructions += "\nGaranta que toda a sua resposta seja APENAS o objeto JSON válido, sem nenhum texto introdutório, explicações ou considerações finais."
print(f"Converter: Aprimorando prompt para saída {self._output_type}.")
return base_prompt + instructions
```
*Nota: O prompt pode precisar de ajustes conforme o agente/LLM usado.*
5. **Implementar `post_process_result`**:
Esse método recebe a saída em string bruta do agente. Se uma saída estruturada foi solicitada (`json` ou `pydantic`), você deve tentar convertê-la para o formato esperado. Trate erros de parsing caso ocorram (por exemplo, registre-os, tente corrigir, ou lance uma exceção). O método **deve sempre retornar uma string**, mesmo se o formato intermediário seja um dicionário ou objeto Pydantic (por exemplo, serializando novamente para JSON).
```python
import json
from pydantic import ValidationError
def post_process_result(self, result: str) -> str:
"""Pós-processa o resultado do agente para garantir que corresponde ao formato esperado."""
print(f"Converter: Pós-processando resultado para saída {self._output_type}.")
if self._output_type == 'json':
try:
# Tenta fazer parsing e re-serializar para garantir validade e formato consistente
parsed_json = json.loads(result)
# Opcional: Validar contra o schema se for um dicionário JSON schema
# from jsonschema import validate
# validate(instance=parsed_json, schema=self._output_schema)
return json.dumps(parsed_json)
except json.JSONDecodeError as e:
print(f"Erro: Falha ao fazer parsing da saída JSON: {e}\nSaída bruta:\n{result}")
# Trate o erro: retorne bruto, lance exceção, ou tente corrigir
return result # Exemplo: retorna a saída bruta caso falhe
# except Exception as e: # Captura erros de validação se usar jsonschema
# print(f"Erro: saída JSON falhou na validação do schema: {e}\nSaída bruta:\n{result}")
# return result
elif self._output_type == 'pydantic':
try:
# Tenta fazer parsing para o modelo Pydantic
model_instance = self._output_schema.model_validate_json(result)
# Retorna o modelo serializado de volta para JSON
return model_instance.model_dump_json()
except ValidationError as e:
print(f"Erro: Falha ao validar saída Pydantic: {e}\nSaída bruta:\n{result}")
# Trate o erro
return result # Exemplo: retorna a saída bruta caso falhe
except json.JSONDecodeError as e:
print(f"Erro: Falha ao fazer parsing do JSON para o modelo Pydantic: {e}\nSaída bruta:\n{result}")
return result
else: # 'text'
return result # Sem processamento para texto puro
```
Implementando esses métodos, seu `MyCustomConverterAdapter` assegurará que as solicitações de saída estruturada das tarefas do CrewAI sejam corretamente tratadas pelo seu agente externo integrado, aumentando a confiabilidade e a usabilidade do seu agente customizado dentro do framework CrewAI.
## Adapters prontos para uso
Fornecemos adapters prontos para uso para os seguintes frameworks:
1. LangGraph
2. Agentes OpenAI
## Iniciando uma crew com agentes adaptados:
```python
import json
import os
from typing import List
from crewai_tools import SerperDevTool
from src.crewai import Agent, Crew, Task
from langchain_openai import ChatOpenAI
from pydantic import BaseModel
from crewai.agents.agent_adapters.langgraph.langgraph_adapter import (
LangGraphAgentAdapter,
)
from crewai.agents.agent_adapters.openai_agents.openai_adapter import OpenAIAgentAdapter
# Agente CrewAI
code_helper_agent = Agent(
role="Code Helper",
goal="Help users solve coding problems effectively and provide clear explanations.",
backstory="You are an experienced programmer with deep knowledge across multiple programming languages and frameworks. You specialize in solving complex coding challenges and explaining solutions clearly.",
allow_delegation=False,
verbose=True,
)
# OpenAI Agent Adapter
link_finder_agent = OpenAIAgentAdapter(
role="Link Finder",
goal="Find the most relevant and high-quality resources for coding tasks.",
backstory="You are a research specialist with a talent for finding the most helpful resources. You're skilled at using search tools to discover documentation, tutorials, and examples that directly address the user's coding needs.",
tools=[SerperDevTool()],
allow_delegation=False,
verbose=True,
)
# LangGraph Agent Adapter
reporter_agent = LangGraphAgentAdapter(
role="Reporter",
goal="Report the results of the tasks.",
backstory="You are a reporter who reports the results of the other tasks",
llm=ChatOpenAI(model="gpt-4o"),
allow_delegation=True,
verbose=True,
)
class Code(BaseModel):
code: str
task = Task(
description="Give an answer to the coding question: {task}",
expected_output="A thorough answer to the coding question: {task}",
agent=code_helper_agent,
output_json=Code,
)
task2 = Task(
description="Find links to resources that can help with coding tasks. Use the serper tool to find resources that can help.",
expected_output="A list of links to resources that can help with coding tasks",
agent=link_finder_agent,
)
class Report(BaseModel):
code: str
links: List[str]
task3 = Task(
description="Report the results of the tasks.",
expected_output="A report of the results of the tasks. this is the code produced and then the links to the resources that can help with the coding task.",
agent=reporter_agent,
output_json=Report,
)
# Usando no CrewAI
crew = Crew(
agents=[code_helper_agent, link_finder_agent, reporter_agent],
tasks=[task, task2, task3],
verbose=True,
)
result = crew.kickoff(
inputs={"task": "How do you implement an abstract class in python?"}
)
# Imprima o resultado bruto primeiro
print("Raw result:", result)
# Lide com o resultado de acordo com seu tipo
if hasattr(result, "json_dict") and result.json_dict:
json_result = result.json_dict
print("\nStructured JSON result:")
print(f"{json.dumps(json_result, indent=2)}")
# Acesse os campos de forma segura
if isinstance(json_result, dict):
if "code" in json_result:
print("\nCode:")
print(
json_result["code"][:200] + "..."
if len(json_result["code"]) > 200
else json_result["code"]
)
if "links" in json_result:
print("\nLinks:")
for link in json_result["links"][:5]: # Print first 5 links
print(f"- {link}")
if len(json_result["links"]) > 5:
print(f"...and {len(json_result['links']) - 5} more links")
elif hasattr(result, "pydantic") and result.pydantic:
print("\nPydantic model result:")
print(result.pydantic.model_dump_json(indent=2))
else:
# Fallback para saída bruta
print("\nNo structured result available, using raw output:")
print(result.raw[:500] + "..." if len(result.raw) > 500 else result.raw)
```

View File

@@ -0,0 +1,96 @@
---
title: Agentes de Codificação
description: Aprenda como habilitar seus Agentes CrewAI para escrever e executar código, e explore funcionalidades avançadas para maior potencial.
icon: rectangle-code
mode: "wide"
---
## Introdução
Os Agentes CrewAI agora têm a poderosa capacidade de escrever e executar código, aumentando significativamente suas habilidades de resolução de problemas. Esse recurso é particularmente útil para tarefas que exigem soluções computacionais ou programáticas.
## Habilitando a Execução de Código
Para habilitar a execução de código para um agente, defina o parâmetro `allow_code_execution` como `True` ao criar o agente.
Veja um exemplo:
```python Code
from crewai import Agent
coding_agent = Agent(
role="Senior Python Developer",
goal="Craft well-designed and thought-out code",
backstory="You are a senior Python developer with extensive experience in software architecture and best practices.",
allow_code_execution=True
)
```
<Note>
Observe que o parâmetro `allow_code_execution` é `False` por padrão.
</Note>
## Considerações Importantes
1. **Seleção de Modelo**: É fortemente recomendado utilizar modelos mais avançados como Claude 3.5 Sonnet e GPT-4 ao habilitar a execução de código.
Esses modelos têm melhor compreensão de conceitos de programação e tendem a gerar códigos mais corretos e eficientes.
2. **Tratamento de Erros**: O recurso de execução de código inclui tratamento de erros. Se o código executado gerar uma exceção, o agente receberá a mensagem de erro e poderá tentar corrigir o código ou
fornecer soluções alternativas. O parâmetro `max_retry_limit`, que por padrão é 2, controla o número máximo de tentativas para uma tarefa.
3. **Dependências**: Para usar o recurso de execução de código, é necessário instalar o pacote `crewai_tools`. Caso não esteja instalado, o agente registrará uma mensagem informativa:
"Ferramentas de codificação não disponíveis. Instale crewai_tools."
## Processo de Execução de Código
Quando um agente com execução de código habilitada encontra uma tarefa que requer programação:
<Steps>
<Step title="Análise da Tarefa">
O agente analisa a tarefa e determina que a execução de código é necessária.
</Step>
<Step title="Formulação do Código">
Ele formula o código Python necessário para resolver o problema.
</Step>
<Step title="Execução do Código">
O código é enviado para a ferramenta interna de execução de código (`CodeInterpreterTool`).
</Step>
<Step title="Interpretação dos Resultados">
O agente interpreta o resultado e o incorpora na sua resposta ou o utiliza para aprofundar a solução do problema.
</Step>
</Steps>
## Exemplo de Uso
Veja um exemplo detalhado de como criar um agente com capacidade de execução de código e utilizá-lo em uma tarefa:
```python Code
from crewai import Agent, Task, Crew
# 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.",
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.",
agent=coding_agent
)
# Create a crew and add the task
analysis_crew = Crew(
agents=[coding_agent],
tasks=[data_analysis_task]
)
# Execute the crew
result = analysis_crew.kickoff()
print(result)
```
Neste exemplo, o `coding_agent` pode escrever e executar código Python para realizar tarefas de análise de dados.

View File

@@ -0,0 +1,90 @@
---
title: Tarefas Condicionais
description: Saiba como usar tarefas condicionais em um kickoff do crewAI
icon: diagram-subtask
mode: "wide"
---
## Introdução
As Tarefas Condicionais no crewAI permitem a adaptação dinâmica do fluxo de trabalho com base nos resultados de tarefas anteriores.
Esse recurso poderoso possibilita que crews tomem decisões e executem tarefas seletivamente, aumentando a flexibilidade e a eficiência dos seus processos orientados por IA.
## Exemplo de Uso
```python Code
from typing import List
from pydantic import BaseModel
from crewai import Agent, Crew
from crewai.tasks.conditional_task import ConditionalTask
from crewai.tasks.task_output import TaskOutput
from crewai.task import Task
from crewai_tools import SerperDevTool
# Define a condition function for the conditional task
# If false, the task will be skipped, if true, then execute the task.
def is_data_missing(output: TaskOutput) -> bool:
return len(output.pydantic.events) < 10 # this will skip this task
# Define the agents
data_fetcher_agent = Agent(
role="Data Fetcher",
goal="Fetch data online using Serper tool",
backstory="Backstory 1",
verbose=True,
tools=[SerperDevTool()]
)
data_processor_agent = Agent(
role="Data Processor",
goal="Process fetched data",
backstory="Backstory 2",
verbose=True
)
summary_generator_agent = Agent(
role="Summary Generator",
goal="Generate summary from fetched data",
backstory="Backstory 3",
verbose=True
)
class EventOutput(BaseModel):
events: List[str]
task1 = Task(
description="Fetch data about events in San Francisco using Serper tool",
expected_output="List of 10 things to do in SF this week",
agent=data_fetcher_agent,
output_pydantic=EventOutput,
)
conditional_task = ConditionalTask(
description="""
Check if data is missing. If we have less than 10 events,
fetch more events using Serper tool so that
we have a total of 10 events in SF this week..
""",
expected_output="List of 10 Things to do in SF this week",
condition=is_data_missing,
agent=data_processor_agent,
)
task3 = Task(
description="Generate summary of events in San Francisco from fetched data",
expected_output="A complete report on the customer and their customers and competitors, including their demographics, preferences, market positioning and audience engagement.",
agent=summary_generator_agent,
)
# Create a crew with the tasks
crew = Crew(
agents=[data_fetcher_agent, data_processor_agent, summary_generator_agent],
tasks=[task1, conditional_task, task3],
verbose=True,
planning=True
)
# Run the crew
result = crew.kickoff()
print("results", result)
```

View File

@@ -0,0 +1,124 @@
---
title: Criar Ferramentas Personalizadas
description: Guia abrangente sobre como criar, utilizar e gerenciar ferramentas personalizadas dentro do framework CrewAI, incluindo novas funcionalidades e tratamento de erros.
icon: hammer
mode: "wide"
---
## Criando e Utilizando Ferramentas no CrewAI
Este guia traz instruções detalhadas sobre como criar ferramentas personalizadas para o framework CrewAI e como gerenciar e utilizar essas ferramentas de forma eficiente,
incorporando funcionalidades recentes, como delegação de ferramentas, tratamento de erros e chamada dinâmica de ferramentas. Destaca também a importância de ferramentas de colaboração,
permitindo que agentes executem uma ampla gama de ações.
<Tip>
**Quer publicar sua ferramenta para a comunidade?** Se você está construindo uma ferramenta que pode beneficiar outros, confira o guia [Publicar Ferramentas Personalizadas](/pt-BR/guides/tools/publish-custom-tools) para aprender como empacotar e distribuir sua ferramenta no PyPI.
</Tip>
### Subclassificando `BaseTool`
Para criar uma ferramenta personalizada, herde de `BaseTool` e defina os atributos necessários, incluindo o `args_schema` para validação de entrada e o método `_run`.
```python Code
from typing import Type
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
class MyToolInput(BaseModel):
"""Input schema for MyCustomTool."""
argument: str = Field(..., description="Description of the argument.")
class MyCustomTool(BaseTool):
name: str = "Name of my tool"
description: str = "What this tool does. It's vital for effective utilization."
args_schema: Type[BaseModel] = MyToolInput
def _run(self, argument: str) -> str:
# Your tool's logic here
return "Tool's result"
```
### Usando o Decorador `tool`
Como alternativa, você pode utilizar o decorador de ferramenta `@tool`. Esta abordagem permite definir os atributos e as funcionalidades da ferramenta diretamente em uma função,
oferecendo uma maneira concisa e eficiente de criar ferramentas especializadas de acordo com suas necessidades.
```python Code
from crewai.tools import tool
@tool("Tool Name")
def my_simple_tool(question: str) -> str:
"""Tool description for clarity."""
# Tool logic here
return "Tool output"
```
### Definindo uma Função de Cache para a Ferramenta
Para otimizar o desempenho da ferramenta com cache, defina estratégias de cache personalizadas utilizando o atributo `cache_function`.
```python Code
@tool("Tool with Caching")
def cached_tool(argument: str) -> str:
"""Tool functionality description."""
return "Cacheable result"
def my_cache_strategy(arguments: dict, result: str) -> bool:
# Define custom caching logic
return True if some_condition else False
cached_tool.cache_function = my_cache_strategy
```
### Criando Ferramentas Assíncronas
O CrewAI suporta ferramentas assíncronas para operações de I/O não bloqueantes. Isso é útil quando sua ferramenta precisa fazer requisições HTTP, consultas a banco de dados ou outras operações de I/O.
#### Usando o Decorador `@tool` com Funções Assíncronas
A maneira mais simples de criar uma ferramenta assíncrona é usando o decorador `@tool` com uma função async:
```python Code
import aiohttp
from crewai.tools import tool
@tool("Async Web Fetcher")
async def fetch_webpage(url: str) -> str:
"""Fetch content from a webpage asynchronously."""
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
```
#### Subclassificando `BaseTool` com Suporte Assíncrono
Para maior controle, herde de `BaseTool` e implemente os métodos `_run` (síncrono) e `_arun` (assíncrono):
```python Code
import requests
import aiohttp
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
class WebFetcherInput(BaseModel):
"""Input schema for WebFetcher."""
url: str = Field(..., description="The URL to fetch")
class WebFetcherTool(BaseTool):
name: str = "Web Fetcher"
description: str = "Fetches content from a URL"
args_schema: type[BaseModel] = WebFetcherInput
def _run(self, url: str) -> str:
"""Synchronous implementation."""
return requests.get(url).text
async def _arun(self, url: str) -> str:
"""Asynchronous implementation for non-blocking I/O."""
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
```
Seguindo essas orientações e incorporando novas funcionalidades e ferramentas de colaboração nos seus processos de criação e gerenciamento de ferramentas,
você pode aproveitar ao máximo as capacidades do framework CrewAI, aprimorando tanto a experiência de desenvolvimento quanto a eficiência dos seus agentes de IA.

View File

@@ -0,0 +1,123 @@
---
title: Implementação de LLM Personalizada
description: Aprenda a criar implementações personalizadas de LLM no CrewAI.
icon: code
mode: "wide"
---
## Visão Geral
O CrewAI oferece suporte a implementações personalizadas de LLM por meio da classe abstrata `BaseLLM`. Isso permite integrar qualquer provedor de LLM que não tenha suporte nativo no LiteLLM ou implementar mecanismos de autenticação personalizados.
## Início Rápido
Aqui está uma implementação mínima de LLM personalizada:
```python
# (não traduzir blocos de código)
```
## Usando Seu LLM Personalizado
```python
# (não traduzir blocos de código)
```
## Métodos Necessários
### Construtor: `__init__()`
**Crítico**: Você deve chamar `super().__init__(model, temperature)` com os parâmetros necessários:
```python
# (não traduzir blocos de código)
```
### Método Abstrato: `call()`
O método `call()` é o núcleo da sua implementação de LLM. Ele deve:
- Aceitar mensagens (string ou lista de dicionários com 'role' e 'content')
- Retornar uma resposta como string
- Lidar com ferramentas e chamada de funções, se suportado
- Lançar exceções apropriadas para erros
### Métodos Opcionais
```python
# (não traduzir blocos de código)
```
## Padrões Comuns
### Tratamento de Erros
```python
# (não traduzir blocos de código)
```
### Autenticação Personalizada
```python
# (não traduzir blocos de código)
```
### Suporte a Stop Words
O CrewAI adiciona automaticamente `"\nObservation:"` como stop word para controlar o comportamento do agente. Se o seu LLM suporta stop words:
```python
# (não traduzir blocos de código)
```
Se o seu LLM não suporta stop words nativamente:
```python
# (não traduzir blocos de código)
```
## Chamada de Funções
Se o seu LLM suporta chamada de funções, implemente o fluxo completo:
```python
# (não traduzir blocos de código)
```
## Solução de Problemas
### Problemas Comuns
**Erros no Construtor**
```python
# ❌ Errado - parâmetros obrigatórios ausentes
def __init__(self, api_key: str):
super().__init__()
# ✅ Correto
def __init__(self, model: str, api_key: str, temperature: Optional[float] = None):
super().__init__(model=model, temperature=temperature)
```
**Chamada de Funções Não Funciona**
- Certifique-se de que `supports_function_calling()` retorna `True`
- Verifique se você lida com `tool_calls` na resposta
- Assegure-se de que o parâmetro `available_functions` está sendo corretamente utilizado
**Falhas de Autenticação**
- Verifique o formato e as permissões da chave de API
- Confira o formato do header de autenticação
- Certifique-se de que as URLs dos endpoints estão corretas
**Erros de Parsing de Resposta**
- Valide a estrutura da resposta antes de acessar campos aninhados
- Trate casos em que o content pode ser None
- Adicione tratamento de erros para respostas malformadas
## Testando Seu LLM Personalizado
```python
# (não traduzir blocos de código)
```
Este guia cobre o essencial para implementar LLMs personalizados no CrewAI.

View File

@@ -0,0 +1,91 @@
---
title: Agente Gerente Personalizado
description: Saiba como definir um agente personalizado como gerente no CrewAI, proporcionando mais controle sobre o gerenciamento e a coordenação das tarefas.
icon: user-shield
mode: "wide"
---
# Definindo um Agente Específico como Gerente no CrewAI
O CrewAI permite que usuários definam um agente específico como gerente da crew, oferecendo mais controle sobre o gerenciamento e a coordenação das tarefas.
Esse recurso possibilita a personalização do papel gerencial para se adequar melhor às necessidades do seu projeto.
## Utilizando o Atributo `manager_agent`
### Agente Gerente Personalizado
O atributo `manager_agent` permite que você defina um agente personalizado para gerenciar a crew. Este agente supervisionará todo o processo, garantindo que as tarefas sejam concluídas de forma eficiente e com o mais alto padrão de qualidade.
### Exemplo
```python Code
import os
from crewai import Agent, Task, Crew, Process
# Define your agents
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.",
allow_delegation=False,
)
writer = Agent(
role="Senior Writer",
goal="Create compelling content about AI and AI agents",
backstory="You're a senior writer, specialized in technology, software engineering, AI, and startups. You work as a freelancer and are currently writing content for a new client.",
allow_delegation=False,
)
# Define your 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.",
)
# Define the manager agent
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.",
allow_delegation=True,
)
# Instantiate your crew with a custom manager
crew = Crew(
agents=[researcher, writer],
tasks=[task],
manager_agent=manager,
process=Process.hierarchical,
)
# Start the crew's work
result = crew.kickoff()
```
## Benefícios de um Agente Gerente Personalizado
- **Controle aprimorado**: Adapte a abordagem de gerenciamento para atender às necessidades específicas do seu projeto.
- **Coordenação melhorada**: Assegure uma coordenação e gestão eficiente das tarefas por um agente experiente.
- **Gestão personalizável**: Defina funções e responsabilidades gerenciais que estejam alinhadas aos objetivos do seu projeto.
## Definindo um Manager LLM
Se você estiver utilizando o processo hierarchical e não quiser definir um agente gerente personalizado, é possível especificar o modelo de linguagem para o gerente:
```python Code
from crewai import LLM
manager_llm = LLM(model="gpt-4o")
crew = Crew(
agents=[researcher, writer],
tasks=[task],
process=Process.hierarchical,
manager_llm=manager_llm
)
```
<Note>
É necessário definir `manager_agent` ou `manager_llm` ao utilizar o processo hierarchical.
</Note>

View File

@@ -0,0 +1,107 @@
---
title: Personalize Agentes
description: Um guia abrangente para adaptar agentes a funções específicas, tarefas e customizações avançadas dentro do framework CrewAI.
icon: user-pen
mode: "wide"
---
## Atributos Personalizáveis
A construção de uma equipe CrewAI eficiente depende da capacidade de adaptar dinamicamente seus agentes de IA para atender aos requisitos únicos de qualquer projeto. Esta seção aborda os atributos fundamentais que você pode personalizar.
### Principais Atributos para Personalização
| Atributo | Descrição |
|:------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Role** | Especifica a função do agente dentro da equipe, como 'Analista' ou 'Representante de Atendimento ao Cliente'. |
| **Goal** | Define os objetivos do agente, alinhados à sua função e à missão geral da equipe. |
| **Backstory** | Fornece profundidade à persona do agente, aprimorando motivações e engajamento dentro da equipe. |
| **Tools** *(Opcional)* | Representa as capacidades ou métodos que o agente utiliza para tarefas, desde funções simples até integrações complexas. |
| **Cache** *(Opcional)* | Determina se o agente deve usar cache para o uso de ferramentas. |
| **Max RPM** | Define o número máximo de requisições por minuto (`max_rpm`). Pode ser definido como `None` para requisições ilimitadas a serviços externos. |
| **Verbose** *(Opcional)* | Ativa registros detalhados para depuração e otimização, fornecendo insights sobre os processos de execução. |
| **Allow Delegation** *(Opcional)* | Controla a delegação de tarefas para outros agentes, padrão é `False`. |
| **Max Iter** *(Opcional)* | Limita o número máximo de iterações (`max_iter`) para uma tarefa, prevenindo loops infinitos, com valor padrão de 25. |
| **Max Execution Time** *(Opcional)* | Define o tempo máximo permitido para que o agente complete uma tarefa. |
| **System Template** *(Opcional)* | Define o formato do sistema para o agente. |
| **Prompt Template** *(Opcional)* | Define o formato do prompt para o agente. |
| **Response Template** *(Opcional)* | Define o formato da resposta para o agente. |
| **Use System Prompt** *(Opcional)* | Controla se o agente irá usar um prompt de sistema durante a execução de tarefas. |
| **Respect Context Window** | Ativa uma janela deslizante de contexto por padrão, mantendo o tamanho do contexto. |
| **Max Retry Limit** | Define o número máximo de tentativas (`max_retry_limit`) para um agente em caso de erros. |
## Opções Avançadas de Personalização
Além dos atributos básicos, o CrewAI permite customizações mais profundas para aprimorar significativamente o comportamento e as capacidades de um agente.
### Personalização de Modelo de Linguagem
Agentes podem ser personalizados com modelos de linguagem específicos (`llm`) e modelos de linguagem com chamada de função (`function_calling_llm`), oferecendo controle avançado sobre o processamento e a tomada de decisão.
É importante notar que definir o `function_calling_llm` permite sobrescrever o modelo padrão de chamada de função da equipe, proporcionando maior grau de personalização.
## Ajustes de Performance e Depuração
Ajustar a performance do agente e monitorar suas operações é fundamental para a execução eficiente de tarefas.
### Modo Verbose e Limite de RPM
- **Modo Verbose**: Ativa o registro detalhado das ações do agente, útil para depuração e otimização. Especificamente, fornece insights sobre os processos de execução do agente, auxiliando na otimização de performance.
- **Limite de RPM**: Define o número máximo de requisições por minuto (`max_rpm`). Este atributo é opcional e pode ser definido como `None` para não haver limite, permitindo consultas ilimitadas a serviços externos, se necessário.
### Máximo de Iterações por Execução de Tarefa
O atributo `max_iter` permite ao usuário definir o número máximo de iterações que um agente pode executar para uma única tarefa, prevenindo loops infinitos ou execuções excessivamente longas.
O valor padrão é 25, fornecendo um equilíbrio entre profundidade e eficiência. Quando o agente chega próximo a esse número, ele tentará entregar a melhor resposta possível.
## Personalizando Agentes e Ferramentas
Agentes são personalizados definindo seus atributos e ferramentas durante a inicialização. As ferramentas são críticas para a funcionalidade do agente, permitindo que realizem tarefas especializadas.
O atributo `tools` deve ser um array de ferramentas que o agente pode utilizar, e, por padrão, é inicializado como uma lista vazia. As ferramentas podem ser adicionadas ou modificadas após a criação do agente para se adaptar a novos requisitos.
```shell
pip install 'crewai[tools]'
```
### Exemplo: Atribuindo Ferramentas a um Agente
```python Code
import os
from crewai import Agent
from crewai_tools import SerperDevTool
# Defina as chaves de API para inicialização da ferramenta
os.environ["OPENAI_API_KEY"] = "Sua Chave"
os.environ["SERPER_API_KEY"] = "Sua Chave"
# Inicialize uma ferramenta de busca
search_tool = SerperDevTool()
# Inicialize o agente com opções avançadas
agent = Agent(
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,
max_rpm=None, # Sem limite de requisições por minuto
max_iter=25, # Valor padrão de máximo de iterações
)
```
## Delegação e Autonomia
Controlar a capacidade de um agente delegar tarefas ou fazer perguntas é fundamental para ajustar sua autonomia e a dinâmica de colaboração dentro do framework CrewAI. Por padrão,
o atributo `allow_delegation` agora é definido como `False`, desabilitando para que agentes busquem assistência ou deleguem tarefas conforme necessário. Esse comportamento padrão pode ser alterado para promover resolução colaborativa de problemas e
eficiência dentro do ecossistema CrewAI. Se necessário, a delegação pode ser ativada para atender requisitos operacionais específicos.
### Exemplo: Desabilitando Delegação para um Agente
```python Code
agent = Agent(
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
)
```

View File

@@ -0,0 +1,74 @@
---
title: "Geração de Imagens com DALL-E"
description: "Aprenda a usar o DALL-E para geração de imagens com IA em seus projetos CrewAI"
icon: "image"
mode: "wide"
---
O CrewAI oferece integração com o DALL-E da OpenAI, permitindo que seus agentes de IA gerem imagens como parte de suas tarefas. Este guia irá orientá-lo sobre como configurar e utilizar a ferramenta DALL-E em seus projetos CrewAI.
## Pré-requisitos
- crewAI instalado (última versão)
- Chave de API OpenAI com acesso ao DALL-E
## Configurando a Ferramenta DALL-E
<Steps>
<Step title="Importe a ferramenta DALL-E">
```python
from crewai_tools import DallETool
```
</Step>
<Step title="Adicione a ferramenta DALL-E na configuração do seu agente">
```python
@agent
def researcher(self) -> Agent:
return Agent(
config=self.agents_config['researcher'],
tools=[SerperDevTool(), DallETool()], # Add DallETool to the list of tools
allow_delegation=False,
verbose=True
)
```
</Step>
</Steps>
## Utilizando a Ferramenta DALL-E
Depois de adicionar a ferramenta DALL-E ao seu agente, ele poderá gerar imagens baseadas em prompts de texto. A ferramenta retornará uma URL para a imagem gerada, que pode ser utilizada na resposta do agente ou repassada para outros agentes para processamento adicional.
### Exemplo de Configuração de Agente
```yaml
role: >
Pesquisador Sênior de Dados para Perfis do LinkedIn
goal: >
Encontrar perfis detalhados do LinkedIn com base no nome fornecido {name} e domínio {domain}
Gerar uma imagem com o Dall-e baseada no domínio {domain}
backstory: >
Você é um pesquisador experiente com habilidade para encontrar os perfis do LinkedIn mais relevantes.
Conhecido por sua eficiência em navegar no LinkedIn, você se destaca em reunir e apresentar
informações profissionais de forma clara e concisa.
```
### Resultado Esperado
O agente com a ferramenta DALL-E conseguirá gerar a imagem e fornecer uma URL em sua resposta. Você poderá então baixar a imagem.
<Frame>
<img src="/images/enterprise/dall-e-image.png" alt="Imagem DALL-E" />
</Frame>
## Boas Práticas
1. **Seja específico nos prompts de geração de imagem** para obter melhores resultados.
2. **Considere o tempo de geração** - A geração de imagens pode levar algum tempo, então inclua isso no seu planejamento de tarefas.
3. **Siga as políticas de uso** - Sempre cumpra as políticas de uso da OpenAI ao gerar imagens.
## Solução de Problemas
1. **Verifique o acesso à API** - Certifique-se de que sua chave de API OpenAI possui acesso ao DALL-E.
2. **Compatibilidade de versões** - Verifique se você está utilizando a versão mais recente do crewAI e crewai-tools.
3. **Configuração da ferramenta** - Confirme que a ferramenta DALL-E foi corretamente adicionada à lista de ferramentas do agente.

View File

@@ -0,0 +1,379 @@
---
title: Visão Geral dos Hooks de Execução
description: Entendendo e usando hooks de execução no CrewAI para controle fino sobre operações de agentes
mode: "wide"
---
Os Hooks de Execução fornecem controle fino sobre o comportamento em tempo de execução dos seus agentes CrewAI. Diferentemente dos hooks de kickoff que são executados antes e depois da execução da crew, os hooks de execução interceptam operações específicas durante a execução do agente, permitindo que você modifique comportamentos, implemente verificações de segurança e adicione monitoramento abrangente.
## Tipos de Hooks de Execução
O CrewAI fornece duas categorias principais de hooks de execução:
### 1. [Hooks de Chamada LLM](/learn/llm-hooks)
Controle e monitore interações com o modelo de linguagem:
- **Antes da Chamada LLM**: Modifique prompts, valide entradas, implemente gates de aprovação
- **Depois da Chamada LLM**: Transforme respostas, sanitize saídas, atualize histórico de conversação
**Casos de Uso:**
- Limitação de iterações
- Rastreamento de custos e monitoramento de uso de tokens
- Sanitização de respostas e filtragem de conteúdo
- Aprovação humana para chamadas LLM
- Adição de diretrizes de segurança ou contexto
- Logging de debug e inspeção de requisição/resposta
[Ver Documentação de Hooks LLM →](/learn/llm-hooks)
### 2. [Hooks de Chamada de Ferramenta](/learn/tool-hooks)
Controle e monitore execução de ferramentas:
- **Antes da Chamada de Ferramenta**: Modifique entradas, valide parâmetros, bloqueie operações perigosas
- **Depois da Chamada de Ferramenta**: Transforme resultados, sanitize saídas, registre detalhes de execução
**Casos de Uso:**
- Guardrails de segurança para operações destrutivas
- Aprovação humana para ações sensíveis
- Validação e sanitização de entrada
- Cache de resultados e limitação de taxa
- Análise de uso de ferramentas
- Logging de debug e monitoramento
[Ver Documentação de Hooks de Ferramenta →](/learn/tool-hooks)
## Métodos de Registro
### 1. Hooks Baseados em Decoradores (Recomendado)
A maneira mais limpa e pythônica de registrar hooks:
```python
from crewai.hooks import before_llm_call, after_llm_call, before_tool_call, after_tool_call
@before_llm_call
def limit_iterations(context):
"""Previne loops infinitos limitando iterações."""
if context.iterations > 10:
return False # Bloquear execução
return None
@after_llm_call
def sanitize_response(context):
"""Remove dados sensíveis das respostas do LLM."""
if "API_KEY" in context.response:
return context.response.replace("API_KEY", "[CENSURADO]")
return None
@before_tool_call
def block_dangerous_tools(context):
"""Bloqueia operações destrutivas."""
if context.tool_name == "delete_database":
return False # Bloquear execução
return None
@after_tool_call
def log_tool_result(context):
"""Registra execução de ferramenta."""
print(f"Ferramenta {context.tool_name} concluída")
return None
```
### 2. Hooks com Escopo de Crew
Aplica hooks apenas a instâncias específicas de crew:
```python
from crewai import CrewBase
from crewai.project import crew
from crewai.hooks import before_llm_call_crew, after_tool_call_crew
@CrewBase
class MyProjCrew:
@before_llm_call_crew
def validate_inputs(self, context):
# Aplica-se apenas a esta crew
print(f"Chamada LLM em {self.__class__.__name__}")
return None
@after_tool_call_crew
def log_results(self, context):
# Logging específico da crew
print(f"Resultado da ferramenta: {context.tool_result[:50]}...")
return None
@crew
def crew(self) -> Crew:
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential
)
```
## Fluxo de Execução de Hooks
### Fluxo de Chamada LLM
```
Agente precisa chamar LLM
[Hooks Antes da Chamada LLM Executam]
├→ Hook 1: Validar contagem de iterações
├→ Hook 2: Adicionar contexto de segurança
└→ Hook 3: Registrar requisição
Se algum hook retornar False:
├→ Bloquear chamada LLM
└→ Lançar ValueError
Se todos os hooks retornarem True/None:
├→ Chamada LLM prossegue
└→ Resposta gerada
[Hooks Depois da Chamada LLM Executam]
├→ Hook 1: Sanitizar resposta
├→ Hook 2: Registrar resposta
└→ Hook 3: Atualizar métricas
Resposta final retornada
```
### Fluxo de Chamada de Ferramenta
```
Agente precisa executar ferramenta
[Hooks Antes da Chamada de Ferramenta Executam]
├→ Hook 1: Verificar se ferramenta é permitida
├→ Hook 2: Validar entradas
└→ Hook 3: Solicitar aprovação se necessário
Se algum hook retornar False:
├→ Bloquear execução da ferramenta
└→ Retornar mensagem de erro
Se todos os hooks retornarem True/None:
├→ Execução da ferramenta prossegue
└→ Resultado gerado
[Hooks Depois da Chamada de Ferramenta Executam]
├→ Hook 1: Sanitizar resultado
├→ Hook 2: Fazer cache do resultado
└→ Hook 3: Registrar métricas
Resultado final retornado
```
## Objetos de Contexto de Hook
### LLMCallHookContext
Fornece acesso ao estado de execução do LLM:
```python
class LLMCallHookContext:
executor: CrewAgentExecutor # Acesso completo ao executor
messages: list # Lista de mensagens mutável
agent: Agent # Agente atual
task: Task # Tarefa atual
crew: Crew # Instância da crew
llm: BaseLLM # Instância do LLM
iterations: int # Iteração atual
response: str | None # Resposta do LLM (hooks posteriores)
```
### ToolCallHookContext
Fornece acesso ao estado de execução da ferramenta:
```python
class ToolCallHookContext:
tool_name: str # Ferramenta sendo chamada
tool_input: dict # Parâmetros de entrada mutáveis
tool: CrewStructuredTool # Instância da ferramenta
agent: Agent | None # Agente executando
task: Task | None # Tarefa atual
crew: Crew | None # Instância da crew
tool_result: str | None # Resultado da ferramenta (hooks posteriores)
```
## Padrões Comuns
### Segurança e Validação
```python
@before_tool_call
def safety_check(context):
"""Bloqueia operações destrutivas."""
dangerous = ['delete_file', 'drop_table', 'system_shutdown']
if context.tool_name in dangerous:
print(f"🛑 Bloqueado: {context.tool_name}")
return False
return None
@before_llm_call
def iteration_limit(context):
"""Previne loops infinitos."""
if context.iterations > 15:
print("⛔ Máximo de iterações excedido")
return False
return None
```
### Humano no Loop
```python
@before_tool_call
def require_approval(context):
"""Requer aprovação para operações sensíveis."""
sensitive = ['send_email', 'make_payment', 'post_message']
if context.tool_name in sensitive:
response = context.request_human_input(
prompt=f"Aprovar {context.tool_name}?",
default_message="Digite 'sim' para aprovar:"
)
if response.lower() != 'sim':
return False
return None
```
### Monitoramento e Análise
```python
from collections import defaultdict
import time
metrics = defaultdict(lambda: {'count': 0, 'total_time': 0})
@before_tool_call
def start_timer(context):
context.tool_input['_start'] = time.time()
return None
@after_tool_call
def track_metrics(context):
start = context.tool_input.get('_start', time.time())
duration = time.time() - start
metrics[context.tool_name]['count'] += 1
metrics[context.tool_name]['total_time'] += duration
return None
```
## Gerenciamento de Hooks
### Limpar Todos os Hooks
```python
from crewai.hooks import clear_all_global_hooks
# Limpa todos os hooks de uma vez
result = clear_all_global_hooks()
print(f"Limpou {result['total']} hooks")
```
### Limpar Tipos Específicos de Hooks
```python
from crewai.hooks import (
clear_before_llm_call_hooks,
clear_after_llm_call_hooks,
clear_before_tool_call_hooks,
clear_after_tool_call_hooks
)
# Limpar tipos específicos
llm_before_count = clear_before_llm_call_hooks()
tool_after_count = clear_after_tool_call_hooks()
```
## Melhores Práticas
### 1. Mantenha os Hooks Focados
Cada hook deve ter uma responsabilidade única e clara.
### 2. Trate Erros Graciosamente
```python
@before_llm_call
def safe_hook(context):
try:
if some_condition:
return False
except Exception as e:
print(f"Erro no hook: {e}")
return None # Permitir execução apesar do erro
```
### 3. Modifique o Contexto In-Place
```python
# ✅ Correto - modificar in-place
@before_llm_call
def add_context(context):
context.messages.append({"role": "system", "content": "Seja conciso"})
# ❌ Errado - substitui referência
@before_llm_call
def wrong_approach(context):
context.messages = [{"role": "system", "content": "Seja conciso"}]
```
### 4. Use Type Hints
```python
from crewai.hooks import LLMCallHookContext, ToolCallHookContext
def my_llm_hook(context: LLMCallHookContext) -> bool | None:
return None
def my_tool_hook(context: ToolCallHookContext) -> str | None:
return None
```
### 5. Limpe em Testes
```python
import pytest
from crewai.hooks import clear_all_global_hooks
@pytest.fixture(autouse=True)
def clean_hooks():
"""Reseta hooks antes de cada teste."""
yield
clear_all_global_hooks()
```
## Quando Usar Qual Hook
### Use Hooks LLM Quando:
- Implementar limites de iteração
- Adicionar contexto ou diretrizes de segurança aos prompts
- Rastrear uso de tokens e custos
- Sanitizar ou transformar respostas
- Implementar gates de aprovação para chamadas LLM
- Fazer debug de interações de prompt/resposta
### Use Hooks de Ferramenta Quando:
- Bloquear operações perigosas ou destrutivas
- Validar entradas de ferramenta antes da execução
- Implementar gates de aprovação para ações sensíveis
- Fazer cache de resultados de ferramenta
- Rastrear uso e performance de ferramentas
- Sanitizar saídas de ferramenta
- Limitar taxa de chamadas de ferramenta
### Use Ambos Quando:
Construir sistemas abrangentes de observabilidade, segurança ou aprovação que precisam monitorar todas as operações do agente.
## Documentação Relacionada
- [Hooks de Chamada LLM →](/learn/llm-hooks) - Documentação detalhada de hooks LLM
- [Hooks de Chamada de Ferramenta →](/learn/tool-hooks) - Documentação detalhada de hooks de ferramenta
- [Hooks Antes e Depois do Kickoff →](/learn/before-and-after-kickoff-hooks) - Hooks do ciclo de vida da crew
- [Humano no Loop →](/learn/human-in-the-loop) - Padrões de entrada humana
## Conclusão
Os Hooks de Execução fornecem controle poderoso sobre o comportamento em tempo de execução do agente. Use-os para implementar guardrails de segurança, fluxos de trabalho de aprovação, monitoramento abrangente e lógica de negócio personalizada. Combinados com tratamento adequado de erros, segurança de tipos e considerações de performance, os hooks permitem sistemas de agentes seguros, prontos para produção e observáveis.

View File

@@ -0,0 +1,51 @@
---
title: Forçar a Saída da Ferramenta como Resultado
description: Aprenda como forçar a saída de uma ferramenta como resultado em uma tarefa de Agent no CrewAI.
icon: wrench-simple
mode: "wide"
---
## Introdução
No CrewAI, você pode forçar a saída de uma ferramenta como o resultado de uma tarefa de um agent.
Esse recurso é útil quando você deseja garantir que a saída da ferramenta seja capturada e retornada como resultado da tarefa, evitando quaisquer modificações pelo agent durante a execução da tarefa.
## Forçando a Saída da Ferramenta como Resultado
Para forçar a saída da ferramenta como resultado da tarefa de um agent, você precisa definir o parâmetro `result_as_answer` como `True` ao adicionar uma ferramenta ao agent.
Esse parâmetro garante que a saída da ferramenta seja capturada e retornada como resultado da tarefa, sem qualquer modificação pelo agent.
Veja um exemplo de como forçar a saída da ferramenta como resultado da tarefa de um agent:
```python Code
from crewai.agent import Agent
from my_tool import MyCustomTool
# Create a coding agent with the custom tool
coding_agent = Agent(
role="Data Scientist",
goal="Produce amazing reports on AI",
backstory="You work with data and AI",
tools=[MyCustomTool(result_as_answer=True)],
)
# Assuming the tool's execution and result population occurs within the system
task_result = coding_agent.execute_task(task)
```
## Fluxo de Trabalho em Ação
<Steps>
<Step title="Execução da Tarefa">
O agent executa a tarefa utilizando a ferramenta fornecida.
</Step>
<Step title="Saída da Ferramenta">
A ferramenta gera a saída, que é capturada como resultado da tarefa.
</Step>
<Step title="Interação do Agent">
O agent pode refletir e aprender com a ferramenta, mas a saída não é modificada.
</Step>
<Step title="Retorno do Resultado">
A saída da ferramenta é retornada como resultado da tarefa sem quaisquer modificações.
</Step>
</Steps>

View File

@@ -0,0 +1,112 @@
---
title: Processo Hierárquico
description: Um guia abrangente para compreender e aplicar o processo hierárquico em seus projetos CrewAI, atualizado para refletir as práticas de codificação e funcionalidades mais recentes.
icon: sitemap
mode: "wide"
---
## Introdução
O processo hierárquico no CrewAI introduz uma abordagem estruturada para a gestão de tarefas, simulando hierarquias organizacionais tradicionais para uma delegação e execução eficiente de tarefas.
Esse fluxo de trabalho sistemático melhora os resultados do projeto ao garantir que as tarefas sejam tratadas com máxima eficiência e precisão.
<Tip>
O processo hierárquico foi projetado para alavancar modelos avançados como o GPT-4, otimizando o uso de tokens enquanto lida com tarefas complexas de forma mais eficiente.
</Tip>
## Visão Geral do Processo Hierárquico
Por padrão, as tarefas no CrewAI são gerenciadas por meio de um processo sequencial. No entanto, adotar uma abordagem hierárquica permite uma hierarquia clara na gestão de tarefas,
onde um agente 'gerente' coordena o fluxo de trabalho, delega tarefas e valida os resultados para uma execução eficaz e simplificada. Esse agente gerente pode agora ser
criado automaticamente pelo CrewAI ou explicitamente definido pelo usuário.
### Principais Características
- **Delegação de Tarefas**: Um agente gerente distribui tarefas entre os membros da crew com base em seus papéis e capacidades.
- **Validação de Resultados**: O gerente avalia os resultados para garantir que atendam aos padrões exigidos.
- **Fluxo de Trabalho Eficiente**: Emula estruturas corporativas, oferecendo uma abordagem organizada para a gestão de tarefas.
- **Manipulação de System Prompt**: Opcionalmente, especifique se o sistema deve usar prompts predefinidos.
- **Controle de Stop Words**: Opcionalmente, especifique se stop words devem ser usadas, oferecendo suporte a diversos modelos, incluindo os modelos o1.
- **Respeito à Context Window**: Priorização de contexto relevante ativando o respeito à context window, que agora é o comportamento padrão.
- **Controle de Delegação**: A delegação agora está desativada por padrão para dar controle explícito ao usuário.
- **Máximo de Requisições por Minuto**: Opção configurável para definir o número máximo de requisições por minuto.
- **Máximo de Iterações**: Limitação do número máximo de iterações até a obtenção de uma resposta final.
## Implementando o Processo Hierárquico
Para utilizar o processo hierárquico, é essencial definir explicitamente o atributo de processo como `Process.hierarchical`, já que o comportamento padrão é `Process.sequential`.
Defina uma crew com um gerente designado e estabeleça uma cadeia de comando clara.
<Tip>
Atribua ferramentas no nível do agente para facilitar a delegação e execução de tarefas pelos agentes designados sob a orientação do gerente.
Ferramentas também podem ser especificadas no nível da tarefa, para um controle preciso sobre a disponibilidade de ferramentas durante a execução das tarefas.
</Tip>
<Tip>
Configurar o parâmetro `manager_llm` é fundamental para o processo hierárquico.
O sistema exige a configuração de um LLM do gerente para funcionar corretamente, garantindo tomadas de decisão personalizadas.
</Tip>
```python Code
from crewai import Crew, Process, Agent
# Agents are defined with attributes for backstory, cache, and verbose mode
researcher = Agent(
role='Researcher',
goal='Conduct in-depth analysis',
backstory='Experienced data analyst with a knack for uncovering hidden trends.',
)
writer = Agent(
role='Writer',
goal='Create engaging content',
backstory='Creative writer passionate about storytelling in technical domains.',
)
# Establishing the crew with a hierarchical process and additional configurations
project_crew = Crew(
tasks=[...], # Tasks to be delegated and executed under the manager's supervision
agents=[researcher, writer],
manager_llm="gpt-4o", # Specify which LLM the manager should use
process=Process.hierarchical,
planning=True,
)
```
### Usando um Agente Gerente Personalizado
Alternativamente, você pode criar um agente gerente personalizado com atributos específicos adaptados às necessidades de gestão do seu projeto. Isso oferece maior controle sobre o comportamento e as capacidades do gerente.
```python
# Define a custom manager agent
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.",
allow_delegation=True,
)
# Use the custom manager in your crew
project_crew = Crew(
tasks=[...],
agents=[researcher, writer],
manager_agent=manager, # Use your custom manager agent
process=Process.hierarchical,
planning=True,
)
```
<Tip>
Para mais detalhes sobre a criação e personalização de um agente gerente, confira a [documentação do Custom Manager Agent](/pt-BR/learn/custom-manager-agent).
</Tip>
### Fluxo de Trabalho na Prática
1. **Atribuição de Tarefas**: O gerente atribui as tarefas estrategicamente, considerando as capacidades de cada agente e as ferramentas disponíveis.
2. **Execução e Revisão**: Os agentes concluem suas tarefas com a opção de execução assíncrona e funções de callback para fluxos de trabalho otimizados.
3. **Progresso Sequencial das Tarefas**: Apesar de ser um processo hierárquico, as tarefas seguem uma ordem lógica para um progresso fluido, facilitado pela supervisão do gerente.
## Conclusão
Adotar o processo hierárquico no CrewAI, com as configurações corretas e o entendimento das capacidades do sistema, facilita uma abordagem organizada e eficiente para o gerenciamento de projetos.
Aproveite os recursos avançados e as personalizações para ajustar o fluxo de trabalho conforme suas necessidades, garantindo a execução ideal das tarefas e o sucesso do projeto.

View File

@@ -0,0 +1,697 @@
---
title: Feedback Humano em Flows
description: Aprenda como integrar feedback humano diretamente nos seus CrewAI Flows usando o decorador @human_feedback
icon: user-check
mode: "wide"
---
## Visão Geral
<Note>
O decorador `@human_feedback` requer **CrewAI versão 1.8.0 ou superior**. Certifique-se de atualizar sua instalação antes de usar este recurso.
</Note>
O decorador `@human_feedback` permite fluxos de trabalho human-in-the-loop (HITL) diretamente nos CrewAI Flows. Ele permite pausar a execução do flow, apresentar a saída para um humano revisar, coletar seu feedback e, opcionalmente, rotear para diferentes listeners com base no resultado do feedback.
Isso é particularmente valioso para:
- **Garantia de qualidade**: Revisar conteúdo gerado por IA antes de ser usado downstream
- **Portões de decisão**: Deixar humanos tomarem decisões críticas em fluxos automatizados
- **Fluxos de aprovação**: Implementar padrões de aprovar/rejeitar/revisar
- **Refinamento interativo**: Coletar feedback para melhorar saídas iterativamente
```mermaid
flowchart LR
A[Método do Flow] --> B[Saída Gerada]
B --> C[Humano Revisa]
C --> D{Feedback}
D -->|emit especificado| E[LLM Mapeia para Outcome]
D -->|sem emit| F[HumanFeedbackResult]
E --> G["@listen('approved')"]
E --> H["@listen('rejected')"]
F --> I[Próximo Listener]
```
## Início Rápido
Aqui está a maneira mais simples de adicionar feedback humano a um flow:
```python Code
from crewai.flow.flow import Flow, start, listen
from crewai.flow.human_feedback import human_feedback
class SimpleReviewFlow(Flow):
@start()
@human_feedback(message="Por favor, revise este conteúdo:")
def generate_content(self):
return "Este é um conteúdo gerado por IA que precisa de revisão."
@listen(generate_content)
def process_feedback(self, result):
print(f"Conteúdo: {result.output}")
print(f"Humano disse: {result.feedback}")
flow = SimpleReviewFlow()
flow.kickoff()
```
Quando este flow é executado, ele irá:
1. Executar `generate_content` e retornar a string
2. Exibir a saída para o usuário com a mensagem de solicitação
3. Aguardar o usuário digitar o feedback (ou pressionar Enter para pular)
4. Passar um objeto `HumanFeedbackResult` para `process_feedback`
## O Decorador @human_feedback
### Parâmetros
| Parâmetro | Tipo | Obrigatório | Descrição |
|-----------|------|-------------|-----------|
| `message` | `str` | Sim | A mensagem mostrada ao humano junto com a saída do método |
| `emit` | `Sequence[str]` | Não | Lista de possíveis outcomes. O feedback é mapeado para um destes, que dispara decoradores `@listen` |
| `llm` | `str \| BaseLLM` | Quando `emit` especificado | LLM usado para interpretar o feedback e mapear para um outcome |
| `default_outcome` | `str` | Não | Outcome a usar se nenhum feedback for fornecido. Deve estar em `emit` |
| `metadata` | `dict` | Não | Dados adicionais para integrações enterprise |
| `provider` | `HumanFeedbackProvider` | Não | Provider customizado para feedback assíncrono/não-bloqueante. Veja [Feedback Humano Assíncrono](#feedback-humano-assíncrono-não-bloqueante) |
| `learn` | `bool` | Não | Habilitar aprendizado HITL: destila lições do feedback e pré-revisa saídas futuras. Padrão `False`. Veja [Aprendendo com Feedback](#aprendendo-com-feedback) |
| `learn_limit` | `int` | Não | Máximo de lições passadas para recuperar na pré-revisão. Padrão `5` |
### Uso Básico (Sem Roteamento)
Quando você não especifica `emit`, o decorador simplesmente coleta o feedback e passa um `HumanFeedbackResult` para o próximo listener:
```python Code
@start()
@human_feedback(message="O que você acha desta análise?")
def analyze_data(self):
return "Resultados da análise: Receita aumentou 15%, custos diminuíram 8%"
@listen(analyze_data)
def handle_feedback(self, result):
# result é um HumanFeedbackResult
print(f"Análise: {result.output}")
print(f"Feedback: {result.feedback}")
```
### Roteamento com emit
Quando você especifica `emit`, o decorador se torna um roteador. O feedback livre do humano é interpretado por um LLM e mapeado para um dos outcomes especificados:
```python Code
from crewai.flow.flow import Flow, start, listen, or_
from crewai.flow.human_feedback import human_feedback
class ReviewFlow(Flow):
@start()
def generate_content(self):
return "Rascunho do post do blog aqui..."
@human_feedback(
message="Você aprova este conteúdo para publicação?",
emit=["approved", "rejected", "needs_revision"],
llm="gpt-4o-mini",
default_outcome="needs_revision",
)
@listen(or_("generate_content", "needs_revision"))
def review_content(self):
return "Rascunho do post do blog aqui..."
@listen("approved")
def publish(self, result):
print(f"Publicando! Usuário disse: {result.feedback}")
@listen("rejected")
def discard(self, result):
print(f"Descartando. Motivo: {result.feedback}")
```
Quando o humano diz algo como "precisa de mais detalhes", o LLM mapeia para `"needs_revision"`, que dispara `review_content` novamente via `or_()` — criando um loop de revisão. O loop continua até que o outcome seja `"approved"` ou `"rejected"`.
<Tip>
O LLM usa saídas estruturadas (function calling) quando disponível para garantir que a resposta seja um dos seus outcomes especificados. Isso torna o roteamento confiável e previsível.
</Tip>
<Warning>
Um método `@start()` só executa uma vez no início do flow. Se você precisa de um loop de revisão, separe o método start do método de revisão e use `@listen(or_("trigger", "revision_outcome"))` no método de revisão para habilitar o self-loop.
</Warning>
## HumanFeedbackResult
O dataclass `HumanFeedbackResult` contém todas as informações sobre uma interação de feedback humano:
```python Code
from crewai.flow.human_feedback import HumanFeedbackResult
@dataclass
class HumanFeedbackResult:
output: Any # A saída original do método mostrada ao humano
feedback: str # O texto bruto do feedback do humano
outcome: str | None # O outcome mapeado (se emit foi especificado)
timestamp: datetime # Quando o feedback foi recebido
method_name: str # Nome do método decorado
metadata: dict # Qualquer metadata passado ao decorador
```
### Acessando em Listeners
Quando um listener é disparado por um método `@human_feedback` com `emit`, ele recebe o `HumanFeedbackResult`:
```python Code
@listen("approved")
def on_approval(self, result: HumanFeedbackResult):
print(f"Saída original: {result.output}")
print(f"Feedback do usuário: {result.feedback}")
print(f"Outcome: {result.outcome}") # "approved"
print(f"Recebido em: {result.timestamp}")
```
## Acessando o Histórico de Feedback
A classe `Flow` fornece dois atributos para acessar o feedback humano:
### last_human_feedback
Retorna o `HumanFeedbackResult` mais recente:
```python Code
@listen(some_method)
def check_feedback(self):
if self.last_human_feedback:
print(f"Último feedback: {self.last_human_feedback.feedback}")
```
### human_feedback_history
Uma lista de todos os objetos `HumanFeedbackResult` coletados durante o flow:
```python Code
@listen(final_step)
def summarize(self):
print(f"Total de feedbacks coletados: {len(self.human_feedback_history)}")
for i, fb in enumerate(self.human_feedback_history):
print(f"{i+1}. {fb.method_name}: {fb.outcome or 'sem roteamento'}")
```
<Warning>
Cada `HumanFeedbackResult` é adicionado a `human_feedback_history`, então múltiplos passos de feedback não sobrescrevem uns aos outros. Use esta lista para acessar todo o feedback coletado durante o flow.
</Warning>
## Exemplo Completo: Fluxo de Aprovação de Conteúdo
Aqui está um exemplo completo implementando um fluxo de revisão e aprovação de conteúdo:
<CodeGroup>
```python Code
from crewai.flow.flow import Flow, start, listen, or_
from crewai.flow.human_feedback import human_feedback, HumanFeedbackResult
from pydantic import BaseModel
class ContentState(BaseModel):
draft: str = ""
revision_count: int = 0
status: str = "pending"
class ContentApprovalFlow(Flow[ContentState]):
"""Um flow que gera conteúdo e faz loop até o humano aprovar."""
@start()
def generate_draft(self):
self.state.draft = "# IA Segura\n\nEste é um rascunho sobre IA Segura..."
return self.state.draft
@human_feedback(
message="Por favor, revise este rascunho. Aprove, rejeite ou descreva o que precisa mudar:",
emit=["approved", "rejected", "needs_revision"],
llm="gpt-4o-mini",
default_outcome="needs_revision",
)
@listen(or_("generate_draft", "needs_revision"))
def review_draft(self):
self.state.revision_count += 1
return f"{self.state.draft} (v{self.state.revision_count})"
@listen("approved")
def publish_content(self, result: HumanFeedbackResult):
self.state.status = "published"
print(f"Conteúdo aprovado e publicado! Revisor disse: {result.feedback}")
return "published"
@listen("rejected")
def handle_rejection(self, result: HumanFeedbackResult):
self.state.status = "rejected"
print(f"Conteúdo rejeitado. Motivo: {result.feedback}")
return "rejected"
flow = ContentApprovalFlow()
result = flow.kickoff()
print(f"\nFlow finalizado. Status: {flow.state.status}, Revisões: {flow.state.revision_count}")
```
```text Output
==================================================
OUTPUT FOR REVIEW:
==================================================
# IA Segura
Este é um rascunho sobre IA Segura... (v1)
==================================================
Por favor, revise este rascunho. Aprove, rejeite ou descreva o que precisa mudar:
(Press Enter to skip, or type your feedback)
Your feedback: Preciso de mais detalhes sobre segurança em IA.
==================================================
OUTPUT FOR REVIEW:
==================================================
# IA Segura
Este é um rascunho sobre IA Segura... (v2)
==================================================
Por favor, revise este rascunho. Aprove, rejeite ou descreva o que precisa mudar:
(Press Enter to skip, or type your feedback)
Your feedback: Parece bom, aprovado!
Conteúdo aprovado e publicado! Revisor disse: Parece bom, aprovado!
Flow finalizado. Status: published, Revisões: 2
```
</CodeGroup>
## Combinando com Outros Decoradores
O decorador `@human_feedback` funciona com `@start()`, `@listen()` e `or_()`. Ambas as ordens de decoradores funcionam — o framework propaga atributos em ambas as direções — mas os padrões recomendados são:
```python Code
# Revisão única no início do flow (sem self-loop)
@start()
@human_feedback(message="Revise isto:", emit=["approved", "rejected"], llm="gpt-4o-mini")
def my_start_method(self):
return "content"
# Revisão linear em um listener (sem self-loop)
@listen(other_method)
@human_feedback(message="Revise isto também:", emit=["good", "bad"], llm="gpt-4o-mini")
def my_listener(self, data):
return f"processed: {data}"
# Self-loop: revisão que pode voltar para revisões
@human_feedback(message="Aprovar ou revisar?", emit=["approved", "revise"], llm="gpt-4o-mini")
@listen(or_("upstream_method", "revise"))
def review_with_loop(self):
return "content for review"
```
### Padrão de self-loop
Para criar um loop de revisão, o método de revisão deve escutar **ambos** um gatilho upstream e seu próprio outcome de revisão usando `or_()`:
```python Code
@start()
def generate(self):
return "initial draft"
@human_feedback(
message="Aprovar ou solicitar alterações?",
emit=["revise", "approved"],
llm="gpt-4o-mini",
default_outcome="approved",
)
@listen(or_("generate", "revise"))
def review(self):
return "content"
@listen("approved")
def publish(self):
return "published"
```
Quando o outcome é `"revise"`, o flow roteia de volta para `review` (porque ele escuta `"revise"` via `or_()`). Quando o outcome é `"approved"`, o flow continua para `publish`. Isso funciona porque o engine de flow isenta roteadores da regra "fire once", permitindo que eles re-executem em cada iteração do loop.
### Roteadores encadeados
Um listener disparado pelo outcome de um roteador pode ser ele mesmo um roteador:
```python Code
@start()
@human_feedback(message="Primeira revisão:", emit=["approved", "rejected"], llm="gpt-4o-mini")
def draft(self):
return "draft content"
@listen("approved")
@human_feedback(message="Revisão final:", emit=["publish", "revise"], llm="gpt-4o-mini")
def final_review(self, prev):
return "final content"
@listen("publish")
def on_publish(self, prev):
return "published"
```
### Limitações
- **Métodos `@start()` executam uma vez**: Um método `@start()` não pode fazer self-loop. Se você precisa de um ciclo de revisão, use um método `@start()` separado como ponto de entrada e coloque o `@human_feedback` em um método `@listen()`.
- **Sem `@start()` + `@listen()` no mesmo método**: Esta é uma restrição do framework de Flow. Um método é ou um ponto de início ou um listener, não ambos.
## Melhores Práticas
### 1. Escreva Mensagens de Solicitação Claras
O parâmetro `message` é o que o humano vê. Torne-o acionável:
```python Code
# ✅ Bom - claro e acionável
@human_feedback(message="Este resumo captura com precisão os pontos-chave? Responda 'sim' ou explique o que está faltando:")
# ❌ Ruim - vago
@human_feedback(message="Revise isto:")
```
### 2. Escolha Outcomes Significativos
Ao usar `emit`, escolha outcomes que mapeiem naturalmente para respostas humanas:
```python Code
# ✅ Bom - outcomes em linguagem natural
emit=["approved", "rejected", "needs_more_detail"]
# ❌ Ruim - técnico ou pouco claro
emit=["state_1", "state_2", "state_3"]
```
### 3. Sempre Forneça um Outcome Padrão
Use `default_outcome` para lidar com casos onde usuários pressionam Enter sem digitar:
```python Code
@human_feedback(
message="Aprovar? (pressione Enter para solicitar revisão)",
emit=["approved", "needs_revision"],
llm="gpt-4o-mini",
default_outcome="needs_revision", # Padrão seguro
)
```
### 4. Use o Histórico de Feedback para Trilhas de Auditoria
Acesse `human_feedback_history` para criar logs de auditoria:
```python Code
@listen(final_step)
def create_audit_log(self):
log = []
for fb in self.human_feedback_history:
log.append({
"step": fb.method_name,
"outcome": fb.outcome,
"feedback": fb.feedback,
"timestamp": fb.timestamp.isoformat(),
})
return log
```
### 5. Trate Feedback Roteado e Não Roteado
Ao projetar flows, considere se você precisa de roteamento:
| Cenário | Use |
|---------|-----|
| Revisão simples, só precisa do texto do feedback | Sem `emit` |
| Precisa ramificar para caminhos diferentes baseado na resposta | Use `emit` |
| Portões de aprovação com aprovar/rejeitar/revisar | Use `emit` |
| Coletando comentários apenas para logging | Sem `emit` |
## Feedback Humano Assíncrono (Não-Bloqueante - Human in the loop)
Por padrão, `@human_feedback` bloqueia a execução aguardando entrada no console. Para aplicações de produção, você pode precisar de feedback **assíncrono/não-bloqueante** que se integre com sistemas externos como Slack, email, webhooks ou APIs.
### A Abstração de Provider
Use o parâmetro `provider` para especificar uma estratégia customizada de coleta de feedback:
```python Code
from crewai.flow import Flow, start, human_feedback, HumanFeedbackProvider, HumanFeedbackPending, PendingFeedbackContext
class WebhookProvider(HumanFeedbackProvider):
"""Provider que pausa o flow e aguarda callback de webhook."""
def __init__(self, webhook_url: str):
self.webhook_url = webhook_url
def request_feedback(self, context: PendingFeedbackContext, flow: Flow) -> str:
# Notifica sistema externo (ex: envia mensagem Slack, cria ticket)
self.send_notification(context)
# Pausa execução - framework cuida da persistência automaticamente
raise HumanFeedbackPending(
context=context,
callback_info={"webhook_url": f"{self.webhook_url}/{context.flow_id}"}
)
class ReviewFlow(Flow):
@start()
@human_feedback(
message="Revise este conteúdo:",
emit=["approved", "rejected"],
llm="gpt-4o-mini",
provider=WebhookProvider("https://myapp.com/api"),
)
def generate_content(self):
return "Conteúdo gerado por IA..."
@listen("approved")
def publish(self, result):
return "Publicado!"
```
<Tip>
O framework de flow **persiste automaticamente o estado** quando `HumanFeedbackPending` é lançado. Seu provider só precisa notificar o sistema externo e lançar a exceção—não são necessárias chamadas manuais de persistência.
</Tip>
### Tratando Flows Pausados
Ao usar um provider assíncrono, `kickoff()` retorna um objeto `HumanFeedbackPending` em vez de lançar uma exceção:
```python Code
flow = ReviewFlow()
result = flow.kickoff()
if isinstance(result, HumanFeedbackPending):
# Flow está pausado, estado é automaticamente persistido
print(f"Aguardando feedback em: {result.callback_info['webhook_url']}")
print(f"Flow ID: {result.context.flow_id}")
else:
# Conclusão normal
print(f"Flow concluído: {result}")
```
### Retomando um Flow Pausado
Quando o feedback chega (ex: via webhook), retome o flow:
```python Code
# Handler síncrono:
def handle_feedback_webhook(flow_id: str, feedback: str):
flow = ReviewFlow.from_pending(flow_id)
result = flow.resume(feedback)
return result
# Handler assíncrono (FastAPI, aiohttp, etc.):
async def handle_feedback_webhook(flow_id: str, feedback: str):
flow = ReviewFlow.from_pending(flow_id)
result = await flow.resume_async(feedback)
return result
```
### Tipos Principais
| Tipo | Descrição |
|------|-----------|
| `HumanFeedbackProvider` | Protocolo para providers de feedback customizados |
| `PendingFeedbackContext` | Contém todas as informações necessárias para retomar um flow pausado |
| `HumanFeedbackPending` | Retornado por `kickoff()` quando o flow está pausado para feedback |
| `ConsoleProvider` | Provider padrão de entrada bloqueante no console |
### PendingFeedbackContext
O contexto contém tudo necessário para retomar:
```python Code
@dataclass
class PendingFeedbackContext:
flow_id: str # Identificador único desta execução de flow
flow_class: str # Nome qualificado completo da classe
method_name: str # Método que disparou o feedback
method_output: Any # Saída mostrada ao humano
message: str # A mensagem de solicitação
emit: list[str] | None # Outcomes possíveis para roteamento
default_outcome: str | None
metadata: dict # Metadata customizado
llm: str | None # LLM para mapeamento de outcome
requested_at: datetime
```
### Exemplo Completo de Flow Assíncrono
```python Code
from crewai.flow import (
Flow, start, listen, human_feedback,
HumanFeedbackProvider, HumanFeedbackPending, PendingFeedbackContext
)
class SlackNotificationProvider(HumanFeedbackProvider):
"""Provider que envia notificações Slack e pausa para feedback assíncrono."""
def __init__(self, channel: str):
self.channel = channel
def request_feedback(self, context: PendingFeedbackContext, flow: Flow) -> str:
# Envia notificação Slack (implemente você mesmo)
slack_thread_id = self.post_to_slack(
channel=self.channel,
message=f"Revisão necessária:\n\n{context.method_output}\n\n{context.message}",
)
# Pausa execução - framework cuida da persistência automaticamente
raise HumanFeedbackPending(
context=context,
callback_info={
"slack_channel": self.channel,
"thread_id": slack_thread_id,
}
)
class ContentPipeline(Flow):
@start()
@human_feedback(
message="Aprova este conteúdo para publicação?",
emit=["approved", "rejected"],
llm="gpt-4o-mini",
default_outcome="rejected",
provider=SlackNotificationProvider("#content-reviews"),
)
def generate_content(self):
return "Conteúdo de blog post gerado por IA..."
@listen("approved")
def publish(self, result):
print(f"Publicando! Revisor disse: {result.feedback}")
return {"status": "published"}
@listen("rejected")
def archive(self, result):
print(f"Arquivado. Motivo: {result.feedback}")
return {"status": "archived"}
# Iniciando o flow (vai pausar e aguardar resposta do Slack)
def start_content_pipeline():
flow = ContentPipeline()
result = flow.kickoff()
if isinstance(result, HumanFeedbackPending):
return {"status": "pending", "flow_id": result.context.flow_id}
return result
# Retomando quando webhook do Slack dispara (handler síncrono)
def on_slack_feedback(flow_id: str, slack_message: str):
flow = ContentPipeline.from_pending(flow_id)
result = flow.resume(slack_message)
return result
# Se seu handler é assíncrono (FastAPI, aiohttp, Slack Bolt async, etc.)
async def on_slack_feedback_async(flow_id: str, slack_message: str):
flow = ContentPipeline.from_pending(flow_id)
result = await flow.resume_async(slack_message)
return result
```
<Warning>
Se você está usando um framework web assíncrono (FastAPI, aiohttp, Slack Bolt modo async), use `await flow.resume_async()` em vez de `flow.resume()`. Chamar `resume()` de dentro de um event loop em execução vai lançar um `RuntimeError`.
</Warning>
### Melhores Práticas para Feedback Assíncrono
1. **Verifique o tipo de retorno**: `kickoff()` retorna `HumanFeedbackPending` quando pausado—não precisa de try/except
2. **Use o método resume correto**: Use `resume()` em código síncrono, `await resume_async()` em código assíncrono
3. **Armazene informações de callback**: Use `callback_info` para armazenar URLs de webhook, IDs de tickets, etc.
4. **Implemente idempotência**: Seu handler de resume deve ser idempotente por segurança
5. **Persistência automática**: O estado é automaticamente salvo quando `HumanFeedbackPending` é lançado e usa `SQLiteFlowPersistence` por padrão
6. **Persistência customizada**: Passe uma instância de persistência customizada para `from_pending()` se necessário
## Aprendendo com Feedback
O parâmetro `learn=True` habilita um ciclo de feedback entre revisores humanos e o sistema de memória. Quando habilitado, o sistema melhora progressivamente suas saídas aprendendo com correções humanas anteriores.
### Como Funciona
1. **Após o feedback**: O LLM extrai lições generalizáveis da saída + feedback e as armazena na memória com `source="hitl"`. Se o feedback for apenas aprovação (ex: "parece bom"), nada é armazenado.
2. **Antes da próxima revisão**: Lições HITL passadas são recuperadas da memória e aplicadas pelo LLM para melhorar a saída antes que o humano a veja.
Com o tempo, o humano vê saídas pré-revisadas progressivamente melhores porque cada correção informa revisões futuras.
### Exemplo
```python Code
class ArticleReviewFlow(Flow):
@start()
def generate_article(self):
return self.crew.kickoff(inputs={"topic": "AI Safety"}).raw
@human_feedback(
message="Revise este rascunho do artigo:",
emit=["approved", "needs_revision"],
llm="gpt-4o-mini",
learn=True, # enable HITL learning
)
@listen(or_("generate_article", "needs_revision"))
def review_article(self):
return self.last_human_feedback.output if self.last_human_feedback else "article draft"
@listen("approved")
def publish(self):
print(f"Publishing: {self.last_human_feedback.output}")
```
**Primeira execução**: O humano vê a saída bruta e diz "Sempre inclua citações para afirmações factuais." A lição é destilada e armazenada na memória.
**Segunda execução**: O sistema recupera a lição sobre citações, pré-revisa a saída para adicionar citações e então mostra a versão melhorada. O trabalho do humano muda de "corrigir tudo" para "identificar o que o sistema deixou passar."
### Configuração
| Parâmetro | Padrão | Descrição |
|-----------|--------|-----------|
| `learn` | `False` | Habilitar aprendizado HITL |
| `learn_limit` | `5` | Máximo de lições passadas para recuperar na pré-revisão |
### Decisões de Design Principais
- **Mesmo LLM para tudo**: O parâmetro `llm` no decorador é compartilhado pelo mapeamento de outcome, destilação de lições e pré-revisão. Não é necessário configurar múltiplos modelos.
- **Saída estruturada**: Tanto a destilação quanto a pré-revisão usam function calling com modelos Pydantic quando o LLM suporta, com fallback para parsing de texto caso contrário.
- **Armazenamento não-bloqueante**: Lições são armazenadas via `remember_many()` que executa em uma thread em segundo plano -- o flow continua imediatamente.
- **Degradação graciosa**: Se o LLM falhar durante a destilação, nada é armazenado. Se falhar durante a pré-revisão, a saída bruta é mostrada. Nenhuma falha bloqueia o flow.
- **Sem escopo/categorias necessários**: Ao armazenar lições, apenas `source` é passado. O pipeline de codificação infere escopo, categorias e importância automaticamente.
<Note>
`learn=True` requer que o Flow tenha memória disponível. Flows obtêm memória automaticamente por padrão, mas se você a desabilitou com `_skip_auto_memory`, o aprendizado HITL será silenciosamente ignorado.
</Note>
## Documentação Relacionada
- [Visão Geral de Flows](/pt-BR/concepts/flows) - Aprenda sobre CrewAI Flows
- [Gerenciamento de Estado em Flows](/pt-BR/guides/flows/mastering-flow-state) - Gerenciando estado em flows
- [Persistência de Flows](/pt-BR/concepts/flows#persistence) - Persistindo estado de flows
- [Roteamento com @router](/pt-BR/concepts/flows#router) - Mais sobre roteamento condicional
- [Input Humano na Execução](/pt-BR/learn/human-input-on-execution) - Input humano no nível de task
- [Memória](/pt-BR/concepts/memory) - O sistema unificado de memória usado pelo aprendizado HITL

View File

@@ -0,0 +1,120 @@
---
title: "Workflows Human-in-the-Loop (HITL)"
description: "Aprenda como implementar workflows Human-in-the-Loop na CrewAI para aprimorar a tomada de decisões"
icon: "user-check"
mode: "wide"
---
Human-in-the-Loop (HITL) é uma abordagem poderosa que combina a inteligência artificial com a experiência humana para aprimorar a tomada de decisões e melhorar os resultados das tarefas. CrewAI oferece várias maneiras de implementar HITL dependendo das suas necessidades.
## Escolhendo Sua Abordagem HITL
CrewAI oferece duas abordagens principais para implementar workflows human-in-the-loop:
| Abordagem | Melhor Para | Integração | Versão |
|----------|----------|-------------|---------|
| **Baseada em Flow** (decorador `@human_feedback`) | Desenvolvimento local, revisão via console, workflows síncronos | [Feedback Humano em Flows](/pt-BR/learn/human-feedback-in-flows) | **1.8.0+** |
| **Baseada em Webhook** (Enterprise) | Deployments em produção, workflows assíncronos, integrações externas (Slack, Teams, etc.) | Este guia | - |
<Tip>
Se você está construindo flows e deseja adicionar etapas de revisão humana com roteamento baseado em feedback, confira o guia [Feedback Humano em Flows](/pt-BR/learn/human-feedback-in-flows) para o decorador `@human_feedback`.
</Tip>
## Configurando Workflows HITL Baseados em Webhook
<Steps>
<Step title="Configure sua Tarefa">
Configure sua tarefa com a entrada humana habilitada:
<Frame>
<img src="/images/enterprise/crew-human-input.png" alt="Entrada Humana Crew" />
</Frame>
</Step>
<Step title="Forneça a URL do Webhook">
Ao iniciar seu crew, inclua uma URL de webhook para entrada humana:
<Frame>
<img src="/images/enterprise/crew-webhook-url.png" alt="URL do Webhook Crew" />
</Frame>
</Step>
<Step title="Receba Notificação do Webhook">
Assim que o crew concluir a tarefa que requer entrada humana, você receberá uma notificação de webhook contendo:
- Execution ID
- Task ID
- Task output
</Step>
<Step title="Revise o Resultado da Tarefa">
O sistema irá pausar no estado `Pending Human Input`. Revise cuidadosamente o resultado da tarefa.
</Step>
<Step title="Envie o Feedback Humano">
Chame o endpoint de retomada do seu crew com as seguintes informações:
<Frame>
<img src="/images/enterprise/crew-resume-endpoint.png" alt="Endpoint de Retomada Crew" />
</Frame>
<Warning>
**Crítico: URLs de Webhook Devem Ser Fornecidas Novamente**:
Você **deve** fornecer as mesmas URLs de webhook (`taskWebhookUrl`, `stepWebhookUrl`, `crewWebhookUrl`) na chamada de resume que você usou na chamada de kickoff. As configurações de webhook **NÃO** são automaticamente transferidas do kickoff - elas devem ser explicitamente incluídas na solicitação de resume para continuar recebendo notificações de conclusão de tarefa, etapas do agente e conclusão do crew.
</Warning>
Exemplo de chamada resume com webhooks:
```bash
curl -X POST {BASE_URL}/resume \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"execution_id": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
"task_id": "research_task",
"human_feedback": "Ótimo trabalho! Por favor, adicione mais detalhes.",
"is_approve": true,
"taskWebhookUrl": "https://your-server.com/webhooks/task",
"stepWebhookUrl": "https://your-server.com/webhooks/step",
"crewWebhookUrl": "https://your-server.com/webhooks/crew"
}'
```
<Warning>
**Impacto do Feedback na Execução da Tarefa**:
É fundamental ter cuidado ao fornecer feedback, pois todo o conteúdo do feedback será incorporado como contexto adicional para execuções futuras da tarefa.
</Warning>
Isso significa:
- Todas as informações do seu feedback passam a fazer parte do contexto da tarefa.
- Detalhes irrelevantes podem influenciar negativamente.
- Feedback conciso e relevante ajuda a manter o foco e a eficiência da tarefa.
- Sempre revise seu feedback cuidadosamente antes de enviar para garantir que contenha apenas informações pertinentes que irão guiar positivamente a execução da tarefa.
</Step>
<Step title="Lidar com Feedback Negativo">
Se você fornecer um feedback negativo:
- O crew irá tentar novamente a tarefa com o contexto adicionado do seu feedback.
- Você receberá outra notificação de webhook para nova revisão.
- Repita os passos 4-6 até ficar satisfeito.
</Step>
<Step title="Continuação da Execução">
Quando você enviar um feedback positivo, a execução prosseguirá para as próximas etapas.
</Step>
</Steps>
## Melhores Práticas
- **Seja Específico**: Forneça feedback claro e acionável que trate diretamente da tarefa em questão
- **Mantenha-se Relevante**: Inclua apenas informações que ajudem a melhorar a execução da tarefa
- **Seja Ágil**: Responda rapidamente às solicitações HITL para evitar atrasos no fluxo
- **Reveja Cuidadosamente**: Verifique seu feedback antes de enviar para garantir a precisão
## Casos de Uso Comuns
Workflows HITL são particularmente valiosos para:
- Garantia de qualidade e validação
- Cenários de tomada de decisão complexa
- Operações sensíveis ou de alto risco
- Tarefas criativas que requerem julgamento humano
- Revisões de conformidade e regulamentação
## Recursos Enterprise
<Card title="Plataforma de Gerenciamento HITL para Flows" icon="users-gear" href="/pt-BR/enterprise/features/flow-hitl-management">
O CrewAI Enterprise oferece um sistema abrangente de gerenciamento HITL para Flows com revisão na plataforma, atribuição de respondentes, permissões, políticas de escalação, gerenciamento de SLA, roteamento dinâmico e análises completas. [Saiba mais →](/pt-BR/enterprise/features/flow-hitl-management)
</Card>

View File

@@ -0,0 +1,99 @@
---
title: Input Humano na Execução
description: Integrando o CrewAI com input humano durante a execução em processos complexos de tomada de decisão e aproveitando ao máximo todos os atributos e ferramentas do agente.
icon: user-plus
mode: "wide"
---
## Input humano na execução dos agentes
O input humano é fundamental em vários cenários de execução de agentes, permitindo que os agentes solicitem informações adicionais ou esclarecimentos quando necessário.
Esse recurso é especialmente útil em processos complexos de tomada de decisão ou quando os agentes precisam de mais detalhes para concluir uma tarefa de forma eficaz.
## Usando input humano com CrewAI
Para integrar input humano durante a execução do agente, defina o parâmetro `human_input` na definição da tarefa. Quando ativado, o agente solicitará informações ao usuário antes de fornecer sua resposta final.
Esse input pode oferecer contexto extra, esclarecer ambiguidades ou validar a saída produzida pelo agente.
### Exemplo:
```shell
pip install crewai
```
```python Code
import os
from crewai import Agent, Task, Crew
from crewai_tools import SerperDevTool
os.environ["SERPER_API_KEY"] = "Your Key" # serper.dev API key
os.environ["OPENAI_API_KEY"] = "Your Key"
# Loading Tools
search_tool = SerperDevTool()
# Define your agents with roles, goals, tools, and additional attributes
researcher = Agent(
role='Senior Research Analyst',
goal='Uncover cutting-edge developments in AI and data science',
backstory=(
"You are a Senior Research Analyst at a leading tech think tank. "
"Your expertise lies in identifying emerging trends and technologies in AI and data science. "
"You have a knack for dissecting complex data and presenting actionable insights."
),
verbose=True,
allow_delegation=False,
tools=[search_tool]
)
writer = Agent(
role='Tech Content Strategist',
goal='Craft compelling content on tech advancements',
backstory=(
"You are a renowned Tech Content Strategist, known for your insightful and engaging articles on technology and innovation. "
"With a deep understanding of the tech industry, you transform complex concepts into compelling narratives."
),
verbose=True,
allow_delegation=True,
tools=[search_tool],
cache=False, # Disable cache for this agent
)
# Create tasks for your agents
task1 = Task(
description=(
"Conduct a comprehensive analysis of the latest advancements in AI in 2025. "
"Identify key trends, breakthrough technologies, and potential industry impacts. "
"Compile your findings in a detailed report. "
"Make sure to check with a human if the draft is good before finalizing your answer."
),
expected_output='A comprehensive full report on the latest AI advancements in 2025, leave nothing out',
agent=researcher,
human_input=True
)
task2 = Task(
description=(
"Using the insights from the researcher\'s report, 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. "
"Aim for a narrative that captures the essence of these breakthroughs and their implications for the future."
),
expected_output='A compelling 3 paragraphs blog post formatted as markdown about the latest AI advancements in 2025',
agent=writer,
human_input=True
)
# Instantiate your crew with a sequential process
crew = Crew(
agents=[researcher, writer],
tasks=[task1, task2],
verbose=True,
memory=True,
planning=True # Enable planning feature for the crew
)
# Get your crew to work!
result = crew.kickoff()
print("######################")
print(result)
```

View File

@@ -0,0 +1,306 @@
---
title: Inicie uma Crew de Forma Assíncrona
description: Inicie uma Crew de Forma Assíncrona
icon: rocket-launch
mode: "wide"
---
## Introdução
A CrewAI oferece a capacidade de iniciar uma crew de forma assíncrona, permitindo que você comece a execução da crew de maneira não bloqueante.
Esse recurso é especialmente útil quando você deseja executar múltiplas crews simultaneamente ou quando precisa realizar outras tarefas enquanto a crew está em execução.
O CrewAI oferece duas abordagens para execução assíncrona:
| Método | Tipo | Descrição |
|--------|------|-------------|
| `akickoff()` | Async nativo | Async/await verdadeiro em toda a cadeia de execução |
| `kickoff_async()` | Baseado em thread | Envolve execução síncrona em `asyncio.to_thread` |
<Note>
Para cargas de trabalho de alta concorrência, `akickoff()` é recomendado pois usa async nativo para execução de tasks, operações de memória e recuperação de conhecimento.
</Note>
## Execução Async Nativa com `akickoff()`
O método `akickoff()` fornece execução async nativa verdadeira, usando async/await em toda a cadeia de execução, incluindo execução de tasks, operações de memória e consultas de conhecimento.
### Assinatura do Método
```python Code
async def akickoff(self, inputs: dict) -> CrewOutput:
```
### Parâmetros
- `inputs` (dict): Um dicionário contendo os dados de entrada necessários para as tarefas.
### Retorno
- `CrewOutput`: Um objeto que representa o resultado da execução da crew.
### Exemplo: Execução Async Nativa de Crew
```python Code
import asyncio
from crewai import Crew, Agent, Task
# Criar um agente
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.",
allow_code_execution=True
)
# Criar uma tarefa
data_analysis_task = Task(
description="Analyze the given dataset and calculate the average age of participants. Ages: {ages}",
agent=coding_agent,
expected_output="The average age of the participants."
)
# Criar uma crew
analysis_crew = Crew(
agents=[coding_agent],
tasks=[data_analysis_task]
)
# Execução async nativa
async def main():
result = await analysis_crew.akickoff(inputs={"ages": [25, 30, 35, 40, 45]})
print("Crew Result:", result)
asyncio.run(main())
```
### Exemplo: Múltiplas Crews Async Nativas
Execute múltiplas crews concorrentemente usando `asyncio.gather()` com async nativo:
```python Code
import asyncio
from crewai import Crew, Agent, Task
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.",
allow_code_execution=True
)
task_1 = Task(
description="Analyze the first dataset and calculate the average age. Ages: {ages}",
agent=coding_agent,
expected_output="The average age of the participants."
)
task_2 = Task(
description="Analyze the second dataset and calculate the average age. Ages: {ages}",
agent=coding_agent,
expected_output="The average age of the participants."
)
crew_1 = Crew(agents=[coding_agent], tasks=[task_1])
crew_2 = Crew(agents=[coding_agent], tasks=[task_2])
async def main():
results = await asyncio.gather(
crew_1.akickoff(inputs={"ages": [25, 30, 35, 40, 45]}),
crew_2.akickoff(inputs={"ages": [20, 22, 24, 28, 30]})
)
for i, result in enumerate(results, 1):
print(f"Crew {i} Result:", result)
asyncio.run(main())
```
### Exemplo: Async Nativo para Múltiplas Entradas
Use `akickoff_for_each()` para executar sua crew contra múltiplas entradas concorrentemente com async nativo:
```python Code
import asyncio
from crewai import Crew, Agent, Task
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.",
allow_code_execution=True
)
data_analysis_task = Task(
description="Analyze the dataset and calculate the average age. Ages: {ages}",
agent=coding_agent,
expected_output="The average age of the participants."
)
analysis_crew = Crew(
agents=[coding_agent],
tasks=[data_analysis_task]
)
async def main():
datasets = [
{"ages": [25, 30, 35, 40, 45]},
{"ages": [20, 22, 24, 28, 30]},
{"ages": [30, 35, 40, 45, 50]}
]
results = await analysis_crew.akickoff_for_each(datasets)
for i, result in enumerate(results, 1):
print(f"Dataset {i} Result:", result)
asyncio.run(main())
```
## Async Baseado em Thread com `kickoff_async()`
O método `kickoff_async()` fornece execução async envolvendo o `kickoff()` síncrono em uma thread. Isso é útil para integração async mais simples ou compatibilidade retroativa.
### Assinatura do Método
```python Code
async def kickoff_async(self, inputs: dict) -> CrewOutput:
```
### Parâmetros
- `inputs` (dict): Um dicionário contendo os dados de entrada necessários para as tarefas.
### Retorno
- `CrewOutput`: Um objeto que representa o resultado da execução da crew.
### Exemplo: Execução Async Baseada em Thread
```python Code
import asyncio
from crewai import Crew, Agent, Task
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.",
allow_code_execution=True
)
data_analysis_task = Task(
description="Analyze the given dataset and calculate the average age of participants. Ages: {ages}",
agent=coding_agent,
expected_output="The average age of the participants."
)
analysis_crew = Crew(
agents=[coding_agent],
tasks=[data_analysis_task]
)
async def async_crew_execution():
result = await analysis_crew.kickoff_async(inputs={"ages": [25, 30, 35, 40, 45]})
print("Crew Result:", result)
asyncio.run(async_crew_execution())
```
### Exemplo: Múltiplas Crews Async Baseadas em Thread
```python Code
import asyncio
from crewai import Crew, Agent, Task
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.",
allow_code_execution=True
)
task_1 = Task(
description="Analyze the first dataset and calculate the average age of participants. Ages: {ages}",
agent=coding_agent,
expected_output="The average age of the participants."
)
task_2 = Task(
description="Analyze the second dataset and calculate the average age of participants. Ages: {ages}",
agent=coding_agent,
expected_output="The average age of the participants."
)
crew_1 = Crew(agents=[coding_agent], tasks=[task_1])
crew_2 = Crew(agents=[coding_agent], tasks=[task_2])
async def async_multiple_crews():
result_1 = crew_1.kickoff_async(inputs={"ages": [25, 30, 35, 40, 45]})
result_2 = crew_2.kickoff_async(inputs={"ages": [20, 22, 24, 28, 30]})
results = await asyncio.gather(result_1, result_2)
for i, result in enumerate(results, 1):
print(f"Crew {i} Result:", result)
asyncio.run(async_multiple_crews())
```
## Streaming Assíncrono
Ambos os métodos async suportam streaming quando `stream=True` está definido na crew:
```python Code
import asyncio
from crewai import Crew, Agent, Task
agent = Agent(
role="Researcher",
goal="Research and summarize topics",
backstory="You are an expert researcher."
)
task = Task(
description="Research the topic: {topic}",
agent=agent,
expected_output="A comprehensive summary of the topic."
)
crew = Crew(
agents=[agent],
tasks=[task],
stream=True # Habilitar streaming
)
async def main():
streaming_output = await crew.akickoff(inputs={"topic": "AI trends in 2024"})
# Iteração async sobre chunks de streaming
async for chunk in streaming_output:
print(f"Chunk: {chunk.content}")
# Acessar resultado final após streaming completar
result = streaming_output.result
print(f"Final result: {result.raw}")
asyncio.run(main())
```
## Possíveis Casos de Uso
- **Geração Paralela de Conteúdo**: Inicie múltiplas crews independentes de forma assíncrona, cada uma responsável por gerar conteúdo sobre temas diferentes. Por exemplo, uma crew pode pesquisar e redigir um artigo sobre tendências em IA, enquanto outra gera posts para redes sociais sobre o lançamento de um novo produto.
- **Tarefas Conjuntas de Pesquisa de Mercado**: Lance múltiplas crews de forma assíncrona para realizar pesquisas de mercado em paralelo. Uma crew pode analisar tendências do setor, outra examinar estratégias de concorrentes e ainda outra avaliar o sentimento do consumidor.
- **Módulos Independentes de Planejamento de Viagem**: Execute crews separadas para planejar diferentes aspectos de uma viagem de forma independente. Uma crew pode cuidar das opções de voo, outra das acomodações e uma terceira do planejamento das atividades.
## Escolhendo entre `akickoff()` e `kickoff_async()`
| Recurso | `akickoff()` | `kickoff_async()` |
|---------|--------------|-------------------|
| Modelo de execução | Async/await nativo | Wrapper baseado em thread |
| Execução de tasks | Async com `aexecute_sync()` | Síncrono em thread pool |
| Operações de memória | Async | Síncrono em thread pool |
| Recuperação de conhecimento | Async | Síncrono em thread pool |
| Melhor para | Alta concorrência, cargas I/O-bound | Integração async simples |
| Suporte a streaming | Sim | Sim |

View File

@@ -0,0 +1,54 @@
---
title: Kickoff Crew para Cada
description: Kickoff Crew para Cada Item em uma Lista
icon: at
mode: "wide"
---
## Introdução
A CrewAI oferece a capacidade de iniciar um crew para cada item em uma lista, permitindo que você execute o crew para cada item da lista.
Esse recurso é particularmente útil quando é necessário realizar o mesmo conjunto de tarefas para vários itens.
## Iniciando um Crew para Cada Item
Para iniciar um crew para cada item em uma lista, utilize o método `kickoff_for_each()`.
Esse método executa o crew para cada item da lista, permitindo o processamento eficiente de múltiplos itens.
Veja um exemplo de como iniciar um crew para cada item em uma lista:
```python Code
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.",
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}",
agent=coding_agent,
expected_output="The average age calculated from the dataset"
)
# Create a crew and add the task
analysis_crew = Crew(
agents=[coding_agent],
tasks=[data_analysis_task],
verbose=True,
memory=False
)
datasets = [
{ "ages": [25, 30, 35, 40, 45] },
{ "ages": [20, 25, 30, 35, 40] },
{ "ages": [30, 35, 40, 45, 50] }
]
# Execute the crew
result = analysis_crew.kickoff_for_each(inputs=datasets)
```

View File

@@ -0,0 +1,213 @@
---
title: Conecte-se a qualquer LLM
description: Guia abrangente sobre como integrar o CrewAI a diversos Large Language Models (LLMs) usando o LiteLLM, incluindo provedores compatíveis e opções de configuração.
icon: brain-circuit
mode: "wide"
---
## Conecte o CrewAI a LLMs
O CrewAI conecta-se a LLMs por meio de integrações nativas via SDK para os provedores mais populares (OpenAI, Anthropic, Google Gemini, Azure e AWS Bedrock), e usa o LiteLLM como alternativa flexível para todos os demais provedores.
<Note>
Por padrão, o CrewAI usa o modelo `gpt-4o-mini`. Isso é determinado pela variável de ambiente `OPENAI_MODEL_NAME`, que tem como padrão "gpt-4o-mini" se não for definida.
Você pode facilmente configurar seus agentes para usar um modelo ou provedor diferente, conforme descrito neste guia.
</Note>
## Provedores Compatíveis
O LiteLLM oferece suporte a uma ampla gama de provedores, incluindo, mas não se limitando a:
- OpenAI
- Anthropic
- Google (Vertex AI, Gemini)
- Azure OpenAI
- AWS (Bedrock, SageMaker)
- Cohere
- VoyageAI
- Hugging Face
- Ollama
- Mistral AI
- Replicate
- Together AI
- AI21
- Cloudflare Workers AI
- DeepInfra
- Groq
- SambaNova
- [NVIDIA NIMs](https://docs.api.nvidia.com/nim/reference/models-1)
- E muitos outros!
Para uma lista completa e sempre atualizada dos provedores suportados, consulte a [documentação de Provedores do LiteLLM](https://docs.litellm.ai/docs/providers).
<Info>
Para usar qualquer provedor não coberto por uma integração nativa, adicione o LiteLLM como dependência ao seu projeto:
```bash
uv add 'crewai[litellm]'
```
Provedores nativos (OpenAI, Anthropic, Google Gemini, Azure, AWS Bedrock) usam seus próprios extras de SDK — consulte os [Exemplos de Configuração de Provedores](/pt-BR/concepts/llms#exemplos-de-configuração-de-provedores).
</Info>
## Alterando a LLM
Para utilizar uma LLM diferente com seus agentes CrewAI, você tem várias opções:
<Tabs>
<Tab title="Usando um Identificador de String">
Passe o nome do modelo como uma string ao inicializar o agente:
<CodeGroup>
```python Code
from crewai import Agent
# Usando o GPT-4 da OpenAI
openai_agent = Agent(
role='OpenAI Expert',
goal='Provide insights using GPT-4',
backstory="An AI assistant powered by OpenAI's latest model.",
llm='gpt-4'
)
# Usando o Claude da Anthropic
claude_agent = Agent(
role='Anthropic Expert',
goal='Analyze data using Claude',
backstory="An AI assistant leveraging Anthropic's language model.",
llm='claude-2'
)
```
</CodeGroup>
</Tab>
<Tab title="Usando a Classe LLM">
Para uma configuração mais detalhada, utilize a classe LLM:
<CodeGroup>
```python Code
from crewai import Agent, LLM
llm = LLM(
model="gpt-4",
temperature=0.7,
base_url="https://api.openai.com/v1",
api_key="your-api-key-here"
)
agent = Agent(
role='Customized LLM Expert',
goal='Provide tailored responses',
backstory="An AI assistant with custom LLM settings.",
llm=llm
)
```
</CodeGroup>
</Tab>
</Tabs>
## Opções de Configuração
Ao configurar uma LLM para o seu agente, você tem acesso a uma variedade de parâmetros:
| Parâmetro | Tipo | Descrição |
|:----------|:-----:|:-------------|
| **model** | `str` | O nome do modelo a ser utilizado (ex.: "gpt-4", "claude-2") |
| **temperature** | `float` | Controla o grau de aleatoriedade nas respostas (0.0 a 1.0) |
| **max_tokens** | `int` | Número máximo de tokens a serem gerados |
| **top_p** | `float` | Controla a diversidade das respostas (0.0 a 1.0) |
| **frequency_penalty** | `float` | Penaliza novos tokens com base na frequência em que já apareceram no texto |
| **presence_penalty** | `float` | Penaliza novos tokens com base na presença deles no texto até o momento |
| **stop** | `str`, `List[str]` | Sequência(s) que interrompem a geração do texto |
| **base_url** | `str` | URL base do endpoint da API |
| **api_key** | `str` | Sua chave de API para autenticação |
Para uma lista completa de parâmetros e suas respectivas descrições, consulte a documentação da classe LLM.
## Conectando-se a LLMs Compatíveis com OpenAI
Você pode se conectar a LLMs compatíveis com a OpenAI usando variáveis de ambiente ou definindo atributos específicos na classe LLM:
<Tabs>
<Tab title="Usando Variáveis de Ambiente">
<CodeGroup>
```python Generic
import os
os.environ["OPENAI_API_KEY"] = "your-api-key"
os.environ["OPENAI_API_BASE"] = "https://api.your-provider.com/v1"
os.environ["OPENAI_MODEL_NAME"] = "your-model-name"
```
```python Google
import os
# Exemplo usando a API compatível com OpenAI do Gemini.
os.environ["OPENAI_API_KEY"] = "your-gemini-key" # Deve começar com AIza...
os.environ["OPENAI_API_BASE"] = "https://generativelanguage.googleapis.com/v1beta/openai/"
os.environ["OPENAI_MODEL_NAME"] = "openai/gemini-2.0-flash" # Adicione aqui seu modelo do Gemini, sob openai/
```
</CodeGroup>
</Tab>
<Tab title="Usando Atributos da Classe LLM">
<CodeGroup>
```python Generic
llm = LLM(
model="custom-model-name",
api_key="your-api-key",
base_url="https://api.your-provider.com/v1"
)
agent = Agent(llm=llm, ...)
```
```python Google
# Exemplo usando a API compatível com OpenAI do Gemini
llm = LLM(
model="openai/gemini-2.0-flash",
base_url="https://generativelanguage.googleapis.com/v1beta/openai/",
api_key="your-gemini-key", # Deve começar com AIza...
)
agent = Agent(llm=llm, ...)
```
</CodeGroup>
</Tab>
</Tabs>
## Utilizando Modelos Locais com Ollama
Para modelos locais como os oferecidos pelo Ollama:
<Steps>
<Step title="Baixe e instale o Ollama">
[Clique aqui para baixar e instalar o Ollama](https://ollama.com/download)
</Step>
<Step title="Puxe o modelo desejado">
Por exemplo, execute `ollama pull llama3.2` para baixar o modelo.
</Step>
<Step title="Configure seu agente">
<CodeGroup>
```python Code
agent = Agent(
role='Local AI Expert',
goal='Process information using a local model',
backstory="An AI assistant running on local hardware.",
llm=LLM(model="ollama/llama3.2", base_url="http://localhost:11434")
)
```
</CodeGroup>
</Step>
</Steps>
## Alterando a URL Base da API
Você pode alterar a URL base da API para qualquer provedor de LLM definindo o parâmetro `base_url`:
```python Code
llm = LLM(
model="custom-model-name",
base_url="https://api.your-provider.com/v1",
api_key="your-api-key"
)
agent = Agent(llm=llm, ...)
```
Isso é particularmente útil ao trabalhar com APIs compatíveis com a OpenAI ou quando você precisa especificar um endpoint diferente para o provedor escolhido.
## Conclusão
Ao utilizar o LiteLLM, o CrewAI oferece integração transparente com uma vasta gama de LLMs. Essa flexibilidade permite que você escolha o modelo mais adequado para sua necessidade específica, seja priorizando desempenho, custo-benefício ou implantação local. Lembre-se de consultar a [documentação do LiteLLM](https://docs.litellm.ai/docs/) para obter as informações mais atualizadas sobre modelos suportados e opções de configuração.

View File

@@ -0,0 +1,388 @@
---
title: Hooks de Chamada LLM
description: Aprenda a usar hooks de chamada LLM para interceptar, modificar e controlar interações com modelos de linguagem no CrewAI
mode: "wide"
---
Os Hooks de Chamada LLM fornecem controle fino sobre interações com modelos de linguagem durante a execução do agente. Esses hooks permitem interceptar chamadas LLM, modificar prompts, transformar respostas, implementar gates de aprovação e adicionar logging ou monitoramento personalizado.
## Visão Geral
Os hooks LLM são executados em dois pontos críticos:
- **Antes da Chamada LLM**: Modificar mensagens, validar entradas ou bloquear execução
- **Depois da Chamada LLM**: Transformar respostas, sanitizar saídas ou modificar histórico de conversação
## Tipos de Hook
### Hooks Antes da Chamada LLM
Executados antes de cada chamada LLM, esses hooks podem:
- Inspecionar e modificar mensagens enviadas ao LLM
- Bloquear execução LLM com base em condições
- Implementar limitação de taxa ou gates de aprovação
- Adicionar contexto ou mensagens do sistema
- Registrar detalhes da requisição
**Assinatura:**
```python
def before_hook(context: LLMCallHookContext) -> bool | None:
# Retorne False para bloquear execução
# Retorne True ou None para permitir execução
...
```
### Hooks Depois da Chamada LLM
Executados depois de cada chamada LLM, esses hooks podem:
- Modificar ou sanitizar respostas do LLM
- Adicionar metadados ou formatação
- Registrar detalhes da resposta
- Atualizar histórico de conversação
- Implementar filtragem de conteúdo
**Assinatura:**
```python
def after_hook(context: LLMCallHookContext) -> str | None:
# Retorne string de resposta modificada
# Retorne None para manter resposta original
...
```
## Contexto do Hook LLM
O objeto `LLMCallHookContext` fornece acesso abrangente ao estado de execução:
```python
class LLMCallHookContext:
executor: CrewAgentExecutor # Referência completa ao executor
messages: list # Lista de mensagens mutável
agent: Agent # Agente atual
task: Task # Tarefa atual
crew: Crew # Instância da crew
llm: BaseLLM # Instância do LLM
iterations: int # Contagem de iteração atual
response: str | None # Resposta do LLM (apenas hooks posteriores)
```
### Modificando Mensagens
**Importante:** Sempre modifique mensagens in-place:
```python
# ✅ Correto - modificar in-place
def add_context(context: LLMCallHookContext) -> None:
context.messages.append({"role": "system", "content": "Seja conciso"})
# ❌ Errado - substitui referência da lista
def wrong_approach(context: LLMCallHookContext) -> None:
context.messages = [{"role": "system", "content": "Seja conciso"}]
```
## Métodos de Registro
### 1. Registro Baseado em Decoradores (Recomendado)
Use decoradores para sintaxe mais limpa:
```python
from crewai.hooks import before_llm_call, after_llm_call
@before_llm_call
def validate_iteration_count(context):
"""Valida a contagem de iterações."""
if context.iterations > 10:
print("⚠️ Máximo de iterações excedido")
return False # Bloquear execução
return None
@after_llm_call
def sanitize_response(context):
"""Remove dados sensíveis."""
if context.response and "API_KEY" in context.response:
return context.response.replace("API_KEY", "[CENSURADO]")
return None
```
### 2. Hooks com Escopo de Crew
Registre hooks para uma instância específica de crew:
```python
from crewai import CrewBase
from crewai.project import crew
from crewai.hooks import before_llm_call_crew, after_llm_call_crew
@CrewBase
class MyProjCrew:
@before_llm_call_crew
def validate_inputs(self, context):
# Aplica-se apenas a esta crew
if context.iterations == 0:
print(f"Iniciando tarefa: {context.task.description}")
return None
@after_llm_call_crew
def log_responses(self, context):
# Logging específico da crew
print(f"Comprimento da resposta: {len(context.response)}")
return None
@crew
def crew(self) -> Crew:
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True
)
```
## Casos de Uso Comuns
### 1. Limitação de Iterações
```python
@before_llm_call
def limit_iterations(context: LLMCallHookContext) -> bool | None:
"""Previne loops infinitos limitando iterações."""
max_iterations = 15
if context.iterations > max_iterations:
print(f"⛔ Bloqueado: Excedeu {max_iterations} iterações")
return False # Bloquear execução
return None
```
### 2. Gate de Aprovação Humana
```python
@before_llm_call
def require_approval(context: LLMCallHookContext) -> bool | None:
"""Requer aprovação após certas iterações."""
if context.iterations > 5:
response = context.request_human_input(
prompt=f"Iteração {context.iterations}: Aprovar chamada LLM?",
default_message="Pressione Enter para aprovar, ou digite 'não' para bloquear:"
)
if response.lower() == "não":
print("🚫 Chamada LLM bloqueada pelo usuário")
return False
return None
```
### 3. Adicionando Contexto do Sistema
```python
@before_llm_call
def add_guardrails(context: LLMCallHookContext) -> None:
"""Adiciona diretrizes de segurança a cada chamada LLM."""
context.messages.append({
"role": "system",
"content": "Garanta que as respostas sejam factuais e cite fontes quando possível."
})
return None
```
### 4. Sanitização de Resposta
```python
@after_llm_call
def sanitize_sensitive_data(context: LLMCallHookContext) -> str | None:
"""Remove padrões sensíveis."""
if not context.response:
return None
import re
sanitized = context.response
sanitized = re.sub(r'\b\d{3}\.\d{3}\.\d{3}-\d{2}\b', '[CPF-CENSURADO]', sanitized)
sanitized = re.sub(r'\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b', '[CARTÃO-CENSURADO]', sanitized)
return sanitized
```
### 5. Rastreamento de Custos
```python
import tiktoken
@before_llm_call
def track_token_usage(context: LLMCallHookContext) -> None:
"""Rastreia tokens de entrada."""
encoding = tiktoken.get_encoding("cl100k_base")
total_tokens = sum(
len(encoding.encode(msg.get("content", "")))
for msg in context.messages
)
print(f"📊 Tokens de entrada: ~{total_tokens}")
return None
@after_llm_call
def track_response_tokens(context: LLMCallHookContext) -> None:
"""Rastreia tokens de resposta."""
if context.response:
encoding = tiktoken.get_encoding("cl100k_base")
tokens = len(encoding.encode(context.response))
print(f"📊 Tokens de resposta: ~{tokens}")
return None
```
### 6. Logging de Debug
```python
@before_llm_call
def debug_request(context: LLMCallHookContext) -> None:
"""Debug de requisição LLM."""
print(f"""
🔍 Debug de Chamada LLM:
- Agente: {context.agent.role}
- Tarefa: {context.task.description[:50]}...
- Iteração: {context.iterations}
- Contagem de Mensagens: {len(context.messages)}
- Última Mensagem: {context.messages[-1] if context.messages else 'Nenhuma'}
""")
return None
@after_llm_call
def debug_response(context: LLMCallHookContext) -> None:
"""Debug de resposta LLM."""
if context.response:
print(f"✅ Preview da Resposta: {context.response[:100]}...")
return None
```
## Gerenciamento de Hooks
### Desregistrando Hooks
```python
from crewai.hooks import (
unregister_before_llm_call_hook,
unregister_after_llm_call_hook
)
# Desregistrar hook específico
def my_hook(context):
...
register_before_llm_call_hook(my_hook)
# Mais tarde...
unregister_before_llm_call_hook(my_hook) # Retorna True se encontrado
```
### Limpando Hooks
```python
from crewai.hooks import (
clear_before_llm_call_hooks,
clear_after_llm_call_hooks,
clear_all_llm_call_hooks
)
# Limpar tipo específico de hook
count = clear_before_llm_call_hooks()
print(f"Limpou {count} hooks antes")
# Limpar todos os hooks LLM
before_count, after_count = clear_all_llm_call_hooks()
print(f"Limpou {before_count} hooks antes e {after_count} hooks depois")
```
## Padrões Avançados
### Execução Condicional de Hook
```python
@before_llm_call
def conditional_blocking(context: LLMCallHookContext) -> bool | None:
"""Bloqueia apenas em condições específicas."""
# Bloquear apenas para agentes específicos
if context.agent.role == "researcher" and context.iterations > 10:
return False
# Bloquear apenas para tarefas específicas
if "sensível" in context.task.description.lower() and context.iterations > 5:
return False
return None
```
### Modificações com Consciência de Contexto
```python
@before_llm_call
def adaptive_prompting(context: LLMCallHookContext) -> None:
"""Adiciona contexto diferente baseado na iteração."""
if context.iterations == 0:
context.messages.append({
"role": "system",
"content": "Comece com uma visão geral de alto nível."
})
elif context.iterations > 3:
context.messages.append({
"role": "system",
"content": "Foque em detalhes específicos e forneça exemplos."
})
return None
```
## Melhores Práticas
1. **Mantenha Hooks Focados**: Cada hook deve ter uma responsabilidade única
2. **Evite Computação Pesada**: Hooks executam em cada chamada LLM
3. **Trate Erros Graciosamente**: Use try-except para prevenir falhas de hooks
4. **Use Type Hints**: Aproveite `LLMCallHookContext` para melhor suporte IDE
5. **Documente Comportamento do Hook**: Especialmente para condições de bloqueio
6. **Teste Hooks Independentemente**: Teste unitário de hooks antes de usar em produção
7. **Limpe Hooks em Testes**: Use `clear_all_llm_call_hooks()` entre execuções de teste
8. **Modifique In-Place**: Sempre modifique `context.messages` in-place, nunca substitua
## Tratamento de Erros
```python
@before_llm_call
def safe_hook(context: LLMCallHookContext) -> bool | None:
try:
# Sua lógica de hook
if some_condition:
return False
except Exception as e:
print(f"⚠️ Erro no hook: {e}")
# Decida: permitir ou bloquear em erro
return None # Permitir execução apesar do erro
```
## Segurança de Tipos
```python
from crewai.hooks import LLMCallHookContext, BeforeLLMCallHookType, AfterLLMCallHookType
# Anotações de tipo explícitas
def my_before_hook(context: LLMCallHookContext) -> bool | None:
return None
def my_after_hook(context: LLMCallHookContext) -> str | None:
return None
# Registro type-safe
register_before_llm_call_hook(my_before_hook)
register_after_llm_call_hook(my_after_hook)
```
## Solução de Problemas
### Hook Não Está Executando
- Verifique se o hook está registrado antes da execução da crew
- Verifique se hook anterior retornou `False` (bloqueia hooks subsequentes)
- Garanta que assinatura do hook corresponda ao tipo esperado
### Modificações de Mensagem Não Persistem
- Use modificações in-place: `context.messages.append()`
- Não substitua a lista: `context.messages = []`
### Modificações de Resposta Não Funcionam
- Retorne a string modificada dos hooks posteriores
- Retornar `None` mantém a resposta original
## Conclusão
Os Hooks de Chamada LLM fornecem capacidades poderosas para controlar e monitorar interações com modelos de linguagem no CrewAI. Use-os para implementar guardrails de segurança, gates de aprovação, logging, rastreamento de custos e sanitização de respostas. Combinados com tratamento adequado de erros e segurança de tipos, os hooks permitem sistemas de agentes robustos e prontos para produção.

View File

@@ -0,0 +1,815 @@
---
title: "Guia Estratégico de Seleção de LLMs"
description: "Framework estratégico para escolher o LLM certo para seus agentes CrewAI e escrever definições eficazes de tarefas e agentes"
icon: "brain-circuit"
mode: "wide"
---
## A Abordagem CrewAI para Seleção de LLMs
Em vez de recomendações prescritivas de modelos, defendemos um **framework de pensamento** que ajude você a tomar decisões informadas com base no seu caso de uso, restrições e requisitos específicos. O cenário de LLMs evolui rapidamente, com novos modelos surgindo regularmente e os existentes sendo atualizados frequentemente. O que mais importa é desenvolver uma abordagem sistemática de avaliação que permaneça relevante independentemente dos modelos disponíveis no momento.
<Note>
Este guia foca em pensamento estratégico em vez de recomendações de modelos
específicos, já que o cenário dos LLMs evolui rapidamente.
</Note>
## Framework de Decisão Rápida
<Steps>
<Step title="Analise Suas Tarefas">
Comece entendendo profundamente o que suas tarefas realmente exigem.
Considere a complexidade cognitiva envolvida, a profundidade de raciocínio
necessária, o formato dos resultados esperados e a quantidade de contexto
que o modelo precisará processar. Essa análise fundamental guiará todas as
decisões seguintes.
</Step>
<Step title="Mapeie as Capacidades dos Modelos">
Assim que você compreende seus requisitos, mapeie-os para as forças dos
modelos. Diferentes famílias de modelos se destacam em diferentes tipos de
trabalho; alguns são otimizados para raciocínio e análise, outros para
criatividade e geração de conteúdo, e outros para velocidade e eficiência.
</Step>
<Step title="Considere Restrições">
Leve em conta suas reais restrições operacionais, incluindo limitações
orçamentárias, requisitos de latência, necessidades de privacidade de dados
e capacidades de infraestrutura. O melhor modelo teoricamente pode não ser a
melhor escolha prática para sua situação.
</Step>
<Step title="Teste e Itere">
Comece com modelos confiáveis e bem conhecidos e otimize com base no
desempenho real no seu caso de uso. Os resultados práticos frequentemente
diferem dos benchmarks teóricos, então testes empíricos são cruciais.
</Step>
</Steps>
## Framework Central de Seleção
### a. Pensamento Orientado à Tarefa
O passo mais crítico na seleção de LLMs é entender o que sua tarefa realmente exige. Frequentemente, equipes escolhem modelos com base em reputação geral ou pontuações de benchmark, sem analisar cuidadosamente suas necessidades específicas. Essa abordagem leva tanto ao superdimensionamento de tarefas simples usando modelos caros e complexos quanto à subutilização em tarefas sofisticadas com modelos sem as capacidades necessárias.
<Tabs>
<Tab title="Complexidade de Raciocínio">
- **Tarefas Simples** representam a maioria do trabalho diário de IA e incluem seguir instruções básicas, processar dados simples e formatação elementar. Estas tarefas geralmente têm entradas e saídas claras, com mínima ambiguidade. A carga cognitiva é baixa e o modelo precisa apenas seguir instruções explícitas, não realizar raciocínio complexo.
- **Tarefas Complexas** exigem raciocínio de múltiplas etapas, pensamento estratégico e a capacidade de lidar com informações ambíguas ou incompletas. Podem envolver análise de múltiplas fontes de dados, desenvolvimento de estratégias abrangentes ou resolução de problemas que precisam ser decompostos em componentes menores. O modelo deve manter o contexto ao longo de várias etapas de raciocínio e frequentemente precisa inferir informações não explicitamente declaradas.
- **Tarefas Criativas** exigem um tipo diferente de capacidade cognitiva, focada em gerar conteúdo novo, envolvente e adequado ao contexto. Isso inclui storytelling, criação de textos de marketing e solução criativa de problemas. O modelo deve compreender nuances, tom e público, produzindo conteúdo autêntico e envolvente, não apenas fórmulas.
</Tab>
<Tab title="Requisitos de Saída">
- **Dados Estruturados** exigem precisão e consistência na adesão ao formato. Ao trabalhar com JSON, XML ou formatos de banco de dados, o modelo deve produzir saídas sintaticamente corretas, que possam ser processadas programaticamente. Essas tarefas possuem requisitos rígidos de validação e pouca tolerância a erros de formato, tornando a confiabilidade mais importante que a criatividade.
- **Conteúdo Criativo** requer equilíbrio entre competência técnica e criatividade. O modelo precisa compreender o público, tom e voz da marca, ao mesmo tempo em que produz conteúdo que engaja leitores e atinge objetivos comunicativos específicos. A qualidade aqui é mais subjetiva e exige modelos capazes de adaptar o estilo de escrita a diferentes contextos e propósitos.
- **Conteúdo Técnico** situa-se entre dados estruturados e conteúdo criativo, demandando precisão e clareza. Documentação, geração de código e análises técnicas precisam ser exatas e completas, mas ainda assim acessíveis ao público-alvo. O modelo deve entender conceitos técnicos complexos e comunicá-los de forma eficaz.
</Tab>
<Tab title="Necessidades de Contexto">
- **Contexto Curto** envolve tarefas imediatas e focalizadas, onde o modelo processa informações limitadas rapidamente. São interações transacionais em que velocidade e eficiência importam mais do que compreensão profunda. O modelo não precisa manter histórico extenso ou processar grandes documentos.
- **Contexto Longo** é necessário ao lidar com documentos substanciais, conversas extensas ou tarefas complexas de múltiplas partes. O modelo precisa manter coerência ao longo de milhares de tokens, referenciando informações anteriores com precisão. Essencial para análise de documentos, pesquisa abrangente e sistemas de diálogo sofisticados.
- **Contexto Muito Longo** ultrapassa os limites do possível hoje, com processamento de documentos massivos, síntese de pesquisas extensas ou interações multi-sessão. São casos que exigem modelos projetados especificamente para lidar com contexto estendido e envolvem trade-offs entre extensão e velocidade.
</Tab>
</Tabs>
### b. Mapeamento de Capacidades do Modelo
Entender as capacidades dos modelos exige ir além do marketing e dos benchmarks, analisando forças e limitações fundamentais das arquiteturas e métodos de treinamento.
<AccordionGroup>
<Accordion title="Modelos de Raciocínio" icon="brain">
Modelos de raciocínio formam uma categoria especializada, projetada para tarefas de pensamento complexo e de múltiplas etapas. Eles se destacam na resolução de problemas que requerem análise cuidadosa, planejamento estratégico ou decomposição sistemática. Normalmente aplicam técnicas como chain-of-thought ou tree-of-thought para conduzir o raciocínio passo a passo.
O ponto forte é manter consistência lógica em cadeias longas de raciocínio e decompor problemas complexos em partes gerenciáveis. São especialmente valiosos para planejamento estratégico, análise complexa e situações onde a qualidade do raciocínio importa mais que a velocidade.
Entretanto, há trade-offs em termos de custo e velocidade. Podem ser menos adequados para tarefas criativas ou operações simples, onde suas capacidades avançadas não são necessárias. Considere-os quando as tarefas realmente se beneficiarem dessa análise detalhada.
</Accordion>
<Accordion title="Modelos de Uso Geral" icon="microchip">
Modelos de uso geral oferecem uma abordagem equilibrada, com desempenho sólido em uma ampla gama de tarefas, sem especialização extrema. São treinados em conjuntos de dados diversificados e otimizados para versatilidade.
A principal vantagem é a confiabilidade previsível em diversos trabalhos: pesquisa, análise, criação de conteúdo, processamento de dados. São ótimas opções iniciais para equipes que buscam consistência ao lidar com fluxos variados.
Embora não atinjam picos de desempenho como modelos especializados, oferecem simplicidade operacional e baixa complexidade na gestão. São o melhor ponto de partida para novos projetos, permitindo descobertas de necessidades antes de avançar para otimizações.
</Accordion>
<Accordion title="Modelos Rápidos & Eficientes" icon="bolt">
Modelos rápidos e eficientes priorizam velocidade, custo e eficiência de recursos, em vez de raciocínio sofisticado. São otimizados para cenários de alto volume onde respostas rápidas e baixos custos são mais importantes que compreensão ou criatividade profunda.
Brilham em operações rotineiras, processamento simples de dados, chamadas de funções e tarefas de alto volume. Aplicações que processam muitos pedidos rapidamente ou operam sob restrições orçamentárias se beneficiam desses modelos.
O ponto crucial é garantir que suas capacidades atendam às exigências da tarefa. Podem não atender tarefas que exijam entendimento profundo, raciocínio complexo ou geração de conteúdo sofisticado. São ideais para tarefas rotineiras bem definidas.
</Accordion>
<Accordion title="Modelos Criativos" icon="pen">
Modelos criativos são otimizados para geração de conteúdo, qualidade de escrita e pensamento inovador. Excelentes na compreensão de nuances, tom e estilo, produzindo conteúdo envolvente e natural.
O ponto forte está em adaptar o estilo para diferentes públicos, manter voz e tom consistentes e engajar leitores. Performam melhor em storytelling, textos publicitários, comunicações de marca e outras tarefas com criatividade como foco.
Ao selecionar esses modelos, considere não apenas a habilidade de gerar texto, mas a compreensão de público, contexto e objetivo. Os melhores modelos criativos adaptam a saída à voz da marca, diferentes segmentos e mantêm consistência em peças longas.
</Accordion>
<Accordion title="Modelos Open Source" icon="code">
Modelos open source oferecem vantagens em controle de custos, potencial de customização, privacidade de dados e flexibilidade de deployment. Podem ser rodados localmente ou em infraestrutura própria, dando controle total sobre dados e comportamento.
Os principais benefícios incluem eliminação de custos por token, possibilidade de fine-tuning, privacidade total e independência de fornecedores externos. Perfeitos para organizações com necessidade de privacidade, orçamento limitado ou desejo de customização.
Contudo, requerem maior expertise técnica para implantar e manter. Considere custos de infraestrutura, complexidade de gestão e esforços contínuos de atualização e otimização ao avaliar modelos open source. O custo total pode ser maior que o de alternativas em nuvem devido a esse overhead.
</Accordion>
</AccordionGroup>
## Padrões Estratégicos de Configuração
### a. Abordagem Multi-Modelo
<Tip>
Use diferentes modelos para diferentes propósitos dentro da mesma crew para
otimizar desempenho e custos.
</Tip>
As implementações CrewAI mais sofisticadas empregam múltiplos modelos estrategicamente, designando-os conforme as funções e necessidades dos agentes. Assim, é possível otimizar desempenho e custos usando o modelo mais adequado para cada tipo de tarefa.
Agentes de planejamento se beneficiam de modelos de raciocínio para pensamento estratégico e análise multi-etapas. Esses agentes funcionam como o "cérebro" da operação. Agentes de conteúdo têm melhor desempenho com modelos criativos focados em qualidade de escrita e engajamento. Agentes de processamento, responsáveis por operações rotineiras, podem usar modelos eficientes priorizando velocidade.
**Exemplo: Crew de Pesquisa e Análise**
```python
from crewai import Agent, Task, Crew, LLM
# Modelo de raciocínio para planejamento estratégico
manager_llm = LLM(model="gemini-2.5-flash-preview-05-20", temperature=0.1)
# Modelo criativo para gerar conteúdo
content_llm = LLM(model="claude-3-5-sonnet-20241022", temperature=0.7)
# Modelo eficiente para processamento de dados
processing_llm = LLM(model="gpt-4o-mini", temperature=0)
research_manager = Agent(
role="Research Strategy Manager",
goal="Develop comprehensive research strategies and coordinate team efforts",
backstory="Expert research strategist with deep analytical capabilities",
llm=manager_llm, # Modelo de alto nível para raciocínio complexo
verbose=True
)
content_writer = Agent(
role="Research Content Writer",
goal="Transform research findings into compelling, well-structured reports",
backstory="Skilled writer who excels at making complex topics accessible",
llm=content_llm, # Modelo criativo para conteúdo envolvente
verbose=True
)
data_processor = Agent(
role="Data Analysis Specialist",
goal="Extract and organize key data points from research sources",
backstory="Detail-oriented analyst focused on accuracy and efficiency",
llm=processing_llm, # Modelo rápido para tarefas rotineiras
verbose=True
)
crew = Crew(
agents=[research_manager, content_writer, data_processor],
tasks=[...], # Suas tarefas específicas
manager_llm=manager_llm, # Manager usa o modelo de raciocínio
verbose=True
)
```
O segredo do sucesso na implementação multi-modelo está em entender como os agentes interagem e garantir que as capacidades dos modelos estejam alinhadas às responsabilidades. Isso exige planejamento estratégico, mas traz ganhos significativos em qualidade dos resultados e eficiência operacional.
### b. Seleção Específica por Componente
<Tabs>
<Tab title="Manager LLM">
O manager LLM desempenha papel central em fluxos hierárquicos CrewAI, coordenando agentes e tarefas. Este modelo precisa se destacar em delegação, priorização de tarefas e manutenção de contexto em várias operações simultâneas.
LLMs de manager eficazes exigem forte raciocínio para delegar bem, desempenho consistente para coordenar previsivelmente e excelente gestão de contexto para acompanhar o estado dos agentes. O modelo deve entender capacidades e limitações dos agentes enquanto otimiza a alocação de tarefas.
O custo é especialmente relevante, já que este LLM participa de todas as operações. O modelo precisa entregar capacidades suficientes, sem o preço premium de opções sofisticadas demais, buscando sempre o equilíbrio entre performance e valor.
</Tab>
<Tab title="Function Calling LLM">
LLMs de function calling gerenciam o uso de ferramentas por todos os agentes, sendo críticos em crews que dependem fortemente de APIs externas e ferramentas. Devem ser precisos na extração de parâmetros e no processamento das respostas.
As características mais importantes são precisão e confiabilidade, não criatividade ou raciocínio avançado. O modelo deve extrair parâmetros corretos de comandos em linguagem natural consistentemente e processar respostas de ferramentas adequadamente. Velocidade também importa, pois o uso de ferramentas pode envolver múltiplas idas e vindas de informação.
Muitas equipes descobrem que modelos especializados em function calling ou de uso geral com forte suporte a ferramentas funcionam melhor do que modelos criativos ou de raciocínio nesse papel. O fundamental é assegurar que o modelo consiga converter instruções em chamadas estruturadas sem falhas.
</Tab>
<Tab title="Sobrescritas Específicas de Agente">
Agentes individuais podem sobrescrever o LLM do nível da crew quando suas necessidades diferem significativamente das do restante. Isso permite otimização pontual, mantendo a simplicidade operacional para os demais agentes.
Considere sobrescritas quando a função do agente exige capacidades distintas. Por exemplo, um agente de redação criativa pode se beneficiar de um LLM otimizado para geração de conteúdo, enquanto um analista de dados pode preferir um modelo voltado ao raciocínio.
O desafio é balancear otimização com complexidade operacional. Cada modelo adicional aumenta a complexidade de deployment, monitoramento e custos. Foque em sobrescritas apenas quando a melhoria justificar essa complexidade.
</Tab>
</Tabs>
## Framework de Definição de Tarefas
### a. Foque em Clareza, Não em Complexidade
Definir bem as tarefas é frequentemente mais importante do que a seleção do modelo no resultado gerado pelos agentes CrewAI. Tarefas bem formuladas orientam claramente mesmo modelos simples a terem bom desempenho. Já tarefas mal definidas prejudicam até os modelos mais avançados.
<AccordionGroup>
<Accordion title="Descrições de Tarefas Eficazes" icon="list-check">
As melhores descrições de tarefas equilibram detalhamento e clareza. Devem definir o objetivo de forma clara e sem ambiguidade, além de explicar o método a ser usado com detalhes que permitam ao agente agir corretamente.
Descrições eficazes incluem contexto relevante e restrições, ajudando o agente a entender o propósito maior e quaisquer limitações. Divida trabalhos complexos em etapas gerenciáveis em vez de objetivos genéricos e sobrecarregados.
Erros comuns incluem objetivos vagos, falta de contexto, critérios de sucesso mal definidos ou mistura de tarefas totalmente distintas em um mesmo texto. O objetivo é passar informação suficiente para o sucesso, mas mantendo foco no resultado claro.
</Accordion>
<Accordion title="Diretrizes para a Saída Esperada" icon="bullseye">
As diretrizes da saída esperada funcionam como contrato entre definição de tarefa e agente, especificando claramente o que deve ser entregue e como será avaliado. Elas abrangem formato, estrutura e elementos essenciais.
As melhores diretrizes incluem exemplos concretos de indicadores de qualidade e critérios claros de conclusão, de modo que agente e revisores humanos possam avaliar o resultado facilmente. Isso reduz ambiguidades e garante resultados consistentes.
Evite descrições genéricas que serviriam para qualquer tarefa, ausência de especificações de formato, padrões vagos ou falta de exemplos/modelos que ajudem o agente a entender as expectativas.
</Accordion>
</AccordionGroup>
### b. Estratégia de Sequenciamento de Tarefas
<Tabs>
<Tab title="Dependências Sequenciais">
Dependências são essenciais quando as tarefas se baseiam em resultados prévios, informações fluem de uma tarefa para outra, ou a qualidade depende da conclusão de fases anteriores. Assim, cada tarefa recebe o contexto correto para o sucesso.
Para implementar bem, use o parâmetro de contexto para encadear tarefas, desenvolvendo gradualmente a complexidade. Cada tarefa deve gerar saídas que alimentam as próximas. O objetivo é manter um fluxo lógico entre as tarefas dependentes, evitando gargalos desnecessários.
Funciona melhor quando há progressão lógica evidente e quando a saída de uma tarefa realmente agrega valor nas etapas seguintes. Cuidado com os gargalos; foque nas dependências essenciais.
</Tab>
<Tab title="Execução Paralela">
A execução paralela é valiosa quando as tarefas são independentes, o tempo é crítico ou há expertise distintas que não exigem coordenação. Pode reduzir drasticamente o tempo total, permitindo que agentes especializados atuem simultaneamente.
Para isso, identifique tarefas realmente independentes, agrupe fluxos de trabalho distintos e planeje a integração dos resultados posteriormente. O ponto-chave é garantir que tarefas paralelas não gerem conflitos ou redundâncias.
Considere o paralelo em múltiplos fluxos independentes, diferentes tipos de análise autônoma, ou criação de conteúdo que pode ser feita ao mesmo tempo. Mas atente-se à alocação de recursos, evitando sobrecarga de modelos ou estouro no orçamento.
</Tab>
</Tabs>
## Otimizando a Configuração dos Agentes para Desempenho de LLMs
### a. Seleção de LLM Guiada pelo Papel
<Warning>
Funções genéricas de agentes tornam impossível escolher o LLM certo. Funções
específicas permitem otimização do modelo conforme a função.
</Warning>
A especificidade das funções dos agentes determina quais capacidades de LLM mais importam para alto desempenho, criando oportunidade estratégica de alinhar forças do modelo ao papel do agente.
**Impacto de Funções Genéricas vs. Específicas:**
Ao definir funções, pense no conhecimento do domínio, estilo de trabalho e frameworks decisórios mais valiosos para o tipo de tarefa do agente. Quanto mais específica e contextualizada a função, melhor o modelo incorporará esse papel.
```python
# ✅ Função específica - requisitos claros de LLM
specific_agent = Agent(
role="SaaS Revenue Operations Analyst", # Expertise de domínio clara
goal="Analyze recurring revenue metrics and identify growth opportunities",
backstory="Specialist in SaaS business models with deep understanding of ARR, churn, and expansion revenue",
llm=LLM(model="gpt-4o") # Raciocínio justificado para análise complexa
)
```
**Estratégia de Mapeamento de Função para Modelo:**
- **"Research Analyst"** → Modelo de raciocínio (GPT-4o, Claude Sonnet) para análise complexa
- **"Content Editor"** → Modelo criativo (Claude, GPT-4o) para qualidade de escrita
- **"Data Processor"** → Modelo eficiente (GPT-4o-mini, Gemini Flash) para tarefas estruturadas
- **"API Coordinator"** → Modelo otimizado para function calling (GPT-4o, Claude) para uso de ferramentas
### b. Backstory como Amplificador de Contexto do Modelo
<Info>
Backstories estratégicos maximizam a eficácia do LLM ao contextualizar as
respostas de forma que prompts genéricos não conseguem.
</Info>
Um bom backstory transforma a escolha do LLM de genérica a especializada. Isso é crucial para otimizar custos: um modelo eficiente com contexto certo pode superar um premium sem contexto.
**Exemplo de Performance Guiada por Contexto:**
```python
# Contexto amplifica a efetividade do modelo
domain_expert = Agent(
role="B2B SaaS Marketing Strategist",
goal="Develop comprehensive go-to-market strategies for enterprise software",
backstory="""
You have 10+ years of experience scaling B2B SaaS companies from Series A to IPO.
You understand the nuances of enterprise sales cycles, the importance of product-market
fit in different verticals, and how to balance growth metrics with unit economics.
You've worked with companies like Salesforce, HubSpot, and emerging unicorns, giving
you perspective on both established and disruptive go-to-market strategies.
""",
llm=LLM(model="claude-3-5-sonnet", temperature=0.3) # Criatividade balanceada com conhecimento de domínio
)
# Esse contexto faz o Claude agir como especialista do setor
# Sem isso, mesmo ele entregaria respostas genéricas
```
**Elementos de Backstory que Potencializam a Performance de LLMs:**
- **Experiência de Domínio**: "10+ anos em vendas enterprise SaaS"
- **Expertise Específica**: "Especialista em due diligence técnica para Série B+"
- **Estilo de Trabalho**: "Decisões orientadas a dados, documentação clara"
- **Padrões de Qualidade**: "Sempre cita fontes e mostra análise detalhada"
### c. Otimização Holística de Agente + LLM
As configurações mais eficazes criam sinergia entre função específica, profundidade do backstory e escolha do LLM. Cada elemento reforça o outro para maximizar rendimento.
**Framework de Otimização:**
```python
# Exemplo: Agente de Documentação Técnica
tech_writer = Agent(
role="API Documentation Specialist",
goal="Create comprehensive, developer-friendly API documentation",
backstory="""
You're a technical writer with 8+ years documenting REST APIs, GraphQL endpoints,
and SDK integration guides. You've worked with developer tools companies and
understand what developers need: clear examples, comprehensive error handling,
and practical use cases. You prioritize accuracy and usability over marketing fluff.
""",
llm=LLM(
model="claude-3-5-sonnet",
temperature=0.1
),
tools=[code_analyzer_tool, api_scanner_tool],
verbose=True
)
```
**Checklist de Alinhamento:**
- ✅ **Função Específica**: Domínio e responsabilidades claras
- ✅ **Correspondência do LLM**: Forças do modelo conectadas à função
- ✅ **Profundidade do Backstory**: Contexto de domínio disponível pro modelo
- ✅ **Integração de Ferramentas**: Ferramentas fortalecem a função do agente
- ✅ **Ajuste de Parâmetros**: Temperatura e configs otimizadas para a função
O segredo é criar agentes onde cada configuração reforça sua estratégia de escolha do LLM, maximizando rendimento e otimizando custos.
## Checklist Prático de Implementação
Em vez de repetir o framework estratégico, segue um checklist tático para implementar as decisões de seleção de LLM em CrewAI:
<Steps>
<Step title="Audite Sua Configuração Atual" icon="clipboard-check">
**O que analisar:**
- Todos os agentes usam o mesmo LLM por padrão?
- Quais agentes lidam com tarefas mais complexas?
- Quais agentes só processam ou formatam dados?
- Algum agente depende fortemente de ferramentas?
**Ação**: Documente funções dos agentes e identifique oportunidades de otimização.
</Step>
<Step title="Implemente Estratégia no Nível da Crew" icon="users-gear">
**Defina sua Base:**
```python
# Comece com um padrão confiável para a crew
default_crew_llm = LLM(model="gpt-4o-mini") # Base econômica
crew = Crew(
agents=[...],
tasks=[...],
memory=True
)
```
**Ação**: Defina o LLM padrão da crew antes de otimizar agentes individuais.
</Step>
<Step title="Otimize Agentes de Maior Impacto" icon="star">
**Identifique e Aprimore Agentes-Chave:**
```python
# Agentes gerenciadores ou de coordenação
manager_agent = Agent(
role="Project Manager",
llm=LLM(model="gemini-2.5-flash-preview-05-20"),
# ... demais configs
)
# Agentes criativos ou customer-facing
content_agent = Agent(
role="Content Creator",
llm=LLM(model="claude-3-5-sonnet"),
# ... demais configs
)
```
**Ação**: Faça upgrade dos 20% dos agentes que tratam 80% da complexidade.
</Step>
<Step title="Valide com Testes Empresariais" icon="test-tube">
**Após colocar os agentes em produção:**
- Use [CrewAI AMP platform](https://app.crewai.com) para testar seleções de modelo A/B
- Execute múltiplas iterações com inputs reais para medir consistência e performance
- Compare custo vs performance na configuração otimizada
- Compartilhe resultados com o time para tomada coletiva de decisão
**Ação**: Substitua achismos por validação com dados reais usando a plataforma de testes.
</Step>
</Steps>
### Quando Usar Tipos Diferentes de Modelos
<Tabs>
<Tab title="Modelos de Raciocínio">
Modelos de raciocínio tornam-se essenciais quando tarefas exigem pensamento lógico genuíno em múltiplas etapas, planejamento estratégico ou decisões complexas beneficiadas por análise sistemática. Brilham na decomposição de problemas e análise estruturada, não no simples seguimento de padrões.
Considere-os para desenvolvimento de estratégias de negócios, análise de dados combinados de múltiplas fontes, resolução de problemas dependente de etapas sucessivas e planejamento estratégico envolvendo múltiplas variáveis.
Entretanto, esses modelos são mais caros e lentos, devendo ser reservados para tarefas onde suas capacidades agregam valor real — evite usá-los apenas para operações simples.
</Tab>
<Tab title="Modelos Criativos">
Modelos criativos são valiosos quando a principal entrega é geração de conteúdo e a qualidade, estilo e engajamento desse conteúdo impactam o sucesso. Se destacam quando redação e estilo importam, ideação criativa é necessária, ou voz de marca é fundamental.
Use-os em redação de posts, criação de artigos, textos de marketing com viés persuasivo, storytelling e comunicações da marca. Costumam captar nuances e contexto melhor do que generalistas.
Podem ser menos adequados para tarefas técnicas ou analíticas, onde precisão supera criatividade. Use-os quando aspectos comunicativos são fatores críticos de sucesso.
</Tab>
<Tab title="Modelos Eficientes">
Modelos eficientes são ideais para operações frequentes e rotineiras, onde velocidade e custo são prioridade. Trabalham melhor em tarefas com parâmetros bem definidos, sem necessidade de raciocínio avançado ou criatividade.
Considere-os para processamento e transformação de dados, formatação simples, chamadas de funções (function calling) e operações em alto volume onde custo importa mais.
O ponto crítico é verificar adequação à tarefa. Funcionam para muitos fluxos rotineiros, mas podem falhar se a tarefa exigir compreensão técnica ou raciocínio.
</Tab>
<Tab title="Modelos Open Source">
Modelos open source são atraentes quando há restrição orçamentária, necessidade de privacidade, personalização especial ou exigência de deployment local.
Considere para ferramentas internas de empresas, aplicações sensíveis, projetos onde não é possível usar APIs externas, casos com orçamento apertado ou requisitos de customização.
Mas lembre-se: exigem mais expertise, manutenção e investimentos em infraestrutura. Avalie o custo total da operação ao avaliar esses modelos.
</Tab>
</Tabs>
## Armadilhas Comuns na Seleção de Modelos CrewAI
<AccordionGroup>
<Accordion title="A Armadilha do 'Um Modelo Serve para Tudo'" icon="triangle-exclamation">
**O problema**: Usar o mesmo LLM para todos os agentes, independentemente das funções. Prática padrão, mas raramente ótima.
**Exemplo real**: Usar GPT-4o tanto para planejamento estratégico quanto para extração simples de dados. O manager precisa do raciocínio premium, mas o extrator poderia usar o GPT-4o-mini, muito mais barato.
**Solução CrewAI**: Configure modelos específicos por agente:
```python
# Agente estratégico recebe modelo premium
manager = Agent(role="Strategy Manager", llm=LLM(model="gpt-4o"))
# Agente de processamento recebe modelo eficiente
processor = Agent(role="Data Processor", llm=LLM(model="gpt-4o-mini"))
```
</Accordion>
<Accordion title="Ignorar Hierarquia de LLM entre Crew e Agente" icon="shuffle">
**O problema**: Não entender como funciona a hierarquia LLM da CrewAI — configurações conflitam entre crew, manager e agentes.
**Exemplo real**: Configurar crew com Claude, mas agentes com GPT, gerando comportamento inconsistente e trocas desnecessárias.
**Solução CrewAI**: Planeje a hierarquia estrategicamente:
```python
crew = Crew(
agents=[agent1, agent2],
tasks=[task1, task2],
manager_llm=LLM(model="gpt-4o"),
process=Process.hierarchical
)
# Agentes herdam o LLM da crew, salvo sobrescrita
agent1 = Agent(llm=LLM(model="claude-3-5-sonnet"))
```
</Accordion>
<Accordion title="Incompatibilidade para Function Calling" icon="screwdriver-wrench">
**O problema**: Escolher modelos pela capacidade geral e ignorar o desempenho em function calling em workflows intensivos em ferramentas.
**Exemplo real**: Selecionar modelo criativo para agente que só precisa chamar APIs e processar dados estruturados, resultando em má extração de parâmetros.
**Solução CrewAI**: Priorize desempenho em function calling para agentes que usam ferramentas:
```python
# Para agentes com muitas ferramentas
tool_agent = Agent(
role="API Integration Specialist",
tools=[search_tool, api_tool, data_tool],
llm=LLM(model="gpt-4o"),
# OU
llm=LLM(model="claude-3-5-sonnet")
)
```
</Accordion>
<Accordion title="Otimização Prematura sem Teste" icon="gear">
**O problema**: Decidir configurações complexas de modelo com base em hipóteses não validadas nos fluxos e tarefas reais CrewAI.
**Exemplo real**: Implementar lógica elaborada de troca de modelo por tipo de tarefa sem testar se os ganhos compensam a complexidade.
**Solução CrewAI**: Comece simples e otimize baseado em dados reais:
```python
# Comece assim
crew = Crew(agents=[...], tasks=[...], llm=LLM(model="gpt-4o-mini"))
# Teste a performance e só depois otimize agentes específicos
# Use testes Enterprise para validar melhorias
```
</Accordion>
<Accordion title="Ignorar Limites de Contexto e Memória" icon="brain">
**O problema**: Não considerar como janela de contexto dos modelos interage com memória e compartilhamento de contexto entre agentes CrewAI.
**Exemplo real**: Usar modelo de contexto curto para agentes que precisam manter histórico ao longo de múltiplas iterações ou equipes com comunicação extensiva agent-to-agent.
**Solução CrewAI**: Alinhe capacidades de contexto ao padrão de comunicação da crew.
</Accordion>
</AccordionGroup>
## Estratégia de Teste e Iteração
<Steps>
<Step title="Comece Simples" icon="play">
Comece com modelos de uso geral, confiáveis e amplamente suportados. Isso
estabelece base estável para entender necessidades e expectativas de
desempenho antes de otimizar para demandas especializadas.
</Step>
<Step title="Meça o que Importa" icon="chart-line">
Desenvolva métricas alinhadas ao seu caso de uso e metas de negócio, não
apenas benchmarks gerais. Foque na mensuração de resultados relevantes ao
seu sucesso.
</Step>
<Step title="Itere Baseado em Resultados" icon="arrows-rotate">
Faça mudanças baseadas no desempenho observado no seu contexto, não apenas
considerações teóricas ou recomendações genéricas. O desempenho prático
costuma ser bem diferente dos benchmarks.
</Step>
<Step title="Considere o Custo Total" icon="calculator">
Avalie todo custo de operação, incluindo modelo, tempo de desenvolvimento,
manutenção e complexidade. O modelo mais barato por token pode não ser o
mais econômico ao considerar todos os fatores.
</Step>
</Steps>
<Tip>
Foque em entender seus requisitos primeiro, e então escolha modelos que melhor
correspondam a essas necessidades. O melhor LLM é aquele que consistentemente
entrega os resultados esperados dentro das suas restrições.
</Tip>
### Validação de Modelos em Nível Enterprise
Para equipes sérias sobre otimização, a **plataforma CrewAI AMP** oferece testes sofisticados que vão além do CLI. Ela permite avaliação completa para decisões orientadas por dados na estratégia de LLM.
<Frame>
![Enterprise Testing Interface](/images/enterprise/enterprise-testing.png)
</Frame>
**Funcionalidades Avançadas de Teste:**
- **Comparação Multi-Modelo**: Teste diversos LLMs simultaneamente nas mesmas tarefas e entradas. Compare desempenho entre GPT-4o, Claude, Llama, Groq, Cerebras, e outros líderes em paralelo para identificar a melhor opção para você.
- **Rigor Estatístico**: Configure múltiplas iterações com inputs consistentes para medir confiabilidade e variação no desempenho. Assim, identifica modelos que performam bem e de modo consistente.
- **Validação no Mundo Real**: Use os inputs e cenários reais da sua crew, e não apenas benchmarks sintéticos. A plataforma permite testar no contexto da sua indústria, empresa e casos de uso.
- **Analytics Completo**: Acesse métricas detalhadas de desempenho, tempos de execução e análise de custos para todos os modelos testados. Decisões baseadas em dados reais, não apenas reputação.
- **Colaboração em Equipe**: Compartilhe resultados e análises com seu time, favorecendo decisões coletivas e estratégias alinhadas.
Acesse [app.crewai.com](https://app.crewai.com) para começar!
<Info>
A plataforma Enterprise transforma a seleção de modelos de um "palpite" para
um processo orientado por dados, permitindo validar os princípios deste guia
com seus próprios casos de uso.
</Info>
## Resumo dos Princípios-Chave
<CardGroup cols={2}>
<Card title="Seleção Orientada à Tarefa" icon="bullseye">
Escolha os modelos pelo que sua tarefa realmente requer, não por reputação ou capacidades teóricas.
</Card>
{" "}
<Card title="Combinação de Capacidades" icon="puzzle-piece">
Alinhe forças do modelo a papéis e responsabilidades dos agentes para melhor
desempenho.
</Card>
{" "}
<Card title="Consistência Estratégica" icon="link">
Mantenha uma estratégia coerente de seleção de modelos em fluxos e componentes
relacionados.
</Card>
{" "}
<Card title="Testes Práticos" icon="flask">
Valide escolhas em uso real, não apenas em benchmarks.
</Card>
{" "}
<Card title="Iteração Contínua" icon="arrow-up">
Comece simples e otimize com base na performance e necessidade práticas.
</Card>
<Card title="Equilíbrio Operacional" icon="scale-balanced">
Equilibre performance requerida, custo e complexidade.
</Card>
</CardGroup>
<Check>
Lembre-se: o melhor LLM é o que entrega consistentemente os resultados de que
você precisa dentro de suas restrições. Conheça seu requisito primeiro, depois
selecione o modelo mais adequado.
</Check>
## Panorama Atual dos Modelos (Junho/2025)
<Warning>
**Retrato do Momento**: Os rankings a seguir representam o estado da arte em
Junho de 2025, compilados do [LMSys Arena](https://arena.lmsys.org/),
[Artificial Analysis](https://artificialanalysis.ai/) e outros benchmarks
líderes. Performance, disponibilidade e preço mudam rapidamente. Sempre valide
com seus dados e casos reais.
</Warning>
### Principais Modelos por Categoria
As tabelas abaixo mostram uma amostra dos modelos de maior destaque em cada categoria, junto de orientação sobre aplicação em agentes CrewAI:
<Note>
Estas tabelas exibem apenas alguns modelos líderes por categoria. Existem
muitos outros excelentes. O objetivo é ilustrar exemplos de capacidades
buscadas em vez de apresentar um catálogo completo.
</Note>
<Tabs>
<Tab title="Raciocínio & Planejamento">
**Melhores para LLMs Manager e Análises Complexas**
| Modelo | Score de Inteligência | Custo ($/M tokens) | Velocidade | Melhor Uso em CrewAI |
|:------|:---------------------|:-------------------|:-----------|:--------------------|
| **o3** | 70 | $17.50 | Rápido | Manager LLM para coordenação multi-agente |
| **Gemini 2.5 Pro** | 69 | $3.44 | Rápido | Agentes de planejamento estratégico, coordenação de pesquisa |
| **DeepSeek R1** | 68 | $0.96 | Moderada | Raciocínio com bom custo-benefício |
| **Claude 4 Sonnet** | 53 | $6.00 | Rápido | Agentes de análise que precisam de nuance |
| **Qwen3 235B (Reasoning)** | 62 | $2.63 | Moderada | Alternativa open source para raciocínio |
Esses modelos se destacam em raciocínio multi-etapas e são ideais para agentes que desenvolvem estratégias, coordenam outros agentes ou analisam informações complexas.
</Tab>
<Tab title="Codificação & Técnica">
**Melhores para Desenvolvimento e Workflows com Ferramentas**
| Modelo | Performance em Coding | Tool Use Score | Custo ($/M tokens) | Melhor Uso em CrewAI |
|:--------|:---------------------|:--------------|:-------------------|:--------------------|
| **Claude 4 Sonnet** | Excelente | 72.7% | $6.00 | Agente principal de código/documentação técnica |
| **Claude 4 Opus** | Excelente | 72.5% | $30.00 | Arquitetura complexa, code review |
| **DeepSeek V3** | Muito bom | Alto | $0.48 | Coding econômico para desenvolvimentos rotineiros |
| **Qwen2.5 Coder 32B** | Muito bom | Médio | $0.15 | Agente de código econômico |
| **Llama 3.1 405B** | Bom | 81.1% | $3.50 | LLM para function calling em workflows intensivos em ferramentas |
Otimizados para geração de código, debugging e solução técnica, ideais para equipes de desenvolvimento.
</Tab>
<Tab title="Velocidade & Eficiência">
**Melhores para Operações em Massa e Aplicações em Tempo Real**
| Modelo | Velocidade (tokens/s) | Latência (TTFT) | Custo ($/M tokens) | Melhor Uso em CrewAI |
|:-------|:---------------------|:----------------|:-------------------|:---------------------|
| **Llama 4 Scout** | 2.600 | 0.33s | $0.27 | Agentes de processamento de alto volume |
| **Gemini 2.5 Flash** | 376 | 0.30s | $0.26 | Agentes de resposta em tempo real |
| **DeepSeek R1 Distill** | 383 | Variável | $0.04 | Processamento rápido de baixo custo |
| **Llama 3.3 70B** | 2.500 | 0.52s | $0.60 | Equilíbrio entre velocidade e capacidade |
| **Nova Micro** | Alto | 0.30s | $0.04 | Execução rápida de tarefas simples |
Priorizam velocidade e eficiência, perfeitos para agentes em operações de rotina ou resposta ágil. **Dica:** Usar provedores de inference rápidos como Groq potencializa open source como Llama.
</Tab>
<Tab title="Performance Equilibrada">
**Melhores Modelos Coringa para Crews Diversos**
| Modelo | Score Global | Versatilidade | Custo ($/M tokens) | Melhor Uso em CrewAI |
|:------------|:--------------|:-------------|:-------------------|:--------------------|
| **GPT-4.1** | 53 | Excelente | $3.50 | LLM generalista para equipes variadas |
| **Claude 3.7 Sonnet** | 48 | Muito boa | $6.00 | Raciocínio e criatividade balanceados |
| **Gemini 2.0 Flash** | 48 | Boa | $0.17 | Generalista de bom custo benefício |
| **Llama 4 Maverick** | 51 | Boa | $0.37 | Open source para usos gerais |
| **Qwen3 32B** | 44 | Boa | $1.23 | Versatilidade econômica |
Oferecem bom desempenho geral, adequados para crews com demandas amplas.
</Tab>
</Tabs>
### Framework de Seleção para Modelos Atuais
<AccordionGroup>
<Accordion title="Crews de Alta Performance" icon="rocket">
**Priorizando performance**: Use modelos topo de linha como **o3**, **Gemini 2.5 Pro** ou **Claude 4 Sonnet** para managers e agentes críticos. Excelentes em raciocínio e coordenação, porém mais caros.
**Estratégia**: Implemente abordagem multi-modelo, reservando premium para raciocínio estratégico e eficientes para operações rotineiras.
</Accordion>
<Accordion title="Crews de Baixo Custo" icon="dollar-sign">
**Foco no orçamento**: Foque em modelos como **DeepSeek R1**, **Llama 4 Scout** ou **Gemini 2.0 Flash**, que trazem ótimo desempenho com investimento reduzido.
**Estratégia**: Use modelos econômicos para maioria dos agentes, reservando premium apenas para funções críticas.
</Accordion>
<Accordion title="Workflows Especializados" icon="screwdriver-wrench">
**Para expertise específica**: Escolha modelos otimizados para seu principal caso de uso: **Claude 4** em código, **Gemini 2.5 Pro** em pesquisa, **Llama 405B** em function calling.
**Estratégia**: Selecione conforme a principal função da crew, garantindo alinhamento de capacidade e modelo.
</Accordion>
<Accordion title="Empresa & Privacidade" icon="shield">
**Para operações sensíveis**: Avalie modelos open source como **Llama 4** series, **DeepSeek V3** ou **Qwen3** para deployment privado, mantendo performance competitiva.
**Estratégia**: Use open source em infraestrutura própria e aceite possíveis trade-offs por controle dos dados.
</Accordion>
</AccordionGroup>
### Considerações-Chave na Seleção de Modelos
- **Tendências de Performance**: O cenário atual mostra competição forte entre modelos de raciocínio (o3, Gemini 2.5 Pro) e equilibrados (Claude 4, GPT-4.1). Modelos como DeepSeek R1 entregam excelente custo/performance.
- **Trade-off Velocidade x Inteligência**: Modelos como Llama 4 Scout priorizam velocidade (2.600 tokens/s) e inteligência razoável, enquanto outros como o3 maximizam raciocínio em detrimento de velocidade/preço.
- **Viabilidade Open Source**: A distância entre open source e proprietários diminui a cada mês, com Llama 4 Maverick e DeepSeek V3 entregando performance competitiva a preços atrativos. Inferência rápida via Groq maximiza custo-benefício nesses casos.
<Info>
**Testes são essenciais**: Rankings servem de orientação geral, mas seu caso
de uso, prompt e critério podem gerar resultados distintos. Sempre teste
modelos candidatos com suas tarefas e dados reais antes de decidir.
</Info>
### Estratégia Prática de Implementação
<Steps>
<Step title="Comece por Modelos Validados">
Inicie com opções consagradas como **GPT-4.1**, **Claude 3.7 Sonnet** ou **Gemini 2.0 Flash**, que oferecem bom desempenho e ampla validação.
</Step>
<Step title="Identifique Demandas Especializadas">
Descubra se sua crew possui requisitos específicos (código, raciocínio,
velocidade) que justifiquem modelos como **Claude 4 Sonnet** para
desenvolvimento ou **o3** para análise. Para aplicações críticas em
velocidade, considere Groq aliado à seleção do modelo.
</Step>
<Step title="Implemente Estratégia Multi-Modelo">
Use modelos diferentes para agentes distintos conforme o papel. Modelos de
alta capacidade para managers e tarefas complexas, eficientes para rotinas.
</Step>
<Step title="Monitore e Otimize">
Acompanhe métricas relevantes ao seu caso e esteja pronto para ajustar modelos conforme lançamentos ou mudanças de preços.
</Step>
</Steps>

View File

@@ -0,0 +1,141 @@
---
title: Usando Agentes Multimodais
description: Aprenda como habilitar e usar capacidades multimodais em seus agentes para processar imagens e outros conteúdos não textuais dentro do framework CrewAI.
icon: video
mode: "wide"
---
## Usando Agentes Multimodais
O CrewAI suporta agentes multimodais que podem processar tanto conteúdo textual quanto não textual, como imagens. Este guia mostrará como habilitar e utilizar capacidades multimodais em seus agentes.
### Habilitando Capacidades Multimodais
Para criar um agente multimodal, basta definir o parâmetro `multimodal` como `True` ao inicializar seu agente:
```python
from crewai import Agent
agent = Agent(
role="Image Analyst",
goal="Analyze and extract insights from images",
backstory="An expert in visual content interpretation with years of experience in image analysis",
multimodal=True # This enables multimodal capabilities
)
```
Ao definir `multimodal=True`, o agente é automaticamente configurado com as ferramentas necessárias para lidar com conteúdo não textual, incluindo a `AddImageTool`.
### Trabalhando com Imagens
O agente multimodal vem pré-configurado com a `AddImageTool`, permitindo que ele processe imagens. Não é necessário adicionar esta ferramenta manualmente ela é automaticamente incluída ao habilitar capacidades multimodais.
Aqui está um exemplo completo mostrando como usar um agente multimodal para analisar uma imagem:
```python
from crewai import Agent, Task, Crew
# Create a multimodal agent
image_analyst = Agent(
role="Product Analyst",
goal="Analyze product images and provide detailed descriptions",
backstory="Expert in visual product analysis with deep knowledge of design and features",
multimodal=True
)
# Create a task for image analysis
task = Task(
description="Analyze the product image at https://example.com/product.jpg and provide a detailed description",
expected_output="A detailed description of the product image",
agent=image_analyst
)
# Create and run the crew
crew = Crew(
agents=[image_analyst],
tasks=[task]
)
result = crew.kickoff()
```
### Uso Avançado com Contexto
Você pode fornecer contexto adicional ou perguntas específicas sobre a imagem ao criar tarefas para agentes multimodais. A descrição da tarefa pode incluir aspectos específicos nos quais você deseja que o agente foque:
```python
from crewai import Agent, Task, Crew
# Create a multimodal agent for detailed analysis
expert_analyst = Agent(
role="Visual Quality Inspector",
goal="Perform detailed quality analysis of product images",
backstory="Senior quality control expert with expertise in visual inspection",
multimodal=True # AddImageTool is automatically included
)
# Create a task with specific analysis requirements
inspection_task = Task(
description="""
Analyze the product image at https://example.com/product.jpg with focus on:
1. Quality of materials
2. Manufacturing defects
3. Compliance with standards
Provide a detailed report highlighting any issues found.
""",
expected_output="A detailed report highlighting any issues found",
agent=expert_analyst
)
# Create and run the crew
crew = Crew(
agents=[expert_analyst],
tasks=[inspection_task]
)
result = crew.kickoff()
```
### Detalhes da Ferramenta
Ao trabalhar com agentes multimodais, a `AddImageTool` é automaticamente configurada com o seguinte esquema:
```python
class AddImageToolSchema:
image_url: str # Required: The URL or path of the image to process
action: Optional[str] = None # Optional: Additional context or specific questions about the image
```
O agente multimodal irá automaticamente realizar o processamento de imagens por meio de suas ferramentas internas, permitindo que ele:
- Acesse imagens via URLs ou caminhos de arquivos locais
- Processe o conteúdo da imagem com contexto opcional ou perguntas específicas
- Forneça análises e insights com base nas informações visuais e requisitos da tarefa
### Boas Práticas
Ao trabalhar com agentes multimodais, tenha em mente as seguintes boas práticas:
1. **Acesso à Imagem**
- Certifique-se de que suas imagens estejam acessíveis via URLs alcançáveis pelo agente
- Para imagens locais, considere hospedá-las temporariamente ou utilize caminhos absolutos
- Verifique se as URLs das imagens são válidas e acessíveis antes de rodar as tarefas
2. **Descrição da Tarefa**
- Seja específico sobre quais aspectos da imagem você deseja que o agente analise
- Inclua perguntas ou requisitos claros na descrição da tarefa
- Considere usar o parâmetro opcional `action` para uma análise focada
3. **Gerenciamento de Recursos**
- O processamento de imagens pode exigir mais recursos computacionais do que tarefas apenas textuais
- Alguns modelos de linguagem podem exigir codificação em base64 para dados de imagem
- Considere o processamento em lote para múltiplas imagens visando otimizar o desempenho
4. **Configuração do Ambiente**
- Verifique se seu ambiente possui as dependências necessárias para processamento de imagens
- Certifique-se de que seu modelo de linguagem suporta capacidades multimodais
- Teste primeiro com imagens pequenas para validar sua configuração
5. **Tratamento de Erros**
- Implemente tratamento apropriado para falhas no carregamento de imagens
- Tenha estratégias de contingência para casos onde o processamento de imagens falhar
- Monitore e registre operações de processamento de imagens para depuração

View File

@@ -0,0 +1,159 @@
---
title: "Visão Geral"
description: "Aprenda como construir, personalizar e otimizar suas aplicações CrewAI com guias e tutoriais completos"
icon: "face-smile"
mode: "wide"
---
## Aprenda CrewAI
Esta seção fornece guias e tutoriais completos para ajudar você a dominar o CrewAI, desde conceitos básicos até técnicas avançadas. Seja você iniciante ou esteja buscando otimizar suas implementações existentes, estes recursos o guiarão por todos os aspectos da construção de workflows poderosos de agentes de IA.
## Guias de Introdução
### Conceitos Centrais
<CardGroup cols={2}>
<Card title="Processo Sequencial" icon="list-ol" href="/pt-BR/learn/sequential-process">
Aprenda a executar tarefas em ordem sequencial para workflows estruturados.
</Card>
<Card title="Processo Hierárquico" icon="sitemap" href="/pt-BR/learn/hierarchical-process">
Implemente execução hierárquica de tarefas com agentes gerentes supervisionando workflows.
</Card>
<Card title="Tarefas Condicionais" icon="code-branch" href="/pt-BR/learn/conditional-tasks">
Crie workflows dinâmicos com execução condicional de tarefas baseada em resultados.
</Card>
<Card title="Kickoff Assíncrono" icon="bolt" href="/pt-BR/learn/kickoff-async">
Execute crews de forma assíncrona para melhorar desempenho e concorrência.
</Card>
</CardGroup>
### Desenvolvimento de Agentes
<CardGroup cols={2}>
<Card title="Personalizando Agentes" icon="user-gear" href="/pt-BR/learn/customizing-agents">
Aprenda como personalizar o comportamento, funções e capacidades dos agentes.
</Card>
<Card title="Codificando Agentes" icon="code" href="/pt-BR/learn/coding-agents">
Construa agentes que podem escrever, executar e depurar código automaticamente.
</Card>
<Card title="Agentes Multimodais" icon="images" href="/pt-BR/learn/multimodal-agents">
Crie agentes capazes de processar texto, imagens e outros tipos de mídia.
</Card>
<Card title="Agente Gerente Personalizado" icon="user-tie" href="/pt-BR/learn/custom-manager-agent">
Implemente agentes gerentes personalizados para workflows hierárquicos complexos.
</Card>
</CardGroup>
## Funcionalidades Avançadas
### Controle de Workflow
<CardGroup cols={2}>
<Card title="Humano no Loop" icon="user-check" href="/pt-BR/learn/human-in-the-loop">
Integre supervisão e intervenção humana aos workflows dos agentes.
</Card>
<Card title="Entrada Humana na Execução" icon="hand-paper" href="/pt-BR/learn/human-input-on-execution">
Permita entrada humana durante a execução de tarefas para tomada de decisões dinâmicas.
</Card>
<Card title="Repetir Tarefas" icon="rotate-left" href="/pt-BR/learn/replay-tasks-from-latest-crew-kickoff">
Refaça e retome tarefas a partir de execuções anteriores de crews.
</Card>
<Card title="Kickoff para Cada" icon="repeat" href="/pt-BR/learn/kickoff-for-each">
Execute crews múltiplas vezes com diferentes entradas de maneira eficiente.
</Card>
</CardGroup>
### Personalização & Integração
<CardGroup cols={2}>
<Card title="LLM Personalizado" icon="brain" href="/pt-BR/learn/custom-llm">
Integre modelos de linguagem personalizados e provedores ao CrewAI.
</Card>
<Card title="Conexões LLM" icon="link" href="/pt-BR/learn/llm-connections">
Configure e gerencie conexões com vários provedores de LLM.
</Card>
<Card title="Criar Ferramentas Personalizadas" icon="wrench" href="/pt-BR/learn/create-custom-tools">
Construa ferramentas personalizadas para estender as capacidades dos agentes.
</Card>
<Card title="Usando Anotações" icon="at" href="/pt-BR/learn/using-annotations">
Use anotações Python para um código mais limpo e fácil de manter.
</Card>
</CardGroup>
## Aplicações Especializadas
### Conteúdo & Mídia
<CardGroup cols={2}>
<Card title="Geração de Imagens DALL-E" icon="image" href="/pt-BR/learn/dalle-image-generation">
Gere imagens utilizando a integração DALL-E com seus agentes.
</Card>
<Card title="Traga Seu Próprio Agente" icon="user-plus" href="/pt-BR/learn/bring-your-own-agent">
Integre agentes e modelos já existentes aos workflows do CrewAI.
</Card>
</CardGroup>
### Gerenciamento de Ferramentas
<CardGroup cols={2}>
<Card title="Forçar Saída da Ferramenta como Resultado" icon="hammer" href="/pt-BR/learn/force-tool-output-as-result">
Configure ferramentas para retornarem sua saída diretamente como resultado da tarefa.
</Card>
</CardGroup>
## Recomendações de Rotas de Aprendizagem
### Para Iniciantes
1. Comece pelo **Processo Sequencial** para entender a execução básica de workflows
2. Aprenda **Personalizando Agentes** para criar configurações de agentes eficazes
3. Explore **Criar Ferramentas Personalizadas** para estender funcionalidades
4. Experimente **Humano no Loop** para workflows interativos
### Para Usuários Intermediários
1. Domine **Processo Hierárquico** para sistemas multiagente complexos
2. Implemente **Tarefas Condicionais** para workflows dinâmicos
3. Utilize **Kickoff Assíncrono** para otimizar desempenho
4. Integre **LLM Personalizado** para modelos especializados
### Para Usuários Avançados
1. Construa **Agentes Multimodais** para processamento complexo de mídias
2. Crie **Agentes Gerentes Personalizados** para orquestração sofisticada
3. Implemente **Traga Seu Próprio Agente** para sistemas híbridos
4. Use **Repetir Tarefas** para recuperação de erros robusta
## Melhores Práticas
### Desenvolvimento
- **Comece Simples**: Inicie com workflows sequenciais básicos antes de adicionar complexidade
- **Teste de Forma Incremental**: Teste cada componente antes de integrar em sistemas maiores
- **Use Anotações**: Aproveite as anotações Python para código mais limpo e sustentável
- **Ferramentas Personalizadas**: Crie ferramentas reutilizáveis que possam ser compartilhadas entre diferentes agentes
### Produção
- **Tratamento de Erros**: Implemente mecanismos robustos de tratamento e recuperação de erros
- **Desempenho**: Utilize execução assíncrona e otimize chamadas a LLM para melhor desempenho
- **Monitoramento**: Integre ferramentas de observabilidade para acompanhar o desempenho dos agentes
- **Supervisão Humana**: Inclua checkpoints humanos para decisões críticas
### Otimização
- **Gestão de Recursos**: Monitore e otimize o uso de tokens e custos de API
- **Design de Workflow**: Elabore workflows que minimizem chamadas desnecessárias ao LLM
- **Eficiência das Ferramentas**: Crie ferramentas eficientes que ofereçam máximo valor com o mínimo de overhead
- **Aprimoramento Iterativo**: Use feedback e métricas para melhorar continuamente o desempenho dos agentes
## Obtendo Ajuda
- **Documentação**: Cada guia inclui exemplos detalhados e explicações
- **Comunidade**: Participe do [Fórum CrewAI](https://community.crewai.com) para discussões e suporte
- **Exemplos**: Consulte a seção de Exemplos para implementações completas e funcionais
- **Suporte**: Entre em contato via [support@crewai.com](mailto:support@crewai.com) para assistência técnica
Comece pelos guias que atendem às suas necessidades atuais e, gradualmente, explore tópicos mais avançados conforme você se sentir confortável com os fundamentos.

View File

@@ -0,0 +1,79 @@
---
title: Reexecutar Tarefas a partir do Último Crew Kickoff
description: Reexecute tarefas a partir do último crew.kickoff(...)
icon: arrow-right
mode: "wide"
---
## Introdução
O CrewAI oferece a capacidade de reexecutar uma tarefa especificada a partir do último crew kickoff. Esse recurso é particularmente útil quando você concluiu um kickoff e deseja tentar novamente determinadas tarefas, ou não precisa buscar dados novamente porque seus agentes já possuem o contexto salvo da execução do kickoff, sendo necessário apenas reexecutar as tarefas desejadas.
<Note>
Você deve executar `crew.kickoff()` antes de poder reexecutar uma tarefa.
Atualmente, apenas o kickoff mais recente é suportado, então se você utilizar `kickoff_for_each`, será possível reexecutar apenas a partir da execução de crew mais recente.
</Note>
Aqui está um exemplo de como reexecutar a partir de uma tarefa:
### Reexecutando a partir de uma Tarefa Específica Usando o CLI
Para utilizar o recurso de reexecução, siga estes passos:
<Steps>
<Step title="Abra seu terminal ou prompt de comando."></Step>
<Step title="Navegue até o diretório onde está localizado seu projeto CrewAI."></Step>
<Step title="Execute os seguintes comandos:">
Para visualizar os task_ids do último kickoff, utilize:
```shell
crewai log-tasks-outputs
```
Após identificar o `task_id` que deseja reexecutar, utilize:
```shell
crewai replay -t <task_id>
```
</Step>
</Steps>
<Note>
Certifique-se de que o `crewai` está instalado e devidamente configurado no seu ambiente de desenvolvimento.
</Note>
### Reexecutando uma Tarefa Programaticamente
Para reexecutar uma tarefa programaticamente, siga os passos abaixo:
<Steps>
<Step title="Especifique o `task_id` e os parâmetros de entrada para o processo de reexecução.">
Especifique o `task_id` e os parâmetros de entrada para o processo de reexecução.
</Step>
<Step title="Execute o comando de reexecução dentro de um bloco try-except para lidar com possíveis erros.">
Execute o comando de reexecução dentro de um bloco try-except para lidar com possíveis erros.
<CodeGroup>
```python Code
def replay():
"""
Replay the crew execution from a specific task.
"""
task_id = '<task_id>'
inputs = {"topic": "CrewAI Training"} # This is optional; you can pass in the inputs you want to replay; otherwise, it uses the previous kickoff's inputs.
try:
YourCrewName_Crew().crew().replay(task_id=task_id, inputs=inputs)
except subprocess.CalledProcessError as e:
raise Exception(f"An error occurred while replaying the crew: {e}")
except Exception as e:
raise Exception(f"An unexpected error occurred: {e}")
```
</CodeGroup>
</Step>
</Steps>
## Conclusão
Com as melhorias acima e funcionalidades detalhadas, a reexecução de tarefas específicas no CrewAI ficou mais eficiente e robusta.
Certifique-se de seguir exatamente os comandos e passos para aproveitar ao máximo esses recursos.

View File

@@ -0,0 +1,128 @@
---
title: Processos Sequenciais
description: Um guia abrangente para utilizar os processos sequenciais na execução de tarefas em projetos CrewAI.
icon: forward
mode: "wide"
---
## Introdução
O CrewAI oferece uma estrutura flexível para execução de tarefas de maneira estruturada, suportando tanto processos sequenciais quanto hierárquicos.
Este guia descreve como implementar esses processos de forma eficaz para garantir execução eficiente das tarefas e a conclusão do projeto.
## Visão Geral do Processo Sequencial
O processo sequencial garante que as tarefas sejam executadas uma após a outra, seguindo um progresso linear.
Essa abordagem é ideal para projetos nos quais as tarefas precisam ser concluídas em uma ordem específica.
### Principais Características
- **Fluxo Linear de Tarefas**: Garante o progresso ordenado ao tratar tarefas em uma sequência pré-determinada.
- **Simplicidade**: Melhor opção para projetos com tarefas claras e passo a passo.
- **Fácil Monitoramento**: Facilita o acompanhamento da conclusão das tarefas e do progresso do projeto.
## Implementando o Processo Sequencial
Para utilizar o processo sequencial, monte sua crew e defina as tarefas na ordem em que devem ser executadas.
```python Code
from crewai import Crew, Process, Agent, Task, TaskOutput, CrewOutput
# Define your agents
researcher = Agent(
role='Researcher',
goal='Conduct foundational research',
backstory='An experienced researcher with a passion for uncovering insights'
)
analyst = Agent(
role='Data Analyst',
goal='Analyze research findings',
backstory='A meticulous analyst with a knack for uncovering patterns'
)
writer = Agent(
role='Writer',
goal='Draft the final report',
backstory='A skilled writer with a talent for crafting compelling narratives'
)
# Define your tasks
research_task = Task(
description='Gather relevant data...',
agent=researcher,
expected_output='Raw Data'
)
analysis_task = Task(
description='Analyze the data...',
agent=analyst,
expected_output='Data Insights'
)
writing_task = Task(
description='Compose the report...',
agent=writer,
expected_output='Final Report'
)
# Form the crew with a sequential process
report_crew = Crew(
agents=[researcher, analyst, writer],
tasks=[research_task, analysis_task, writing_task],
process=Process.sequential
)
# Execute the crew
result = report_crew.kickoff()
# Accessing the type-safe output
task_output: TaskOutput = result.tasks[0].output
crew_output: CrewOutput = result.output
```
### Nota:
Cada tarefa em um processo sequencial **deve** ter um agente atribuído. Certifique-se de que todo `Task` inclua um parâmetro `agent`.
### Fluxo de Trabalho em Ação
1. **Tarefa Inicial**: Em um processo sequencial, o primeiro agente conclui sua tarefa e sinaliza a finalização.
2. **Tarefas Subsequentes**: Os agentes assumem suas tarefas conforme o tipo de processo, com os resultados das tarefas anteriores ou diretrizes orientando sua execução.
3. **Finalização**: O processo é concluído assim que a última tarefa é executada, levando à conclusão do projeto.
## Funcionalidades Avançadas
### Delegação de Tarefas
Em processos sequenciais, se um agente possui `allow_delegation` definido como `True`, ele pode delegar tarefas para outros agentes na crew.
Esse recurso é configurado automaticamente quando há múltiplos agentes na crew.
### Execução Assíncrona
As tarefas podem ser executadas de forma assíncrona, permitindo processamento paralelo quando apropriado.
Para criar uma tarefa assíncrona, defina `async_execution=True` ao criar a tarefa.
### Memória e Cache
O CrewAI suporta recursos de memória e cache:
- **Memória**: Habilite definindo `memory=True` ao criar a Crew. Isso permite aos agentes reter informações entre as tarefas.
- **Cache**: Por padrão, o cache está habilitado. Defina `cache=False` para desativá-lo.
### Callbacks
Você pode definir callbacks tanto no nível da tarefa quanto no nível de etapa:
- `task_callback`: Executado após a conclusão de cada tarefa.
- `step_callback`: Executado após cada etapa na execução de um agente.
### Métricas de Uso
O CrewAI rastreia o uso de tokens em todas as tarefas e agentes. Você pode acessar essas métricas após a execução.
## Melhores Práticas para Processos Sequenciais
1. **A Ordem Importa**: Organize as tarefas em uma sequência lógica, onde cada uma aproveite o resultado da anterior.
2. **Descrições Claras de Tarefas**: Forneça descrições detalhadas para cada tarefa, orientando os agentes de forma eficaz.
3. **Seleção Apropriada de Agentes**: Relacione as habilidades e funções dos agentes às necessidades de cada tarefa.
4. **Use o Contexto**: Aproveite o contexto das tarefas anteriores para informar as seguintes.
Esta documentação atualizada garante que os detalhes reflitam com precisão as últimas mudanças no código e descreve claramente como aproveitar novos recursos e configurações.
O conteúdo foi mantido simples e direto para garantir fácil compreensão.

View File

@@ -0,0 +1,384 @@
---
title: Streaming na Execução da Crew
description: Transmita saída em tempo real da execução da sua crew no CrewAI
icon: wave-pulse
mode: "wide"
---
## Introdução
O CrewAI fornece a capacidade de transmitir saída em tempo real durante a execução da crew, permitindo que você exiba resultados conforme são gerados, em vez de esperar que todo o processo seja concluído. Este recurso é particularmente útil para construir aplicações interativas, fornecer feedback ao usuário e monitorar processos de longa duração.
## Como o Streaming Funciona
Quando o streaming está ativado, o CrewAI captura respostas do LLM e chamadas de ferramentas conforme acontecem, empacotando-as em chunks estruturados que incluem contexto sobre qual task e agent está executando. Você pode iterar sobre esses chunks em tempo real e acessar o resultado final quando a execução for concluída.
## Ativando o Streaming
Para ativar o streaming, defina o parâmetro `stream` como `True` ao criar sua crew:
```python Code
from crewai import Agent, Crew, Task
# Crie seus agentes e tasks
researcher = Agent(
role="Research Analyst",
goal="Gather comprehensive information on topics",
backstory="You are an experienced researcher with excellent analytical skills.",
)
task = Task(
description="Research the latest developments in AI",
expected_output="A detailed report on recent AI advancements",
agent=researcher,
)
# Ativar streaming
crew = Crew(
agents=[researcher],
tasks=[task],
stream=True # Ativar saída em streaming
)
```
## Streaming Síncrono
Quando você chama `kickoff()` em uma crew com streaming ativado, ele retorna um objeto `CrewStreamingOutput` que você pode iterar para receber chunks conforme chegam:
```python Code
# Iniciar execução com streaming
streaming = crew.kickoff(inputs={"topic": "artificial intelligence"})
# Iterar sobre chunks conforme chegam
for chunk in streaming:
print(chunk.content, end="", flush=True)
# Acessar o resultado final após o streaming completar
result = streaming.result
print(f"\n\nSaída final: {result.raw}")
```
### Informações do Chunk de Stream
Cada chunk fornece contexto rico sobre a execução:
```python Code
streaming = crew.kickoff(inputs={"topic": "AI"})
for chunk in streaming:
print(f"Task: {chunk.task_name} (índice {chunk.task_index})")
print(f"Agent: {chunk.agent_role}")
print(f"Content: {chunk.content}")
print(f"Type: {chunk.chunk_type}") # TEXT ou TOOL_CALL
if chunk.tool_call:
print(f"Tool: {chunk.tool_call.tool_name}")
print(f"Arguments: {chunk.tool_call.arguments}")
```
### Acessando Resultados do Streaming
O objeto `CrewStreamingOutput` fornece várias propriedades úteis:
```python Code
streaming = crew.kickoff(inputs={"topic": "AI"})
# Iterar e coletar chunks
for chunk in streaming:
print(chunk.content, end="", flush=True)
# Após a iteração completar
print(f"\nCompletado: {streaming.is_completed}")
print(f"Texto completo: {streaming.get_full_text()}")
print(f"Todos os chunks: {len(streaming.chunks)}")
print(f"Resultado final: {streaming.result.raw}")
```
## Streaming Assíncrono
Para aplicações assíncronas, você pode usar `akickoff()` (async nativo) ou `kickoff_async()` (baseado em threads) com iteração assíncrona:
### Async Nativo com `akickoff()`
O método `akickoff()` fornece execução async nativa verdadeira em toda a cadeia:
```python Code
import asyncio
async def stream_crew():
crew = Crew(
agents=[researcher],
tasks=[task],
stream=True
)
# Iniciar streaming async nativo
streaming = await crew.akickoff(inputs={"topic": "AI"})
# Iteração assíncrona sobre chunks
async for chunk in streaming:
print(chunk.content, end="", flush=True)
# Acessar resultado final
result = streaming.result
print(f"\n\nSaída final: {result.raw}")
asyncio.run(stream_crew())
```
### Async Baseado em Threads com `kickoff_async()`
Para integração async mais simples ou compatibilidade retroativa:
```python Code
import asyncio
async def stream_crew():
crew = Crew(
agents=[researcher],
tasks=[task],
stream=True
)
# Iniciar streaming async baseado em threads
streaming = await crew.kickoff_async(inputs={"topic": "AI"})
# Iteração assíncrona sobre chunks
async for chunk in streaming:
print(chunk.content, end="", flush=True)
# Acessar resultado final
result = streaming.result
print(f"\n\nSaída final: {result.raw}")
asyncio.run(stream_crew())
```
<Note>
Para cargas de trabalho de alta concorrência, `akickoff()` é recomendado pois usa async nativo para execução de tasks, operações de memória e recuperação de conhecimento. Consulte o guia [Iniciar Crew de Forma Assíncrona](/pt-BR/learn/kickoff-async) para mais detalhes.
</Note>
## Streaming com kickoff_for_each
Ao executar uma crew para múltiplas entradas com `kickoff_for_each()`, o streaming funciona de forma diferente dependendo se você usa síncrono ou assíncrono:
### kickoff_for_each Síncrono
Com `kickoff_for_each()` síncrono, você obtém uma lista de objetos `CrewStreamingOutput`, um para cada entrada:
```python Code
crew = Crew(
agents=[researcher],
tasks=[task],
stream=True
)
inputs_list = [
{"topic": "AI in healthcare"},
{"topic": "AI in finance"}
]
# Retorna lista de saídas de streaming
streaming_outputs = crew.kickoff_for_each(inputs=inputs_list)
# Iterar sobre cada saída de streaming
for i, streaming in enumerate(streaming_outputs):
print(f"\n=== Entrada {i + 1} ===")
for chunk in streaming:
print(chunk.content, end="", flush=True)
result = streaming.result
print(f"\n\nResultado {i + 1}: {result.raw}")
```
### kickoff_for_each_async Assíncrono
Com `kickoff_for_each_async()` assíncrono, você obtém um único `CrewStreamingOutput` que produz chunks de todas as crews conforme chegam concorrentemente:
```python Code
import asyncio
async def stream_multiple_crews():
crew = Crew(
agents=[researcher],
tasks=[task],
stream=True
)
inputs_list = [
{"topic": "AI in healthcare"},
{"topic": "AI in finance"}
]
# Retorna saída de streaming única para todas as crews
streaming = await crew.kickoff_for_each_async(inputs=inputs_list)
# Chunks de todas as crews chegam conforme são gerados
async for chunk in streaming:
print(f"[{chunk.task_name}] {chunk.content}", end="", flush=True)
# Acessar todos os resultados
results = streaming.results # Lista de objetos CrewOutput
for i, result in enumerate(results):
print(f"\n\nResultado {i + 1}: {result.raw}")
asyncio.run(stream_multiple_crews())
```
## Tipos de Chunk de Stream
Chunks podem ser de diferentes tipos, indicados pelo campo `chunk_type`:
### Chunks TEXT
Conteúdo de texto padrão de respostas do LLM:
```python Code
for chunk in streaming:
if chunk.chunk_type == StreamChunkType.TEXT:
print(chunk.content, end="", flush=True)
```
### Chunks TOOL_CALL
Informações sobre chamadas de ferramentas sendo feitas:
```python Code
for chunk in streaming:
if chunk.chunk_type == StreamChunkType.TOOL_CALL:
print(f"\nChamando ferramenta: {chunk.tool_call.tool_name}")
print(f"Argumentos: {chunk.tool_call.arguments}")
```
## Exemplo Prático: Construindo uma UI com Streaming
Aqui está um exemplo completo mostrando como construir uma aplicação interativa com streaming:
```python Code
import asyncio
from crewai import Agent, Crew, Task
from crewai.types.streaming import StreamChunkType
async def interactive_research():
# Criar crew com streaming ativado
researcher = Agent(
role="Research Analyst",
goal="Provide detailed analysis on any topic",
backstory="You are an expert researcher with broad knowledge.",
)
task = Task(
description="Research and analyze: {topic}",
expected_output="A comprehensive analysis with key insights",
agent=researcher,
)
crew = Crew(
agents=[researcher],
tasks=[task],
stream=True,
verbose=False
)
# Obter entrada do usuário
topic = input("Digite um tópico para pesquisar: ")
print(f"\n{'='*60}")
print(f"Pesquisando: {topic}")
print(f"{'='*60}\n")
# Iniciar execução com streaming
streaming = await crew.kickoff_async(inputs={"topic": topic})
current_task = ""
async for chunk in streaming:
# Mostrar transições de task
if chunk.task_name != current_task:
current_task = chunk.task_name
print(f"\n[{chunk.agent_role}] Trabalhando em: {chunk.task_name}")
print("-" * 60)
# Exibir chunks de texto
if chunk.chunk_type == StreamChunkType.TEXT:
print(chunk.content, end="", flush=True)
# Exibir chamadas de ferramentas
elif chunk.chunk_type == StreamChunkType.TOOL_CALL and chunk.tool_call:
print(f"\n🔧 Usando ferramenta: {chunk.tool_call.tool_name}")
# Mostrar resultado final
result = streaming.result
print(f"\n\n{'='*60}")
print("Análise Completa!")
print(f"{'='*60}")
print(f"\nUso de Tokens: {result.token_usage}")
asyncio.run(interactive_research())
```
## Casos de Uso
O streaming é particularmente valioso para:
- **Aplicações Interativas**: Fornecer feedback em tempo real aos usuários enquanto os agentes trabalham
- **Tasks de Longa Duração**: Mostrar progresso para pesquisa, análise ou geração de conteúdo
- **Depuração e Monitoramento**: Observar comportamento e tomada de decisão dos agentes em tempo real
- **Experiência do Usuário**: Reduzir latência percebida mostrando resultados incrementais
- **Dashboards ao Vivo**: Construir interfaces de monitoramento que exibem status de execução da crew
## Cancelamento e Limpeza de Recursos
`CrewStreamingOutput` suporta cancelamento gracioso para que o trabalho em andamento pare imediatamente quando o consumidor desconecta.
### Gerenciador de Contexto Assíncrono
```python Code
streaming = await crew.akickoff(inputs={"topic": "AI"})
async with streaming:
async for chunk in streaming:
print(chunk.content, end="", flush=True)
```
### Cancelamento Explícito
```python Code
streaming = await crew.akickoff(inputs={"topic": "AI"})
try:
async for chunk in streaming:
print(chunk.content, end="", flush=True)
finally:
await streaming.aclose() # assíncrono
# streaming.close() # equivalente síncrono
```
Após o cancelamento, `streaming.is_cancelled` e `streaming.is_completed` são ambos `True`. Tanto `aclose()` quanto `close()` são idempotentes.
## Notas Importantes
- O streaming ativa automaticamente o streaming do LLM para todos os agentes na crew
- Você deve iterar através de todos os chunks antes de acessar a propriedade `.result`
- Para `kickoff_for_each_async()` com streaming, use `.results` (plural) para obter todas as saídas
- O streaming adiciona overhead mínimo e pode realmente melhorar a performance percebida
- Cada chunk inclui contexto completo (task, agente, tipo de chunk) para UIs ricas
## Tratamento de Erros
Trate erros durante a execução com streaming:
```python Code
streaming = crew.kickoff(inputs={"topic": "AI"})
try:
for chunk in streaming:
print(chunk.content, end="", flush=True)
result = streaming.result
print(f"\nSucesso: {result.raw}")
except Exception as e:
print(f"\nErro durante o streaming: {e}")
if streaming.is_completed:
print("O streaming foi completado mas ocorreu um erro")
```
Ao aproveitar o streaming, você pode construir aplicações mais responsivas e interativas com o CrewAI, fornecendo aos usuários visibilidade em tempo real da execução dos agentes e resultados.

View File

@@ -0,0 +1,498 @@
---
title: Hooks de Chamada de Ferramenta
description: Aprenda a usar hooks de chamada de ferramenta para interceptar, modificar e controlar execução de ferramentas no CrewAI
mode: "wide"
---
Os Hooks de Chamada de Ferramenta fornecem controle fino sobre a execução de ferramentas durante operações do agente. Esses hooks permitem interceptar chamadas de ferramenta, modificar entradas, transformar saídas, implementar verificações de segurança e adicionar logging ou monitoramento abrangente.
## Visão Geral
Os hooks de ferramenta são executados em dois pontos críticos:
- **Antes da Chamada de Ferramenta**: Modificar entradas, validar parâmetros ou bloquear execução
- **Depois da Chamada de Ferramenta**: Transformar resultados, sanitizar saídas ou registrar detalhes de execução
## Tipos de Hook
### Hooks Antes da Chamada de Ferramenta
Executados antes de cada execução de ferramenta, esses hooks podem:
- Inspecionar e modificar entradas de ferramenta
- Bloquear execução de ferramenta com base em condições
- Implementar gates de aprovação para operações perigosas
- Validar parâmetros
- Registrar invocações de ferramenta
**Assinatura:**
```python
def before_hook(context: ToolCallHookContext) -> bool | None:
# Retorne False para bloquear execução
# Retorne True ou None para permitir execução
...
```
### Hooks Depois da Chamada de Ferramenta
Executados depois de cada execução de ferramenta, esses hooks podem:
- Modificar ou sanitizar resultados de ferramenta
- Adicionar metadados ou formatação
- Registrar resultados de execução
- Implementar validação de resultado
- Transformar formatos de saída
**Assinatura:**
```python
def after_hook(context: ToolCallHookContext) -> str | None:
# Retorne string de resultado modificado
# Retorne None para manter resultado original
...
```
## Contexto do Hook de Ferramenta
O objeto `ToolCallHookContext` fornece acesso abrangente ao estado de execução da ferramenta:
```python
class ToolCallHookContext:
tool_name: str # Nome da ferramenta sendo chamada
tool_input: dict[str, Any] # Parâmetros de entrada mutáveis da ferramenta
tool: CrewStructuredTool # Referência da instância da ferramenta
agent: Agent | BaseAgent | None # Agente executando a ferramenta
task: Task | None # Tarefa atual
crew: Crew | None # Instância da crew
tool_result: str | None # Resultado da ferramenta (apenas hooks posteriores)
```
### Modificando Entradas de Ferramenta
**Importante:** Sempre modifique entradas de ferramenta in-place:
```python
# ✅ Correto - modificar in-place
def sanitize_input(context: ToolCallHookContext) -> None:
context.tool_input['query'] = context.tool_input['query'].lower()
# ❌ Errado - substitui referência do dict
def wrong_approach(context: ToolCallHookContext) -> None:
context.tool_input = {'query': 'nova consulta'}
```
## Métodos de Registro
### 1. Registro Baseado em Decoradores (Recomendado)
Use decoradores para sintaxe mais limpa:
```python
from crewai.hooks import before_tool_call, after_tool_call
@before_tool_call
def block_dangerous_tools(context):
"""Bloqueia ferramentas perigosas."""
dangerous_tools = ['delete_database', 'drop_table', 'rm_rf']
if context.tool_name in dangerous_tools:
print(f"⛔ Ferramenta perigosa bloqueada: {context.tool_name}")
return False # Bloquear execução
return None
@after_tool_call
def sanitize_results(context):
"""Sanitiza resultados."""
if context.tool_result and "password" in context.tool_result.lower():
return context.tool_result.replace("password", "[CENSURADO]")
return None
```
### 2. Hooks com Escopo de Crew
Registre hooks para uma instância específica de crew:
```python
from crewai import CrewBase
from crewai.project import crew
from crewai.hooks import before_tool_call_crew, after_tool_call_crew
@CrewBase
class MyProjCrew:
@before_tool_call_crew
def validate_tool_inputs(self, context):
# Aplica-se apenas a esta crew
if context.tool_name == "web_search":
if not context.tool_input.get('query'):
print("❌ Consulta de busca inválida")
return False
return None
@after_tool_call_crew
def log_tool_results(self, context):
# Logging de ferramenta específico da crew
print(f"✅ {context.tool_name} concluída")
return None
@crew
def crew(self) -> Crew:
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True
)
```
## Casos de Uso Comuns
### 1. Guardrails de Segurança
```python
@before_tool_call
def safety_check(context: ToolCallHookContext) -> bool | None:
"""Bloqueia ferramentas que podem causar danos."""
destructive_tools = [
'delete_file',
'drop_table',
'remove_user',
'system_shutdown'
]
if context.tool_name in destructive_tools:
print(f"🛑 Ferramenta destrutiva bloqueada: {context.tool_name}")
return False
# Avisar em operações sensíveis
sensitive_tools = ['send_email', 'post_to_social_media', 'charge_payment']
if context.tool_name in sensitive_tools:
print(f"⚠️ Executando ferramenta sensível: {context.tool_name}")
return None
```
### 2. Gate de Aprovação Humana
```python
@before_tool_call
def require_approval_for_actions(context: ToolCallHookContext) -> bool | None:
"""Requer aprovação para ações específicas."""
approval_required = [
'send_email',
'make_purchase',
'delete_file',
'post_message'
]
if context.tool_name in approval_required:
response = context.request_human_input(
prompt=f"Aprovar {context.tool_name}?",
default_message=f"Entrada: {context.tool_input}\nDigite 'sim' para aprovar:"
)
if response.lower() != 'sim':
print(f"❌ Execução de ferramenta negada: {context.tool_name}")
return False
return None
```
### 3. Validação e Sanitização de Entrada
```python
@before_tool_call
def validate_and_sanitize_inputs(context: ToolCallHookContext) -> bool | None:
"""Valida e sanitiza entradas."""
# Validar consultas de busca
if context.tool_name == 'web_search':
query = context.tool_input.get('query', '')
if len(query) < 3:
print("❌ Consulta de busca muito curta")
return False
# Sanitizar consulta
context.tool_input['query'] = query.strip().lower()
# Validar caminhos de arquivo
if context.tool_name == 'read_file':
path = context.tool_input.get('path', '')
if '..' in path or path.startswith('/'):
print("❌ Caminho de arquivo inválido")
return False
return None
```
### 4. Sanitização de Resultado
```python
@after_tool_call
def sanitize_sensitive_data(context: ToolCallHookContext) -> str | None:
"""Sanitiza dados sensíveis."""
if not context.tool_result:
return None
import re
result = context.tool_result
# Remover chaves de API
result = re.sub(
r'(api[_-]?key|token)["\']?\s*[:=]\s*["\']?[\w-]+',
r'\1: [CENSURADO]',
result,
flags=re.IGNORECASE
)
# Remover endereços de email
result = re.sub(
r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
'[EMAIL-CENSURADO]',
result
)
# Remover números de cartão de crédito
result = re.sub(
r'\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b',
'[CARTÃO-CENSURADO]',
result
)
return result
```
### 5. Análise de Uso de Ferramenta
```python
import time
from collections import defaultdict
tool_stats = defaultdict(lambda: {'count': 0, 'total_time': 0, 'failures': 0})
@before_tool_call
def start_timer(context: ToolCallHookContext) -> None:
context.tool_input['_start_time'] = time.time()
return None
@after_tool_call
def track_tool_usage(context: ToolCallHookContext) -> None:
start_time = context.tool_input.get('_start_time', time.time())
duration = time.time() - start_time
tool_stats[context.tool_name]['count'] += 1
tool_stats[context.tool_name]['total_time'] += duration
if not context.tool_result or 'error' in context.tool_result.lower():
tool_stats[context.tool_name]['failures'] += 1
print(f"""
📊 Estatísticas da Ferramenta {context.tool_name}:
- Execuções: {tool_stats[context.tool_name]['count']}
- Tempo Médio: {tool_stats[context.tool_name]['total_time'] / tool_stats[context.tool_name]['count']:.2f}s
- Falhas: {tool_stats[context.tool_name]['failures']}
""")
return None
```
### 6. Limitação de Taxa
```python
from collections import defaultdict
from datetime import datetime, timedelta
tool_call_history = defaultdict(list)
@before_tool_call
def rate_limit_tools(context: ToolCallHookContext) -> bool | None:
"""Limita taxa de chamadas de ferramenta."""
tool_name = context.tool_name
now = datetime.now()
# Limpar entradas antigas (mais antigas que 1 minuto)
tool_call_history[tool_name] = [
call_time for call_time in tool_call_history[tool_name]
if now - call_time < timedelta(minutes=1)
]
# Verificar limite de taxa (máximo 10 chamadas por minuto)
if len(tool_call_history[tool_name]) >= 10:
print(f"🚫 Limite de taxa excedido para {tool_name}")
return False
# Registrar esta chamada
tool_call_history[tool_name].append(now)
return None
```
### 7. Logging de Debug
```python
@before_tool_call
def debug_tool_call(context: ToolCallHookContext) -> None:
"""Debug de chamada de ferramenta."""
print(f"""
🔍 Debug de Chamada de Ferramenta:
- Ferramenta: {context.tool_name}
- Agente: {context.agent.role if context.agent else 'Desconhecido'}
- Tarefa: {context.task.description[:50] if context.task else 'Desconhecida'}...
- Entrada: {context.tool_input}
""")
return None
@after_tool_call
def debug_tool_result(context: ToolCallHookContext) -> None:
"""Debug de resultado de ferramenta."""
if context.tool_result:
result_preview = context.tool_result[:200]
print(f"✅ Preview do Resultado: {result_preview}...")
else:
print("⚠️ Nenhum resultado retornado")
return None
```
## Gerenciamento de Hooks
### Desregistrando Hooks
```python
from crewai.hooks import (
unregister_before_tool_call_hook,
unregister_after_tool_call_hook
)
# Desregistrar hook específico
def my_hook(context):
...
register_before_tool_call_hook(my_hook)
# Mais tarde...
success = unregister_before_tool_call_hook(my_hook)
print(f"Desregistrado: {success}")
```
### Limpando Hooks
```python
from crewai.hooks import (
clear_before_tool_call_hooks,
clear_after_tool_call_hooks,
clear_all_tool_call_hooks
)
# Limpar tipo específico de hook
count = clear_before_tool_call_hooks()
print(f"Limpou {count} hooks antes")
# Limpar todos os hooks de ferramenta
before_count, after_count = clear_all_tool_call_hooks()
print(f"Limpou {before_count} hooks antes e {after_count} hooks depois")
```
## Padrões Avançados
### Execução Condicional de Hook
```python
@before_tool_call
def conditional_blocking(context: ToolCallHookContext) -> bool | None:
"""Bloqueia apenas em condições específicas."""
# Bloquear apenas para agentes específicos
if context.agent and context.agent.role == "junior_agent":
if context.tool_name in ['delete_file', 'send_email']:
print(f"❌ Agentes júnior não podem usar {context.tool_name}")
return False
# Bloquear apenas durante tarefas específicas
if context.task and "sensível" in context.task.description.lower():
if context.tool_name == 'web_search':
print("❌ Busca na web bloqueada para tarefas sensíveis")
return False
return None
```
### Modificação de Entrada com Consciência de Contexto
```python
@before_tool_call
def enhance_tool_inputs(context: ToolCallHookContext) -> None:
"""Adiciona contexto baseado no papel do agente."""
# Adicionar contexto baseado no papel do agente
if context.agent and context.agent.role == "researcher":
if context.tool_name == 'web_search':
# Adicionar restrições de domínio para pesquisadores
context.tool_input['domains'] = ['edu', 'gov', 'org']
# Adicionar contexto baseado na tarefa
if context.task and "urgente" in context.task.description.lower():
if context.tool_name == 'send_email':
context.tool_input['priority'] = 'high'
return None
```
## Melhores Práticas
1. **Mantenha Hooks Focados**: Cada hook deve ter uma responsabilidade única
2. **Evite Computação Pesada**: Hooks executam em cada chamada de ferramenta
3. **Trate Erros Graciosamente**: Use try-except para prevenir falhas de hooks
4. **Use Type Hints**: Aproveite `ToolCallHookContext` para melhor suporte IDE
5. **Documente Condições de Bloqueio**: Deixe claro quando/por que ferramentas são bloqueadas
6. **Teste Hooks Independentemente**: Teste unitário de hooks antes de usar em produção
7. **Limpe Hooks em Testes**: Use `clear_all_tool_call_hooks()` entre execuções de teste
8. **Modifique In-Place**: Sempre modifique `context.tool_input` in-place, nunca substitua
9. **Registre Decisões Importantes**: Especialmente ao bloquear execução de ferramenta
10. **Considere Performance**: Cache validações caras quando possível
## Tratamento de Erros
```python
@before_tool_call
def safe_validation(context: ToolCallHookContext) -> bool | None:
try:
# Sua lógica de validação
if not validate_input(context.tool_input):
return False
except Exception as e:
print(f"⚠️ Erro no hook: {e}")
# Decida: permitir ou bloquear em erro
return None # Permitir execução apesar do erro
```
## Segurança de Tipos
```python
from crewai.hooks import ToolCallHookContext, BeforeToolCallHookType, AfterToolCallHookType
# Anotações de tipo explícitas
def my_before_hook(context: ToolCallHookContext) -> bool | None:
return None
def my_after_hook(context: ToolCallHookContext) -> str | None:
return None
# Registro type-safe
register_before_tool_call_hook(my_before_hook)
register_after_tool_call_hook(my_after_hook)
```
## Solução de Problemas
### Hook Não Está Executando
- Verifique se hook está registrado antes da execução da crew
- Verifique se hook anterior retornou `False` (bloqueia execução e hooks subsequentes)
- Garanta que assinatura do hook corresponda ao tipo esperado
### Modificações de Entrada Não Funcionam
- Use modificações in-place: `context.tool_input['key'] = value`
- Não substitua o dict: `context.tool_input = {}`
### Modificações de Resultado Não Funcionam
- Retorne a string modificada dos hooks posteriores
- Retornar `None` mantém o resultado original
- Garanta que a ferramenta realmente retornou um resultado
### Ferramenta Bloqueada Inesperadamente
- Verifique todos os hooks antes por condições de bloqueio
- Verifique ordem de execução do hook
- Adicione logging de debug para identificar qual hook está bloqueando
## Conclusão
Os Hooks de Chamada de Ferramenta fornecem capacidades poderosas para controlar e monitorar execução de ferramentas no CrewAI. Use-os para implementar guardrails de segurança, gates de aprovação, validação de entrada, sanitização de resultado, logging e análise. Combinados com tratamento adequado de erros e segurança de tipos, os hooks permitem sistemas de agentes seguros e prontos para produção com observabilidade abrangente.

View File

@@ -0,0 +1,155 @@
---
title: "Usando Anotações no crew.py"
description: "Aprenda como usar anotações para estruturar corretamente agentes, tarefas e componentes no CrewAI"
icon: "at"
mode: "wide"
---
Este guia explica como utilizar anotações para referenciar corretamente **agentes**, **tarefas** e outros componentes em um arquivo `crew.py` clássico.
<Note>
Novos projetos criados com `crewai create crew <name>` são JSON-first e usam `crew.jsonc` com `agents/*.jsonc`. Use este guia ao trabalhar em um projeto clássico criado com `crewai create crew <name> --classic`, ao migrar um projeto Python/YAML existente ou quando precisar de controle via decorators em Python.
</Note>
## Introdução
As anotações no framework CrewAI são utilizadas para decorar classes e métodos, fornecendo metadados e funcionalidades para diversos componentes do seu crew. Em projetos clássicos Python/YAML, elas organizam o código que carrega `config/agents.yaml`, `config/tasks.yaml` e retorna o objeto `Crew`.
## Anotações Disponíveis
O framework CrewAI fornece as seguintes anotações:
- `@CrewBase`: Usada para decorar a classe principal do crew.
- `@agent`: Decora métodos que definem e retornam objetos Agent.
- `@task`: Decora métodos que definem e retornam objetos Task.
- `@crew`: Decora o método que cria e retorna o objeto Crew.
- `@llm`: Decora métodos que inicializam e retornam objetos Language Model.
- `@tool`: Decora métodos que inicializam e retornam objetos Tool.
- `@callback`: Utilizada para definir métodos de callback.
- `@output_json`: Utilizada para métodos que retornam dados em JSON.
- `@output_pydantic`: Utilizada para métodos que retornam modelos Pydantic.
- `@cache_handler`: Utilizada para definição de métodos de manipulação de cache.
## Exemplos de Uso
Vamos passar por exemplos de como utilizar essas anotações:
### 1. Classe Base do Crew
```python
@CrewBase
class LinkedinProfileCrew():
"""LinkedinProfile crew"""
agents_config = 'config/agents.yaml'
tasks_config = 'config/tasks.yaml'
```
A anotação `@CrewBase` é usada para decorar a classe principal do crew. Esta classe geralmente contém as configurações e métodos para criação de agentes, tarefas e do próprio crew.
<Tip>
`@CrewBase` faz bem mais do que registrar a classe:
- **Inicialização de configuração:** busca `agents_config` e `tasks_config` (padrões `config/agents.yaml` e `config/tasks.yaml`) ao lado do arquivo da classe, carrega esses YAMLs na inicialização e utiliza dicionários vazios quando os arquivos não existem.
- **Orquestração de decoradores:** mantém versões memoizadas dos métodos marcados com `@agent`, `@task`, `@before_kickoff` e `@after_kickoff` para que sejam instanciados uma única vez por crew e respeitem a ordem de declaração.
- **Encadeamento de hooks:** conecta automaticamente os hooks preservados ao objeto `Crew` retornado pelo método `@crew`, garantindo que executem antes e depois de `.kickoff()`.
- **Integração MCP:** quando a classe define `mcp_server_params`, `get_mcp_tools()` cria sob demanda um adaptador MCP, carrega as ferramentas declaradas e um hook interno pós-kickoff encerra o adaptador. Consulte a [visão geral de MCP](/pt-BR/mcp/overview) para detalhes de configuração.
</Tip>
### 2. Definição de Tool
```python
@tool
def myLinkedInProfileTool(self):
return LinkedInProfileTool()
```
A anotação `@tool` é usada para decorar métodos que retornam objetos tool. Essas ferramentas podem ser usadas por agentes para executar tarefas específicas.
### 3. Definição de LLM
```python
@llm
def groq_llm(self):
api_key = os.getenv('api_key')
return ChatGroq(api_key=api_key, temperature=0, model_name="mixtral-8x7b-32768")
```
A anotação `@llm` é usada para decorar métodos que inicializam e retornam objetos Language Model. Esses LLMs são utilizados pelos agentes para tarefas de processamento de linguagem natural.
### 4. Definição de Agente
```python
@agent
def researcher(self) -> Agent:
return Agent(
config=self.agents_config['researcher']
)
```
A anotação `@agent` é usada para decorar métodos que definem e retornam objetos Agent.
### 5. Definição de Tarefa
```python
@task
def research_task(self) -> Task:
return Task(
config=self.tasks_config['research_linkedin_task'],
agent=self.researcher()
)
```
A anotação `@task` é usada para decorar métodos que definem e retornam objetos Task. Esses métodos especificam a configuração da tarefa e o agente responsável por ela.
### 6. Criação do Crew
```python
@crew
def crew(self) -> Crew:
"""Creates the LinkedinProfile crew"""
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True
)
```
A anotação `@crew` é usada para decorar o método que cria e retorna o objeto `Crew`. Este método reúne todos os componentes (agentes e tarefas) em um crew funcional.
## Configuração YAML Clássica
Em projetos clássicos, as configurações dos agentes geralmente são armazenadas em um arquivo YAML. Veja um exemplo de como o arquivo `agents.yaml` pode ser estruturado para o agente researcher:
```yaml
researcher:
role: >
LinkedIn Profile Senior Data Researcher
goal: >
Uncover detailed LinkedIn profiles based on provided name {name} and domain {domain}
Generate a Dall-E image based on domain {domain}
backstory: >
You're a seasoned researcher with a knack for uncovering the most relevant LinkedIn profiles.
Known for your ability to navigate LinkedIn efficiently, you excel at gathering and presenting
professional information clearly and concisely.
allow_delegation: False
verbose: True
llm: groq_llm
tools:
- myLinkedInProfileTool
- mySerperDevTool
- myDallETool
```
Esta configuração YAML corresponde ao agente researcher definido na classe `LinkedinProfileCrew`. A configuração especifica o papel do agente, objetivo, contexto e outras propriedades, como o LLM e as tools que ele utiliza.
Repare como os campos `llm` e `tools` no arquivo YAML correspondem aos métodos decorados com `@llm` e `@tool` na classe Python.
## Boas Práticas
- **Nomenclatura Consistente**: Utilize nomenclatura clara e consistente para seus métodos. Por exemplo, métodos de agentes podem ser nomeados de acordo com suas funções (ex: researcher, reporting_analyst).
- **Variáveis de Ambiente**: Utilize variáveis de ambiente para informações sensíveis como chaves de API.
- **Flexibilidade**: Estruture seu crew de forma flexível, permitindo fácil adição ou remoção de agentes e tarefas.
- **Correspondência YAML-Código**: Em projetos clássicos, assegure que os nomes e estruturas nos arquivos YAML correspondam corretamente aos métodos decorados em seu código Python.
Seguindo essas orientações e utilizando corretamente as anotações, você conseguirá manter crews clássicos bem estruturados. Para novas crews, prefira a estrutura JSON-first em [Crews](/pt-BR/concepts/crews).