Processamento em lote com o DeepSeek Flash v4.1: como rodar milhares de chamadas sem se perder

fluxo de processamento em lote com DeepSeek Flash v4.1 organizando fila de chamadas por ID
Resposta rápida

O processamento em lote com o DeepSeek Flash v4.1 acontece no cliente: a referência oficial da API documenta Chat Completions, Responses, FIM Completion e listagem de modelos, e não há endpoint de batch offline documentado. Na prática, você fatia a fila com ID estável por item, força saída JSON com response_format, segura a concorrência com semáforo abaixo do limite da conta (a tabela oficial lista 2500 conexões simultâneas para deepseek-v4-flash), grava resultado parcial em JSONL e reprocessa só os IDs que faltaram. Some reasoning_effort = none nas tarefas mecânicas, prompt-prefixo fixo pro cache automático e rodada fora do pico, onde o preço é metade do de pico.

Fala aí, beleza? A DeepSeek soltou o DeepSeek-V4.1-Flash em 10/09/2026, já disponível na API e com suporte multimodal nativo, e a primeira coisa que passa na cabeça de quem trabalha com volume é a mesma: dá pra jogar minha fila de 50 mil itens nisso?

Dá, mas tem um detalhe que muda TODO o desenho do seu código

A referência oficial da API DeepSeek documenta Chat Completions, Responses, FIM Completion e listagem de modelos

Não tem endpoint de batch offline ali (aquela fila assíncrona onde você sobe um arquivo, vai tomar um café e volta pra buscar o resultado)

Ou seja: o lote é orquestrado por você, no cliente, com requisições concorrentes normais

E isso é menos assustador do que parece 🙂 Você precisa de quatro coisas: ID estável por item, um teto de concorrência, gravação parcial e uma fila de reprocesso. O resto é ajuste fino de custo.

O motor combina bem com esse papel: é um MoE multimodal com 552B de parâmetros no backbone, arquitetura Causal Encoder-Decoder de 40 camadas (20 de encoder causal + 20 de decoder), ativando 8B de parâmetros por token no prefill e 16B no decode

Bora montar o pipeline?

O que você precisa antes de disparar a primeira leva

Antes de escrever o loop, resolve essas decisões. Elas evitam refazer a rodada inteira depois.

Chave da API e SDK

A API DeepSeek é compatível com o formato da OpenAI, então dá pra usar o SDK da OpenAI só trocando a base_url para https://api.deepseek.com

Se você já tem código escrito pra OpenAI, é praticamente plug and play

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
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["DEEPSEEK_API_KEY"],
    base_url="https://api.deepseek.com",
)

Qual identificador de modelo usar

O identificador pra chamar o V4.1-Flash é deepseek-flash

Os antigos deepseek-v4-flash e deepseek-v4-flash-vision-exp roteiam temporariamente pro V4.1-Flash por compatibilidade, então código legado não quebra

E se liga nisso, porque mexe com orçamento: a partir de 04:00 UTC de 14/09/2026, todas as requisições para deepseek-v4-pro passam a ser roteadas pro V4.1-Flash e cobradas nas tarifas do V4.1-Flash, até o lançamento do V4.1-Pro

Se o seu pipeline hoje aponta pro Pro, vale antes revisar quando usar Pro e quando usar Flash em cada etapa do projeto

Thinking ligado ou desligado?

O modo de raciocínio é controlado pelo parâmetro reasoning_effort

O valor none desativa o thinking, e low, high e max ativam. O padrão é high

Pra lote mecânico (classificar, extrair campo, normalizar), thinking ligado é output caro pagando por raciocínio que você nem vai ler

max_tokens

max_tokens aceita de 1 a 384K (393216)

O padrão é 8K sem thinking e 64K com thinking (128K quando reasoning_effort é max)

Em lote, deixar o padrão passar é convite pra resposta gorda. Aperte o teto de acordo com a tarefa.

Passo a passo: montando o pipeline em lote com o DeepSeek Flash v4.1

A lógica é sempre a mesma, muda só o prompt lá dentro

  1. Fatie a fila em unidades pequenas, com ID estável por item

ID estável é o item que carrega identidade própria e não depende da ordem do arquivo. Se você usar o número da linha como ID, o dia que a fila for reordenada seu reprocesso vira loteria.

import hashlib, json

def carregar_fila(caminho):
    itens = []
    with open(caminho, encoding="utf-8") as f:
        for linha in f:
            reg = json.loads(linha)
            item_id = reg.get("id") or hashlib.sha1(
                reg["texto"].encode("utf-8")
            ).hexdigest()
            itens.append({"id": item_id, "texto": reg["texto"]})
    return itens

