\n\n\n\n Modelli de Middleware do Agente: Uma Exploração Aprofundada com Exemplos Práticos - AgntKit \n

Modelli de Middleware do Agente: Uma Exploração Aprofundada com Exemplos Práticos

📖 18 min read3,477 wordsUpdated Apr 5, 2026

“`html

Introdução ao Agente Middleware

O surgimento de agentes de IA sofisticados marcou o início de uma nova era no desenvolvimento de software. Essas entidades autônomas, capazes de raciocínio complexo, decisão e interação, estão se tornando centrais em muitas aplicações. No entanto, orquestrar seu comportamento, gerenciar seu estado e garantir seu bom funcionamento frequentemente requer mais do que uma simples invocação direta. É aqui que entram em jogo os modelos de agente middleware. Semelhante aos middlewares web tradicionais, o agente middleware intercepta e gerencia as solicitações e respostas, mas no contexto único do ciclo de vida de um agente, desde sua percepção até suas ações e comunicações.

O agente middleware funciona como uma camada crucial entre a lógica central do agente e seu ambiente, ou entre diferentes componentes de um sistema multi-agentes. Fornece uma maneira estruturada de injetar preocupações transversais, melhorar as capacidades, gerenciar o estado e fazer cumprir as políticas sem sobrecarregar o código principal para a decisão do agente. Nesta exploração aprofundada, examinaremos os modelos de agente middleware comuns, compreendendo suas aplicações práticas e ilustrando-os com exemplos concretos, focando principalmente em frameworks ou implementações conceituais baseadas em Python.

A Necessidade do Agente Middleware

Antes de explorar os modelos, compreendamos por que o agente middleware é indispensável:

  • Separação de Preocupações: Os agentes frequentemente têm uma inteligência central (por exemplo, planejamento, raciocínio) e preocupações periféricas (por exemplo, logging, monitoramento, autenticação, transformação de dados). O middleware permite gerenciar essas preocupações externamente.
  • Modularidade e Reutilização: Funcionalidades comuns podem ser encapsuladas em componentes middleware reutilizáveis.
  • Extensibilidade: Novas funcionalidades ou comportamentos podem ser adicionados aos agentes sem modificar sua lógica central.
  • Solidez e Resiliência: O middleware pode gerenciar erros, tentativas de reexecução e circuit breaking para interações externas.
  • Observabilidade: O logging centralizado, a coleta de métricas e o rastreamento se tornam muito mais simples.
  • Segurança e Aplicação de Políticas: A autorização, o rate limiting e a validação de inputs podem ser aplicados de forma consistente.

Modelos Comuns de Agente Middleware

Classificaremos os modelos de agente middleware com base em sua função principal e em sua interação com o ciclo de vida do agente.

1. O Modelo do Interceptor

O modelo do Interceptor é talvez o mais fundamental e amplamente utilizado. Permite interceptar as chamadas aos métodos de um agente ou suas interações com serviços externos, realizando um pré-processamento antes da chamada e um pós-processamento após. Isso é análogo à Programação Orientada a Aspectos (POA) ou ao middleware tradicional de solicitação/resposta.

Exemplo Prático: Interceptor de Logging e Métricas

Imagine um agente que realiza ações com base em indicações do usuário. Queremos registrar cada ação realizada e medir seu tempo de execução.

“`


import time
import logging

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

class AgentAction:
 def __init__(self, name, payload):
 self.name = name
 self.payload = payload

 def __repr__(self):
 return f"Action(name='{self.name}', payload={self.payload})"

class AgentResponse:
 def __init__(self, success, result=None, error=None):
 self.success = success
 self.result = result
 self.error = error

 def __repr__(self):
 return f"Response(success={self.success}, result={self.result}, error={self.error})"

