Como classificar ticket, e-mail e mensagem com lista fechada de opções na Decisions API da OpenAI

Resposta rápida

A Decisions API da OpenAI (endpoint POST /v1/decisions, em beta pública desde 06/10/2026 e hoje só com o gpt-6-luna) responde escolhendo entre opções que você define, em vez de gerar texto livre. Pra classificar ticket, e-mail e mensagem, use perguntas do tipo choice com valores distintos e mutuamente exclusivos, cada um com a descrição de quando se aplica, e inclua uma saída other como boa prática. A resposta traz o valor escolhido, a probabilidade de cada opção e a confiança: confiança baixa ou other vai pra fila humana. Cobra só entrada, US$ 0,10 por 1 milhão de tokens

Se tu já colocou um LLM pra triar ticket, tu conhece a dor: um dia ele responde Financeiro, no outro Cobrança, no outro cobranca sem acento, e de vez em quando inventa uma categoria novinha que não existe em lugar nenhum 😅

Aí o roteamento quebra, o ticket cai no limbo e alguém do suporte descobre isso três dias depois

A Decisions API da OpenAI ataca exatamente esse problema: em vez de gerar texto livre, ela responde perguntas escolhendo entre respostas que VOCÊ definiu antes

Tu manda um contexto (texto ou imagem), manda as perguntas com as respostas possíveis, e ela devolve uma resposta por pergunta

A própria OpenAI apresenta o uso pra classificar conteúdo, rotear pedidos e escolher a próxima ação de um agente

Ela foi apresentada no DevDay, em 29/09/2026, em preview limitado, e desde 06/10/2026 está aberta em beta pública pra todos os desenvolvedores

Bora ver como montar uma lista fechada que funciona de verdade? 🙂

Por que uma lista fechada muda o jogo na triagem e no roteamento?

Formação Claude Code
Formação Recomendada

Formação Claude Code

Domine Claude Code do absoluto zero até o avançado

  • 120 aulas
  • 4 projetos
  • 9h 45min

Pensa no texto livre como pedir pra alguém "descrever" o assunto do e-mail

Cada pessoa descreve de um jeito, né? E aí tu precisa de uma camada inteira de código só pra normalizar: tirar acento, padronizar caixa, mapear sinônimo, tratar o caso que não bate com nada…

Com lista fechada é como entregar um formulário com caixinhas pra marcar

No tipo choice da Decisions API, o retorno é sempre um dos valores que tu forneceu, então ele vira direto a chave da fila, a tag ou a rota no seu código, sem tradução no meio

E tem um bônus que faz MUITA diferença: além do valor escolhido, a resposta traz a probabilidade de cada opção e um número de confiança separado

Que confiança? É o quanto o modelo "bancou" aquela escolha

Com isso tu deixa de confiar cegamente na resposta e passa a decidir com regra: confiança alta segue automático, confiança baixa vai pra uma pessoa olhar

O ganho real é de engenharia: saída previsível e um sinal claro de quando desconfiar

O que você precisa antes de começar:

A lista é curta, e só com o que está confirmado:

  • Acesso à API da OpenAI: a Decisions API está em beta pública pra todos os desenvolvedores desde 06/10/2026, e a disponibilidade geral (GA) ainda não saiu (a OpenAI fala em "próximas semanas")
  • Modelo: hoje o único suportado é o gpt-6-luna, uma versão especializada do GPT-6 Luna
  • Endpoint: POST /v1/decisions, separado das outras rotas da API

Se tu lida com dado sensível (saúde, dado pessoal de cliente e etc), se liga nisso: o endpoint suporta Zero Data Retention e uso HIPAA pra clientes elegíveis, além de residência de dados com processamento regional nos EUA e na Europa (EEE + Suíça)

A referência oficial é o guia da Decisions API, deixa ele aberto do lado enquanto monta as coisas

Passo a passo: classificando tickets com o tipo choice

A lógica aqui é explicar o PORQUÊ de cada passo e já mostrar onde o pessoal costuma tropeçar

