12 papers de IA que mudaram tudo: explicação detalhada com exemplos
1. Visão geral
A maioria dos sistemas de IA que você usa todos os dias — ChatGPT, Midjourney, Google Search com AI Overview — ficam de pé nos ombros de cerca de uma dúzia de papers de pesquisa. Este artigo passa por esses 12 papers, explica as ideias centrais em linguagem fácil de entender, e ilustra cada ideia com um trecho de código Java curto. Após ler, você entenderá por que Transformer “dominou” todo o mundo do NLP, por que RAG consegue resolver hallucinations, e por que um prompt “vamos pensar passo a passo” é tão poderoso.
2. AlexNet (2012) — deep learning começa a “enxergar”
Antes do AlexNet, visão computacional era baseada em engenharia manual de features. AlexNet usou convolutional neural network (CNN) com ativação ReLU e dropout, treinado em GPU, e derrotou todos os concorrentes no ImageNet 2012 com erro quase 10 pontos percentuais menor. Este foi o boom que marcou o início da era do deep learning.
public class ConvOutputSizeCalculator {
public static int outputSize(int inputSize, int kernelSize, int stride, int padding) {
return (inputSize - kernelSize + 2 * padding) / stride + 1;
}
public static void main(String[] args) {
// Imagem de entrada do AlexNet: 227x227, kernel 11x11, stride 4
int size = outputSize(227, 11, 4, 0);
System.out.println(size);
}
}
55
outputSize calcula o tamanho do feature map após uma camada conv. Com entrada 227×227 e kernel 11×11 stride 4, a saída é 55×55×96 — exatamente o tamanho da primeira camada do AlexNet. ReLU ajuda o gradiente a não “morrer” como em sigmoid, então redes mais profundas ainda conseguem treinar.
3. GAN (2014) — duas redes em confronto para gerar imagens realistas
Generative Adversarial Network coloca duas redes em posição de confronto: o gerador tenta criar imagens falsas para enganar o discriminador, e o discriminador tenta distinguir imagens reais/falsas. Ambos melhoram a cada rodada de treinamento.
public record GanLosses(double discriminatorLoss, double generatorLoss) {}
public class GanLossCalculator {
public static GanLosses compute(double probReal, double probFake) {
double dLoss = -(Math.log(probReal) + Math.log(1 - probFake));
double gLoss = -Math.log(probFake);
return new GanLosses(dLoss, gLoss);
}
}
probReal é a probabilidade do discriminador adivinhar corretamente a imagem real, probFake é a probabilidade de ser enganado pelo gerador. O discriminador quer probReal → 1 e probFake → 0; o gerador quer o oposto. Este é um jogo de soma zero típico.
Lembrete: GAN é famoso por ser difícil de treinar — é fácil encontrar mode collapse (o gerador cria apenas alguns tipos de imagens repetidas). Modelos de difusão posteriores são muito mais estáveis, então a maioria dos sistemas modernos de geração de imagens (DALL·E, Stable Diffusion) não usam mais GAN.
4. Transformer (2017) — “Attention Is All You Need”
Transformer abandona completamente RNN/LSTM, substituindo-os por self-attention: cada token olha diretamente para todos os outros tokens na frase para calcular relevância, sem necessidade de processamento sequencial. Esta é a arquitetura base do GPT, Claude, Llama e BERT.
public class ScaledDotProductAttention {
public static double[] attendFirstToken(double[][] query, double[][] key) {
int seqLen = key.length;
int dim = query[0].length;
double scale = Math.sqrt(dim);
double[] scores = new double[seqLen];
for (int j = 0; j < seqLen; j++) {
double dot = 0;
for (int k = 0; k < dim; k++) dot += query[0][k] * key[j][k];
scores[j] = dot / scale;
}
return softmax(scores);
}
private static double[] softmax(double[] row) {
double max = Arrays.stream(row).max().orElse(0);
double sum = 0;
double[] exps = new double[row.length];
for (int i = 0; i < row.length; i++) {
exps[i] = Math.exp(row[i] - max);
sum += exps[i];
}
for (int i = 0; i < exps.length; i++) exps[i] /= sum;
return exps;
}
}
A linha dot / scale divide o produto escalar por sqrt(dim) para evitar que valores muito grandes saturem o softmax. O resultado do softmax são os pesos de atenção — tokens que se relacionam muito com o token em questão terão pesos altos, usados para combinar os value vectors.
5. Scaling Laws (2020) — loss diminui segundo uma lei de potência
OpenAI descobriu: aumentar o número de parâmetros, dados ou compute exponencialmente faz a loss diminuir ao longo de uma curva de lei de potência bastante suave e previsível — não há “magia”, basta escalar corretamente.
public class ScalingLawEstimator {
// L(N) = (Nc / N)^alpha — N: número de bilhões de parâmetros, Nc, alpha: constantes empíricas
public static double estimateLoss(double paramsBillion, double nc, double alpha) {
return Math.pow(nc / paramsBillion, alpha);
}
}
Com nc e alpha fixos a partir de dados empíricos, aumentar paramsBillion faz estimateLoss diminuir gradualmente, mas mais lentamente (diminishing returns). Esta é a razão pela qual labs de IA investem centenas de milhões de dólares em compute: a redução de loss é previsível, não é uma aposta.
Lembrete: Scaling laws não são infinitas. Após certo ponto, para diminuir a loss um pouco mais é necessário aumentar compute exponencialmente de forma gigantesca — essa é a razão pela qual a indústria está se voltando para melhorar dados e arquitetura em vez de apenas “ficar maior”.
6. GPT-3 (2020) — escala cria novas capacidades
GPT-3 com 175 bilhões de parâmetros demonstra: se grande o suficiente, um modelo pode fazer few-shot learning — basta alguns exemplos no prompt, sem necessidade de ajustar pesos novamente.
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
@Service
public class FewShotClassifier {
private final ChatClient chatClient;
public FewShotClassifier(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
public String classifySentiment(String review) {
String prompt = """
Avaliação: "Produto bom, entrega rápida" -> Positivo
Avaliação: "Produto com defeito, não funciona" -> Negativo
Avaliação: "%s" ->
""".formatted(review);
return chatClient.prompt(prompt).call().content();
}
}
Dois exemplos no prompt servem para “ensinar” o modelo o formato da resposta diretamente no contexto — sem necessidade de treinar novamente. Esta é precisamente a habilidade emergente que modelos menores não conseguem fazer bem.
7. InstructGPT & RLHF (2022) — transformar LLM bruto em assistente útil
GPT-3 original prevê bem o próximo token, mas não “obedece” — pode responder fora do tópico ou de forma prejudicial. InstructGPT usa Reinforcement Learning from Human Feedback (RLHF): humanos classificam respostas, treinam um modelo de recompensa a partir disso, e usam o modelo de recompensa para otimizar a policy com PPO.
public record Completion(String text, double rewardScore) {}
public class RewardBasedSelector {
public Completion pickBest(List<Completion> candidates) {
return candidates.stream()
.max(Comparator.comparingDouble(Completion::rewardScore))
.orElseThrow();
}
}
O código acima apenas ilustra o passo final: selecionar a conclusão com maior recompensa de acordo com a avaliação do modelo de recompensa. Na prática, PPO atualiza os pesos do modelo de policy gradualmente para que ele gere respostas de alta pontuação desde o início, sem necessidade de filtragem posterior.
Lembrete: RLHF requer uma grande quantidade de dados rotulados por humanos (ranking), caro e tendencioso de acordo com o viés do avaliador. Técnicas como DPO (Direct Preference Optimization) surgiram depois para reduzir esse custo.
8. ViT (2020) — imagem também é uma “frase”
Vision Transformer divide a imagem em pequenos patches (por exemplo, 16×16 pixels), achata cada patch em um vetor, e os trata como tokens enviados para um encoder Transformer — a arquitetura é idêntica ao processamento de texto.
public class PatchEmbeddingCalculator {
public static int numPatches(int imageSize, int patchSize) {
int gridSize = imageSize / patchSize;
return gridSize * gridSize;
}
}
Com uma imagem 224×224 e patches 16×16, numPatches retorna 196 — equivalente a uma “frase” de 196 tokens enviada para o Transformer. Dessa forma, ViT reutiliza todas as técnicas de atenção já comprovadas em NLP para tarefas de visão, e supera CNN quando os dados de treinamento são grandes o suficiente.
9. DDPM (2020) — adicionar ruído e aprender a remover
Denoising Diffusion Probabilistic Model estabelece a base para todos os modelos de difusão modernos: o processo forward adiciona ruído Gaussiano gradualmente à imagem ao longo de muitas etapas, o processo reverse aprende a prever e remover esse ruído para reconstruir a imagem original.
public class ForwardDiffusion {
public static double[] addNoise(double[] x0, double alphaBarT, Random random) {
double[] xt = new double[x0.length];
for (int i = 0; i < x0.length; i++) {
double noise = random.nextGaussian();
xt[i] = Math.sqrt(alphaBarT) * x0[i] + Math.sqrt(1 - alphaBarT) * noise;
}
return xt;
}
}
alphaBarT controla a proporção de imagem original retida em relação ao ruído no passo t: próximo a 1 significa que ainda está perto da imagem original, próximo a 0 significa que é quase ruído puro. O modelo gerador aprende o processo inverso — começando de ruído puro, remove gradualmente o ruído a cada etapa para gerar uma imagem significativa.
10. Latent Diffusion (2021) — denoising em espaço comprimido
Executar difusão diretamente em pixels consome muito compute. Latent Diffusion comprime a imagem para um espaço latente menor usando um autoencoder, executa todo o processo de denoising lá, e depois decodifica de volta para imagem — este é o design por trás do Stable Diffusion.
public class LatentCompressionCalculator {
public static long pixelCount(int width, int height, int channels) {
return (long) width * height * channels;
}
}
pixelCount(512, 512, 3) = 786_432 // espaço de pixel
pixelCount(64, 64, 4) = 16_384 // espaço latente
A taxa de compressão de cerca de 48 vezes ajuda a difusão a rodar muito mais rápido enquanto mantém a qualidade da imagem, porque a maioria das informações “redundantes” no espaço de pixel (áreas de cor uniforme, pequenos detalhes) foram removidas pelo autoencoder durante a compressão.
11. CLIP (2021) — ligar imagem e texto em um espaço comum
CLIP treina aprendizado contrastivo em centenas de milhões de pares (imagem, caption): pares corretos têm embeddings próximos, pares incorretos têm embeddings distantes. O resultado é um espaço comum que permite comparar texto e imagem usando similaridade do cosseno.
@Service
public class ImageTextMatcher {
private final EmbeddingModel embeddingModel;
public ImageTextMatcher(EmbeddingModel embeddingModel) {
this.embeddingModel = embeddingModel;
}
public double similarity(String caption, float[] imageEmbedding) {
float[] textEmbedding = embeddingModel.embed(caption);
return cosine(textEmbedding, imageEmbedding);
}
private double cosine(float[] a, float[] b) {
double dot = 0, normA = 0, normB = 0;
for (int i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
}
}
similarity retorna um valor próximo a 1 se a legenda corresponde ao conteúdo da imagem, próximo a 0 ou negativo se não estiver relacionada. Este é o mecanismo por trás da busca de imagens por descrição de texto natural (text-to-image search) que muitos produtos de e-commerce estão usando.
12. Chain-of-Thought (2022) — uma frase de prompt libera o raciocínio
Basta adicionar a frase “vamos pensar passo a passo” ao prompt, e LLMs grandes automaticamente quebram o problema complexo em passos pequenos, reduzindo significativamente erros de cálculo e lógica em comparação com respostas diretas.
public String solveWithReasoning(ChatClient chatClient, String question) {
String prompt = """
Vamos pensar passo a passo antes de responder.
Pergunta: %s
Raciocínio:
""".formatted(question);
return chatClient.prompt(prompt).call().content();
}
Pedir ao modelo para “raciocinar” antes de finalizar a resposta força a gerar tokens intermediários que servem como suporte — assim como as pessoas rabiscam antes de responder uma pergunta difícil.
Lembrete: Chain-of-Thought aumenta o número de tokens gerados, resultando em custo e latência mais altos. Para perguntas simples (busca de fato direto), forçar CoT apenas torna mais lento sem melhorar a precisão.
13. RAG (2020) — recuperar depois gerar, sem mais invenção
Retrieval-Augmented Generation acopla um LLM com uma etapa de recuperação de documentos reais antes de gerar a resposta, ajudando a reduzir alucinações e permitindo respostas baseadas em dados atualizados fora do escopo de treinamento original.
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pgvector-store-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
@Service
public class DocumentAnsweringService {
private final VectorStore vectorStore;
private final ChatClient chatClient;
public DocumentAnsweringService(VectorStore vectorStore, ChatClient.Builder builder) {
this.vectorStore = vectorStore;
this.chatClient = builder.build();
}
public String answer(String question) {
List<Document> relevant = vectorStore.similaritySearch(
SearchRequest.query(question).withTopK(3));
String context = relevant.stream()
.map(Document::getContent)
.collect(Collectors.joining("\n---\n"));
String prompt = """
Com base nos documentos a seguir, responda à pergunta. Se não houver informação, diga "Não sei".
Documentos:
%s
Pergunta: %s
""".formatted(context, question);
return chatClient.prompt(prompt).call().content();
}
}
similaritySearch recupera os 3 trechos de documentos mais semanticamente próximos da pergunta, insere-os no prompt como contexto, e força o modelo a responder baseado nesse contexto em vez de “lembrar” vagamente do treinamento.
class DocumentAnsweringServiceTest {
@Test
void shouldReturnUnknownWhenNoRelevantDocument() {
VectorStore emptyStore = mock(VectorStore.class);
when(emptyStore.similaritySearch(any())).thenReturn(List.of());
ChatClient stubClient = mock(ChatClient.class, RETURNS_DEEP_STUBS);
when(stubClient.prompt(anyString()).call().content()).thenReturn("Não sei");
ChatClient.Builder builder = mock(ChatClient.Builder.class);
when(builder.build()).thenReturn(stubClient);
DocumentAnsweringService service = new DocumentAnsweringService(emptyStore, builder);
String result = service.answer("Quando a empresa foi fundada?");
assertThat(result).contains("Não sei");
}
}
O teste confirma que quando nenhum documento relevante é encontrado, a resposta deve admitir “Não sei” em vez de inventar uma resposta — exactamente o objetivo de grounding do RAG.
Lembrete: Se seu repositório de documentos tiver apenas algumas dezenas de páginas, colocar tudo diretamente na janela de contexto é mais simples e barato do que construir um pipeline RAG completo com vector store. RAG só vale a pena usar quando os dados são grandes ou mudam frequentemente.
14. Conclusão
Esses 12 papers não são independentes — eles se constroem um sobre o outro: Transformer é a base para GPT-3 e ViT; scaling laws explicam por que GPT-3 funciona; RLHF transforma GPT-3 em ChatGPT; DDPM é a base do Latent Diffusion; CLIP é a ponte para que modelos de difusão entendam prompts de texto. Entender cada peça do quebra-cabeça ajuda você a ler novos papers mais rapidamente, porque a maioria das ideias “novas” atualmente são variações ou combinações dessas bases.