Pular para o conteúdo
mnzes

Como o DSPy otimiza um prompt?

PorDiógenes MenezesAprendendo IA em público

13 min de leitura

Compilar, no DSPy, é procurar a melhor combinação de texto de instrução e exemplos para cada módulo do seu programa. O compilador propõe candidatos, roda o programa inteiro no seu conjunto de casos, pontua cada saída pela sua métrica e fica com o que pontuou melhor. Nenhum peso é alterado: o que muda é o texto que chega ao modelo.

A palavra “compilar” é uma analogia e cobra atenção. Um compilador de linguagem faz uma tradução determinística; este faz uma busca guiada por medição, e o resultado depende da amostra. Rodar duas vezes pode dar dois prompts diferentes, e os dois podem estar certos.

Este artigo é a mecânica por dentro do que o DSPy chama de compilação. Tudo aqui pressupõe um conjunto de avaliação com métrica automática, e a família mais recente de otimizadores, da qual o GEPA é o exemplo de 2025, muda a forma de propor candidatos sem mudar essa dependência.

O laço

propor candidatos(instrução e exemplos)rodar o programano conjuntopontuar cada saídapela sua métricamanter os melhorese descartar o restopropõe a partir do que pontuou
Figura 1O laço é banal e a métrica é o que o torna útil. A seta de retorno é a diferença entre busca cega e busca informada: a proposta seguinte usa as notas anteriores.

O laço tem quatro passos e nenhum deles é sofisticado.

Propor. O otimizador monta candidatos. Um candidato é um par: o texto da instrução de um módulo e o conjunto de demonstrações que acompanha esse módulo. Em um programa de três módulos, o candidato é uma escolha por módulo, e o espaço cresce multiplicativamente.

Rodar. O programa inteiro é executado nos casos do conjunto com aquele candidato aplicado.

Pontuar. A sua função de métrica recebe o exemplo e a saída e devolve um número, ou um booleano. Ela é o único juízo de valor no processo.

Manter. Os candidatos com nota melhor sobrevivem e alimentam a proposta seguinte.

A seta de retorno é o que separa isso de amostragem aleatória. Nos otimizadores que propõem instrução, o modelo que gera a próxima proposta recebe as tentativas anteriores com as notas correspondentes. Essa ideia foi formulada em 2023 como usar o próprio modelo de linguagem como otimizador: você alimenta o modelo com as soluções já avaliadas e suas pontuações, e pede as próximas1.

De onde vêm os exemplos

O nome que aparece na documentação e nos tutoriais é bootstrap, e a mecânica explica o nome.

O otimizador roda o programa nos casos de treino, com a instrução inicial e sem demonstração nenhuma. Para cada caso, ele guarda o traço da execução: a entrada e a saída de cada módulo naquela passagem. Depois aplica a sua métrica ao resultado final e descarta os traços dos casos em que ela não passou.

O que sobra é um estoque de execuções que deram certo. Cada uma delas é uma demonstração pronta para qualquer módulo do programa, com entrada e saída no formato exato daquele módulo. É essa a peça que o paper de 2023 descreve quando diz que os módulos são parametrizados no sentido de aprenderem criando e colhendo demonstrações2.

Repare no que isso resolve. Escrever demonstração à mão para o módulo do meio de um pipeline é chato porque você precisa inventar a entrada intermediária, que nem existe até o programa rodar. O bootstrap não inventa nada: ele colhe o que apareceu.

E repare no que isso não resolve. Se a instrução inicial for ruim demais, quase nenhum caso passa, e o estoque de traços sai vazio. É o modo de falha mais comum de uma primeira compilação, e o sintoma é uma compilação rápida demais com resultado igual ao da linha de base.

De onde vem o texto da instrução

Colher exemplo é a metade barata. Propor instrução é a metade difícil, porque o espaço é aberto.

O trabalho de 2024 que definiu o padrão atual quebra o problema em duas partes que podem ser otimizadas separadamente, instrução e demonstração, e propõe três estratégias que valem entender3.

A primeira é propor instrução com consciência do programa e dos dados. Em vez de pedir a um modelo “melhore este prompt”, o proponente recebe o código do programa, uma amostra do conjunto e o histórico de tentativas, e escreve uma instrução com base nisso. Uma instrução ancorada na tarefa vence uma reescrita genérica.