class AgentCore:
 def execute_action(self, action: AgentAction) -> AgentResponse:
 logging.info(f"AgentCore: Executando ação '{action.name}' com payload {action.payload}")
 if action.name == "search_web":
 # Simular pesquisa na web
 time.sleep(0.5)
 return AgentResponse(success=True, result=f"Resultados encontrados para '{action.payload}'")
 elif action.name == "send_email":
 # Simular envio de email
 time.sleep(0.2)
 if "@" in str(action.payload): # Validação simples
 return AgentResponse(success=True, result=f"Email enviado para '{action.payload}'")
 else:
 return AgentResponse(success=False, error="Formato de email inválido")
 else:
 return AgentResponse(success=False, error=f"Ação desconhecida: {action.name}")


class LoggingMetricsInterceptor:
 def __init__(self, next_handler):
 self.next_handler = next_handler

 def execute_action(self, action: AgentAction) -> AgentResponse:
 start_time = time.perf_counter()
 logging.info(f"Interceptor: Pré-processando a ação '{action.name}'")
 
 try:
 response = self.next_handler.execute_action(action)
 except Exception as e:
 logging.error(f"Interceptor: Erro durante a ação '{action.name}': {e}")
 response = AgentResponse(success=False, error=str(e))

 end_time = time.perf_counter()
 duration = (end_time - start_time) * 1000 # milissegundos
 logging.info(f"Interceptor: Pós-processando a ação '{action.name}'. Duração: {duration:.2f}ms. Sucesso: {response.success}")
 # Em um sistema real, você enviaria métricas para Prometheus/Grafana etc.
 return response


# Conectando o agente com o middleware
agent = LoggingMetricsInterceptor(AgentCore())

# Casos de teste
print("\n--- Teste 1: Pesquisa na Web Bem-Sucedida ---")
response1 = agent.execute_action(AgentAction("search_web", "últimas notícias IA"))
print(f"Resposta Final: {response1}")

print("\n--- Teste 2: Envio de Email Bem-Sucedido ---")
response2 = agent.execute_action(AgentAction("send_email", "[email protected]"))
print(f"Resposta Final: {response2}")

print("\n--- Teste 3: Falha no Envio de Email (Erro de Validação) ---")
response3 = agent.execute_action(AgentAction("send_email", "email-inválido"))
print(f"Resposta Final: {response3}")

print("\n--- Teste 4: Ação Desconhecida ---")
response4 = agent.execute_action(AgentAction("unknown_task", "dados"))
print(f"Resposta Final: {response4}")

Neste exemplo, LoggingMetricsInterceptor encapsula AgentCore. Qualquer chamada a execute_action passa primeiro pelo interceptor, que registra, mede o tempo e depois passa o controle para o próximo manipulador (AgentCore), e finalmente processa a resposta.

2. O Modelo da Cadeia de Responsabilidade

O modelo da Cadeia de Responsabilidade permite que vários manipuladores (componentes middleware) processem uma solicitação de forma sequencial. Cada manipulador decide se deve processar a solicitação, passá-la para o próximo manipulador na cadeia ou interromper o processamento. Isso é ideal para cenários em que várias condições ou transformações podem ser aplicadas à entrada ou saída de um agente.

Exemplo Prático: Cadeia de Validação e Transformação de Entradas

Consideremos um agente que recebe comandos em linguagem natural. Antes que o agente principal processe o comando, poderíamos querer validar a entrada, limpá-la ou traduzi-la para um formato estruturado.


class Command:
 def __init__(self, original_text: str, processed_data: dict = None):
 self.original_text = original_text
 self.processed_data = processed_data if processed_data is not None else {}
 self.is_valid = True
 self.error_message = None

 def __repr__(self):
 return f"Command(original='{self.original_text}', processed={self.processed_data}, valid={self.is_valid}, error='{self.error_message}')"

class AgentRequestHandler:
 def handle_command(self, command: Command) -> Command:
 raise NotImplementedError

class InputSanitizer(AgentRequestHandler):
 def __init__(self, next_handler: AgentRequestHandler = None):
 self.next_handler = next_handler

 def handle_command(self, command: Command) -> Command:
 if not command.is_valid:
 return command # Se não for válido, para aqui

 # Sanitização simples: remover espaços antes/depois, converter para minúsculas
 command.processed_data['sanitized_text'] = command.original_text.strip().lower()
 logging.info(f"Sanitizer: Sanitizado '{command.original_text}' em '{command.processed_data['sanitized_text']}'")

 if self.next_handler:
 return self.next_handler.handle_command(command)
 return command

