Documentação como Efeito Colateral: Arquitetando Pipelines de Docs Geradas por IA que Não Mentem
Existe um cenário que se repete em praticamente toda empresa que adotou geração de documentação com IA sem pensar em arquitetura: alguém roda um comando, um LLM lê o código, produz um markdown bonito, o time comemora, faz commit, e seis meses depois aquele documento descreve uma API que já foi refatorada três vezes. Ninguém percebeu porque a documentação “existia” — só não era mais verdade. O problema não é a IA ter gerado algo errado no momento zero. É que ninguém desenhou um mecanismo para que a documentação continuasse correta quando o código mudasse. Você trocou o problema “documentação inexistente” pelo problema, mais sutil e mais perigoso, “documentação obsoleta com aparência de autoridade”.
Esse é o ponto cego de quase todo tutorial de “gere docs com IA em 5 minutos”: eles resolvem a geração, não o ciclo de vida. Para quem já vive esse problema em produção, a pergunta relevante não é “como peço para o Claude documentar essa função”, mas “que arquitetura garante que a documentação gerada por IA continue confiável daqui a um ano, sem revisão manual constante”. É isso que vamos desenhar aqui: um pipeline de documentação viva, com verificação automática, versionamento semântico de conteúdo e pontos de falha explícitos — não mais um passo a passo de prompt engineering.
O erro de modelo mental: documentação como artefato, não como processo
A maior parte das ferramentas de “AI docs” trata documentação como um artefato gerado uma vez: você aponta para um repositório, ela cospe um README ou um conjunto de páginas, fim. Isso funciona bem para demos e mal para sistemas que evoluem em produção. O modelo mental correto é tratar documentação como um build target — algo que é recompilado a partir do código-fonte sempre que este muda, exatamente como você recompila um binário.
Isso muda completamente as decisões de arquitetura:
- Documentação vira saída determinística de uma pipeline, não um texto solto mantido por convenção humana.
- O “source of truth” nunca é o markdown gerado — é sempre o código, os tipos, os testes e os contratos (OpenAPI, protobuf, JSON Schema).
- Toda divergência entre docs e código deve ser detectável por máquina, não por revisão visual de PR.
💡 Dica do Mestre: o conceito de “docs as code” — tratar documentação com o mesmo rigor de versionamento, revisão e CI que se aplica a software — é discutido em profundidade por Anne Gentle em Docs Like Code. A tese central: documentação que não passa por pipeline de build e teste automaticamente decai. IA não elimina essa lei, apenas muda quem escreve o primeiro rascunho.
Arquitetura em três camadas: geração, verificação e publicação
Uma pipeline madura de documentação assistida por IA separa claramente três responsabilidades que costumam ser misturadas em soluções ingênuas:
1. Camada de geração
Responsável por produzir o conteúdo textual a partir do código-fonte, assinaturas de função, comentários estruturados e, idealmente, exemplos de uso extraídos de testes reais. Aqui entra o LLM.
2. Camada de verificação
Responsável por validar que o que foi gerado corresponde ao estado atual do código: assinaturas batem, exemplos de código compilam e executam, links internos resolvem, parâmetros documentados existem de fato na função.
3. Camada de publicação
Responsável por versionar, indexar e disponibilizar o conteúdo — site estático, portal interno, ou injeção em um índice de RAG para atendimento e onboarding.
A falha mais comum é pular a camada 2 inteiramente. É ela que transforma “documentação gerada por IA” em “documentação confiável gerada por IA”. Sem verificação, você está apenas automatizando a produção de alucinação plausível em escala.
Passo a passo: construindo a camada de geração com contexto estrutural
O erro clássico é jogar arquivos de código inteiros para o modelo e pedir “documente isso”. Funciona mal em bases grandes porque o modelo perde o contexto de contratos externos (quem chama essa função, o que espera como retorno, quais invariantes existem). A abordagem que escala é gerar contexto estruturado primeiro, depois delegar apenas a redação para a IA.
Exemplo em TypeScript, extraindo metadados via AST antes de acionar o modelo:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// extract-context.ts import { Project } from "ts-morph"; const project = new Project({ tsConfigFilePath: "tsconfig.json" }); const sourceFile = project.getSourceFileOrThrow("src/billing/invoice.ts"); const functions = sourceFile.getFunctions().map((fn) => ({ name: fn.getName(), params: fn.getParameters().map((p) => ({ name: p.getName(), type: p.getType().getText(), })), returnType: fn.getReturnType().getText(), jsDoc: fn.getJsDocs().map((d) => d.getText()), callers: fn.findReferencesAsNodes().length, })); console.log(JSON.stringify(functions, null, 2)); |
Esse JSON estruturado — não o arquivo bruto — é o que você envia ao modelo. O prompt fica objetivo e ancorado em fatos verificáveis, reduzindo drasticamente a superfície de alucinação:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import anthropic client = anthropic.Anthropic() def generate_doc(function_metadata: dict) -> str: prompt = f""" Você é um redator técnico. Gere documentação em formato JSDoc estritamente baseada nos metadados abaixo. Não invente parâmetros, comportamentos ou exemplos que não possam ser inferidos dos tipos. Se não houver informação suficiente para descrever o comportamento, escreva "TODO: descrição pendente de revisão humana". Metadados: {function_metadata} """ response = client.messages.create( model="claude-sonnet-4-5", max_tokens=500, messages=[{"role": "user", "content": prompt}], ) return response.content[0].text |
Repare na instrução explícita para admitir incerteza. Isso é decisão de arquitetura, não estilo de prompt: você está desenhando um sistema que prefere lacunas visíveis a preenchimento confiante e falso. Um “TODO” é um sinal barato de resolver depois; uma descrição de comportamento inventada é uma mina que vai explodir na produção de outra pessoa.
Camada de verificação: o que a maioria das soluções de mercado ignora
É aqui que a arquitetura séria se separa da demo de conferência. Três verificações mínimas que qualquer pipeline de docs-por-IA deveria ter:
Verificação de assinatura
Compare os parâmetros documentados contra a assinatura real extraída via AST ou reflection. Um script simples de diff resolve grande parte dos casos:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
def verify_signature(documented_params: list[str], actual_params: list[str]) -> list[str]: missing = set(actual_params) - set(documented_params) extra = set(documented_params) - set(actual_params) errors = [] if missing: errors.append(f"Parâmetros não documentados: {missing}") if extra: errors.append(f"Parâmetros documentados mas inexistentes: {extra}") return errors |
Verificação de exemplos executáveis
Todo exemplo de código dentro da documentação deve ser extraído e executado como teste. Ferramentas como doctests do Rust já resolvem isso nativamente há anos — a lição vale para qualquer stack: se o exemplo não roda, o build quebra.
Para linguagens sem suporte nativo, você constrói isso com um extrator simples de blocos de código com marcação especial:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# extract_examples.py import re import subprocess def extract_code_blocks(markdown_path: str) -> list[str]: content = open(markdown_path).read() return re.findall(r"```python\n(.*?)```", content, re.DOTALL) def run_example(code: str) -> bool: result = subprocess.run( ["python", "-c", code], capture_output=True, timeout=10, ) return result.returncode == 0 for block in extract_code_blocks("docs/billing.md"): if not run_example(block): raise SystemExit("Exemplo de documentação falhou na execução") |
Verificação de deriva semântica
Mais avançada e mais cara: usar um segundo modelo para comparar a descrição de comportamento documentada contra o comportamento observado em testes existentes, sinalizando divergências para revisão humana em vez de aprovação automática. Esse é o mesmo princípio discutido no problema do “aprovador automático” em code review — nunca deixe a IA ser juiz e réu do próprio trabalho sem um humano no laço para casos ambíguos.
Integrando ao CI: documentação quebra o build, não é sugestão
A decisão de arquitetura mais importante é tratar falha de documentação com a mesma severidade de falha de teste. Um exemplo de pipeline com GitHub Actions:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
name: docs-verify on: pull_request: paths: - "src/**" - "docs/**" jobs: verify-docs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.12" - run: pip install -r requirements-docs.txt - name: Extrair contexto do código run: python scripts/extract_context.py - name: Gerar documentação run: python scripts/generate_docs.py - name: Verificar assinaturas run: python scripts/verify_signature.py - name: Executar exemplos documentados run: python scripts/extract_examples.py - name: Bloquear merge se houver TODO não resolvido run: | if grep -r "TODO: descrição pendente" docs/; then echo "Documentação incompleta detectada" exit 1 fi |
Note a última etapa: ela é uma escolha deliberada de política de qualidade, não uma verificação técnica. Times sérios decidem, como regra de negócio, que documentação incompleta bloqueia merge. Isso é caro no curto prazo e evita a acumulação silenciosa de dívida documental — o mesmo trade-off que se aplica a cobertura de testes mínima obrigatória.
Casos difíceis que a documentação oficial das ferramentas não menciona
Código com efeitos colaterais implícitos
LLMs são excelentes em descrever o que uma função retorna, e sistematicamente ruins em capturar efeitos colaterais não explícitos na assinatura — uma função que parece pura, mas dispara um evento assíncrono, grava em cache ou modifica estado global. Nenhuma verificação de assinatura pega isso. A mitigação prática é convenção de código: efeitos colaterais devem ser sinalizados explicitamente via nomenclatura ou anotação (@sideEffect, sufixo _mut, etc.), porque a IA só documenta bem o que o código já expõe estruturalmente.
APIs versionadas com comportamento condicional
Quando uma função se comporta diferente dependendo de feature flags ou de versão de configuração, a documentação gerada automaticamente tende a descrever apenas o caminho “feliz” mais comum no código analisado. Isso exige uma camada adicional: gerar documentação por variante de configuração, não uma única passada genérica. Trata-se de mais engenharia de pipeline, não de melhor prompt.
Deriva entre documentação pública e código privado interno
Times que documentam APIs públicas a partir de contratos como OpenAPI têm vantagem estrutural aqui: o contrato já é a fonte de verdade, e a IA só precisa gerar prosa a partir dele — não inferir comportamento a partir de implementação, que é uma tarefa fundamentalmente mais sujeita a erro.
💡 Dica do Mestre: sempre que possível, inverta a ordem: escreva o contrato formal (OpenAPI, protobuf, JSON Schema) primeiro, gere a implementação e a documentação como duas saídas independentes do mesmo contrato. Isso elimina a classe inteira de erros em que docs e código divergem, porque ambos derivam da mesma fonte — o mesmo princípio central por trás de spec driven development.
Custo de manutenção: o que ninguém calcula antes de adotar
Pipelines de documentação automática não são gratuitas depois de montadas. Existem três custos recorrentes que precisam entrar na decisão de arquitetura desde o início:
- Custo de tokens em CI: gerar documentação a cada PR que toca código relevante tem custo direto de API. Em bases grandes, isso justifica gerar apenas para o diff, não para o arquivo inteiro — reduz custo e reduz risco de o modelo reescrever contexto que já estava correto.
- Custo de falso positivo: verificações de assinatura rígidas demais bloqueiam PRs legítimos por mudanças triviais de formatação. É preciso calibrar tolerância — normalização de tipos antes de comparar, por exemplo.
- Custo de revisão humana residual: mesmo com pipeline robusto, decisões de nuance semântica (“essa função é thread-safe?”) continuam exigindo revisão humana pontual. A pipeline reduz o volume dessa revisão, não a elimina.
Quando esse custo total supera o custo de manter documentação manual disciplinada em times pequenos, a automação não vale a pena. A decisão correta depende de escala: equipes com dezenas de serviços e rotatividade de pessoas se beneficiam enormemente; um time de três pessoas em um monólito estável pode preferir disciplina manual com revisão em PR.
Quando não vale a pena automatizar
Vale ser honesto sobre os limites. Documentação gerada automaticamente tende a ser fraca em três cenários específicos:
- Decisões arquiteturais e trade-offs (ADRs): um LLM pode descrever o que o código faz, mas não sabe por que uma decisão foi tomada em detrimento de outra, a menos que essa justificativa já esteja registrada em algum lugar. ADRs continuam sendo trabalho humano.
- Guias de onboarding narrativos: a sequência pedagógica ideal para ensinar um sistema complexo a uma pessoa nova raramente coincide com a estrutura do código-fonte. Isso exige curadoria humana de narrativa.
- Documentação de intenção de negócio: “por que esse desconto é aplicado antes do imposto e não depois” é uma regra de negócio, não uma inferência de tipo.
A arquitetura correta reconhece essa fronteira: documentação de referência técnica (parâmetros, retornos, exemplos) é candidata forte à automação total. Documentação de intenção e arquitetura continua sendo trabalho humano, no máximo assistido por IA como redator, nunca como fonte de verdade.
Aprofunde essa discussão com quem já enfrentou esses problemas em produção
Arquitetar pipelines de documentação que sobrevivem a refatorações, mudanças de equipe e anos de manutenção é um problema de engenharia, não de prompt. Se você quer trocar experiências reais sobre isso — o que funcionou, o que quebrou em produção, como outras equipes calibraram o trade-off entre automação e revisão humana — entre na Comunidade Dev’s AI. É um espaço de desenvolvedores seniores discutindo arquitetura de sistemas com IA aplicada, sem o superficialismo dos tutoriais de “gere isso em 5 minutos”.
Conclusão
Documentação gerada por IA sem arquitetura de verificação é apenas dívida técnica com boa aparência tipográfica. O valor real não está na capacidade do modelo de escrever prosa fluente sobre uma função — isso qualquer LLM moderno faz bem. O valor está no pipeline que garante que essa prosa continue verdadeira depois que três engenheiros diferentes tiverem mexido naquele código seis meses depois. Trate documentação como build target, separe geração de verificação, torne divergência um erro de CI e reserve para humanos o que só humanos sabem: por que as decisões foram tomadas. Feito assim, a IA deixa de ser um gerador de texto plausível e passa a ser o que ela deveria ter sido desde o início — uma parte confiável da sua esteira de entrega de software.