Objetivo da Aula
Distinguir uma skill de uma tool e de um trecho de prompt solto
Projetar uma skill como unidade determinística: contrato de entrada e saída, sem estado oculto
Definir critérios objetivos para decidir o que vira skill e o que fica como raciocínio livre do modelo
Estruturar o empacotamento de uma skill (metadados, instruções, recursos) para descoberta pelo harness
Avaliar o trade-off entre determinismo (skill) e flexibilidade (inferência probabilística)
Por que isso importa
Todo agente que você já viu em produção resolve dois tipos de problema com a mesma ferramenta — o modelo de linguagem. O primeiro tipo é aberto: “investigue por que essa métrica caiu”. O segundo é fechado: “gere um changelog no formato X a partir destes commits” ou “valide se este arquivo de metadados tem os quinze campos obrigatórios”. O problema fechado tem uma resposta certa, testável, repetível. Resolver esse tipo de problema deixando o modelo “pensar” do zero a cada chamada é desperdício: você paga tokens de raciocínio por algo que já sabe como fazer, e ainda corre o risco de o modelo variar o resultado entre uma execução e outra.
Skill é a resposta arquitetural para essa classe de problema. É a unidade que empacota uma capacidade determinística — instruções, código auxiliar, formatos de saída — para que o harness a injete quando necessário, sem que o modelo precise reconstruir o raciocínio do zero e sem que dois agentes diferentes reimplementem a mesma lógica cada um do seu jeito.
Impacto direto no seu trabalho: toda vez que você decide “isso vira uma skill ou fica no prompt”, está fazendo uma escolha de arquitetura com consequência em custo, previsibilidade e manutenção. Empacotar demais engessa o sistema; empacotar de menos multiplica variância e tokens gastos em raciocínio redundante. Este capítulo dá o critério para essa decisão.
Conceitos Fundamentais
Skill não é tool
Tool (ou function calling) é uma chamada nomeada com schema de parâmetros — o modelo decide invocar buscar_cliente(id) e recebe um retorno estruturado. É uma interface fina para uma API ou função existente. Skill é maior: é um pacote de capacidade que combina instrução (o “como fazer”), recursos (scripts, templates, exemplos de referência) e, frequentemente, uma ou mais tools internamente. Uma skill de “gerar release notes” pode usar uma tool de leitura de git log por baixo, mas o que o harness injeta no agente é a capacidade completa — formato de saída, regras de estilo, casos de borda já resolvidos —, não apenas o acesso ao dado bruto.
Tool: nome + schema de parâmetros + chamada remota
→ "o que o sistema pode fazer"
Skill: metadados + instruções + recursos (scripts, templates)
→ "como uma tarefa específica deve ser feita, sempre da mesma forma"
Uma skill PODE usar tools internamente.
Uma tool sozinha NÃO é uma skill — falta o "como" e o "quando".Anatomia de uma skill bem desenhada
Uma skill tem três camadas, na ordem em que o harness as consome:
- skill/ — diretório raiz do pacote
- SKILL.md — metadados: nome, descrição, QUANDO usar
- instrucoes.md — o procedimento determinístico, passo a passo
- scripts/
- validar.py — código auxiliar determinístico (não é o LLM que valida)
Frontmatter de SKILL.md:
---
name: validador-metadados-frontmatter
description: Valida se um arquivo de conteúdo tem os campos
obrigatórios de frontmatter (title, author, date, tags) e
reporta cada campo ausente ou malformado.
when_to_use: sempre que um arquivo novo de conteúdo for
submetido para publicação
---Note o campo description e o campo when_to_use: eles não são documentação para humanos, são o que o harness (ou o próprio modelo, na descoberta em duas etapas) usa para decidir se aquela skill é relevante para a tarefa corrente. Uma skill mal descrita nunca é escolhida — ou pior, é escolhida no contexto errado.
Determinismo como propriedade de design, não acidente
O ponto central de uma skill bem projetada é que ela reduz a superfície de decisão do modelo. Em vez de pedir “gere um JSON com os campos X, Y, Z, validando tipos”, você entrega uma skill cujo script faz a validação em código puro — sem inferência estatística envolvida na parte que tem resposta certa.
função validar_metadados(arquivo):
campos_obrigatorios = ["title", "author", "date", "tags"]
erros = []
frontmatter = extrair_frontmatter(arquivo)
para cada campo em campos_obrigatorios:
se campo não está em frontmatter:
erros.append(f"campo ausente: {campo}")
senão se tipo(frontmatter[campo]) != tipo_esperado(campo):
erros.append(f"tipo inválido em {campo}")
se erros está vazio:
retornar { status: "ok" }
senão:
retornar { status: "falhou", erros: erros }O modelo não “decide” se o campo date está no formato certo — o script decide, de forma binária e reproduzível. O papel do modelo se reduz a orquestrar a chamada da skill e interpretar o resultado estruturado que ela devolve. Essa é a diferença entre uma skill de verdade e um prompt disfarçado de skill: se o resultado pode variar entre duas execuções com o mesmo input, a parte determinística não foi de fato extraída para código.
Fundamento: Espectro de Determinismo
Toda capacidade de um agente vive num espectro entre dois polos. Num extremo, código puro: mesma entrada, mesma saída, sempre — é o que uma skill bem desenhada encapsula (parsing, validação, geração de artefato em formato fixo). No outro extremo, raciocínio livre do modelo: mesma entrada pode gerar respostas diferentes, porque a tarefa exige julgamento, ambiguidade ou síntese aberta (“resuma o sentimento geral desta thread”). O erro de arquitetura mais comum é dos dois lados: tentar codificar em regras determinísticas algo que exige julgamento (gera um sistema frágil, cheio de exceções) ou deixar para o modelo “decidir na hora” algo que tem uma resposta certa e testável (gera variância, custo e risco de erro silencioso). Skills existem para capturar o primeiro polo e liberar o modelo para o segundo.
Geradores estruturados como caso canônico
O exemplo mais comum de skill em harnesses de produção é o gerador estruturado: uma capacidade que sempre produz a mesma forma de saída a partir de entradas variáveis — um changelog a partir de commits, um relatório de PR a partir de um diff, um resumo de incidente a partir de logs. A parte “o que aconteceu” exige o modelo (síntese de linguagem natural); a parte “em que formato isso sai, com que campos, em que ordem” não exige — e não deveria depender do modelo lembrar o formato certo a cada chamada.
Sem skill (formato depende do modelo "lembrar"):
prompt: "gere um changelog destes commits, use o formato
Keep a Changelog, com Added/Changed/Fixed"
→ variância: às vezes esquece uma seção, às vezes muda
o cabeçalho, às vezes inclui campos extras
Com skill (formato é código, conteúdo é modelo):
1. skill.extrair_commits_por_tipo(log) → determinístico
2. skill.montar_esqueleto_changelog(tipos) → determinístico
3. modelo.preencher_descricoes(esqueleto) → probabilístico,
mas restrito a preencher texto dentro de uma estrutura fixaRepare no padrão: a skill não elimina o modelo, ela contém a parte que não precisa dele e isola a parte que precisa num espaço de decisão bem menor — preencher descrições de texto dentro de uma estrutura já validada, em vez de decidir a estrutura inteira a cada chamada.
Custo comparativo: skill vs. raciocínio livre
A diferença entre encapsular e não encapsular não é apenas qualitativa — ela aparece direto na fatura de tokens. Considere a tarefa de validar cem arquivos de metadados por dia, comparando as duas abordagens:
| Métrica | Sem skill (modelo raciocina do zero) | Com skill (script determinístico + modelo interpreta) |
|---|---|---|
| Execução da lógica de validação | Feita pelo modelo, via raciocínio em linguagem natural | Feita por script determinístico (custo computacional, não de inferência) |
| Prompt por validação | ~350 tokens (instrução completa de quais campos checar, formatos esperados, exemplos) | ~40 tokens ("interprete este resultado estruturado e decida o próximo passo") |
| Resposta do modelo | ~120 tokens | ~30 tokens |
| Custo por validação (inferência real) | ~470 tokens | ~70 tokens |
| 100 validações/dia | 47.000 tokens/dia processados pelo modelo, com variância de formato entre execuções | 7.000 tokens/dia processados pelo modelo, resultado sempre no mesmo formato |
A economia de tokens é real, mas o ganho maior é a eliminação da variância: o script sempre aplica a mesma regra da mesma forma, enquanto o modelo, mesmo com instruções idênticas, pode interpretar um caso de borda de forma diferente entre duas execuções. Para uma tarefa com resposta certa, essa variância não é flexibilidade — é risco de inconsistência silenciosa.
Como o modelo escolhe entre skills concorrentes
Quando o catálogo tem mais de uma skill com descrições parecidas, a escolha do modelo depende inteiramente da qualidade dos metadados de descoberta — não existe mecanismo mágico de desambiguação além do texto que descreve cada skill.
Descrições ambíguas (colisão de intenção):
skill A: description: "processa arquivos de conteúdo"
skill B: description: "valida arquivos de conteúdo"
→ para uma tarefa de "verificar se o arquivo está correto",
as duas descrições competem, o modelo pode escolher errado
Descrições específicas (sem ambiguidade):
skill A: description: "normaliza formatação markdown de
arquivos de conteúdo (espaçamento, headers, links)"
skill B: description: "valida se o frontmatter de um arquivo
de conteúdo tem os campos obrigatórios antes da publicação"
→ intenções claramente distintas, escolha determinística
mesmo sendo o modelo quem decideIsso muda como você deve pensar em escrever description e when_to_use: não são comentários de documentação para humanos que vão ler o código depois — são, na prática, a interface pela qual o modelo decide qual capacidade invocar. Uma descrição vaga tem o mesmo efeito prático de uma skill mal implementada.
Aprofundamento Técnico
Quando não fazer uma skill
Encapsulamento tem custo de manutenção e custo de indireção — cada skill é mais um artefato para versionar, testar e manter descoberto pelo catálogo (tema do próximo capítulo). Três sinais indicam que uma capacidade não deveria virar skill:
Sinal 1 — a tarefa muda de forma a cada execução. Se o “formato certo” depende fortemente do contexto de negócio de cada chamada, engessar isso em código gera uma skill cheia de flags condicionais que, na prática, reintroduz a complexidade que você tentou eliminar.
Sinal 2 — você só usou essa lógica uma vez. Skill compensa em reuso. Uma capacidade usada por um único agente, uma única vez, é mais barata como raciocínio direto no prompt do que como artefato empacotado, versionado e testado.
Sinal 3 — a “resposta certa” é, na verdade, uma opinião. Se dois especialistas humanos discordariam do resultado esperado, a tarefa pertence ao polo probabilístico — tentar validá-la em código puro só move a ambiguidade para dentro de regras frágeis, sem removê-la.
Testabilidade determinística — golden tests
A vantagem que justifica o custo de empacotar uma skill é que ela vira testável como qualquer outro código: entrada fixa, saída esperada fixa, sem necessidade de avaliação subjetiva por LLM-juiz.
teste("validador rejeita frontmatter sem campo date"):
entrada = frontmatter_sem_date_fixture()
resultado = validar_metadados(entrada)
assert resultado.status == "falhou"
assert "campo ausente: date" em resultado.erros
teste("validador aceita frontmatter completo"):
entrada = frontmatter_valido_fixture()
resultado = validar_metadados(entrada)
assert resultado.status == "ok"Isso muda o regime de confiança do sistema. Testes de comportamento do modelo (avaliação de qualidade de texto gerado, por exemplo) são caros, ruidosos e exigem amostragem. Testes de uma skill determinística rodam em milissegundos, em CI, sem custo de inferência — e falham de forma binária, não estatística.
Idempotência e efeitos colaterais
Uma skill bem projetada é idempotente sempre que a operação permite: rodar duas vezes com a mesma entrada produz o mesmo resultado e não duplica efeito. Isso importa especialmente quando o harness reexecuta uma skill após falha parcial — um retry automático de uma skill não idempotente pode, por exemplo, criar dois registros em vez de um.
Não idempotente (perigoso sob retry):
skill.criar_ticket(dados) → sempre insere um novo registro
Idempotente (seguro sob retry):
skill.upsert_ticket(chave_natural, dados)
→ insere se não existe, atualiza se já existe,
mesma chave nunca gera duas linhasDecisão de Arquitetura: Granularidade da Skill
Uma skill grande demais (“processar-pull-request-completo”) vira uma caixa-preta difícil de testar e de reaproveitar parcialmente — se só a parte de validação de título fosse útil para outro agente, ela está presa dentro de um pacote maior. Uma skill pequena demais (“verificar-se-string-e-vazia”) multiplica o catálogo sem ganho real de reuso e aumenta o custo de descoberta (mais opções para o modelo avaliar a cada chamada). O critério prático: uma skill deve corresponder a uma unidade de capacidade que um humano descreveria com um verbo e um objeto direto — “validar metadados”, “gerar changelog”, “normalizar CSV” — não a um passo interno de uma dessas operações, nem a um fluxo de trabalho inteiro que combina várias capacidades independentes.
Recursos auxiliares dentro do pacote da skill
Além de instruções e scripts de validação, uma skill frequentemente empacota recursos de referência que o modelo consulta apenas quando necessário — um dicionário de códigos de erro, um exemplo de saída bem formada, uma tabela de mapeamento entre formatos legados e o formato atual. Esses recursos não entram no contexto por padrão; ficam disponíveis para leitura sob demanda, o que evita pagar o custo de tokens de todo o material de referência em toda chamada da skill.
- skill/
- SKILL.md
- instrucoes.md
- scripts/
- validar.py
- referencia/
- exemplos_validos.md — consultado só se o modelo pedir exemplo de referência
- tabela_codigos_erro.md — consultado só ao interpretar um erro específico retornado pelo script
Esse padrão — instrução mínima sempre presente, material de referência disponível mas não pré-carregado — é o mesmo princípio de divulgação progressiva que vai reaparecer no próximo capítulo aplicado ao catálogo inteiro de skills, não só ao conteúdo interno de uma única skill.
Esse critério de granularidade é o que prepara o terreno para o próximo capítulo: uma vez que a skill está bem isolada, ela deixa de pertencer a um agente específico e passa a ser um recurso que o harness pode injetar em qualquer agente que precise da mesma capacidade — sem duplicar o código-fonte da skill em cada lugar que a usa.