class CommandValidator(AgentRequestHandler):
 def __init__(self, next_handler: AgentRequestHandler = None):
 self.next_handler = next_handler

 def handle_command(self, command: Command) -> Command:
 if not command.is_valid:
 return command
 
 sanitized_text = command.processed_data.get('sanitized_text', command.original_text)
 if len(sanitized_text) < 5:
 command.is_valid = False
 command.error_message = "O comando é muito curto."
 logging.warning(f"Validator: Comando não válido '{sanitized_text}' - muito curto.")
 return command # Para o tratamento se não for válido
 
 logging.info(f"Validator: Comando '{sanitized_text}' passou no teste de comprimento.")

 if self.next_handler:
 return self.next_handler.handle_command(command)
 return command

class IntentRecognizer(AgentRequestHandler):
 def __init__(self, next_handler: AgentRequestHandler = None):
 self.next_handler = next_handler

 def handle_command(self, command: Command) -> Command:
 if not command.is_valid:
 return command
 
 sanitized_text = command.processed_data.get('sanitized_text', command.original_text)
 if "schedule" in sanitized_text or "book" in sanitized_text:
 command.processed_data['intent'] = 'schedule_event'
 command.processed_data['params'] = {'topic': 'meeting'}
 elif "weather" in sanitized_text:
 command.processed_data['intent'] = 'get_weather'
 command.processed_data['params'] = {'location': 'current'}
 else:
 command.processed_data['intent'] = 'unknown'

 logging.info(f"IntentRecognizer: Intenção detectada '{command.processed_data['intent']}' para '{sanitized_text}'")

 if self.next_handler:
 return self.next_handler.handle_command(command)
 return command

class AgentCoreProcessor(AgentRequestHandler):
 def handle_command(self, command: Command) -> Command:
 if not command.is_valid:
 logging.error(f"Core: Impossível processar o comando não válido: {command.error_message}")
 return command
 
 logging.info(f"Core: Processando o comando com a intenção '{command.processed_data.get('intent')}' e os parâmetros {command.processed_data.get('params')}")
 command.processed_data['core_result'] = f"Executado {command.processed_data.get('intent')} com {command.processed_data.get('params')}"
 return command


# Construção da cadeia
core_processor = AgentCoreProcessor()
intent_recognizer = IntentRecognizer(core_processor)
validator = CommandValidator(intent_recognizer)
sanitizer = InputSanitizer(validator)

# Ponto de entrada para os comandos
agent_entry_point = sanitizer

# Comandos de teste
print("\n--- Teste 1 : Comando de agendamento válido ---")
cmd1 = Command(" Por favor, agende uma reunião para mim ")
processed_cmd1 = agent_entry_point.handle_command(cmd1)
print(f"Comando processado final: {processed_cmd1}")

print("\n--- Teste 2 : Comando do tempo válido ---")
cmd2 = Command("Como está o tempo?")
processed_cmd2 = agent_entry_point.handle_command(cmd2)
print(f"Comando processado final: {processed_cmd2}")

print("\n--- Teste 3 : Comando inválido curto ---")
cmd3 = Command("oi")
processed_cmd3 = agent_entry_point.handle_command(cmd3)
print(f"Comando processado final: {processed_cmd3}")

print("\n--- Teste 4 : Comando desconhecido ---")
cmd4 = Command("conte-me uma piada")
processed_cmd4 = agent_entry_point.handle_command(cmd4)
print(f"Comando processado final: {processed_cmd4}")

Aqui, um Command objeto atravessa uma cadeia: InputSanitizer -> CommandValidator -> IntentRecognizer -> AgentCoreProcessor. Cada componente modifica o objeto Command ou define seu sinalizador is_valid. Se um componente invalidar o comando, os componentes subsequentes podem interromper o tratamento sem problemas.

3. O modelo Adapter para ferramentas/API externas