A segunda é avaliar em minilote. Rodar o conjunto inteiro em cada candidato é caro, então o algoritmo avalia amostras e usa essas avaliações para aprender um modelo substituto do objetivo, que estima quais candidatos merecem uma avaliação completa. É a mesma lógica de otimização bayesiana aplicada a um espaço discreto de textos.

A terceira é meta-otimização: refinar ao longo do tempo a forma como o modelo constrói as propostas, e não só as propostas em si.

Junto com isso vem a atribuição de crédito. Você fornece uma métrica no fim do programa e não rótulo por módulo, então o algoritmo precisa decidir qual etapa merece a mudança. Os autores relatam até 13 pontos de exatidão acima das linhas de base em cinco de sete programas testados com Llama-3-8B3.

O tamanho do espaço de busca

Vale fazer a conta uma vez, porque ela explica por que o algoritmo é o que é.

Suponha um programa de três módulos. Para cada módulo, o otimizador tem dez instruções candidatas e oito conjuntos de demonstração candidatos. Isso dá oitenta combinações por módulo e, como a escolha é independente entre eles, 512 mil combinações no programa inteiro. Avaliar todas em 100 casos seriam 51,2 milhões de execuções do programa.

Nenhuma delas é avaliada. O algoritmo amostra um punhado de combinações, mede em minilote, ajusta a estimativa de onde vale gastar e concentra a avaliação completa nas poucas candidatas promissoras. Uma sessão típica avalia dezenas de combinações, não centenas de milhares.

Isso tem uma consequência que muda a expectativa: o resultado de uma compilação não é o ótimo, é uma amostra boa encontrada com orçamento limitado. Rodar de novo com outra semente pode devolver outro vencedor com nota parecida, e isso é esperado, não sinal de bug.

A métrica precisa ser barata

Uma decisão de projeto tem efeito desproporcional no custo, e é a escolha da métrica.

A métrica roda uma vez por caso, por candidato avaliado. Numa sessão com 30 candidatos e 100 casos, ela é chamada milhares de vezes. Se ela for uma verificação programática, o parse do JSON, a comparação de um campo, o teste que passa, o custo dela é zero e some da conta. Se ela for uma chamada a um modelo juiz, ela dobra o número de chamadas da sessão e passa a dominar o gasto.

Há um segundo efeito, menos óbvio e mais caro. Um juiz por modelo tem variância: o mesmo par de entrada e saída pode receber notas diferentes em execuções distintas. O otimizador não distingue variação da métrica de variação do candidato, então parte da busca vai perseguir ruído do juiz. Com métrica determinística esse problema desaparece.

Daí a regra prática: reduza a saída ao que puder ser verificado por código, e use o juiz só na parte que sobrar. Uma métrica binária por caso, passou ou não passou, costuma ser mais estável e mais barata que uma nota de zero a dez, e é o suficiente para ordenar candidatos.

Antes e depois

Escrito à mãoinstrução em prosasem exemploformato descrito em textoexatidão: a linhade base do seu conjuntomedido uma vezCompiladoinstrução reescrita+ exemplos selecionados+ campos formatadosexatidão: comparadaà mesma linha de basemedido a cada candidato
Figura 2O prompt compilado não é mais bem escrito, é mais bem medido. A comparação só significa algo porque os dois lados foram avaliados no mesmo conjunto.

Vale imprimir o prompt final na primeira vez que você compilar, porque a comparação com o que você escreveu é instrutiva e às vezes desconfortável.

O prompt escrito à mão costuma ser uma instrução em prosa, com o formato descrito em texto e nenhum exemplo. O compilado costuma ser uma instrução mais seca, seguida de três a oito demonstrações completas, com os campos rotulados de forma rígida e repetitiva.

Ele não é mais bonito. Frequentemente é pior de ler. A única coisa que ele tem a mais é ter sido medido contra dezenas de alternativas no seu conjunto, e é essa a propriedade que você está comprando.

Sobre a magnitude do ganho, os números públicos vêm com escopo. No paper de 2023, programas compilados superaram few-shot padrão em geralmente mais de 25% com GPT-3.5 e mais de 65% com llama2-13b-chat, e superaram pipelines com demonstrações escritas por especialistas em faixas de 5% a 46% e 16% a 40%2. São dois estudos de caso, com aqueles modelos, naquelas tarefas. O que se transporta para você é o método, não a porcentagem.

