Objetivo da Aula
Identificar o problema de duplicidade que surge quando cada agente carrega sua própria cópia de uma skill
Projetar um catálogo (registry) de skills como camada de indireção entre agentes e capacidades
Desenhar injeção de skills por escopo — cada agente recebe só o subconjunto relevante ao seu papel
Versionar skills de forma centralizada sem exigir redeploy de cada agente que as consome
Aplicar o motor de resolução condicional (visto na Parte 1) à seleção dinâmica de skills
Por que isso importa
Um sistema com um agente só não tem esse problema: a skill de “validar metadados” vive dentro do agente, ponto final. O problema aparece no segundo agente. Se o agente de revisão de conteúdo e o agente de publicação automática precisam validar o mesmo formato de metadados, você tem duas opções: copiar a lógica de validação para dentro de cada agente, ou fazer os dois agentes apontarem para a mesma skill, mantida em um único lugar.
A primeira opção parece mais simples no dia 1. No dia 90, quando o formato de metadados ganha um campo novo, você precisa lembrar de atualizar os dois agentes — e, na prática, sempre existe um terceiro agente que ninguém lembrou de atualizar, que continua validando contra a regra antiga. Isso não é hipotético: é o mesmo problema de duplicação de lógica de negócio que qualquer engenheiro de sistemas já viu em microsserviços sem biblioteca compartilhada, só que aqui o custo de divergência é pior, porque o comportamento errado de um agente autônomo é mais difícil de notar do que um bug num endpoint REST.
Impacto direto no seu trabalho: a decisão de arquitetura aqui não é “skills são úteis” — isso já ficou estabelecido no capítulo anterior. É “onde a skill mora e como cada agente a enxerga”. Um catálogo central com injeção desacoplada é o que permite escalar de dois agentes para vinte sem multiplicar pontos de manutenção.
Conceitos Fundamentais
O problema N×M
Sem uma camada de indireção, o número de acoplamentos entre agentes e skills cresce como o produto dos dois conjuntos — cada agente que precisa de cada skill representa uma cópia ou uma referência hardcoded específica.
Sem registry (acoplamento direto): cada agente copia o código da skill diretamente — Agente Revisão copia código de validar_metadados(), Agente Publicação copia código de validar_metadados(), Agente Importação copia código de validar_metadados(). Resultado: 3 agentes × 1 skill = 3 cópias divergentes ao longo do tempo.
Com registry (indireção): Agente Revisão, Agente Publicação e Agente Importação apontam para o Registry, que resolve para uma única fonte — validar_metadados(). Resultado: 3 agentes × 1 skill = 1 fonte, 3 referências.
Com N agentes e M skills, o custo de manutenção sem registry cresce em N×M pontos de atualização potencialmente divergentes. Com registry, cresce em N+M: cada agente declara quais skills consome, cada skill existe uma única vez.
Skill Registry como camada de indireção
O registry é o componente do harness que mantém o catálogo de skills disponíveis, seus metadados de descoberta (do capítulo anterior) e a lógica de resolução — qual skill, em qual versão, é entregue para qual agente.
estrutura Registry:
skills: mapa<nome, lista_de_versoes>
função registrar(skill):
skills[skill.nome].adicionar(skill)
função resolver(nome, versao_requisitada="mais_recente_estavel"):
candidatos = skills[nome]
retornar selecionar_versao(candidatos, versao_requisitada)
função skills_para_escopo(escopo_do_agente):
retornar [ s para s em skills.todas()
se s.tags interseciona escopo_do_agente ]Um agente nunca importa o código de uma skill diretamente. Ele declara sua necessidade (“preciso de capacidades de validação de conteúdo”) e o harness resolve, em tempo de montagem do contexto, qual skill concreta atende essa necessidade — a mesma separação entre interface e implementação que existe em qualquer sistema com injeção de dependência.
Injeção por escopo
Carregar todas as skills do catálogo em todo agente resolve a duplicidade, mas cria um problema novo: contexto poluído com capacidades irrelevantes, custando tokens e aumentando a chance de o modelo escolher a skill errada. A injeção desacoplada precisa ser também seletiva — cada agente recebe só o subconjunto de skills relevante ao seu papel.
| Agente | Escopo | Skills recebidas |
|---|---|---|
| Revisor de Conteúdo | validação, formatação | validar_metadados, normalizar_markdown, checar_links |
| Publicador | publicação, notificação | publicar_no_cms, notificar_time, gerar_changelog |
| Importador de Legado | validação, transformação | validar_metadados, converter_formato_antigo |
validar_metadados é a MESMA skill (mesmo código, mesma versão) injetada em dois agentes com escopos diferentes.
Fundamento: Composição em vez de Herança
Sistemas orientados a objeto aprenderam, depois de décadas de hierarquias de herança frágeis, que compor comportamento a partir de peças pequenas e independentes é mais robusto do que herdar de uma superclasse cada vez mais inchada. O mesmo princípio se aplica a agentes: em vez de um “agente base” do qual todo agente especializado herda (e que acumula capacidades que nem todo filho usa), cada agente compõe seu próprio conjunto de skills a partir de um catálogo comum. Um agente não é “um tipo de agente com skills fixas embutidas” — é a combinação de um system prompt, um escopo, e o conjunto de skills que esse escopo resolve no catálogo. Trocar uma skill por uma versão nova não exige tocar na definição do agente, exatamente como trocar uma dependência injetada não exige recompilar quem a consome.
Versionamento e contrato semântico
Skill compartilhada por múltiplos agentes precisa de versionamento explícito — porque uma mudança de contrato (novo campo obrigatório, formato de saída alterado) pode quebrar um agente consumidor que não foi atualizado ao mesmo tempo.
validar_metadados@1.0.0 → contrato: retorna {status, erros}
validar_metadados@2.0.0 → contrato: retorna {status, erros, avisos}
(avisos é campo NOVO, não quebra 1.x)
validar_metadados@3.0.0 → contrato: renomeia "erros" para "falhas"
(BREAKING — agentes presos em 2.x
quebram se migrados sem ajuste)
Agente Revisão → declara: validar_metadados@^2.0.0
Agente Publicação → declara: validar_metadados@^1.0.0 (ainda não migrou)
Registry serve versões diferentes da MESMA skill
para agentes diferentes, sem forçar migração simultânea.Esse é o ganho concreto de ter a skill como artefato versionado e não como código copiado: você pode evoluir o contrato sem quebrar todo consumidor no mesmo instante, e cada agente migra no seu próprio ritmo — desde que declare explicitamente a versão que espera.
Motor de resolução aplicado a skills: exemplo completo
A resolução condicional apresentada na Parte 1 para tools e regras de contexto se aplica ponto a ponto a skills. O harness avalia o estado operacional corrente — quem é o agente, qual a tarefa, qual ambiente — e resolve dinamicamente o conjunto de skills que faz sentido injetar, em vez de um conjunto estático fixado na definição do agente.
função resolver_skills_para_execucao(agente, tarefa, ambiente):
candidatas = registry.skills_para_escopo(agente.escopo)
# filtro adicional por condição operacional, não só por escopo
se ambiente == "producao":
candidatas = candidatas.filtrar(s -> s.aprovada_para_producao)
se tarefa.contem_dados_sensiveis:
candidatas = candidatas.filtrar(s -> s.certificada_lgpd)
retornar candidatas.ordenar_por(relevancia_para(tarefa))
# mesmo agente, dois contextos, dois conjuntos de skills resolvidos:
resolver_skills_para_execucao(agente_revisor, tarefa_X, "staging")
→ inclui skill experimental "sugerir_reescrita_automatica"
resolver_skills_para_execucao(agente_revisor, tarefa_X, "producao")
→ exclui a mesma skill, ainda não aprovada para produçãoO ganho aqui não é apenas evitar duplicidade de código — é que o mesmo agente, com a mesma definição, se comporta de forma apropriada ao ambiente em que roda, porque a resolução de skills acontece no momento da execução, consultando condições que só existem naquele instante.
Aprofundamento Técnico
Progressive disclosure — não carregar tudo de uma vez
Mesmo com filtragem por escopo, um agente com escopo amplo pode acabar elegível para dezenas de skills. Injetar a descrição completa de todas elas no contexto — instruções, exemplos, scripts — consome tokens que competem com o espaço de raciocínio da tarefa. O padrão de mitigação é a divulgação progressiva: o harness injeta apenas os metadados leves (nome, descrição, quando usar) de todas as skills elegíveis, e só carrega o conteúdo completo (instruções detalhadas, scripts) da skill específica que o modelo decidiu invocar.
| Cenário | Composição | Custo em tokens |
|---|---|---|
| Contexto do agente ANTES de decidir qual skill usar | 15 skills × ~30 tokens de metadados | ~450 tokens |
| Contexto do agente DEPOIS de escolher 1 skill | 450 tokens de metadados + 1 skill completa (~2000 tokens) | ~2450 tokens |
| Alternativa ruim (carregar tudo antecipado) | 15 skills completas × ~2000 tokens | ~30.000 tokens (a maior parte nunca é usada nesta chamada) |
Esse padrão conecta diretamente com o motor de resolução condicional da Parte 1: a resolução de skills não é diferente, em espírito, da resolução de tools ou de regras de contexto — o harness decide o que injetar com base no estado da tarefa, não injeta tudo que existe no catálogo por padrão.
Conflitos de namespace entre skills de agentes diferentes
Quando times diferentes contribuem skills para o mesmo catálogo, colisão de nomes é praticamente garantida em algum momento — dois times criam, de forma independente, uma skill chamada gerar_relatorio com contratos incompatíveis. A mitigação estrutural é namespace por domínio, não por convenção informal:
Sem namespace (colisão):
gerar_relatorio → time A: relatório financeiro
gerar_relatorio → time B: relatório de qualidade de código
→ registry não sabe qual servir, comportamento indefinido
Com namespace (sem colisão):
financas.gerar_relatorio
qualidade.gerar_relatorio
→ cada agente declara o namespace completo,
resolução é determinísticaDepreciação sem quebrar consumidores em produção
Assim como versionamento resolve evolução aditiva de contrato, o catálogo precisa de um caminho explícito para aposentar uma skill sem quebrar, da noite para o dia, todo agente que ainda depende dela. O padrão é depreciação em três fases, não remoção direta:
Fase 1 — marcar como depreciada, manter funcionando:
validar_metadados@1.x → status: depreciada
aviso emitido no log a cada uso, mas execução normal
Fase 2 — período de transição com aviso ativo:
registry alerta os times donos de agentes que ainda
declaram validar_metadados@1.x, com prazo definido
Fase 3 — remoção, após confirmação de que nenhum agente
ativo ainda resolve a versão antiga:
validar_metadados@1.x → removida do registry
(agentes que ainda a declarassem passariam a falhar
na resolução — por isso a fase 2 é obrigatória antes
da fase 3, não uma cortesia)Pular direto para remoção é o equivalente, em sistemas multi-agente, de remover um endpoint de API sem aviso: funciona até que alguém descobre, em produção, que um consumidor não migrado quebrou silenciosamente.
Runtime discovery vs. build-time binding
Existem dois momentos possíveis para resolver qual skill concreta um agente vai usar: em tempo de build (o conjunto de skills de um agente é fixado quando ele é definido, e mudanças exigem redeploy) ou em tempo de execução (o agente consulta o registry a cada tarefa, e o conjunto pode mudar sem tocar na definição do agente).
Decisão de Arquitetura: Build-Time ou Runtime?
Build-time binding é mais previsível e mais fácil de auditar — você sabe exatamente quais skills um agente tinha disponíveis numa data específica, útil em contextos regulados. Runtime discovery é mais flexível — corrigir um bug numa skill compartilhada corrige instantaneamente todos os agentes que a usam, sem redeploy — mas introduz uma variável a mais: o comportamento de um agente pode mudar entre duas execuções da mesma tarefa se o catálogo mudou no meio do caminho. Sistemas com requisito de auditoria forte (Parte 6 volta a este tema) tendem a fixar a versão resolvida no início de cada execução e registrá-la no log, mesmo usando runtime discovery — assim você tem a flexibilidade de atualizar o catálogo sem perder rastreabilidade de qual versão rodou em qual execução.
Auditoria: rastrear qual versão resolvida rodou onde
Runtime discovery com registro de auditoria não é opcional em sistemas onde o comportamento de um agente precisa ser explicável depois do fato — por exemplo, quando um agente de publicação libera um conteúdo que depois se revela problemático, e alguém precisa reconstruir exatamente qual versão da skill de validação estava ativa naquele momento.
log_de_execucao = {
execucao_id: "exec-7841",
agente: "publicador",
timestamp: "2026-07-26T14:32:00Z",
skills_resolvidas: [
{ nome: "validar_metadados", versao: "2.3.1" },
{ nome: "publicar_no_cms", versao: "1.0.4" }
]
}
# meses depois, uma investigação pode responder com precisão:
# "no momento da publicação do artigo X, a skill de validação
# estava na versão 2.3.1, que ainda não tinha a regra
# adicionada em 2.4.0 para bloquear links quebrados"Sem esse registro, runtime discovery vira uma caixa-preta temporal — o catálogo evolui, mas ninguém consegue reconstruir com certeza qual versão de qual skill produziu um resultado específico numa data passada. Fixar a versão resolvida no log de cada execução é o que preserva a flexibilidade do catálogo dinâmico sem sacrificar a rastreabilidade.
Com o catálogo de skills resolvido, o problema muda de natureza. Nem toda tarefa que um agente enfrenta tem uma skill esperando por ela no catálogo — algumas exigem que o próprio modelo descubra, em tempo real, quais ações tomar. É o assunto do próximo capítulo: agentes cujo loop é desenhado para o desconhecido, não para uma capacidade pré-empacotada.