Embora não seja estritamente um middleware no sentido de interceptar requisições e respostas, o modelo Adapter é crucial para permitir que os agentes interajam com várias ferramentas e APIs externas de maneira padronizada. Um adaptador encapsula um serviço de terceiros, fornecendo uma interface coerente para que o agente a utilize, abstraindo as especificações da API externa.

Exemplo prático: Acesso unificado às ferramentas

Um agente pode precisar chamar uma API de clima, uma API de calendário e um mecanismo de busca. Cada uma delas tem uma interface diferente. Os adaptadores normalizam essas interações.


import requests
import json

class ToolAdapter:
 def execute(self, tool_name: str, params: dict) -> dict:
 raise NotImplementedError

class WeatherAPIAdapter(ToolAdapter):
 BASE_URL = "https://api.weatherapi.com/v1"
 API_KEY = "YOUR_WEATHER_API_KEY" # Substituir pela chave real

 def execute(self, tool_name: str, params: dict) -> dict:
 if tool_name == "get_current_weather":
 location = params.get("location", "London")
 try:
 response = requests.get(f"{self.BASE_URL}/current.json?key={self.API_KEY}&q={location}")
 response.raise_for_status() # Levanta um HTTPError para respostas erradas (4xx ou 5xx)
 data = response.json()
 return {
 "temperature_c": data['current']['temp_c'],
 "condition": data['current']['condition']['text'],
 "location": data['location']['name']
 }
 except requests.exceptions.RequestException as e:
 logging.error(f"Erro API clima: {e}")
 return {"error": str(e)}
 return {"error": f"Ferramenta clima desconhecida: {tool_name}"}

class CalendarAPIAdapter(ToolAdapter):
 def execute(self, tool_name: str, params: dict) -> dict:
 if tool_name == "create_event":
 title = params.get("title")
 start_time = params.get("start_time")
 end_time = params.get("end_time")
 logging.info(f"Calendário: Criação do evento '{title}' de {start_time} a {end_time}")
 # Simular uma chamada API
 time.sleep(0.1)
 return {"status": "success", "event_id": "cal_123", "title": title}
 elif tool_name == "list_events":
 date = params.get("date")
 logging.info(f"Calendário: Lista de eventos para {date}")
 # Simular uma chamada API
 time.sleep(0.1)
 return {"status": "success", "events": [{"title": "Sincronização de equipe", "time": "10:00"}]}
 return {"error": f"Ferramenta calendário desconhecida: {tool_name}"}

class AgentToolbox:
 def __init__(self):
 self._adapters = {}

 def register_adapter(self, adapter_name: str, adapter: ToolAdapter):
 self._adapters[adapter_name] = adapter
 logging.info(f"Toolbox: Adaptador '{adapter_name}' registrado")

 def use_tool(self, adapter_name: str, tool_name: str, params: dict) -> dict:
 adapter = self._adapters.get(adapter_name)
 if not adapter:
 return {"error": f"Nenhum adaptador registrado para '{adapter_name}'"}
 logging.info(f"Toolbox: Uso da ferramenta '{tool_name}' através do adaptador '{adapter_name}' com os parâmetros {params}")
 return adapter.execute(tool_name, params)


# Inicializando a caixa de ferramentas do agente
agent_toolbox = AgentToolbox()
agent_toolbox.register_adapter("weather", WeatherAPIAdapter())
agent_toolbox.register_adapter("calendar", CalendarAPIAdapter())

# Agente que utiliza sua caixa de ferramentas
print("\n--- Agente que utiliza a ferramenta Clima ---")
weather_info = agent_toolbox.use_tool("weather", "get_current_weather", {"location": "New York"})
print(f"Informações Clima: {weather_info}")

print("\n--- Agente que utiliza a ferramenta Calendário (Criar Evento) ---")
calendar_event = agent_toolbox.use_tool("calendar", "create_event", {"title": "Revisão do projeto", "start_time": "2023-10-27 14:00", "end_time": "2023-10-27 15:00"})
print(f"Evento Calendário: {calendar_event}")