As famílias de otimizador

Elas se diferenciam por como propõem candidatos, e a escolha muda bastante o custo.

Bootstrap de demonstrações. Só colhe traços que passaram e monta conjuntos de exemplos. Barato, sem proposta de instrução, e resolve mais casos do que parece. É por onde começar.

Proposta de instrução com busca. A família do trabalho de 2024: propõe instrução, seleciona demonstração, avalia em minilote e usa modelo substituto para decidir onde gastar avaliação completa3. É o padrão em julho de 2026.

Evolução reflexiva. Em vez de tratar a nota como um escalar, o otimizador lê os traços de execução em linguagem natural, diagnostica o que deu errado e propõe a correção, mantendo uma fronteira de Pareto das próprias tentativas. O GEPA, de 2025, reporta ficar mais de 10% acima do MIPROv2 e superar o GRPO em 6% na média, com até 35 vezes menos execuções4. A economia de execuções é o número que muda o cálculo de quando compilar vale a pena.

Otimização conjunta de peso e prompt. O compilador também gera dados de fine-tuning a partir das execuções. Um trabalho de 2024 mostra que alternar entre otimizar peso e otimizar prompt supera fazer só uma das duas, por até 60% e 6% em média, respectivamente, nos modelos e tarefas testados5.

Onde falha

Sobreajuste ao conjunto. Trinta candidatos avaliados nos mesmos cinquenta casos produzem um vencedor parcialmente sortudo. É o modo de falha mais provável e o mais fácil de evitar: separe o holdout antes de compilar e confirme nele depois.

A métrica vira o alvo. O otimizador vai explorar qualquer atalho que a sua métrica premie. Se ela compara texto por sobreposição de palavra, o vencedor vai ser verboso. Vale ler as saídas vencedoras, não só a nota.

O bootstrap não decola. Instrução inicial fraca produz poucos traços aprovados, e sem traços não há demonstração. A correção é melhorar a instrução inicial à mão antes de compilar, o que soa contraditório e não é: o compilador precisa de um ponto de partida que funcione às vezes.

O prompt cresce. Demonstrações ocupam contexto, e o custo por requisição em produção sobe junto. Um ganho de dois pontos de exatidão que dobra o prompt pode não valer a conta, e a decisão é de produto.

O artefato não se revisa em pull request. O prompt compilado é um blob gerado, e comparar a diferença entre duas compilações não diz nada útil a quem revisa. O que se revisa é o conjunto, a métrica e o número final. Tratar o artefato como código revisável gasta o tempo de quem lê e não pega erro nenhum.

O resultado não transfere. O artefato é ajustado ao modelo e à versão medidos. Guarde o conjunto, a métrica e a semente, porque recompilar é a operação que você vai repetir a cada troca de modelo.

Como conduzir uma compilação

  1. Meça a linha de base sem compilar. O programa com instrução simples e nenhum exemplo. Sem esse número, o resto não tem contra o que comparar.
  2. Separe o holdout antes de qualquer coisa. Vinte por cento, intocado até o fim.
  3. Comece pelo bootstrap. Barato e frequentemente suficiente. Só passe para proposta de instrução se o ganho parar.
  4. Limite o número de candidatos na primeira rodada. Poucos candidatos com conjunto honesto valem mais que muitos com conjunto pequeno.
  5. Imprima o prompt vencedor e leia. É o único jeito de perceber que a métrica premiou a coisa errada.
  6. Meça o tamanho do prompt junto com a exatidão. As duas grandezas decidem juntas.
  7. Versione o artefato compilado com o conjunto e a versão do modelo. Sem os três, você não consegue reproduzir nem explicar o resultado depois.

Quanto custa

Ordem de grandeza. O custo de uma compilação é aproximadamente o número de candidatos multiplicado pelo tamanho do conjunto e pelo custo de uma execução do programa. Com 30 candidatos, 100 casos e um programa de dois módulos, são cerca de 6 mil execuções de módulo por sessão, o que nos preços praticados em julho de 2026 fica na casa de algumas dezenas de dólares. A avaliação em minilote reduz isso, porque nem todo candidato chega à avaliação completa.

