SKILL.md — Modelo de Ator Agha: Design de Sistemas de Agentes Concorrentes
Pontos de Decisão
Escolhendo a Estratégia de Criação de Atores Baseada no Tipo de Tarefa
SE a tarefa tem dependências sequenciais:
├─ Use o padrão de cliente: crie um filho com endereço de resposta
├─ Passe o endereço do cliente para o filho como parâmetro
└─ O filho envia o resultado diretamente ao cliente (não ao pai)
SE a tarefa requer computação longa:
├─ Crie um ator insensível para a computação
├─ Encaminhe as mensagens recebidas para um ator buffer
└─ Retome do buffer quando a computação for concluída
SE a tarefa precisa de alocação dinâmica de recursos:
├─ Crie atores gerenciadores de recursos sob demanda
├─ Passe capacidades (endereços) como dados da mensagem
└─ Sem registro central - endereços fluem pelo sistema
SE a tarefa tem requisitos de isolamento de falhas:
├─ Crie atores filhos supervisionados para operações arriscadas
├─ O supervisor detecta falhas através de respostas ausentes
└─ Substitua atores com falha sem afetar outros
SE estiver compondo sistemas de agentes existentes:
├─ Verifique se a interface preserva a estrutura causal
├─ Teste o comportamento sob composição (não apenas isolamento)
└─ Use protocolos de mensagem como limites (não estado compartilhado)
Árvore de Decisão: Envio de Mensagem vs. Substituição de Estado
SE houver necessidade de coordenação com outros agentes:
├─ ENVIE mensagens (não modifique o estado local primeiro)
├─ Inclua endereço de resposta se uma resposta for esperada
└─ Nunca presuma ordenação de mensagens
SE houver necessidade de computação local:
├─ ESPECIFIQUE comportamento de substituição
├─ Encapsule o novo estado (não exponha detalhes internos)
└─ Garanta processamento de uma mensagem por vez
SE houver necessidade de escalabilidade dinâmica:
├─ CRIE novos atores com comportamentos específicos
├─ Passe endereços necessários para novos atores
└─ Sem estado de inicialização compartilhado
Modos de Falha
1. Anti-Padrão do Orquestrador Central
Detecção: Se você vê um único ator roteando todas as mensagens ou mantendo todo o estado do sistema Sintomas: Ponto único de falha, gargalo sob carga, problema de regressão infinita Correção: Decomponha em uma comunidade de atores, cada um conhecendo apenas o contexto local, use roteamento por capacidade
2. Falácia de Bloqueio Síncrono
Detecção: Se os atores esperam/bloqueiam por respostas em vez de especificar comportamento de substituição Sintomas: Deadlock sob carga, suposições ocultas de tempo, concorrência reduzida Correção: Modele como pares de mensagens requisição-resposta, use o padrão de cliente para dependências, aplique o padrão de ator insensível
3. Contaminação de Estado Compartilhado
Detecção: Se múltiplos atores leem/escrevem a mesma estrutura de dados (mesmo com locks) Sintomas: Condições de corrida, gargalos sequenciais, estado global oculto Correção: Encapsule o estado em um único ator, use passagem de mensagens para coordenação, exclusão mútua é gratuita
4. Verificação Apenas de Saída
Detecção: Se o teste compara apenas saídas finais sem verificar padrões de interação Sintomas: Anomalia de Brock-Ackerman - saídas idênticas mas comportamento de composição diferente Correção: Verifique a preservação da estrutura causal, teste o comportamento sob composição, use equivalência de observação
5. Suposição de Topologia Estática
Detecção: Se o grafo de comunicação é fixo na inicialização sem reconfiguração em tempo de execução Sintomas: Incapacidade de lidar com sistemas abertos, sem gerenciamento dinâmico de recursos, frágil sob mudanças Correção: Trate endereços como dados de primeira classe, implemente roteamento por capacidade, suporte mudanças de topologia em tempo de execução
Exemplos Práticos
Exemplo 1: Decomposição de Tarefas com Padrão de Cliente
Cenário: Um agente precisa processar uma requisição complexa que requer subtarefas sequenciais A → B → C, mas deve permanecer responsivo a outras mensagens.
Abordagem Novata:
receber requisição →
bloquear enquanto chama subtarefa A
bloquear enquanto chama subtarefa B
bloquear enquanto chama subtarefa C
enviar resultado final
Aplicação Especialista do Modelo de Ator:
receber requisição →
criar ator cliente_BC com endereços para B, C, destinatário final
enviar requisição da subtarefa A para processador_A com cliente_BC como endereço de resposta
especificar comportamento de substituição: pronto para próxima requisição
cliente_BC recebe resultado de A →
enviar resultado para processador_B com cliente_C como endereço de resposta
cliente_C recebe resultado de B →
enviar resultado para processador_C com destinatário_final como endereço de resposta
Decisões-chave Tomadas:
- Usou o padrão de cliente para evitar bloqueio
- Cada passo cria o próximo cliente na cadeia
- O agente original permanece responsivo durante todo o processo
- Falha em qualquer subtarefa afeta apenas aquela cadeia
Exemplo 2: Recuperação de Falhas com Supervisão
Cenário: O sistema precisa lidar com falhas de agentes sem cascatear para todo o sistema.
Abordagem Novata: Try-catch em torno de chamadas de agente, reiniciar tudo em caso de falha.
Aplicação Especialista:
supervisor cria ator_trabalhador →
envia tarefa para trabalhador com timeout de resposta
especifica substituição: "aguardando_resposta"
SE resposta recebida dentro do timeout →
encaminhar resultado para cliente
especificar substituição: "pronto"
SE timeout expirar →
criar novo ator_trabalhador (o antigo falhou)
reenviar tarefa para novo trabalhador
especificar substituição: "aguardando_resposta"
Compensações Navegadas:
- Supervisão é uma preocupação separada da lógica de negócio
- Atores com falha são isolados e substituídos, não reparados
- Equilíbrio entre detecção de timeout e entrega garantida
- Sem estado compartilhado entre supervisor e trabalhadores
Gates de Qualidade
- Nenhum ator bloqueia seu loop de processamento de mensagens (padrão de ator insensível aplicado onde necessário)
- Toda coordenação usa passagem de mensagens (sem estado mutável compartilhado entre atores)
- A entrega de mensagens é garantida, mas a ordenação não é presumida
- Endereços são tratados como dados de primeira classe para roteamento por capacidade
- Cada ator especifica comportamento de substituição para cada tipo de mensagem
- A criação de atores acontece dinamicamente com base nas necessidades de computação
- O isolamento de falhas previne falhas em cascata através dos limites dos atores
- A topologia do sistema pode ser reconfigurada em tempo de execução sem registro central
- O comportamento de composição é verificado, não apenas o comportamento isolado dos componentes
- Operações síncronas são modeladas como pares de mensagens requisição-resposta
Limites "NÃO USAR"
Esta skill NÃO deve ser usada para:
- Computações sequenciais simples → use programação funcional
- Sistemas onde memória compartilhada é fisicamente necessária → use padrões de concorrência baseados em lock
- Sistemas em tempo real com restrições de tempo rígidas → use passagem síncrona de mensagens com análise formal de tempo
- Computações matemáticas sem coordenação → use abordagens funcionais puras
Delegue para outras skills quando:
- Implementar frameworks de atores específicos → use guias de implementação específicos da plataforma
- Ajuste de desempenho de sistemas de atores → use a skill [otimização-de-desempenho]
- Verificação formal de propriedades de atores → use a skill [métodos-formais]
- Design de banco de dados para persistência de atores → use a skill [arquitetura-de-dados]
Equívocos comuns sobre o escopo:
- Atores não são apenas "objetos com métodos assíncronos" - eles exigem a tripla completa de resposta
- O modelo de ator não é apenas para sistemas distribuídos - aplica-se a qualquer computação concorrente
- Não é primariamente uma otimização de desempenho - é um framework de correção e composicionalidade