O erro comum deste passo: usar índice de array como ID. Funciona na primeira rodada e te destrói na segunda

  1. Padronize a saída com JSON mode

Pra forçar saída em JSON é preciso configurar response_format como {"type": "json_object"}, citar a palavra "json" no system ou user prompt E dar um exemplo do formato desejado

As três coisas juntas, não duas

SYSTEM = (
    "Você classifica tickets de suporte. "
    "Responda em json seguindo este formato: "
    '{"categoria": "cobranca|tecnico|outro", "confianca": 0.0}'
)

resp = client.chat.completions.create(
    model="deepseek-flash",
    messages=[
        {"role": "system", "content": SYSTEM},
        {"role": "user", "content": item["texto"]},
    ],
    response_format={"type": "json_object"},
    reasoning_effort="none",
    max_tokens=256,
)

O erro comum deste passo: esquecer a palavra "json" no prompt. Você configurou o response_format, jurou que estava certo, e o lote volta torto

Tem um caminho alternativo quando o contrato precisa ser mais duro: o modo strict de function calling, que exige a base_url https://api.deepseek.com/beta e strict: true em todas as functions do parâmetro tools, com o servidor validando o JSON Schema que você mandou

  1. Controle a concorrência com um semáforo

A DeepSeek define limite de concorrência por user_id, calculado no nível da CONTA, independentemente da API Key usada

Ou seja: criar cinco chaves não te dá cinco filas, beleza?

A tabela oficial de rate limit lista deepseek-v4-pro com 500 conexões simultâneas, deepseek-v4-flash com 2500 e deepseek-v4-flash-vision-exp com 2500

E aqui vale um aviso, porque é fácil se embananar: esses são os nomes que aparecem na tabela oficial, e o identificador que a gente usa no código é o deepseek-flash

A tabela não traz uma linha própria pro deepseek-flash, então não dá pra afirmar por achismo qual é o teto exato dele

Na prática isso não muda o desenho do seu pipeline: deixe o semáforo BEM abaixo de qualquer um desses valores, observe se aparece 429 e confira a tabela oficial antes de subir o teto

import asyncio

SEM = asyncio.Semaphore(64)

async def processar(item):
    async with SEM:
        return await chamar_api(item)

async def rodar(itens):
    return await asyncio.gather(
        *(processar(i) for i in itens), return_exceptions=True
    )

O erro comum deste passo: abrir um gather com a lista inteira sem semáforo. Você não dispara 50 mil requisições, você dispara 50 mil erros

  1. Isole filas concorrentes com user_id

O user_id é uma string no padrão [a-zA-Z0-9\-_]+, com no máximo 512 caracteres

Ele serve pra separar filas diferentes dentro da mesma conta: se um user_id específico estoura, só as requisições com aquele user_id recebem 429

resp = client.chat.completions.create(
    model="deepseek-flash",
    messages=mensagens,
    response_format={"type": "json_object"},
    extra_body={"user_id": "lote-classificacao-tickets"},
)

O erro comum deste passo: rodar o lote gigante no mesmo user_id do app em produção. Aí o batch derruba o usuário real, e ninguém merece isso

  1. Salve resultado parcial linha a linha

JSONL com append é o melhor amigo de quem roda lote. Cada item concluído vira uma linha no disco, na hora.

def gravar(caminho, item_id, payload):
    with open(caminho, "a", encoding="utf-8") as f:
        f.write(json.dumps(
            {"id": item_id, "resultado": payload}, ensure_ascii=False
        ) + "\n")

O erro comum deste passo: acumular tudo numa lista em memória e gravar no final. Um Ctrl+C, uma queda de rede, e horas de tokens pagos vão pro ralo

  1. Reprocesse só o que falhou

Como o ID é estável e você gravou linha a linha, o reprocesso é uma subtração

def ja_feitos(caminho):
    feitos = set()
    try:
        with open(caminho, encoding="utf-8") as f:
            for linha in f:
                feitos.add(json.loads(linha)["id"])
    except FileNotFoundError:
        pass
    return feitos

pendentes = [i for i in itens if i["id"] not in ja_feitos(SAIDA)]

Rodar de novo é rodar o mesmo script. Ele simplesmente pula o que já existe

O erro comum deste passo: gravar o item que falhou no MESMO arquivo de sucesso. Aí o filtro considera pronto o que está quebrado. Falha vai pra outro arquivo

  1. Ajuste o custo antes de escalar

Duas alavancas aqui

A primeira é reasoning_effort = none nas tarefas mecânicas, porque output é a parte cara da conta

A segunda é o cache de contexto em disco, que fica ativo por padrão pra todos os usuários, sem parâmetro pra ativar e sem mudar código

