Quase todo fluxo com IA nasce com a mesma forma: pergunte uma coisa, leia a resposta, decida a próxima pergunta, pergunte de novo. É a forma natural de quem veio de LLM, porque com um modelo de texto cada resposta muda o que faz sentido perguntar depois.
O fan-out especulativo troca essa forma por outra. Você lista de uma vez todas as perguntas que qualquer caminho do fluxo pode precisar — inclusive as que só importam em um dos caminhos — manda tudo em uma requisição e decide no código quais respostas ler. A documentação oficial recomenda exatamente isso, e o motivo é técnico: o state entra uma vez e as perguntas são avaliadas em paralelo contra ele, então acrescentar perguntas normalmente não acrescenta latência à resposta.
O que o padrão realmente decide
Este não é um truque de economia. É uma decisão sobre onde mora o desvio do seu sistema.
Na forma sequencial, o desvio mora na rede: o fluxo vai e volta ao modelo a
cada bifurcação, e a latência total é a soma das idas. Na forma de fan-out, o
desvio mora no seu código: você recebe um bloco de respostas e o if fica em
uma função que você pode ler, testar e versionar.
Isso tem três consequências que não aparecem na fatura.
A responsabilidade fica clara. O modelo responde perguntas; o código decide. Quando a triagem manda um caso para o lugar errado, você sabe qual das duas coisas errou, porque as respostas ficam gravadas antes da decisão.
A auditoria fica possível. Como todas as perguntas foram feitas, você tem o bloco completo mesmo dos ramos que não foram usados. Em uma revisão posterior, isso é a diferença entre “o sistema classificou como cobrança” e “o sistema viu severidade baixa, nenhum passo de reprodução, pedido de reembolso provável e frustração alta, e por isso classificou como cobrança”.
O teste fica determinístico. Com o bloco de respostas salvo, a função de roteamento é uma função pura: entra um dicionário, sai uma ação. Dá para testar todos os ramos sem chamar a API.
Como o exemplo oficial é montado
A página oficial usa uma triagem de ticket de suporte. Um ticket só, cinco perguntas numa chamada:
| Pergunta | Primitiva | Para que serve |
|---|---|---|
category | Choice de 4 opções | a classificação que decide o ramo |
bug_severity | Score de 3 níveis | só importa se for bug |
has_reproducible_steps | Noul | só importa se for bug |
refund_requested | Noul | só importa se for cobrança |
frustration | Score de 3 níveis | importa em todos os ramos |
Três das cinco são especulativas: bug_severity e has_reproducible_steps só
fazem sentido se o ticket for um bug, e refund_requested só faz sentido em
cobrança. Elas vão na chamada de qualquer jeito.
Depois o código escolhe. No exemplo oficial, o ramo de bug escala para
engenharia quando bug_severity > 1,5 e has_reproducible_steps > 0,6; o
ramo de cobrança marca reembolso provável quando refund_requested > 0,7; e a
frustração dispara prioridade acima de 1,5 em qualquer ramo. São números do
exemplo da TypeSafe, não recomendação para o seu domínio — os cortes saem dos
seus próprios dados.
respostas = resposta.answers
if respostas["category"].choice == "bug_report":
if respostas["bug_severity"].score > 1.5 and respostas["has_reproducible_steps"].noul > 0.6:
escalar_para_engenharia(ticket_id)
else:
backlog_de_bug(ticket_id)
elif respostas["category"].choice == "billing":
encaminhar_cobranca(ticket_id, reembolso=respostas["refund_requested"].noul > 0.7)
# A frustração vale em qualquer categoria.
if respostas["frustration"].score > 1.5:
marcar_prioridade(ticket_id)
Repare no que não está no código: nenhuma segunda chamada. A árvore de decisão inteira sai de uma requisição.
Onde o padrão para de escalar
O padrão tem um teto, e ele é de tokens. A página de modelos declara 64 mil tokens por requisição e 32 mil para o state mais a pergunta mais longa. O state costuma comer a maior parte desse orçamento, então o limite prático não é “quantas perguntas”, é “qual o tamanho do que eu estou avaliando”. Quando o documento é grande, a conta aperta pelo lado do state, não pelo lado da lista de perguntas.
O segundo teto é humano. Um mapa com sessenta perguntas é um arquivo que alguém precisa manter. Vale agrupar por assunto, nomear as chaves com o vocabulário do domínio e apagar a pergunta que nenhum ramo lê há meses.
Quando não usar
Quando a pergunta seguinte depende do conteúdo da resposta anterior, e não só do valor. Se o segundo passo precisa de um state diferente — o trecho que a primeira resposta apontou, o registro que ela identificou — não há como especular. Aí o desenho certo é o de cascata, com dois estágios, descrito em cascata de extração.
Quando o custo de fazer a pergunta não é só de tokens. Uma pergunta que toca dado sensível, ou que precisa ser registrada por obrigação interna, não é gratuita só porque é barata. Especular sobre dado que você não deveria estar avaliando é pior que uma segunda chamada.
Quando a lista de perguntas depende de um cálculo caro. Se montar a pergunta exige uma busca, uma consulta ou uma chamada externa, você pagou o caro antes de saber se o ramo existe. Nesse caso, classifique primeiro e monte o lote no segundo passo.
Quando o state precisa mudar de tamanho por ramo. O padrão supõe um state só para todas as perguntas. Se metade das perguntas exige o documento inteiro e a outra metade só um parágrafo, mandar o documento para todas custa acurácia, pelo motivo que a própria documentação chama de context rot e que está em context rot.
Por onde continuar
Para ver o padrão aplicado a uma tarefa medida, leia a receita de perguntas paralelas, que é o experimento oficial com treze perguntas sobre um artigo longo. Para decidir qual primitiva cada pergunta do lote deve usar, veja qual primitiva usar. E para entender por que a resposta sozinha não basta para agir, o vizinho natural deste padrão é roteamento por confiança.
Perguntas frequentes
Fan-out especulativo é o mesmo que disparar várias chamadas em paralelo?
Não, é o contrário. Disparar em paralelo mantém várias requisições, e cada uma reenvia o state inteiro. O fan-out especulativo é uma requisição só, com o state uma vez e o mapa de perguntas dentro dela. A documentação oficial diz que as perguntas são avaliadas em paralelo dentro da chamada, então acrescentar perguntas normalmente não acrescenta latência à resposta.
Quantas perguntas cabem numa chamada?
O limite é de tokens, não de contagem: 64 mil tokens por requisição e 32 mil para o state mais a pergunta mais longa, segundo a página de modelos. Na prática o state domina o orçamento e sobra espaço para dezenas de perguntas curtas.
Perguntar algo que eu não vou usar não é desperdício?
Em dinheiro, quase nada: a pergunta extra paga apenas os próprios tokens, porque o state já foi pago. Em manutenção, pode ser: cada pergunta no mapa é uma linha que alguém vai ler daqui a um ano. O critério é se ela evita uma segunda chamada em algum caminho do fluxo.
Qual a diferença entre este padrão e a receita de perguntas paralelas?
O padrão é a decisão de arquitetura: uma chamada por unidade de trabalho, o desvio no código. A receita é o experimento que mede o efeito dessa decisão em uma tarefa concreta de 13 perguntas sobre um artigo longo. O padrão diz o que fazer; a receita mostra quanto isso rendeu ali.
O fan-out atrapalha a qualidade das respostas?
A documentação afirma que cada pergunta é avaliada de forma independente contra o mesmo state, e o cookbook oficial de perguntas paralelas testou isso: as respostas não mudaram entre o lote e as chamadas avulsas. Ainda assim, teste com o seu conteúdo, porque um state grande e cheio de detalhe irrelevante derruba acurácia por outro motivo.