advanced60 minLição 5 de 5

Padrões Avançados: Callbacks, Memória, Config LLM e Testes

Domine step callbacks, callbacks personalizados, tipos de memória de agente, configuração de LLM por agente, temperatura, LLMs para chamada de funções e testes de fluxos CrewAI.

Padrões Avançados: Callbacks, Memória, Config LLM e Testes

Esta lição cobre padrões prontos para produção: monitoramento com callbacks, memória persistente, controle refinado de LLM e estratégias de teste para crews CrewAI. Esses padrões transformam um sistema multi-agente protótipo em uma aplicação de produção confiável, observável e sustentável.


Step Callbacks

Step callbacks são disparados após cada etapa do agente (pensamento, ação ou observação). Use-os para logging, monitoramento ou streaming:

python
from crewai import Agent, Task, Crew, Process def step_callback(step): """Chamado após cada etapa de raciocínio do agente.""" print(f"[ETAPA] Agente: {step.get('agent', 'desconhecido')}") print(f"[ETAPA] Ação: {step.get('action', 'nenhuma')}") print(f"[ETAPA] Saída até agora: {step.get('output', '')[:100]}...") print("-" * 40) agente = Agent( role="Analista de Pesquisa", goal="Coletar inteligência de mercado", backstory="Você é um especialista em pesquisa de mercado.", step_callback=step_callback, # anexar callback ) tarefa = Task( description="Pesquise as últimas tendências de IA.", expected_output="Lista de tendências.", agent=agente, ) crew = Crew( agents=[agente], tasks=[tarefa], verbose=True, ) resultado = crew.kickoff()

O dicionário step contém informações valiosas de depuração:

ChaveTipo de ValorDescrição
agentstrNome/papel do agente
actionstrAção atual (pensamento, chamada de ferramenta, observação)
outputstrSaída parcial acumulada até agora
tool_inputdictEntradas passadas para uma ferramenta (se aplicável)
tool_outputstrSaída retornada por uma ferramenta (se aplicável)

Fluxo da Cadeia de Callbacks

100%

Callbacks Personalizados com Handlers Baseados em Classe

Para monitoramento complexo, crie uma classe de callback:

python
from crewai import Agent, Task, Crew class CallbackLogging: """Rastreia cada etapa do agente para auditoria.""" def __init__(self): self.steps = [] def on_step(self, step): self.steps.append(step) nome_agente = step.get("agent", "?") acao = step.get("action", "?") print(f"[{nome_agente}] → {acao}") def summary(self): print(f"Total de etapas: {len(self.steps)}") for s in self.steps: print(f" - {s.get('agent')}: {s.get('action')}") callback = CallbackLogging() agente = Agent( role="Redator", goal="Escrever um post de blog", backstory="Você é um blogueiro profissional.", step_callback=callback.on_step, ) crew = Crew(agents=[agente], tasks=[Task( description="Escreva um post curto sobre IA.", expected_output="Um post de 200 palavras.", agent=agente, )]) crew.kickoff() callback.summary()
python
# Avançado: callback com rastreamento de métricas class CallbackMetricas: def __init__(self): self.steps = [] self.chamadas_ferramenta = 0 self.total_tokens = 0 def on_step(self, step): self.steps.append(step) if step.get("action") == "tool_call": self.chamadas_ferramenta += 1 def on_task_complete(self, task_output): if task_output.usage: self.total_tokens += task_output.usage.total_tokens def relatorio(self): print(f"Etapas: {len(self.steps)}") print(f"Chamadas de ferramenta: {self.chamadas_ferramenta}") print(f"Total de tokens: {self.total_tokens}")
⚠️Warning

Callbacks executam de forma síncrona durante o raciocínio do agente. Evite operações lentas (como chamadas de rede para APIs externas) dentro de callbacks, pois elas bloquearão o loop de execução do agente. Se precisar de logging assíncrono, armazene eventos em buffer e descarregue-os assincronamente.


Tipos de Memória do Agente

O CrewAI suporta vários backends de memória:

python
from crewai import Agent, Task, Crew, Process # Agente com memória de curto prazo (em processo) agente_memoria = Agent( role="Agente de Suporte", goal="Resolver problemas de clientes em múltiplas interações", backstory="Você é um agente de suporte paciente.", memory=True, ) # Configuração de memória no nível da crew from crewai.memory import ShortTermMemory, LongTermMemory crew = Crew( agents=[agente_memoria], tasks=[...], memory=True, )
Tipo de MemóriaEscopoPersistênciaCaso de Uso
Curto prazo (em processo)Única execuçãoPerdida após kickoff()Conversas multi-turno em uma execução
Longo prazo (SQLite / personalizado)Entre execuçõesPersiste em disco ou bancoPreferências do usuário, histórico entre sessões
Memória de entidadesExtrai e rastreia entidadesEntre tarefas em uma execuçãoGrafos de conhecimento, rastreamento de relacionamentos
📌Important

Memória de curto prazo é ativada com memory=True no agente. Memória de longo prazo e de entidades exigem memory_config no nível da crew. A memória de longo prazo é especialmente valiosa para aplicações onde os agentes precisam lembrar preferências do usuário entre interações separadas.


Fluxo de Memória na Crew

100%

Configurando LLM por Agente

Você pode passar uma instância LLM personalizada para cada agente:

python
from langchain_openai import ChatOpenAI from crewai import Agent # LLM personalizado com modelo e temperatura específicos llm_rapido = ChatOpenAI( model="gpt-4o-mini", temperature=0.1, ) llm_criativo = ChatOpenAI( model="gpt-4o", temperature=0.9, ) analista = Agent( role="Analista de Dados", goal="Produzir análise numérica precisa", backstory="Você é um analista de dados meticuloso.", llm=llm_rapido, temperature=0.1, ) redator = Agent( role="Redator Criativo", goal="Escrever textos de marketing envolventes", backstory="Você é um copywriter com estilo.", llm=llm_criativo, temperature=0.8, )
python
# Múltiplos agentes com diferentes LLMs para otimização de custos llm_barato = ChatOpenAI(model="gpt-4o-mini", temperature=0.0) llm_equilibrado = ChatOpenAI(model="gpt-4o", temperature=0.3) llm_caro = ChatOpenAI(model="gpt-4o", temperature=0.7) pesquisador = Agent( role="Pesquisador", goal="Encontrar informações", backstory="Você encontra fatos.", llm=llm_barato, ) analista = Agent( role="Analista", goal="Analisar resultados", backstory="Você analisa dados.", llm=llm_equilibrado, ) estrategista = Agent( role="Estrategista", goal="Desenvolver estratégia de negócios", backstory="Você cria estratégias.", llm=llm_caro, )
📌Important

Cada agente pode ter uma configuração de LLM completamente independente. Isso permite usar modelos baratos para tarefas simples (pesquisa, entrada de dados) e modelos caros para raciocínio complexo (análise, estratégia). Esta abordagem em camadas pode reduzir custos em 60-80% comparado a usar um modelo caro para todos os agentes.


Configurações de Temperatura — Quando Usar

TemperaturaCaso de UsoExemplo
0.0 – 0.2Tarefas factuais e determinísticasExtração de dados, classificação
0.3 – 0.5Raciocínio equilibradoSumarização, análise
0.6 – 0.8Geração criativaMarketing, narrativas
0.9 – 1.0Altamente criativo / brainstormingGeração de ideias, poesia
python
# Referência rápida: temperatura por tipo de agente guia_temperatura = { "Agente de Extração de Dados": 0.0, "Agente de Classificação": 0.1, "Agente de Sumarização": 0.3, "Agente de Análise": 0.4, "Redator de Conteúdo": 0.7, "Agente Criativo": 0.9, "Agente de Brainstorming": 1.0, }

LLMs para Chamada de Funções

Alguns agentes se beneficiam de um LLM separado para chamadas de ferramentas:

python
from langchain_openai import ChatOpenAI llm_raciocinio = ChatOpenAI(model="gpt-4o", temperature=0.2) llm_chamada_funcao = ChatOpenAI(model="gpt-4o-mini", temperature=0.0) agente = Agent( role="Especialista em Automação", goal="Executar chamadas de API com precisão", backstory="Você automatiza fluxos de trabalho de negócios.", llm=llm_raciocinio, function_calling_llm=llm_chamada_funcao, )

Usar um modelo menor e mais barato para chamadas de ferramentas reduz custos enquanto mantém a qualidade do raciocínio. O function_calling_llm lida com a entrada/saída estruturada das chamadas de ferramenta, enquanto o llm principal lida com o raciocínio complexo.

💡Tip

Use function_calling_llm quando seu agente usar muitas ferramentas. Chamadas de ferramenta exigem saída estruturada (JSON), que modelos menores manipulam bem. Reserve o modelo caro para raciocinar sobre quando e por que usar ferramentas, não a mecânica de usá-las.


Testando Fluxos de Crew

Teste a lógica da sua crew com testes unitários isolados:

python
import pytest from crewai import Agent, Task, Crew @pytest.fixture def agente_pesquisa(): return Agent( role="Pesquisador de Teste", goal="Retornar dados de teste", backstory="Você é um agente de teste.", ) def test_crew_kickoff_retorna_string(agente_pesquisa): tarefa = Task( description="Retorne a palavra 'olá'.", expected_output="A palavra olá.", agent=agente_pesquisa, ) crew = Crew( agents=[agente_pesquisa], tasks=[tarefa], ) resultado = crew.kickoff() assert resultado is not None assert isinstance(str(resultado), str) def test_agente_com_ferramentas(): from crewai.tools import BaseTool class FerramentaEcho(BaseTool): name: str = "Echo" description: str = "Retorna a entrada inalterada." def _run(self, texto: str) -> str: return texto agente = Agent( role="Agente Echo", goal="Ecoar entrada de volta", backstory="Você ecoa tudo que recebe.", tools=[FerramentaEcho()], ) assert len(agente.tools) == 1 assert agente.tools[0].name == "Echo"
python
# Teste avançado: mock LLM para testes determinísticos from unittest.mock import patch def test_crew_com_llm_mockado(): """Testa a lógica da crew sem fazer chamadas LLM reais.""" agente = Agent( role="Agente de Teste", goal="Retornar dados de teste", backstory="Agente de teste.", ) tarefa = Task( description="Retorne um objeto JSON com a chave 'status' definida como 'ok'.", expected_output='{"status": "ok"}', agent=agente, ) crew = Crew( agents=[agente], tasks=[tarefa], ) resultado = crew.kickoff() assert resultado is not None
⚠️Warning

Testar crews com chamadas LLM reais é lento, caro e não-determinístico. Use respostas LLM simuladas para testes unitários e reserve chamadas LLM reais para testes de integração. Sempre valide que a estrutura da saída corresponde às expectativas, não o conteúdo específico.


Estratégia de Testes

Tipo de TesteO que TestarLLM Necessário?Frequência
UnitárioConfig do agente, anexação de ferramentas, params de tarefaNãoA cada commit
IntegraçãoFluxo de execução da crew, passagem de contextoSimPor funcionalidade
RegressãoBugs corrigidos anteriormenteSimAntes do release
PerformanceUso de tokens, tempo de execuçãoSimPeriódico
E2EPipeline completo com ferramentas reaisSimPré-implantação

Callback vs Memória vs Config LLM — Comparação

RecursoPropósitoConfiguraçãoEscopo
Step callbacksMonitoramento e loggingstep_callback no agentePor agente
Memória curto prazoRetenção de contexto na execuçãomemory=True no agentePor execução
Memória longo prazoPersistência entre execuçõesmemory_config na crewEntre execuções
LLM personalizadoControle de modelo/temperaturaParâmetro llm no agentePor agente
LLM chamada funçãoModelo separado para ferramentasfunction_calling_llm no agentePor agente
TestesValidação de corretudepytest / unittestDesenvolvimento

Perguntas Interativas

Practice Question

Sua crew de produção executa lentamente. Você descobre que o step callback está fazendo uma requisição HTTP a um serviço de logging a cada etapa. Qual mudança você deve fazer?

Practice Question

Você tem uma crew de suporte ao cliente. O Usuário A interage na sessão 1, depois o Usuário B na sessão 2. O agente do Usuário B lembra da conversa do Usuário A. Por quê?

Practice Question

Você tem 3 agentes: um pesquisador (consulta simples), um analista (raciocínio moderado) e um estrategista (raciocínio complexo). Como configurar seus LLMs para minimizar custos?

Practice Question

Seu agente usa 8 ferramentas diferentes. Chamadas de ferramenta frequentemente falham devido a saída JSON malformada do LLM. Qual otimização ajuda?

Practice Question

Você executa test_crew_kickoff_retorna_string 5 vezes com chamadas LLM reais. Passa 3 vezes e falha 2 vezes com saídas diferentes. Qual é o problema?


5 Perguntas de Prática

1. Qual é a assinatura de uma função step callback?

  • A) callback(agent, task)
  • B) callback(step) onde step é um dicionário ✅
  • C) callback(output)
  • D) callback()