print("\n--- Agente que utiliza a ferramenta Calendário (Listar Eventos) ---")
list_events = agent_toolbox.use_tool("calendar", "list_events", {"date": "2023-10-27"})
print(f"Eventos listados: {list_events}")

print("\n--- Agente que tenta usar uma ferramenta não registrada ---")
unknown_tool = agent_toolbox.use_tool("search_engine", "google_search", {"query": "tendências IA"})
print(f"Resultado Ferramenta Desconhecida: {unknown_tool}")

Aqui, AgentToolbox funciona como um registro central para as instâncias de ToolAdapter. O agente não precisa conhecer as especificações de como chamar WeatherAPIAdapter ou CalendarAPIAdapter; basta solicitar uma ferramenta pelo nome e fornecer parâmetros. Cada adaptador então traduz esse pedido genérico em chamadas API específicas necessárias.

4. O modelo Registro/Localizador de serviço

O modelo Registro ou Localizador de serviço é comumente usado para fornecer aos agentes acesso a vários serviços, capacidades ou outros agentes em um sistema multi-agente. Em vez de codificar as dependências de forma rígida, os agentes consultam um registro central para descobrir e obter referências aos componentes necessários em tempo real. Isso melhora a flexibilidade e o desacoplamento.

Exemplo prático: Descoberta dinâmica das capacidades do agente

Imagine um agente que precisa de uma capacidade específica, como a síntese de texto ou a geração de imagens. Ele não deveria precisar saber qual serviço específico fornece isso, apenas que a capacidade existe.


class Capability:
 def execute(self, data: str) -> str:
 raise NotImplementedError

class TextSummarizer(Capability):
 def execute(self, text: str) -> str:
 logging.info(f"Resumo do texto: '{text[:30]}...' ")
 # Simula a chamada LLM ou a lógica de resumo
 time.sleep(0.3)
 return f"Resumo de '{text[:20]}...': É uma versão concisa."

class ImageGenerator(Capability):
 def execute(self, prompt: str) -> str:
 logging.info(f"Geração de imagem para o prompt: '{prompt}'")
 # Simula a chamada API para a geração de imagens
 time.sleep(0.7)
 return f"URL da imagem para '{prompt}': https://image.gen/id-123"

class CapabilityRegistry:
 def __init__(self):
 self._capabilities = {}

 def register_capability(self, name: str, capability: Capability):
 if name in self._capabilities:
 logging.warning(f"A capacidade '{name}' já está registrada. Substituindo.")
 self._capabilities[name] = capability
 logging.info(f"Registro : Capacidade '{name}' registrada.")

 def get_capability(self, name: str) -> Capability:
 capability = self._capabilities.get(name)
 if not capability:
 logging.error(f"Registro : Capacidade '{name}' não encontrada.")
 raise ValueError(f"Capacidade '{name}' não encontrada.")
 return capability


class Agent:
 def __init__(self, registry: CapabilityRegistry):
 self.registry = registry

 def process_request(self, request_type: str, data: str) -> str:
 try:
 capability = self.registry.get_capability(request_type)
 result = capability.execute(data)
 return f"O Agente processou '{request_type}': {result}"
 except ValueError as e:
 return f"O Agente não conseguiu processar '{request_type}': {e}"
 except Exception as e:
 return f"O Agente encontrou um erro inesperado para '{request_type}': {e}"


# Configuração do registro
registry = CapabilityRegistry()
registry.register_capability("summarize", TextSummarizer())
registry.register_capability("generate_image", ImageGenerator())

# Criar um agente com acesso ao registro
agent_app = Agent(registry)

# O agente utiliza capacidades
print("\n--- Agente que solicita um resumo ---")
summary_result = agent_app.process_request("summarize", "A rápida coruja marrom salta sobre o cachorro preguiçoso. É um pangrama clássico usado para mostrar todas as letras do alfabeto.")
print(summary_result)

print("\n--- Agente que solicita a geração da imagem ---")
image_result = agent_app.process_request("generate_image", "uma cidade futurista ao pôr do sol")
print(image_result)