Pra ele pegar, o começo do seu prompt precisa ser IGUAL entre os itens: instrução fixa, exemplo de formato, taxonomia, tudo no prefixo, e o conteúdo variável do item por último

A unidade de armazenamento do cache é de 64 tokens, e conteúdo menor que isso não é cacheado. Prompt-prefixo minúsculo simplesmente não entra no jogo

Pra conferir se está funcionando, olhe a resposta:

u = resp.usage
print(u.prompt_cache_hit_tokens, u.prompt_cache_miss_tokens)

Se o prompt_cache_hit_tokens continua zerado depois de centenas de chamadas, seu prefixo não é tão fixo quanto você acha

O erro comum deste passo: carimbar timestamp, ID do item ou contador no começo do system prompt. Isso muda o prefixo e mata o cache

  1. Agende a rodada fora do pico

A janela de pico da API DeepSeek é 01:00 às 04:00 UTC e 06:00 às 10:00 UTC, de segunda a sexta

Todas as demais horas são fora de pico, e os preços em horário de pico são o DOBRO dos de fora de pico

A tabela do Flash em vigor, por 1 milhão de tokens fora de pico:

Componente Off-peak (US$ por 1M de tokens)
Input com cache hit 0,003
Input com cache miss 0,15
Output 0,60

Esses valores entraram em vigor às 04:00 UTC de 10/09/2026 (12:00 no horário de Pequim), revertendo a alta que tinha sido aplicada à série V4 em 17/08/2026, 23 dias antes

Pra fechar a conta do seu volume específico, vale a pena aprender a estimar o gasto por token antes de disparar a fila inteira

O erro comum deste passo: assumir que o horário do seu cron é UTC. Não é, e o lote de madrugada no Brasil pode cair BEM no meio do pico

Quando o lote quebra: 429, respostas fora do formato e parsing travado

Lote quebra. A diferença entre um pipeline maduro e um script de sexta-feira é o que acontece DEPOIS da quebra.

Sintoma: uma enxurrada de HTTP 429

Causa: estourar o limite de concorrência retorna erro HTTP 429. E como o limite é calculado no nível da conta por user_id, outro processo seu rodando ao mesmo tempo entra na mesma conta

Solução: derrube o teto do semáforo, isole a fila com um user_id próprio e mande o item de volta pra fila de pendentes em vez de descartar

Como prevenir: se o volume é real e recorrente, dá pra solicitar ampliação de capacidade à DeepSeek, sem custo adicional, dimensionada conforme a necessidade real do negócio. É pedido, não gambiarra

Sintoma: JSON malformado ou texto solto no meio do lote

Causa: quase sempre é response_format ausente, ou prompt sem a palavra "json", ou sem o exemplo do formato desejado

Solução: fixe o contrato (as três condições juntas) e trate o parse com try/except, mandando o item pra fila de reprocesso em vez de derrubar a rodada inteira

Como prevenir: valide a saída contra um schema antes de gravar, ou vá de function calling em modo strict, onde o servidor valida o JSON Schema enviado

Um cuidado extra que pega gente desprevenida: temperature, top_p, presence_penalty e frequency_penalty NÃO são suportados no modo thinking

Se seu wrapper injeta temperature=0 por padrão em tudo, você tem uma surpresa esperando

Sintoma: seu parser trava no streaming

Causa: requisições em streaming retornam linhas SSE do tipo : keep-alive

Solução: ignore essas linhas, elas não afetam o parsing do corpo JSON

Como prevenir: em lote, streaming raramente compensa. Se a saída é um JSON curto de classificação, resposta completa é mais simples de gravar e de reprocessar

Três lotes que valem a pena rodar no Flash v4.1

Classificação em massa

O caso mais óbvio e o mais barato

Rótulo curto, saída mínima, reasoning_effort = none, max_tokens apertado em algumas dezenas e prompt-prefixo fixo com a taxonomia inteira pro cache pegar

Aqui o custo mora quase todo no input, e é justo onde o cache hit faz o maior estrago a seu favor

Extração de campos de documentos

Nota fiscal, contrato, currículo, ficha de cadastro

Use json_object com exemplo do formato, ou function calling em modo strict quando o schema é grande e você quer validação do lado do servidor

max_tokens acompanha o tamanho real do registro extraído, não o do documento de entrada. Documento de 20 páginas pode virar um JSON de 300 tokens

Resumo de volumes grandes

O contexto de 1 milhão de tokens é o padrão em todos os serviços oficiais da DeepSeek, então o item por chamada pode ser BEM gordo

E como o V4.1-Flash chegou com multimodal nativo, dá pra montar lote com imagem também