Passo 1: desenhe a lista fechada

Antes de escrever qualquer requisição, tu precisa decidir as opções

A orientação da documentação pra perguntas choice é usar valores distintos e uma descrição que explique quando cada opção se aplica

O exemplo oficial de triagem de suporte é este:

billing    -> pagamentos, faturas e reembolsos
technical  -> problemas para usar o produto
shipping   -> entrega e rastreio

Repara que a descrição não é enfeite: é ela que diz pro modelo onde está a fronteira entre uma categoria e outra

O erro comum deste passo: criar duas opções que se sobrepõem, tipo pagamento e reembolso

Reembolso É assunto de pagamento, então o mesmo ticket cabe nas duas e a probabilidade se divide entre elas

Resultado: confiança baixa sem motivo e roteamento instável

Se tu precisa separar reembolso, isso é subcategoria (a gente chega lá no passo 6)

Passo 2: adicione a saída "nenhuma das anteriores"

Todo suporte recebe aquele e-mail que não tem nada a ver com nada: proposta comercial, currículo, alguém agradecendo, por aí vai

Se a lista não tem uma saída pra isso, o modelo é obrigado a encaixar o ticket em alguma categoria "menos pior"

Por isso, como boa prática de design (não é exigência da API), vale incluir uma opção tipo other:

billing    -> pagamentos, faturas e reembolsos
technical  -> problemas para usar o produto
shipping   -> entrega e rastreio
other      -> nenhuma das categorias acima se aplica ou o assunto não está claro

O erro comum deste passo: forçar todo ticket a caber numa categoria

Aí o currículo vai parar na fila técnica e alguém perde tempo lendo… já vi isso acontecer mais vezes do que gostaria haha

Passo 3: monte a requisição

A requisição tem três campos: model escolhe o modelo, input traz o contexto compartilhado (uma string de texto ou mensagens de usuário com texto e imagens) e questions é um array de perguntas

Cada pergunta tem um nome, um tipo, instruções e as opções permitidas

O esqueleto fica assim:

POST /v1/decisions

{
  "model": "gpt-6-luna",
  "input": "Oi, fui cobrado duas vezes no cartão este mês e quero o estorno de uma das cobranças",
  "questions": [
    {
      "name": "departamento_suporte"
      // tipo: choice
      // instruções: "Classifique o departamento que deve atender este ticket"
      // opções: billing, technical, shipping, other (cada uma com valor + descrição)
    }
  ]
}

Os comentários ali dentro marcam o que cada pergunta leva: tipo, instruções e opções (cada opção com valor + descrição), no formato que está no guia oficial 😛

O input é onde entra o texto do ticket, do e-mail ou da mensagem do WhatsApp, o que for

O erro comum deste passo: dar um name genérico tipo q1 ou pergunta

O nome volta na resposta, então se ele não diz nada, ler o array de respostas vira um quebra-cabeça, principalmente quando tu tiver várias perguntas na mesma chamada

Passo 4: leia a resposta (e trate a recusa)

A API repete o name de cada pergunta no array answers, e é por ele que tu casa pergunta com resposta

Na resposta de uma pergunta choice tu tem três coisas: o valor escolhido, a probabilidade de cada opção e a confiança

Só que tem um detalhe: qualquer pergunta pode voltar como recusa (refusal) em vez de resposta

Então a lógica de leitura fica mais ou menos assim:

def resposta_por_nome(answers, nome):
    for resposta in answers:
        if resposta["name"] == nome:
            return resposta
    return None

resposta = resposta_por_nome(answers, "departamento_suporte")

if resposta is None or veio_recusa(resposta):
    mandar_para_fila_humana(ticket)
else:
    valor, confianca = extrair_valor_e_confianca(resposta)

veio_recusa e extrair_valor_e_confianca são funções suas: dentro delas tu lê os campos com os nomes que estão no guia oficial

Isolar isso numa função é massa porque, se o schema mudar até a GA, tu mexe num lugar só

