Em tempos onde a inteligência artificial domina as conversas, decidi ousar e escrever meu primeiro artigo no LinkedIn sobre o tema. Quero compartilhar um pouco sobre meus estudos preliminares e a execução do meu próprio “Hello World” no CrewAI, um projeto incrível desenvolvido pelo brasileiro João (Joe) Moura.
Se você também está interessado no mundo da IA e dos agentes inteligentes, convido você a interagir e seguir junto nessa jornada de aprendizado. A revolução da IA já está em andamento, e quanto mais trocarmos conhecimento, melhor! Fique à vontade para me adicionar no LinkedIn ou entrar em contato diretamente.
Após algumas pesquisas e consumo de conteúdo sobre o tema, escolhi explorar o CrewAI e entender mais a fundo sua arquitetura. O CrewAI se propõe a ser um framework que padroniza a forma como agentes se comunicam com LLMs, mas vai além disso. Ele facilita a estruturação de orquestrações complexas que, sem ele, precisariam ser feitas manualmente via código, o que levaria cada empresa a desenvolver sua própria solução. Se quiser conhecer mais, recomendo conferir o site oficial do CrewAI: CrewAI.
Apesar da excelente documentação do CrewAI, não queria simplesmente rodar o clássico “Hello World” sem propósito. Então, para tornar o aprendizado mais desafiador e produtivo, decidi criar um agente de IA que pudesse ser utilizado na prática.
Assim nasceu o ShopAI – SEO Agent, um projeto open-source com o objetivo de ajudar e-commerces a otimizar seus desafios de SEO. Mais do que isso, é um projeto que convida todos a aprenderem a criar agentes de IA, tornando o conhecimento mais acessível e prático!
Vamos lá?
Para criação do Agente Inteligente utilizamos o CrewAI, e o modelo de LLM que escolhi foi o Google Gemini, atualmente venho estudando bastante sobre os produtos de IA do Google Cloud , pois é a stack que utilizo no trabalho e recentemente me certifiquei como Professional Data Engineer GCP.
Configuramos o arquivo agent.yaml executar as atividiades conforme gostaríamos
# Agent.yaml
title_optimizer:
role: >
Especialista em SEO para Títulos de Produtos
goal: >
Otimizar o titulo a seguir: {titulo}. VOcê deve otimiza-lo para aumentar a visibilidade nas buscas e otimizar a conversão de vendas.
backstory: >
Você é um especialista em SEO para e-commerce, com amplo conhecimento em práticas recomendadas de otimização de títulos.
Seu objetivo é revisar, analisar e sugerir melhorias no seguinte {titulo}, garantindo que sigam as melhores práticas
de SEO, incluindo palavras-chave relevantes, tamanho ideal e apelo comercial. Você entende as diretrizes dos motores de busca
e como os consumidores brasileiros pesquisam produtos online.
Na sequência, configuramos as tasks
title_optimizer_task:
description: >
Analise e otimize a lista csv de titulos a seguir:{products}. Com base nas melhores práticas de SEO para ecommerce.
Certifique-se de incluir palavras-chave relevantes, respeitar o tamanho ideal dos títulos (50-60 caracteres).
expected_output: >
Um CSV contendo uma lista com o id e a nova sugestão de título já otimizado com as seguintes colunas:
- Id do produto.
- Título atual do produto.
- Sugestão de título otimizado.
- Indicação de palavras-chave para configurar o SEO da página de produtos.
agent: title_optimizer
output_file: titles_optimized.csv
Configuramos o CrewAI
import os
import io
import csv
import pandas as pd
from typing import List
from pydantic import BaseModel, Field
from crewai import Agent, Crew, Process, Task, LLM
from crewai.project import CrewBase, agent, crew, task, before_kickoff, after_kickoff
# Modelo Pydantic para a saída da tarefa
class TitleOptimizerOutput(BaseModel):
id: int = Field(..., description="ID do produto")
titulo_atual: str = Field(..., description="Título atual do produto")
sugestao_otimizada: str = Field(..., description="Sugestão de título otimizado")
palavras_chave: str = Field(..., description="Palavras-chave sugeridas para SEO")
@CrewBase
class ShopaiSeoAgent():
"""ShopaiSeoAgent crew"""
# Configurações YAML para agentes e tarefas
agents_config = 'config/agents.yaml'
tasks_config = 'config/tasks.yaml'
@before_kickoff
def before_kickoff_function(self, inputs):
print(f"Before kickoff function with inputs: {inputs}")
return inputs # Pode modificar ou retornar os inputs conforme necessário
@after_kickoff
def after_kickoff_function(self, result):
"""
Função executada após o kickoff que extrai e imprime informações da saída.
Caso o resultado seja um objeto CrewOutput, extrai a saída interna.
"""
# Se o resultado for um objeto CrewOutput, extrai a saída interna.
if hasattr(result, "output"):
print("Detectado objeto CrewOutput; extraindo a saída interna.")
result = result.output
print(f"Tipo do resultado após extração: {type(result)}")
print(f"Conteúdo do resultado (primeiras 500 chars): {str(result)[:500]}")
# Retorna o resultado sem salvar em CSV; a persistência ficará a cargo do framework.
return result
@agent
def title_optimizer(self) -> Agent:
return Agent(
config=self.agents_config['title_optimizer'],
# tools=[], # Adicione ferramentas se necessário
verbose=True,
llm=LLM(model='gemini/gemini-2.0-flash-exp')
)
@task
def title_optimizer_task(self) -> Task:
return Task(
config=self.tasks_config['title_optimizer_task'],
output_file='output/report.md', # Arquivo de relatório gerado, se necessário
output_json=TitleOptimizerOutput
)
@crew
def crew(self) -> Crew:
"""Cria o crew do ShopaiSeoAgent"""
return Crew(
agents=self.agents, # Criado automaticamente pelo decorator @agent
tasks=self.tasks, # Criado automaticamente pelo decorator @task
process=Process.sequential,
verbose=True,
# process=Process.hierarchical, # Se preferir usar o processamento hierárquico
)
Então, o main file
#!/usr/bin/env python
import sys
import os
import math
import pandas as pd
import warnings
from shopai_seo_agent.crew import ShopaiSeoAgent
warnings.filterwarnings("ignore", category=SyntaxWarning, module="pysbd")
def run():
"""
Lê o CSV com todos os produtos, divide em blocos de 100 produtos,
chama o crew para otimização dos títulos e salva a saída em um CSV.
"""
# Define o caminho do CSV de entrada
base_dir = os.path.dirname(os.path.abspath(__file__))
resources_dir = os.path.join(base_dir, "resources")
input_csv = os.path.join(resources_dir, "products.csv")
if not os.path.exists(input_csv):
print(f"Arquivo {input_csv} não encontrado!")
sys.exit(1)
# Lê o CSV (supondo que as colunas sejam 'id' e 'titulo'; se for 'title', ajuste)
df = pd.read_csv(input_csv)
# Verifica se há produtos
if df.empty:
print("Nenhum produto encontrado no CSV.")
sys.exit(1)
# Define o tamanho do bloco (chunk) – 100 produtos por vez
chunk_size = 100
total_products = len(df)
num_chunks = math.ceil(total_products / chunk_size)
# Lista para armazenar os resultados de cada bloco
all_results = []
print(f"Iniciando o processamento de {total_products} produtos em {num_chunks} blocos...")
# Para cada bloco de 100 produtos:
for i in range(num_chunks):
start = i * chunk_size
end = min((i + 1) * chunk_size, total_products)
chunk_df = df.iloc[start:end]
# Cria o input para o crew: uma lista de produtos
# Cada produto é um dicionário com 'id' e 'titulo'
products_list = chunk_df.to_dict(orient='records')
inputs = {'products': products_list}
print(f"Processando bloco {i+1}/{num_chunks} (produtos {start+1} a {end})...")
try:
# Chama o crew para processar o bloco.
# O método kickoff deverá estar preparado para receber inputs com múltiplos produtos.
result = ShopaiSeoAgent().crew().kickoff(inputs=inputs)
# Supondo que o resultado seja uma lista de dicionários, um para cada produto otimizado
# (cada dicionário pode conter os campos originais e os novos, por exemplo, 'optimized_title', 'keywords', etc.)
if isinstance(result, list):
all_results.extend(result)
else:
print(f"A saída do crew não está no formato esperado (lista). Bloco {i+1} ignorado.")
except Exception as e:
print(f"Erro ao processar o bloco {i+1}: {e}")
# Se houver resultados, salva em um CSV
if all_results:
output_df = pd.DataFrame(all_results)
output_csv = os.path.join(resources_dir, "optimized_products.csv")
try:
output_df.to_csv(output_csv, index=False)
print(f"Arquivo CSV com resultados gerado com sucesso: {output_csv}")
except Exception as e:
print(f"Erro ao salvar o CSV: {e}")
else:
print("Nenhum resultado foi obtido. Verifique se o crew está retornando a saída esperada.")
def train():
"""
Treina o crew para um número definido de iterações.
"""
inputs = {
"titulo": "ALI. PRESSAO P/ SOLDA- TIPO U 10 TRAMONTINA 44016/110"
}
try:
ShopaiSeoAgent().crew().train(n_iterations=int(sys.argv[1]), filename=sys.argv[2], inputs=inputs)
except Exception as e:
raise Exception(f"An error occurred while training the crew: {e}")
def replay():
"""
Replay da execução do crew a partir de uma task específica.
"""
try:
ShopaiSeoAgent().crew().replay(task_id=sys.argv[1])
except Exception as e:
raise Exception(f"An error occurred while replaying the crew: {e}")
def test():
"""
Testa a execução do crew e retorna os resultados.
"""
inputs = {
"titulo": "ALI. PRESSAO P/ SOLDA- TIPO U 10 TRAMONTINA 44016/110"
}
try:
ShopaiSeoAgent().crew().test(n_iterations=int(sys.argv[1]), openai_model_name=sys.argv[2], inputs=inputs)
except Exception as e:
raise Exception(f"An error occurred while testing the crew: {e}")
if __name__ == '__main__':
run()
Com isso, temos um agente de IA utilizando o Google Gemini que é um especialista em analisar títulos de produtos e descrições de produtos para um e-commerce, além de sugerir boas keyword para o item
O projeto completo está no meu Github abaixo:
Trata-se de um MVP ainda sem integração direta com os projetos de e-commerce, mas que pode ser incluído facilmente
Se interessou pelo projeto? Entre em contato para saber mais sobre