print("\n--- Agente que solicita uma capacidade desconhecida ---")
unknown_result = agent_app.process_request("translate", "hello world")
print(unknown_result)

O CapabilityRegistry funciona como um localizador de serviço. O Agente não instancia diretamente TextSummarizer ou ImageGenerator; ele solicita ao registro uma capacidade pelo seu nome lógico. Isso permite substituir, atualizar ou adicionar capacidades sem modificar a lógica fundamental do agente.

Combinação de modelos Middleware

Em sistemas de agentes reais, esses modelos são frequentemente combinados. Por exemplo, um comando de usuário que chega pode primeiro passar por uma Cadeia de Responsabilidade para validação e reconhecimento da intenção. A intenção identificada pode então acionar uma ação que utiliza o Registro/Localizador de Serviço para encontrar um Adaptador apropriado para uma ferramenta externa. A execução dessa ferramenta pode então ser envolvida por um Interceptor para registro e gerenciamento de erros.

Exemplo: Um Fluxo de Interação Agente Multinível

Esboçamos brevemente como poderia aparecer:

“`html


# 1. Solicitação recebendo (por exemplo, de uma interface de chat do usuário)
user_input = "Por favor, agende uma reunião sobre os resultados do T4 para amanhã às 15h."

# 2. Cadeia de Responsabilidade para o pré-processamento
# InputSanitizer -> CommandValidator -> IntentRecognizer
command_object = Command(user_input)
processed_command = agent_entry_point.handle_command(command_object) # Utiliza a cadeia do exemplo anterior

if processed_command.is_valid and processed_command.processed_data.get('intent') == 'schedule_event':
 # 3. A lógica fundamental do agente decide usar uma ferramenta
 intent_params = processed_command.processed_data.get('params', {})
 
 # 4. Usar o Registro/Localizador de Serviço para obter o adaptador apropriado
 # O agente sabe que precisa de um adaptador 'calendar' para 'schedule_event'
 
 # 5. A execução da ferramenta é envolta por um Interceptor
 # (Imagine agent_toolbox.use_tool sendo envolto por um Interceptor genérico ToolCallInterceptor)
 # Para simplificar, chamaremos diretamente a caixa de ferramentas aqui, mas imagine que seja um proxy.

 # Simular a análise do tempo a partir da entrada original
 event_title = intent_params.get('topic', 'Reunião Genérica')
 start_time_str = "2023-10-28 15:00" # Analisado de user_input por um IntentRecognizer mais sofisticado
 end_time_str = "2023-10-28 16:00"

 print("\n--- Agente coordenando o uso de uma ferramenta ---")
 tool_call_result = agent_toolbox.use_tool(
 "calendar", 
 "create_event", 
 {"title": event_title, "start_time": start_time_str, "end_time": end_time_str}
 )
 print(f"Resultado da chamada da ferramenta: {tool_call_result}")
else:
 print(f"O Agente não conseguiu processar a solicitação: {processed_command.error_message or 'Intento não válido'}")

Esse fluxo demonstra como diferentes modelos middleware podem ser compostos para criar uma arquitetura de agente sólida e manutenível.

Conclusão

Os modelos middleware para agentes são essenciais para construir sistemas de agentes de IA escaláveis, robustos e manuteníveis. Aplicando modelos como o Interceptor, a Cadeia de Responsabilidade, o Adaptador e o Registro/Localizador de Serviço, os desenvolvedores podem gerenciar efetivamente as preocupações transversais, integrar funcionalidades diversas e abstrair as complexidades. Esses modelos promovem a modularidade, a reutilização e a extensibilidade, permitindo que os agentes evoluam e interajam com seu ambiente de maneira mais inteligente e confiável. À medida que os agentes de IA se tornam mais sofisticados e integrados em nossa vida cotidiana, uma compreensão aprofundada e uma aplicação prática desses modelos middleware serão essenciais para o sucesso.

“`

🕒 Published:

✍️
Written by Jake Chen

AI technology writer and researcher.

Learn more →
Browse Topics: comparisons | libraries | open-source | reviews | toolkits
Scroll to Top