O erro comum deste passo: assumir que sempre vem uma resposta

Caso venha uma recusa e teu código vá direto buscar o valor, ele estoura erro no meio da fila e trava tudo atrás dele

Tome cuidado!

Passo 5: roteie com base na confiança

Agora sim o roteamento, usando o valor E a confiança:

FILAS = {
    "billing": "fila_financeiro",
    "technical": "fila_suporte_tecnico",
    "shipping": "fila_logistica",
}

def rotear(ticket, valor, confianca, limite):
    if valor == "other" or confianca < limite:
        return "fila_humana"
    return FILAS.get(valor, "fila_humana")

E qual o limite? Não existe número mágico

Quem define é a tua base: roda com tickets antigos já classificados e vê a partir de qual confiança os acertos ficam aceitáveis pro teu caso

O erro comum deste passo: usar só o valor e ignorar a confiança

O valor sempre vai ser uma opção válida

E é justamente isso que engana: uma escolha "no chute" parece tão certinha quanto uma escolha firme, e só a confiança mostra a diferença entre as duas

Passo 6: subcategoria ou decisão dependente? Segunda chamada

Todas as perguntas de uma mesma requisição usam o mesmo input

Isso quer dizer que, se a próxima decisão depende de uma resposta anterior, ela precisa de uma segunda requisição

Exemplo: primeiro tu descobre que o ticket é billing, e só então pergunta se é cobrança duplicada, fatura ou reembolso

# chamada 1: departamento
departamento = classificar(ticket, pergunta_departamento)

# chamada 2: só faz sentido depois da primeira
if departamento == "billing":
    subtipo = classificar(ticket, pergunta_subtipo_billing)

O erro comum deste passo: tentar encadear tudo numa requisição só

As perguntas da mesma chamada não "enxergam" a resposta umas das outras, então a pergunta de subcategoria de billing vai ser respondida até pra ticket de entrega, o que não faz sentido nenhum

Choice, predicate ou score: qual tipo usar em cada triagem?

A Decisions API tem três tipos de pergunta, e escolher o certo evita muita gambiarra:

Tipo O que devolve Quando usar na triagem
choice Um dos valores fornecidos, a probabilidade de cada opção e a confiança Departamento, categoria, fila de destino
predicate Probabilidade de 0 a 1 de uma condição ser verdadeira "É spam?", "Pede reembolso?"
score Média dos índices dos níveis, ponderada pela probabilidade Severidade ou urgência em níveis ordenados

Quando usar choice?

Sempre que tu precisa de um rótulo exato pra rotear: departamento de um ticket, tipo de um e-mail, intenção de uma mensagem

É o tipo deste tutorial todo, e é o que acaba com a categoria inventada

Quando usar predicate?

Pra perguntas de sim ou não, tipo "essa mensagem é spam?" ou "esse e-mail pede reembolso?"

Como volta uma probabilidade de 0 a 1, tu decide o corte no teu código

Quando usar score (e por que ele NÃO serve pra rotear)?

O score pontua contra níveis ordenados, tipo baixa, média e alta severidade

Só que ele devolve a média dos índices ponderada pela probabilidade, e o exemplo oficial mostra o pegadinha: probabilidades 0,1, 0,7 e 0,2 em três níveis dão score 1,1

E 1,1 não corresponde a nenhum nível!

É ótimo pra ordenar a fila (o 1,1 vem antes de um 0,4, por exemplo), mas se tu precisa de um rótulo exato pra mandar pra uma rota específica, o certo é choice

Combinando perguntas no mesmo input

Como todas as perguntas da requisição compartilham o mesmo input, tu pode extrair várias informações independentes de um e-mail numa chamada só:

{
  "model": "gpt-6-luna",
  "input": "<texto do e-mail>",
  "questions": [
    { "name": "categoria" },       // tipo choice: billing, technical, shipping, other
    { "name": "urgencia" },        // tipo score: níveis ordenados de urgência
    { "name": "pede_reembolso" }   // tipo predicate
  ]
}