Vale medir uma sessão pequena antes de disparar a grande: dez candidatos em vinte casos dão o custo por execução real e evitam a surpresa de uma conta trinta vezes maior do que a estimada.

Se a métrica usa um modelo como juiz, aproximadamente dobre o número de chamadas. E some o custo que não aparece na sessão: um prompt compilado maior paga a diferença em toda requisição de produção, todo mês, enquanto ele estiver no ar.

Footnotes

  1. Yang et al. (2023) formularam o uso do próprio modelo como otimizador, alimentado com as soluções já avaliadas e suas pontuações.

  2. Khattab et al. (2023) descrevem o compilador que cria e colhe demonstrações, com programas compilados superando few-shot padrão em geralmente mais de 25% com GPT-3.5 e mais de 65% com llama2-13b-chat. 2

  3. Opsahl-Ong et al. (2024) separaram proposta de instrução de seleção de demonstração, com avaliação estocástica em minilote e modelo substituto do objetivo, chegando a 13 pontos acima das linhas de base em cinco de sete programas com Llama-3-8B. 2 3

  4. Agrawal et al. (2025) leem traços de execução em linguagem natural para diagnosticar e corrigir, ficando mais de 10% acima do MIPROv2 e 6% acima do GRPO na média, com até 35 vezes menos execuções.

  5. Soylu et al. (2024) alternaram otimização de pesos e de prompts no mesmo pipeline, superando otimizar só pesos em até 60% e só prompts em até 6%, na média entre modelos e tarefas.

Perguntas frequentes

Como o DSPy otimiza um prompt?
Ele propõe candidatos, avalia cada um no seu conjunto de casos usando a sua métrica e fica com os que pontuaram melhor. Um candidato é uma combinação de texto de instrução e conjunto de exemplos, escolhida por módulo do programa.
Como funciona o bootstrap de exemplos no DSPy?
O otimizador roda o próprio programa nos casos de treino e guarda os traços de execução em que a métrica passou. Esses traços viram demonstrações para os módulos. É por isso que a técnica se chama bootstrap: o exemplo é gerado pelo sistema, não escrito por você.
Como o DSPy escolhe quais exemplos entram no prompt?
Por medição. Ele monta conjuntos candidatos a partir dos traços que passaram, avalia cada combinação no conjunto e mantém a que pontuou melhor. Não há critério de similaridade nem heurística de diversidade decidindo sozinha: quem decide é a nota.
O que é um teleprompter no DSPy?
É o nome que o paper de 2023 deu ao componente que compila o programa. A documentação passou a chamá-lo de optimizer, e o caminho de importação com o nome antigo continuou existindo. Teleprompter e optimizer são o mesmo objeto, em vocabulários de épocas diferentes.
O compilador reescreve a minha instrução?
Reescreve, nos otimizadores que propõem instrução. Eles usam um modelo para gerar variações a partir do seu programa, de amostras dos seus dados e das notas já obtidas. A docstring da signature entra como instrução inicial e pode não sobreviver à compilação.
Quantos casos o DSPy precisa para compilar?
Dezenas resolvem o começo. Poucos exemplos bastam para o bootstrap colher demonstrações, mas ordenar candidatos parecidos exige mais: com 50 casos, uma diferença de três pontos percentuais fica dentro do ruído. Separe também um holdout que não participa da busca.
Preciso de rótulo em cada etapa do pipeline?
Não. Os otimizadores de programas de vários módulos foram desenhados para funcionar sem rótulo intermediário: você fornece a métrica no fim e o algoritmo distribui o crédito entre as etapas. É justamente o problema que o trabalho de 2024 sobre o MIPRO ataca.

Referências

  1. Khattab, O. et al.. DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines (2023)arXiv:2310.03714
  2. Opsahl-Ong, K. et al.. Optimizing Instructions and Demonstrations for Multi-Stage Language Model Programs (2024)arXiv:2406.11695
  3. Yang, C. et al.. Large Language Models as Optimizers (2023)arXiv:2309.03409
  4. Agrawal, L. A. et al.. GEPA: Reflective Prompt Evolution Can Outperform Reinforcement Learning (2025)arXiv:2507.19457
  5. Soylu, D. et al.. Fine-Tuning and Prompt Optimization: Two Great Steps that Work Better Together (2024)arXiv:2407.10930