A narrativa dominante sobre IA em engenharia de software é de produtividade: mais código, mais rápido, com menos esforço. Essa narrativa é parcialmente verdadeira — e parcialmente perigosa. É verdadeira no curto prazo, no nível do desenvolvedor individual, para tarefas bem-definidas. É perigosa quando generalizada sem qualificação, porque esconde um conjunto de riscos que só se materializam no médio prazo, no nível do sistema e da organização, e que são sistematicamente difíceis de detectar antes de se tornarem sérios.
Este conceito cataloga esses riscos com a especificidade necessária para reconhecê-los na prática — não como uma posição cética sobre IA, mas como o contrapeso realista que permite usar LLMs de forma sustentável. Todo engenheiro que usa LLMs com competência também conhece onde não usá-los, quando parar, e quais sinais indicam que o uso está criando problemas que superam os benefícios.
Risco 1: Dívida técnica acelerada
LLMs aceleram a geração de código. Se o processo de revisão não acompanha essa velocidade, a dívida técnica cresce proporcionalmente. Esse é o risco mais imediato e mais frequentemente subestimado porque é invisível no curto prazo — o código passa em CI, vai para produção, parece funcionar. A dívida aparece gradualmente: código inconsistente com padrões do projeto, abstrações incorretas, dependências desnecessárias, testes que cobrem mas não verificam.
Como acontece
Um desenvolvedor usa Copilot ou Claude para gerar código rapidamente. A geração é boa — o código funciona. A pressão por velocidade reduz o tempo de revisão. Ao longo de semanas, decenas de PRs seguem esse padrão. Cada um individualmente parece razoável; coletivamente, o código da base diverge de padrões estabelecidos, accumula inconsistências, e torna-se progressivamente mais difícil de manter. O problema não é o código gerado — é o processo que omitiu revisão adequada.
O acelerador de inconsistência
Código gerado por LLM sem contexto suficiente do projeto tende a introduzir padrões do "estado da arte geral" que podem conflitar com decisões conscientes do projeto. Se o projeto usa um padrão específico para acesso a banco de dados que difere do ORM genérico mais comum, o LLM vai usar o ORM genérico — e introduzir uma inconsistência em cada geração. Multiplicada por vários desenvolvedores ao longo de meses, essa inconsistência cria uma base de código que tem dois dialetos paralelos: o padrão do projeto e o padrão que o LLM prefere.
Se diferentes partes do código fazem a mesma operação de forma diferente (logging, acesso a configuração, tratamento de erro, acesso a banco), e essas diferenças não têm justificativa arquitetural, provavelmente a base está acumulando inconsistências de geração por LLM sem revisão adequada de consistência.
Mitigação
O CLAUDE.md ou system prompt do agente deve incluir explicitamente os padrões do projeto: como se faz acesso a banco neste projeto, como se faz logging, qual é o padrão de error handling. Isso não garante que o LLM seguirá os padrões, mas reduz drasticamente a divergência. Combinado com um step de CI que verifica inconsistência de padrão (mesmo que manualmente, como um item de checklist de PR), o risco é gerenciável.
Risco 2: Atrofia de habilidades fundamentais
Quando uma habilidade deixa de ser exercitada regularmente, ela atrofia. Isso é fisiológico em habilidades motoras e igualmente verdadeiro em habilidades cognitivas. Engenheiros que delegam sistematicamente para LLMs certas categorias de problemas perdem a habilidade de resolver esses problemas sem assistência — e, mais perigosamente, perdem a capacidade de avaliar se a solução do LLM está correta.
As habilidades em risco
Debugging independente: Depurar código exige entender o sistema suficientemente bem para formular hipóteses sobre onde o problema pode estar. Engenheiros que usam LLMs para debugging (descrevendo o sintoma e perguntando qual pode ser o problema) perdem a prática de formular essas hipóteses por conta própria. Quando o LLM não tem o contexto necessário para sugerir a causa correta — o que acontece com bugs sistêmicos, condições de race, e problemas de configuração de ambiente — o engenheiro que atrofiou essa habilidade fica paralisado.
Estimativa e design de baixo nível: Saber intuitivamente que uma consulta vai ser lenta, que uma estrutura de dados vai ter o custo de memória errado, ou que um algoritmo tem a complexidade errada é uma habilidade desenvolvida com prática de estimativa de baixo nível. Delegar sistematicamente decisões de algoritmo e estrutura de dados para LLMs reduz essa prática e, com ela, a intuição que permite identificar problemas de performance antes de implementar.
Leitura de código não familiar: Entender código de outra pessoa, em um estilo diferente, exige a habilidade de mapear código a comportamento sem ter escrito o código. Engenheiros que usam LLMs para explicar código ("explique o que este código faz") perdem prática de desenvolver esse mapeamento por conta própria — o que é precisamente a habilidade necessária quando há um bug num serviço legado às 3 da manhã e o LLM está em timeout porque a API está sobrecarregada.
O paradoxo da avaliação
O problema mais sutil é que a atrofia de uma habilidade impede a avaliação da qualidade do output do LLM naquela área. Se você perdeu a habilidade de estimar complexidade de algoritmo por falta de prática, você também perdeu a capacidade de detectar que o LLM escolheu um algoritmo com complexidade errada para o seu contexto. A atrofia da habilidade e a degradação da capacidade de revisão caminham juntas.
Preserve ativamente as habilidades que você quer manter. Se você usa LLMs para debugging regularmente, reserve tempo para sessões de debugging sem assistência. Se você usa LLMs para design de algoritmo, resolva periodicamente problemas algorítmicos sem assistência. Habilidades que não são exercitadas atrofiam independentemente da sua intenção.
Engenheiros júnior em risco amplificado
Para engenheiros no início da carreira, o risco é amplificado: eles estão em fase de construção de habilidades, não de manutenção. Um engenheiro júnior que usa LLMs para resolver a maioria dos problemas não está aprendendo a resolver problemas — está aprendendo a formular prompts. Essas são habilidades diferentes, e a segunda não substitui a primeira. O resultado é engenheiros que parecem produtivos (produzem código que funciona) mas não desenvolveram as habilidades fundamentais de engenharia que permitiriam resolver problemas mais complexos de forma independente.
Times sênior têm responsabilidade de estruturar o desenvolvimento de júniores de forma que LLMs sejam usados para acelerar aprendizado (explicar conceitos, mostrar padrões), não para substituir a prática deliberada de resolução de problemas.
Risco 3: Vazamento de dados e confidencialidade
Ao submeter código ao contexto de um LLM, você está enviando esse código — e tudo que está no contexto junto com ele — para a API do provedor. Para modelos comerciais como Claude, GPT-4, e Gemini, isso significa que o código trafega pela infraestrutura do provedor, é processado nos servidores do provedor, e pode ser usado para treinamento ou stored nos logs do provedor dependendo dos termos de serviço e configuração da conta.
O que está em risco
Código proprietário: Algoritmos de negócio, implementações de produto diferenciadas, código que constitui vantagem competitiva. Uma vez enviado para a API, o controle de acesso a esse código está fora do alcance da organização.
Dados de clientes em snippets de código: Desenvolvedores frequentemente incluem dados reais em exemplos para mostrar ao LLM o formato do problema: "aqui está um exemplo dos dados que recebo: {"email": "cliente@real.com", "cpf": "123.456.789-00"}". Isso é um vazamento de PII que não é registrado em nenhum log de acesso interno.
Credenciais e secrets: Desenvolvedores que colam código com variáveis de ambiente não substituídas ou comentários com valores de teste de credenciais reais. Acontece por descuido, especialmente em sessões longas onde o contexto acumula.
Informação estratégica em contexto de produto: Ao descrever o problema de negócio para dar contexto ao LLM, o desenvolvedor pode revelar informação sobre produtos não anunciados, parcerias, ou estratégia competitiva.
Categorias de risco por provedor e configuração
O risco varia significativamente por configuração. Anthropic Claude: dados de API não são usados para treinamento de modelos comerciais por padrão, com contrato de Business/Enterprise. Claude.ai (interface web) tem política diferente de API. OpenAI: política similar com configuração enterprise; ChatGPT consumer tem política diferente. GitHub Copilot: código enviado para completions tem políticas específicas no Business tier que diferem do Individual.
Antes de adotar qualquer LLM comercial, leia os termos de serviço da configuração específica que você usa. As diferenças entre consumer, business, e enterprise tiers são significativas e frequentemente não são comunicadas claramente em interfaces de produto.
Mitigação prática
A mitigação mais robusta é usar modelos auto-hospedados (Ollama com Llama, Code Llama, ou modelos específicos de código) para código altamente sensível. O custo é qualidade: modelos locais são consistentemente menos capazes do que os modelos comerciais líderes. O trade-off é explícito e consciente.
Para uso de APIs comerciais: estabeleça categorias de sensibilidade. Código de produto core, algoritmos proprietários, e qualquer arquivo que possa ter dados de cliente — não entra no contexto de LLMs comerciais sem revisão. Código de infraestrutura, scripts utilitários, boilerplate, testes com dados sintéticos — pode ser submetido com menor risco. A política deve ser explícita, documentada, e treinada no time.
Ferramenta prática: pre-commit hook que verifica padrões de PII (CPF, CNPJ, email com domínio de cliente, telefone) no diff antes de permitir que o desenvolvedor copie o código para um prompt. Não é perfeito, mas reduz os casos de descuido.
Risco 4: Erosão da compreensão do sistema
Este é o risco mais insidioso porque opera no nível do time e da organização, não do desenvolvedor individual. Quando código é gerado por LLM, a compreensão de por que o código funciona daquela forma — quais são as invariantes que ele satisfaz, quais são as decisões que foram tomadas e por quê — pode não existir em nenhuma mente humana. O código está lá, funciona, mas ninguém entende por que exatamente funciona.
O problema da geração sem compreensão
Um desenvolvedor que implementa um algoritmo do zero desenvolve compreensão do algoritmo ao longo do processo: entende os casos de borda porque os testou, entende os invariantes porque os verificou, entende as limitações porque as encontrou. Um desenvolvedor que aceita um algoritmo gerado por LLM sem estudá-lo pode ter código correto sem ter essa compreensão.
Isso parece aceitável para algoritmos estáveis. Torna-se problemático quando o algoritmo precisa ser modificado — porque a modificação exige compreensão dos invariantes — ou quando há um bug — porque o debugging exige conhecimento do comportamento esperado em condições específicas. "O LLM gerou esse código" não é uma resposta quando o sistema está falhando em produção às 2 da manhã.
Conhecimento tácito do sistema
Sistemas de software complexos têm conhecimento tácito: informação que não está documentada em nenhum lugar, que existe apenas nas cabeças das pessoas que trabalharam naquelas partes. Quando código é gerado por LLM sem intervenção humana substantiva, esse conhecimento tácito não é criado. O resultado é um sistema que funciona mas que ninguém entende completamente — o que é exatamente o estado de sistemas legados que são considerados impossíveis de manter.
A diferença é a escala de tempo: um sistema legado acumulou esse problema ao longo de anos, com mudanças de equipe, documentação perdida, e turnover. Um sistema desenvolvido com LLMs pode acumular o mesmo problema em meses se o processo não exige compreensão como condição de aceitação.
Para qualquer parte do sistema desenvolvida com LLMs, pergunte: um membro do time consegue explicar por que esse código funciona, quais são suas limitações, e o que aconteceria se mudássemos X? Se a resposta for "não sei, o LLM gerou", há um déficit de compreensão que se tornará problema quando precisar modificar ou debugar.
Compreensão como critério de aceitação
A mitigação é tornar compreensão um critério de aceitação explícito. Código gerado por LLM é aceito quando o desenvolvedor consegue explicar: o que o código faz, por que a abordagem escolhida é adequada para este contexto específico, quais são as limitações da implementação, e o que aconteceria se um aspecto específico do ambiente mudasse. Sem essa capacidade de explicação, o código não foi suficientemente entendido para ser responsabilidade do desenvolvedor.
Isso não exige que o desenvolvedor tenha gerado o código — exige que ele o tenha estudado o suficiente para compreendê-lo. A distinção é importante: usar LLMs para aprender mais rápido é diferente de usar LLMs para evitar o aprendizado.
Risco 5: Dependência de disponibilidade de serviço
Times que integram LLMs profundamente em seu fluxo de trabalho criam dependência na disponibilidade do serviço. APIs de LLM têm indisponibilidade — rate limiting, degradação, outages. Quando o fluxo de trabalho pressupõe disponibilidade de LLM para ser eficiente, uma indisponibilidade não degrada graciosamente — ela paralisa ou reduz drasticamente a produtividade do time.
Isso é análogo à dependência de internet para trabalho remoto: quando estava disponível era transparente, quando ficou indisponível revelou o quanto o fluxo de trabalho havia sido redesenhado em torno de sua disponibilidade.
Escala de dependência
Existe um espectro de dependência: uso ocasional (LLM como uma ferramenta entre várias), uso regular (LLM como ferramenta preferida para certos problemas), e uso integral (LLM como componente necessário para a maioria das tarefas). O nível de risco aumenta com o nível de dependência. Times devem ser conscientes de onde estão nesse espectro e de qual seria o impacto de uma indisponibilidade de 4 horas.
Mitigação: manter fluência nas ferramentas alternativas (IDE sem plugin de LLM, documentação nativa sem assistente), ter um plano de fallback para tarefas críticas, e não reestruturar fundamentalmente o processo de forma que seja inoperável sem LLM disponível.
Risco 6: Problemas de propriedade intelectual e licença
LLMs são treinados em código de repositórios públicos — incluindo código sob licenças copyleft como GPL, AGPL, e MPL. A questão de se código gerado por LLM pode herdar a licença do código de treinamento que influenciou a geração é juridicamente não resolvida. Nenhuma corte estabeleceu precedente definitivo.
O risco prático: se código gerado por LLM inclui trechos substantiais de código copyleft (por coincidência de memorização ou por pattern-matching muito próximo), e esse código vai para um produto commercial closed-source, há risco de violação de licença. A probabilidade é baixa para código funcional comum, mas não zero — e para código de algoritmos específicos que existem em poucas implementações públicas, a probabilidade é maior.
Mitigação
GitHub Copilot tem um filtro de código duplicado que pode ser ativado — ele bloqueia sugestões que coincidem muito com código público. Outros provedores têm capacidades similares. Ativar esses filtros é boa prática, especialmente para produtos commercial closed-source.
Para código em áreas de alto risco (algoritmos específicos, criptografia, protocolos de rede), revisar se o output do LLM é suficientemente diferente de implementações públicas conhecidas — ou, para máxima segurança, implementar manualmente com referência ao algoritmo descrito, não ao código existente.
Risco 7: Falsa confiança como risco sistêmico
O risco que integra todos os anteriores é o da falsa confiança: a sensação de que o sistema está correto porque funciona, os testes passam, e o LLM foi responsável pela implementação. Esta falsa confiança é mais perigosa do que ausência de confiança porque suprime o questionamento crítico que é a última linha de defesa contra problemas que nenhuma ferramenta automática detecta.
A pesquisa de Sandoval et al. (2022) documenta este efeito: participantes que usaram LLMs para escrever código de segurança produziram código de qualidade similar ou ligeiramente inferior ao grupo sem LLM — mas se sentiam significativamente mais confiantes na correção do código. A confiança aumentada com qualidade igual ou menor é uma combinação que leva a menos questionamento crítico e, consequentemente, a mais problemas em produção.
Se você está revisando código gerado por LLM e pensa "parece bom, acho que está certo" — esse é o momento de ativar o ceticismo deliberado. LLMs são otimizados para parecer certo. O sentimento de "parece bom" é precisamente o que eles maximizam, independentemente de o código estar correto.
Limites técnicos: onde LLMs falham sistematicamente
Além dos riscos organizacionais, há limites técnicos onde LLMs falham sistematicamente — não por serem modelos ruins, mas por limitações fundamentais da abordagem. Reconhecer esses limites evita delegar problemas que LLMs não conseguem resolver e interpretar incorretamente o output quando tentam.
Raciocínio formal e provas
LLMs não provam coisas — eles geram sequências de texto plausíveis. Para problemas que requerem raciocínio formal — provar que um algoritmo é correto, verificar que um protocolo de segurança é seguro, demonstrar que uma condição de deadlock não pode ocorrer — LLMs produzem texto que parece argumentação formal mas não tem as garantias de uma prova verificada. O output pode ser convincente e errado.
Para esses problemas, ferramentas formais (Alloy, TLA+, Coq, Lean) são o caminho correto. LLMs podem ajudar a escrever as especificações em linguagem formal, mas a verificação precisa ser feita pela ferramenta formal, não aceita na palavra do LLM.
Conhecimento sobre o seu sistema específico
LLMs conhecem software em geral, frameworks populares, padrões comuns. Eles não conhecem o seu sistema: quais são as invariantes de negócio específicas, qual é o modelo de dados específico, quais são as integrações com sistemas externos com comportamentos não documentados, qual é o histórico de decisões arquiteturais e por que foram tomadas. Quando o problema requer esse conhecimento, o LLM ou chuta com base no que é mais comum ou produz output genérico que parece relevante mas não o é.
Isso não é um problema de contexto que se resolve adicionando mais contexto ao prompt — é uma limitação de que o LLM não pode ter vivido o desenvolvimento do sistema e ter o conhecimento tácito que isso gera. Problemas que dependem fundamentalmente desse conhecimento precisam de soluções que partem desse conhecimento.
Performance e escalabilidade em contexto específico
LLMs podem raciocinar sobre complexidade algorítmica em geral, mas não podem avaliar a performance real de uma implementação no seu ambiente específico: qual é o custo de um round-trip para o seu banco com a sua configuração, qual é o overhead da sua abstração de ORM com o seu volume de dados, qual é o impacto de garbage collection no seu padrão de alocação. Esses julgamentos requerem medição, não raciocínio. LLMs que produzem análises de performance sem medição produzem especulação com aparência de análise.
Novidade e pesquisa
O pre-training de LLMs tem uma data de corte. Bibliotecas lançadas após a data de corte são desconhecidas; versões recentes de frameworks com mudanças significativas de API podem ser parcialmente incorretas; pesquisa publicada após o corte não existe. Para trabalho em áreas que evoluem rapidamente — modelos de ML, protocolos de rede emergentes, novas versões de linguagem — o conhecimento do LLM tem data de validade e deve ser verificado contra documentação atual.
Adoção responsável: o framework de avaliação
Com esse catálogo de riscos em mãos, como avaliar se o uso de LLMs em um contexto específico é apropriado? Um framework simples de três perguntas:
- Consigo verificar o output? Se não tenho o conhecimento de domínio ou as ferramentas para verificar que o código gerado está correto, não tenho como usar LLM com responsabilidade neste contexto. Primeiro adquira o conhecimento ou as ferramentas de verificação, depois use o LLM.
- O custo de estar errado é reversível? Código em desenvolvimento local, scripts utilitários, testes — altamente reversíveis, risco menor. Código que vai para produção com alto tráfego, código de segurança, código que processa dados financeiros ou de saúde — baixa reversibilidade, risco maior, exige revisão mais rigorosa.
- O uso está criando dependência que não quero ter? Se estou delegando sistematicamente uma categoria de problema para LLMs, preciso verificar periodicamente se ainda consigo resolver essa categoria sem assistência. Se não consigo, tenho dependência não gerenciada.
Um "não" em qualquer das três perguntas não proíbe o uso de LLMs — pede atenção especial. "Não consigo verificar" pede que você aprenda antes de usar. "Baixa reversibilidade" pede processo de revisão mais rigoroso. "Criando dependência" pede prática deliberada para manter a habilidade.
Comparação por linguagem
// hooks/pre-commit-sensitive-check.ps1
# Verifica dados sensíveis em arquivos staged antes de commit.
# Não bloqueia o commit, mas emite aviso explícito para revisão.
$patterns = @{
"CPF" = '\d{3}\.\d{3}\.\d{3}-\d{2}'
"CNPJ" = '\d{2}\.\d{3}\.\d{3}/\d{4}-\d{2}'
"Email cliente" = '[a-zA-Z0-9._%+-]+@(?!example\.com|test\.com)[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
"AWS Key" = 'AKIA[0-9A-Z]{16}'
"Private Key" = '-----BEGIN (RSA |EC )?PRIVATE KEY-----'
"API Key generico" = '(?i)(api_key|apikey|secret_key)\s*=\s*["\x27][^"\x27]{10,}'
}
$staged = git diff --cached --name-only --diff-filter=ACM
$warnings = @()
foreach ($file in $staged) {
if ($file -notmatch '\.(cs|json|yaml|yml|xml|config|env)$') { continue }
$content = git show ":$file" 2>$null
if (-not $content) { continue }
foreach ($name in $patterns.Keys) {
if ($content -match $patterns[$name]) {
$warnings += " [$name] em $file"
}
}
}
if ($warnings.Count -gt 0) {
Write-Host ""
Write-Host "⚠️ DADOS SENSÍVEIS DETECTADOS NO DIFF:" -ForegroundColor Yellow
$warnings | ForEach-Object { Write-Host $_ -ForegroundColor Yellow }
Write-Host ""
Write-Host "Antes de submeter este código a um LLM externo (Claude, Copilot, etc.):"
Write-Host " 1. Verifique se os dados acima são reais ou sintéticos"
Write-Host " 2. Se reais, substitua por dados sintéticos antes de copiar"
Write-Host " 3. Revise a política de dados sensíveis em LLMs: docs/ai-policy.md"
Write-Host ""
# Apenas aviso — não bloqueia o commit
# Para bloquear: descomentar a linha abaixo
# exit 1
}
# scripts/ai_dependency_audit.py
# Analisa uso de LLM no histórico de commits do time.
# Usa convenção de tags [gen: ai] em mensagens de commit.
import subprocess
import re
from collections import defaultdict
from datetime import datetime, timedelta
def get_commit_history(days: int = 90) -> list[dict]:
"""Busca commits dos últimos N dias."""
since = (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d")
out = subprocess.check_output([
"git", "log", f"--since={since}",
"--format=%H|%ae|%ad|%s",
"--date=format:%Y-%m-%d"
], text=True)
commits = []
for line in out.strip().splitlines():
parts = line.split("|", 3)
if len(parts) == 4:
commits.append({
"hash": parts[0],
"author": parts[1],
"date": parts[2],
"message": parts[3],
"ai_generated": bool(re.search(
r'\[gen:\s*(?:ai|claude|copilot|chatgpt)\]|Co-Authored-By:\s*Claude',
parts[3], re.IGNORECASE
))
})
return commits
def analyze_dependency(commits: list[dict]) -> dict:
"""Analisa dependência de LLM por autor e período."""
by_author = defaultdict(lambda: {"total": 0, "ai": 0})
by_week = defaultdict(lambda: {"total": 0, "ai": 0})
for c in commits:
author = c["author"]
week = c["date"][:7] # YYYY-MM
by_author[author]["total"] += 1
by_week[week]["total"] += 1
if c["ai_generated"]:
by_author[author]["ai"] += 1
by_week[week]["ai"] += 1
return {"by_author": dict(by_author), "by_week": dict(by_week)}
def print_report(analysis: dict, threshold: float = 0.5) -> None:
print("=== Relatório de Uso de IA em Commits ===\n")
print("Por autor:")
for author, data in sorted(analysis["by_author"].items()):
rate = data["ai"] / data["total"] if data["total"] > 0 else 0
flag = " ⚠️ " if rate > threshold else " "
print(f" {flag}{author}: {data['ai']}/{data['total']} commits com IA ({rate:.0%})")
print("\nPor mês:")
for month, data in sorted(analysis["by_week"].items()):
rate = data["ai"] / data["total"] if data["total"] > 0 else 0
trend = "↑" if rate > threshold else "→"
print(f" {trend} {month}: {data['ai']}/{data['total']} ({rate:.0%})")
print(f"\nThreshold configurado: {threshold:.0%}")
print("Autores acima do threshold: considere check-in de habilidade independente.")
print("Nota: rastreabilidade requer uso consistente de tags [gen: ai] nos commits.\n")
if __name__ == "__main__":
commits = get_commit_history(days=90)
analysis = analyze_dependency(commits)
print_report(analysis, threshold=0.5)
// docs/ai-code-acceptance-protocol.md (template em comentário Go para referência)
/*
PROTOCOLO DE ACEITAÇÃO DE CÓDIGO GERADO POR LLM
Antes de fazer commit de código substancialmente gerado por LLM,
responda estas perguntas. Se não consegue responder, o código
ainda não está suficientemente compreendido.
1. COMPORTAMENTO
Q: O que este código faz quando chamado com input válido?
Q: O que acontece com input inválido ou borda?
Q: Existe estado que persiste entre chamadas? Qual é ele?
2. INVARIANTES
Q: Qual invariante este código mantém ou satisfaz?
Q: Existe alguma condição que deve ser verdadeira antes de
chamar este código (pré-condição)?
Q: Existe alguma condição garantida após a execução (pós-condição)?
3. FALHAS
Q: Quais erros este código pode retornar?
Q: O que acontece com recursos alocados (conexões, arquivos,
goroutines) se um erro ocorre?
Q: A operação pode ser retentada com segurança se falhar?
4. INTEGRAÇÃO
Q: Quais outros componentes do sistema este código toca?
Q: Existe alguma assunção sobre o comportamento desses
componentes que pode não valer no nosso ambiente?
Q: Se o sistema escalar 10x, este código ainda funcionará?
5. MANUTENÇÃO
Q: Se eu precisar modificar este código daqui a 6 meses
sem me lembrar do contexto atual, o que eu precisaria saber?
Q: Onde está a documentação do comportamento esperado
(teste, spec, ou comentário com o "por quê")?
Assinatura: ____________ Data: ____________
(Para código em áreas críticas de negócio ou segurança)
*/
// Exemplo de função aceita com protocolo documentado:
// AcceptedVia: protocolo AI-acceptance v1, respondido por @dev em 2026-05-01
// Entendimento documentado: ver comentário em PR #247
func ProcessPayment(ctx context.Context, req PaymentRequest) (PaymentResult, error) {
// implementação gerada por LLM, revisada e aceita após protocolo
}
A posição correta: nem evangelho nem negação
Os riscos catalogados neste conceito não constituem um argumento contra o uso de LLMs em engenharia — constituem o mapa de onde o cuidado é necessário. A posição de engenheiro sênior não é evangélica ("LLMs são transformadores, use sempre") nem negacionista ("LLMs são perigosos, não use"). É a posição analítica: entenda a ferramenta, conheça seus limites, use onde agrega valor, não use onde o custo supera o benefício, e estabeleça os controles adequados ao nível de risco.
Equipes que adotam LLMs com esse mapa de riscos em mente conseguem extrair o ganho de velocidade enquanto evitam as armadilhas que transformam velocidade de curto prazo em dívida de médio prazo. Equipes que adotam sem esse mapa frequentemente chegam, depois de 6 a 12 meses, à conclusão de que "LLMs criaram mais problemas do que resolveram" — quando na verdade o problema não foi o LLM, foi a ausência de processo adequado.
Exercícios práticos
- Auditoria de dependência: Implemente a convenção de rastreabilidade de LLM no seu projeto (tag de commit ou Co-authored-by). Após 4 semanas, rode o script de análise de dependência (ou equivalente manual). Para cada desenvolvedor com taxa acima de 50%, discuta em 1:1 quais habilidades estão sendo exercitadas independentemente e planejem sessões de prática deliberada sem LLM.
- Teste de compreensão: Escolha três arquivos do seu projeto que foram substancialmente gerados por LLM. Para cada um, aplique o protocolo de aceitação — responda todas as perguntas de compreensão. Para as perguntas que não consegue responder, documente e estude o código até conseguir. Meça o tempo investido: esse é o custo da compreensão que foi omitida quando o código foi aceito.
- Inventário de sensibilidade: Mapeie o código do seu projeto em categorias de sensibilidade para uso de LLMs comerciais: pode submeter livremente, pode submeter com cuidado (remover dados reais), não deve submeter (algoritmos proprietários, código de segurança crítica). Documente esse inventário e distribua para o time. Identifique os casos onde a política atual do time está inconsistente com a categorização.
Referências e leitura complementar
- artigo Do Users Write More Insecure Code with AI Assistants? — Sandoval et al. (2022).
- artigo An Empirical Study of the Impact of AI Coding Tools on Developer Productivity and Code Quality — GitClear (2024).
- artigo The Skilling Paradox: How AI Tools Affect Developer Learning — IEEE Software (2024).
- artigo GitHub Copilot's Influence on Code Quality — Kalliamvakou (2023).
- artigo Generative AI and Intellectual Property Rights — WIPO (2024).
- artigo Privacy Considerations for AI-Assisted Development — IAPP (2024).
- artigo Security Vulnerabilities in AI-Generated Code — Pearce et al. (2022).
- livro The Design of Everyday Things — Norman (1988, rev. 2013).
- artigo Ironies of Automation — Bainbridge (1983).
- artigo Is "Stochastic Parrots" a Good Description of LLMs? — Bender et al. (2021).
- artigo ChatGPT Incorrectness Detection Is Hard — Huang et al. (2023).
- artigo The Costs of Overconfidence in AI — AI Now Institute (2023).