O que vale é a regra do passo 6: isso funciona porque nenhuma dessas perguntas depende da resposta da outra

Quanto custa e quão rápido é classificar em volume?

Os números divulgados pela OpenAI são estes:

  • Preço: só tokens de entrada são cobrados, a US$ 0,10 por 1 milhão de tokens
  • Saída e cache: tokens de saída e leitura/escrita de cache não são cobrados
  • Latência: cerca de 150 ms por decisão, contra cerca de 1,6 s numa chamada padrão do GPT-6 Luna (a OpenAI fala em cerca de 10x mais rápido)

Na prática, o que pesa no custo é o tamanho do que tu manda no input, então ticket gigante com histórico inteiro custa mais que a mensagem curta

Vale pensar no que realmente precisa entrar no contexto pra decidir a categoria

Já a latência abre espaço pros dois cenários: triagem em lote (aquela fila acumulada do fim de semana) e triagem em tempo real, classificando a mensagem no momento em que ela chega, antes de alguém abrir

Só lembra que ainda é beta pública e a GA é esperada nas próximas semanas, então coisa pode mudar até lá 😉

Próximo passo: monte sua primeira lista fechada

Recapitulando o que faz a triagem com a Decisions API funcionar:

  • Opções com valores distintos e mutuamente exclusivos
  • Descrição dizendo quando cada opção se aplica
  • Uma saída other pra o que não cabe em lugar nenhum
  • Confiança (e recusa) decidindo quando o ticket vai pra uma pessoa
  • Segunda chamada pra subcategoria e decisão encadeada

O próximo passo é bem concreto: pega 3 a 5 categorias reais da tua fila de suporte, escreve a descrição de cada uma e roda contra tickets antigos que já têm a categoria certa

Vai ficar claríssimo onde as opções se sobrepõem e qual limite de confiança faz sentido pra você

E aí, vai colocar na tua fila? Bora trocar uma ideia nos comentários 🙂

até o próximo post!

Perguntas frequentes

Qual a diferença entre a Decisions API e mandar um prompt de classificação pro GPT-6 Luna normal?

Na Decisions API a resposta é obrigatoriamente uma das opções que você definiu, com probabilidade por opção e confiança separada. Além disso, segundo a OpenAI, a latência é de cerca de 150 ms contra cerca de 1,6 s numa chamada padrão do GPT-6 Luna, o que ela descreve como cerca de 10x mais rápido.

Quanto custa classificar um ticket com a Decisions API?

Segundo a OpenAI, com o gpt-6-luna a Decisions API cobra US$ 0,10 por 1 milhão de tokens de entrada. Tokens de saída e leitura/escrita de cache não são cobrados, ou seja, custo US$ 0 nesses dois itens.

Posso usar a Decisions API em produção hoje?

Sim, desde 06/10/2026 ela está em beta pública aberta pra todos os desenvolvedores, não é mais o preview limitado anunciado no DevDay. A disponibilidade geral (GA) ainda não saiu, a OpenAI fala em próximas semanas.

Dá pra fazer uma pergunta que depende da resposta de outra na mesma requisição?

Não. Todas as perguntas de uma mesma requisição usam o mesmo input compartilhado, então uma decisão que depende de uma resposta anterior precisa de uma segunda requisição separada.

A Decisions API funciona com imagem, ou só texto de ticket e e-mail?

O campo input aceita tanto uma string de texto quanto mensagens de usuário com texto e imagens. Então classificar um print de erro enviado pelo cliente, por exemplo, está dentro do que o endpoint suporta.

Qual modelo a Decisions API usa pra classificar?

Hoje o único modelo suportado é o gpt-6-luna, uma versão especializada do GPT-6 Luna. Esse é o modelo que aparece no changelog oficial da OpenAI registrando o lançamento em beta.



Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Vibe Coding

Formação Vibe Coding

Do Prompt ao Produto: Crie Software Real com IA

  • 474 aulas
  • 20 projetos
  • 39h 27min

Blog | Mais populares