Files
crewAI/docs/pt-BR/learn/bring-your-own-agent.mdx
Tony Kipkemboi 1a1bb0ca3d docs: Docs updates (#3459)
* docs(cli): document device-code login and config reset guidance; renumber sections

* docs(cli): fix duplicate numbering (renumber Login/API Keys/Configuration sections)

* docs: Fix webhook documentation to include meta dict in all webhook payloads

- Add note explaining that meta objects from kickoff requests are included in all webhook payloads
- Update webhook examples to show proper payload structure including meta field
- Fix webhook examples to match actual API implementation
- Apply changes to English, Korean, and Portuguese documentation

Resolves the documentation gap where meta dict passing to webhooks was not documented despite being implemented in the API.

* WIP: CrewAI docs theme, changelog, GEO, localization

* docs(cli): fix merge markers; ensure mode: "wide"; convert ASCII tables to Markdown (en/pt-BR/ko)

* docs: add group icons across locales; split Automation/Integrations; update tools overviews and links
2025-09-05 17:40:11 -04:00

442 lines
22 KiB
Plaintext

---
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)
```