2. Qual tipo de memória persiste entre múltiplas chamadas crew.kickoff()?

  • A) Memória de curto prazo
  • B) Memória de longo prazo ✅
  • C) Memória de entidades
  • D) Memória em processo

3. Qual efeito temperature=0.1 tem no LLM de um agente?

  • A) Torna a saída mais criativa
  • B) Torna a saída mais determinística e factual ✅
  • C) Aumenta a velocidade de resposta
  • D) Desativa chamadas de ferramentas

4. Por que definir function_calling_llm separadamente de llm?

  • A) Para reduzir custos usando um modelo menor para chamadas de ferramentas ✅
  • B) Para ativar cache
  • C) Para aumentar a verbosidade
  • D) Para desativar delegação

5. Qual ferramenta você usaria para verificar se uma crew retorna uma string válida?

  • A) pytest com assert isinstance(str(resultado), str)
  • B) crew.validate()
  • C) task.inspect()
  • D) agent.test()

Success

Principais Conclusões

  • Step callbacks permitem monitoramento em tempo real do raciocínio do agente.
  • Classes de callback personalizadas podem agregar etapas para auditoria e depuração.
  • Memória de curto prazo é perdida após uma execução; memória de longo prazo persiste.
  • Cada agente pode ter seu próprio LLM com temperatura e modelo independentes.
  • Um function_calling_llm separado reduz custos para agentes que usam muitas ferramentas.
  • Temperatura de 0.0 (determinística) a 1.0 (criativa) controla a variabilidade da saída.
  • Testar crews com pytest garante corretude antes da implantação em produção.
  • Callbacks são síncronos — evite operações bloqueantes dentro deles.
  • Corresponda o tamanho do modelo LLM à complexidade da tarefa para otimização de custos.
  • Simule respostas LLM em testes unitários; use LLMs reais apenas em testes de integração.
Progresso100%