---
title: "API Alucinada"
type: "ai-smell"
slug: "hallucinated-api"
url: "http://localhost:3000/pt-br/ai-smells/hallucinated-api.md"
category: "Corretude"
description: "Código gerado por IA que chama funções, métodos, parâmetros, chaves de configuração ou pacotes que parecem plausíveis, mas que não existem na versão real da biblioteca da qual você depende."
---
# API Alucinada

> Código gerado por IA que chama funções, métodos, parâmetros, chaves de configuração ou pacotes que parecem plausíveis, mas que não existem na versão real da biblioteca da qual você depende.

## Signs and Symptoms

Um revisor identifica uma API Alucinada quando o código lê de forma fluente e "parece" um uso idiomático de uma biblioteca, mas a chamada, opção ou importação específica não pode ser encontrada na superfície real dessa biblioteca. Sinais reveladores:

* Um método ou opção cujo nome é _conveniente demais_ — faz exatamente o que o prompt pediu, com um nome que mescla duas APIs reais (por exemplo, `findLastWhere`, `includesAll`, `parseDateSafe`).
* **Parâmetros** inventados em uma função real (a variante perigosa — muitas vezes compila e só falha em tempo de execução, ou ignora silenciosamente a opção).
* Um `import` de um pacote que não está no `package.json` / `requirements.txt`, ou uma importação nomeada que o módulo nunca exporta.
* Formatos de API que misturam versões: uma assinatura da v2 chamada em um cliente v5, ou um método removido/renomeado várias releases atrás.
* Comentários inline confiantes afirmando que a chamada está correta ("// retorna a cobrança reembolsada").

```js
// Gerado por IA — fluente, plausível e errado
import { formatRelative } from 'date-fns';

// `roundingMethod` é inventado — date-fns não expõe tal opção, ela é silenciosamente ignorada
const label = formatRelative(date, new Date(), { roundingMethod: 'floor' });

// `findLastWhere` não existe em Array — TypeError em tempo de execução
const lastActive = items.findLastWhere(i => i.active);

// Chamada de SDK mesclada: o formato real do Stripe é stripe.refunds.create({ charge })
await stripe.charges.refund(chargeId, { amount: 500 });

```

Uma heurística rápida: se você não consegue apontar a entrada na documentação ou a definição de tipo de uma chamada de terceiros em menos de um minuto, trate-a como alucinada até prova em contrário.

## Reasons for the Problem

**Por que os modelos a produzem**