Atenção ao bolso neste: resumo é a tarefa que mais gera output, e output custa 0,60 contra 0,15 do input com cache miss em off-peak, ou seja, quatro vezes mais por token

Aqui, sim, vale medir se um reasoning_effort mais alto melhora o resultado o suficiente pra justificar

Veja o DeepSeek na prática

Pra quem está começando do zero com o DeepSeek, este vídeo do canal mostra a construção de um app completo usando o DeepSeek dentro do Claude Code, do início até o deploy

Conclusão

Sem endpoint de batch offline documentado, o processamento em lote DeepSeek Flash v4.1 é um problema de engenharia do SEU lado, e a boa notícia é que ele é um problema conhecido

ID estável, gravação parcial linha a linha e fila de reprocesso resolvem a maior parte da dor

O resto é o teto do semáforo bem abaixo do limite da conta, user_id isolando a fila e prompt-prefixo fixo pra deixar o cache automático trabalhar

Próximo passo concreto, e faça o teste antes de escalar: rode uma amostra de 100 itens fora do pico, olhe usage.prompt_cache_hit_tokens e usage.prompt_cache_miss_tokens, ajuste o prefixo até o hit subir, e SÓ ENTÃO aumente a concorrência

E marca no calendário: em 14/09/2026, às 04:00 UTC, o tráfego de deepseek-v4-pro passa a cair no V4.1-Flash e a ser cobrado nas tarifas do Flash. Se você tem pipeline apontando pro Pro, é bom saber disso antes da rodada, não depois…

até o próximo post! 😀

Perguntas frequentes

Como o cache de contexto ajuda a economizar num lote grande de chamadas ao DeepSeek Flash v4.1?

O cache de contexto em disco fica ativo por padrão pra todo mundo, sem precisar mudar código ou configurar nada

A unidade mínima de cache é 64 tokens, então prompts repetidos entre itens do lote (aquele system prompt fixo, por exemplo) tendem a cair em cache hit

Dá pra acompanhar isso direto na resposta da API, nos campos usage.prompt_cache_hit_tokens e usage.prompt_cache_miss_tokens

Vale a pena programar o lote pra rodar fora do horário de pico da API DeepSeek?

Vale, porque o preço em horário de pico é o dobro do preço fora de pico

O pico vai das 01:00 às 04:00 UTC e das 06:00 às 10:00 UTC, de segunda a sexta, então fora dessas janelas (e nos fins de semana) já é considerado fora de pico

Pra série Flash, fora de pico fica em US$ 0,003 por 1M de tokens de input com cache hit, US$ 0,15 com cache miss e US$ 0,60 de output por 1M de tokens

Meu pipeline chama deepseek-v4-pro. O que muda a partir de 14/09/2026?

A partir de 04:00 UTC de 14/09/2026, toda requisição pra deepseek-v4-pro passa a ser roteada automaticamente pro V4.1-Flash, e cobrada nas tarifas do V4.1-Flash

Isso vale até o lançamento do V4.1-Pro

Se seu lote hoje aponta pro Pro, o custo por chamada muda sem você precisar alterar o identificador do modelo no código

Dá pra usar streaming num processamento em lote com o DeepSeek Flash v4.1?

Dá, e é uma opção válida quando você quer começar a gravar o resultado antes da resposta terminar

Só fica atento se você faz parsing manual do SSE: aparecem linhas de keep-alive no formato ": keep-alive" no meio do stream

Elas não afetam o corpo JSON da resposta, mas seu parser precisa ignorá-las em vez de tentar interpretar como dado

Dá pra aumentar o limite de concorrência da conta pra rodar um lote maior?

Dá. A DeepSeek permite solicitar ampliação de capacidade sem custo adicional, dimensionada conforme a necessidade real do negócio

Enquanto isso não acontece, vale olhar a tabela oficial de rate limit, que lista os tetos por nome de modelo: deepseek-v4-pro com 500 conexões simultâneas por user_id, deepseek-v4-flash com 2500 e deepseek-v4-flash-vision-exp com 2500, sempre calculados no nível da conta

Repara que a tabela não traz uma linha própria pro identificador deepseek-flash, o mesmo que você usa nas chamadas, então o caminho seguro é manter a concorrência bem abaixo desses valores e conferir a tabela oficial antes de subir o teto

Por que minha chamada em lote com thinking ligado ignora o parâmetro temperature?

Porque o modo thinking não suporta alguns parâmetros de amostragem: temperature, top_p, presence_penalty e frequency_penalty não funcionam nele

Isso acontece sempre que reasoning_effort está em low, high ou max (o padrão é high)

Se o seu lote depende de ajustar temperature, considere reasoning_effort = none pra desativar o thinking




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