Erro 400 com reasoning_content no DeepSeek: como montar o histórico da conversa sem quebrar a próxima chamada

Se a sua integração quebrou no segundo turno, a regra do reasoning_content DeepSeek mudou e depende de um fator só: a presença do parâmetro tools na requisição. Sem tools, o campo pode ser reenviado à vontade, porque a API ignora ele e não concatena no contexto. Com tools, o reenvio é obrigatório em todas as chamadas seguintes, inclusive nos turnos em que o modelo não fez tool call, e omitir devolve HTTP 400. Orientações antigas associadas ao deepseek-reasoner recomendavam remover o campo, e esse entendimento está desatualizado 🙂
Fala aí, beleza? O primeiro turno passa liso, você manda a segunda mensagem da mesma conversa e a API devolve 400 do nada
No modo de raciocínio da DeepSeek, a cadeia de pensamento não vem embutida na resposta: ela volta em um campo separado chamado reasoning_content, irmão de content dentro da mensagem
A cada turno o modelo devolve as duas coisas: o CoT em reasoning_content e a resposta final em content
E é exatamente o que você faz com esse campo na hora de remontar o histórico que decide se a próxima chamada passa ou quebra
O detalhe cruel é que a orientação parece ter invertido. Guias antigos associados ao deepseek-reasoner recomendavam remover o campo antes da próxima chamada. Hoje, em cenário com tools, é o contrário: não mandar é que dá 400
Erro 400 ao continuar a conversa com tools: sintoma, causa e correção
O sintoma:
A primeira requisição funciona, o modelo responde (às vezes até faz um tool call), e a segunda requisição da MESMA conversa morre com HTTP 400
Integradores relatam a mensagem The reasoning_content in the thinking mode must be passed back to the API
Se você só olha o content no log, parece que está tudo certo no array de mensagens, e aí vem o desespero de reler o payload dez vezes
Formação Claude Code
Domine Claude Code do absoluto zero até o avançado
- 118 aulas
- 4 projetos
- 9h 33min
A causa:
Clientes compatíveis com OpenAI costumam descartar silenciosamente campos que eles não conhecem quando remontam o histórico
E reasoning_content é justamente um campo que não existe no schema padrão deles
Resultado: o campo some no caminho, sem aviso, sem log, sem exceção. A sua mensagem de assistant volta pra API só com content, e a API recusa
Porque a documentação do modo de raciocínio é clara na separação:
- Sem
toolsna requisição: oreasoning_contentnão precisa ser reenviado. Se for enviado, é ignorado e não entra no contexto (não gera erro) - Com
toolsna requisição: oreasoning_contentPRECISA ser reenviado integralmente em todas as requisições seguintes, inclusive nos turnos em que o modelo não fez tool call. Não reenviar retorna 400
Ou seja: o mesmo código que roda lindo no seu chat simples explode no seu agente 😛
A solução:
Preservar o campo irmão de content na mensagem do assistant e devolver ele integral, sem cortar, sem resumir, sem "limpar pra economizar token"
A mensagem que volta pro array precisa ficar mais ou menos assim:
{
"role": "assistant",
"content": "a resposta final que o usuário vê",
"reasoning_content": "a cadeia de pensamento que veio junto nesse mesmo turno",
"tool_calls": [ ... ]
}
Integral mesmo, beleza? A regra vale pra TODAS as requisições subsequentes daquela conversa, não só pra próxima
Como prevenir:
Mapeie o campo explicitamente no seu cliente
Se você usa um wrapper compatível com OpenAI, não confie no round-trip automático do objeto: leia reasoning_content da resposta e escreva ele de volta na mão, no seu próprio modelo de mensagem
E use a página de exemplo oficial de tool call em modo de raciocínio como referência do formato do array de mensagens, em vez de adivinhar
Tome cuidado com serialização também: se a sua camada de persistência salva só role e content no banco, o campo morre ali e o 400 vai voltar depois do primeiro reload da sessão
Erro 400 com tool_choice: o que o modo de raciocínio não aceita
Tem um segundo 400 que aparece mesmo com o histórico impecável, e a causa dele é OUTRA
O sintoma:
Você corrigiu o histórico, o reasoning_content está indo redondinho, e a requisição continua voltando 400
A causa:
No modo de raciocínio não existe suporte a tool_choice do tipo required nem a escolha de ferramenta nomeada
Nesses dois casos a API retorna 400, independente do teu array de mensagens estar perfeito
Faz sentido quando você pensa no PORQUÊ: forçar a mão do modelo ("você VAI chamar essa função agora") briga com o modelo decidindo o caminho durante o raciocínio
A solução:
Pra usar required ou ferramenta nomeada, é preciso desligar o modo de raciocínio naquela chamada
Não dá pra ter os dois ao mesmo tempo, e a doc do modo de raciocínio é a referência pra conferir a sintaxe exata do parâmetro que faz esse desligamento
Como prevenir:
Checar a configuração de tool_choice ANTES de habilitar raciocínio
E se liga nisso: o modo de raciocínio vem ativo por padrão, com reasoning_effort padrão em high
Ou seja, você pode nem ter "ligado" nada, e ainda assim está no thinking mode com esforço alto. Muita gente se ferra aqui achando que está numa chamada comum
A chamada parou de responder: nomes de modelo legados aposentados
Tem ainda um caso em que o erro não tem nada a ver com o teu payload
O sintoma:
Requisições que funcionavam há semanas, sem nenhum deploy seu no meio, passam a retornar erro
A causa:
Os nomes de modelo legados deepseek-chat e deepseek-reasoner foram aposentados e não são mais acessíveis
A aposentadoria está registrada na página de updates da API para 24/07/2026, às 15:59 UTC, e requisições com os nomes antigos passam a retornar erro
A solução:
Cuidado aqui, porque a troca não é tão simples quanto parece: deepseek-v4-flash também já foi aposentado e está apenas temporariamente roteado para o V4.1 Flash por compatibilidade. O nome de modelo atual e correto é deepseek-flash
E se o teu código usa deepseek-v4-pro, fica o alerta: desde 14/09/2026 (04:00 UTC), toda requisição com esse nome está sendo roteada para o V4.1-Flash, com as tarifas do V4.1-Flash, até o lançamento do V4.1-Pro. Ou seja, o nome ainda responde e não quebra com 400, mas não aponta mais pro modelo Pro nem pras tarifas Pro que você imagina estar pagando
{
"model": "deepseek-flash",
"messages": [ ... ],
"tools": [ ... ]
}
Como prevenir:
Fixe o nome do modelo em UM lugar de configuração, variável de ambiente ou arquivo de config, e nunca espalhado como string solta em cinco arquivos diferentes
Quando o fornecedor aposenta ou reroteia um nome, a troca vira uma linha em vez de uma caçada. E como esse tipo de mudança pode acontecer de novo, vale acompanhar a página de updates de vez em quando em vez de confiar que o nome de hoje vai valer pra sempre
E olha: se o teu contato com o modelo é só colar a chave em uma ferramenta de terceiro, tipo conectar o DeepSeek no Janitor AI, essa dor específica de array de mensagens nem te alcança, porque quem monta o histórico é a plataforma
Parâmetros que não fazem o que você espera no modo de raciocínio
Agora a parte traiçoeira: as armadilhas que NÃO dão erro
O 400 pelo menos te avisa. Aqui a requisição passa, retorna 200, e simplesmente ignora o que você pediu 😀
| Parâmetro | Comportamento no modo de raciocínio |
|---|---|
temperature |
Aceito sem erro (compatibilidade), porém sem efeito nenhum |
presence_penalty |
Aceito sem erro, porém sem efeito nenhum |
frequency_penalty |
Aceito sem erro, porém sem efeito nenhum |
top_p |
Funciona, mas com piso: valores abaixo de 0.95 são elevados para 0.95 |
Então aquele temperature: 0.1 que você colocou pra "deixar mais determinístico" não está fazendo NADA
E o top_p: 0.3 que você ajustou com carinho virou 0.95 na prática
Se o teu resultado veio mais criativo do que você esperava, o problema não é o prompt, é o parâmetro que nunca chegou a valer
E o max_tokens?
O valor aceito pela API vai de 1 até 384K (393216)
Os defaults mudam conforme o modo, e é isso que costuma pegar todo mundo de surpresa na conta de token:
- 8K no modo não pensante
- 64K no modo de raciocínio
- 128K com
reasoning_effortemmax
Os níveis de esforço de raciocínio suportados pelo V4-Pro e pelo V4-Flash são três: low, high e max
Repare no salto: sem definir nada, você sai de 8K pra 64K só por estar no thinking mode, que é o padrão
E respostas mais longas demoram mais, o que aumenta a chance de estourar o teu tempo de espera. Se o sintoma for esse, o caminho é outro: retry com espera crescente e fallback resolve melhor do que mexer em max_tokens no chute
Teste em duas rodadas: como observar a diferença de resposta e de tokens
Bora ver na prática? O jeito de não ficar na fé é reproduzir os DOIS cenários na sua própria aplicação, um com tools e outro sem
Em cada chamada, olhe o objeto usage da resposta: dentro do detalhamento de tokens de completion existe o campo reasoning_tokens, e é ele que te mostra quanto foi gasto de raciocínio naquele turno
- Rodada 1, primeira chamada, SEM
tools. Mande uma pergunta qualquer que exija raciocínio e guarde a resposta INTEIRA do assistant,contentereasoning_contentjuntos. Erro comum deste passo: logar só ocontente descobrir depois que você não tem mais o CoT pra reenviar no teste
- Segunda chamada da rodada 1, reenviando o
reasoning_content. Continue a conversa com o campo presente no histórico. Ela passa: semtools, o campo é ignorado e não é concatenado ao contexto. Erro comum deste passo: concluir daqui que "pode mandar sempre" ou que "nunca dá problema"
- Repita a mesma segunda chamada, agora removendo o
reasoning_content. Compare a resposta final com a do passo anterior. Semtools, os dois caminhos são aceitos
- Anote o
reasoning_tokensdas três chamadas. É a sua régua de custo, e é o número que muda quando você mexe noreasoning_effortentrelow,highemax
- Rodada 2, agora COM
toolsna requisição. Refaça a mesma conversa, dessa vez com o parâmetrotoolspresente, e reenvie oreasoning_contentintegral em todas as chamadas seguintes, inclusive nos turnos em que o modelo NÃO fez tool call. Erro comum deste passo: reenviar só quando teve tool call, achando que nos turnos "normais" não precisa
- Quebre de propósito. Na requisição seguinte, omita o
reasoning_contentda mensagem de assistant e confirme o HTTP 400. Sim, quebrar de propósito é útil: agora você sabe reconhecer esse 400 em produção em dez segundos, em vez de dez horas
- Compare as duas rodadas lado a lado. Mesmo histórico, mesma pergunta, um único parâmetro de diferença. Erro comum deste passo, e o mais caro de todos: assumir que o comportamento observado sem
toolsvale pro cenário comtools. É justamente onde a regra inverte
Se você mantém testes automatizados, esse passo 6 vira um teste de regressão ótimo: qualquer refatoração que "limpe" o array de mensagens quebra ele na hora
Conteúdo complementar do canal:
Pra quem quer ver IA lendo código de verdade e produzindo artefato em cima disso, este vídeo do canal mostra a skill Archify:
Conclusão
No fim, a regra do reasoning_content gira em torno de UM fator só: a requisição carrega tools ou não?
Sem tools, o campo é ignorado e não entra no contexto, então mandar ou não mandar dá no mesmo
Com tools, o reenvio integral é obrigatório em todas as chamadas seguintes, e esquecer disso é HTTP 400 na cara
O que confunde é que orientações antigas associadas ao deepseek-reasoner recomendavam remover o campo antes da próxima chamada, o oposto do que vale hoje pra cenários com tools. Aquele modelo já foi aposentado, junto com deepseek-chat, então tratar guias antigos como verdade atual é receita de bug
Próximo passo: roda o teste das duas rodadas na tua aplicação, compara o reasoning_tokens e confere o exemplo oficial de tool call em modo de raciocínio antes de escrever a tua camada de histórico
Até o próximo post! =)
Perguntas frequentes
Preciso reenviar o reasoning_content se a minha conversa não usa tools?
Não. Sem o parâmetro tools na requisição, o reasoning_content não precisa voltar no histórico. Se você mandar mesmo assim, ele é ignorado e não entra no contexto, sem gerar erro.
Por que a mesma conversa funciona no turno 1 e quebra 400 no turno 2?
Porque no primeiro turno não existe histórico anterior pra remontar, então o problema não aparece ainda. No segundo turno, se a requisição carrega tools e o reasoning_content do assistant sumiu do array, a API recusa com 400.
O reasoning_content conta como tokens de raciocínio cobrados?
O detalhamento de uso da resposta traz o campo reasoning_tokens dentro do objeto usage, mostrando quantos tokens foram gerados pra cadeia de pensamento. Isso dá pra comparar o custo entre uma chamada com e sem reenvio do campo.
Dá pra usar tool_choice required com o thinking mode ligado?
Não. No modo de raciocínio não há suporte a tool_choice required nem à escolha de ferramenta nomeada, e a API retorna 400 nesses casos. É preciso desligar o modo de raciocínio pra usar esse tipo de tool_choice.
Definir temperature no modo de raciocínio dá erro?
Não dá erro. temperature, presence_penalty e frequency_penalty são aceitos por compatibilidade no modo de raciocínio, mas não têm efeito nenhum no resultado.
Minhas requisições com deepseek-chat pararam de funcionar do nada, o que houve?
Os nomes legados deepseek-chat e deepseek-reasoner foram aposentados e não são mais acessíveis. Mas atenção: deepseek-v4-flash também já foi aposentado e está só temporariamente roteado, então o nome atual e correto é deepseek-flash. E deepseek-v4-pro, embora ainda responda, está sendo roteado para o V4.1-Flash (com tarifas de Flash) desde 14/09/2026, até o lançamento do V4.1-Pro.
Formações
Formação Vibe Coding
Do Prompt ao Produto: Crie Software Real com IA
- 474 aulas
- 20 projetos
- 39h 27min
Blog | Mais populares
DeepSeek V4 Pro Max: o que é e como escolher entre as variantes da família V4
DeepSeek V4 Pro Max não é um modelo separado: é o modo de raciocínio máximo do V4-Pro. Veja como funciona e como escolher entre as variantes.
Como rodar o DeepSeek V4 no Ollama: o passo a passo e o que checar antes de tentar
Rodar o DeepSeek V4 no Ollama hoje é via tag cloud: veja como fazer login, baixar a tag e usar via CLI ou API local, e quando vale ir de GGUF offline.
DeepSeek V4 Pro: o que é e quando compensa usar em vez do V4 Flash?
DeepSeek V4 Pro tem 1,6 tri de parâmetros e janela de 1 milhão de tokens. Entenda o preço, o desempenho e quando vale mais a pena que o V4 Flash.