* **Plausibilidade do próximo token, não consulta.** Um LLM prevê a continuação estatisticamente mais provável, que é efetivamente a _média_ de cada API similar que ele já viu. Essa média muitas vezes é um método que _deveria_ existir — o modelo emite "o nome conveniente" em vez do real. Estudos de recomendação de API constatam que **58,1%–84,1% das APIs recomendadas não existem no pacote nomeado**, e o erro dominante são nomes de métodos inexistentes ([arXiv 2404.00971](https://arxiv.org/pdf/2404.00971), [ACM TOSEM 2025](https://dl.acm.org/doi/pdf/10.1145/3728894)).
* **Mistura de versões.** Os corpora de treinamento misturam muitas versões de uma biblioteca, então o modelo funde assinaturas da v2 e da v5 em uma que não corresponde a nenhuma. Essas "Alucinações por Conflito de Conhecimento" (por exemplo, parâmetros inexistentes) são especificamente o tipo que **passa despercebido pelos linters e falha em tempo de execução**.
* **Defasagem do corte de treinamento.** O modelo usa com confiança APIs renomeadas, descontinuadas ou removidas desde seu corte, e recorre ao que mais apareceu no corpus — o que, como a OX Security observa, significa que **versões de pacotes mais antigas, às vezes vulneráveis, acabam sendo recomendadas** ([relatório OX, out/2025](https://www.ox.security/blog/ai-code-security-common-threats-and-best-practices-for-securing-ai-generated-code/)).
* **Sem contexto de repositório/dependência.** Sem o seu `package.json` ou o código-fonte real do módulo, o modelo inventa helpers que "parecem" pertencer à sua stack.
* **Bajulação / ânsia por responder.** O assistente quase nunca diz "não tenho certeza de que esse método existe" — ele produz código confiante e com aparência executável, o que reduz a suspeita do revisor.
* **O determinismo o torna explorável.** A alucinação de pacotes não é ruído aleatório: em 16 modelos e 2,23M de gerações, **19,7% dos pacotes recomendados eram fictícios (205.474 nomes únicos), e 58% das alucinações se repetiram em até 10 novos prompts** ([USENIX Security 2025; resumo da SecurityWeek](https://www.securityweek.com/ai-hallucinations-create-a-new-software-supply-chain-threat/)).

**Por que isso prejudica**

* **Correção.** Parâmetros inventados e opções silenciosamente ignoradas produzem comportamento errado em caminhos de código que os testes raramente cobrem; a falha aparece em produção, não em tempo de compilação.
* **Segurança / cadeia de suprimentos.** Um nome de pacote alucinado é um alvo de registro: atacantes publicam malware sob o nome previsto, então o próximo desenvolvedor que aceitar a sugestão o instala — o ataque de **slopsquatting** (termo cunhado por Seth Larson, da PSF). A variante de obsolescência reintroduz silenciosamente APIs descontinuadas ou portadoras de CVEs.
* **Carga de revisão.** Código plausível transfere o ônus para os revisores, que precisam verificar cada chamada desconhecida contra a documentação; a prosa fluente torna essa verificação _menos_ provável de acontecer.
* **Acúmulo de dívida técnica.** Os desenvolvedores muitas vezes colam o stub alucinado "quase funcional" e remendam ao redor dele em vez de corrigir a chamada-raiz — alimentando a tendência mais ampla da era da IA de aumento de copy/paste e queda de refatoração ([GitClear 2025: clones em alta \~8×, linhas movidas por refatoração caindo de 25% para <10%](https://www.gitclear.com/ai%5Fassistant%5Fcode%5Fquality%5F2025%5Fresearch)). Esse padrão já está catalogado entre os code smells específicos de IA ([arXiv 2509.20491](https://arxiv.org/abs/2509.20491)).

## Treatment

**Táticas de processo & prompting**

* **Fundamente o modelo em superfícies reais.** Cole no contexto os stubs de tipo reais, a página de documentação relevante ou o código-fonte da versão instalada, ou use uma ferramenta de recuperação de documentação (estilo Context7 / RAG). Informe a ele as versões _exatas_ das dependências a partir do seu lockfile.
* **Exija citações.** Peça ao modelo que nomeie a entrada oficial da documentação ou a assinatura de tipo de cada chamada de terceiros que ele usar. Regra prática dos praticantes: _toda chamada de método contra uma biblioteca de terceiros deve ser rastreada até sua entrada na documentação antes de o PR ser aprovado._
* **Faça rodar, no loop.** Exija que `tsc` / `mypy` / `pylint` / o build e a suíte de testes passem, e faça o agente de fato executar `npm install` / `pip install` para que um pacote alucinado falhe cedo em vez de chegar à revisão.
* **Peça que ele reutilize, não invente.** Forneça um `grep` do módulo existente e instrua-o a chamar helpers existentes (`reutilize os helpers em utils/http.ts`) em vez de conjurar novos — isso também combate o smell relacionado de duplicação por _helper reinventado_.
* **Controle as dependências.** Use um lockfile + uma allowlist de instalação e um scanner de cadeia de suprimentos (Socket/Snyk) antes que qualquer novo pacote seja adicionado, para que nomes vítimas de slopsquatting não consigam se infiltrar.

**A refatoração do código**

Substitua a chamada inventada pela real e verificada. Se você realmente quer a conveniência que o modelo imaginou, implemente-a uma vez contra a API real por trás de um wrapper de **Extrair Função**, em vez de espalhar a chamada falsa.

```ts
// Antes — parâmetro alucinado + formato de SDK mesclado
async function refundLast(chargeId: string) {
  // `stripe.charges.refund` e este formato de opção não existem
  return stripe.charges.refund(chargeId, { amount: 500, reason: 'requested' });
}

// Depois — verificado contra os tipos/documentação do SDK do Stripe instalado,
// e a "conveniência" encapsulada uma vez para que a API real não seja repetida
async function refundCharge(chargeId: string, amountCents: number) {
  return stripe.refunds.create({
    charge: chargeId,
    amount: amountCents,
    reason: 'requested_by_customer',
  });
}

```

Para a variante de obsolescência, trate uma chamada descontinuada sinalizada como uma tarefa real de atualização: migre para a API atual e fixe a versão, em vez de silenciar o aviso.

**Limites.** Verificadores de tipo e resolvedores capturam o subconjunto _resolvível_ (objetos tipados, importações não resolvidas). O restante dinâmico/não tipado — opções inventadas em `any`, chaves de configuração em string, campos de payload REST — **não tem detector automatizado confiável** e precisa ser verificado por um humano contra a documentação real.

## Detected by

- **eslint-plugin-import** `import/no-unresolved` — Importação não resolvida (https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unresolved.md)
- **eslint-plugin-import** `import/named` — Exportação nomeada inexistente (https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/named.md)
- **typescript-eslint** `@typescript-eslint/no-deprecated` — Uso de API descontinuada (real, porém obsoleta) (https://typescript-eslint.io/rules/no-deprecated/)
- **Pylint** `no-member (E1101)` — Acesso a membro indefinido (https://pylint.readthedocs.io/en/stable/user_guide/messages/error/no-member.html)
- **mypy** `attr-defined` — Atributo/método não definido no tipo (https://mypy.readthedocs.io/en/stable/error_code_list.html#check-that-attribute-exists-attr-defined)
