A DeepSeek tornou-se, em pouco mais de um ano, um dos nomes mais pesquisados no mundo da inteligência artificial, e a sua API compatível com o formato OpenAI é hoje uma das formas mais baratas de meter um modelo de raciocínio a trabalhar dentro de uma aplicação real. Neste tutorial vamos construir, passo a passo, uma aplicação funcional que liga à API da DeepSeek, trata erros, gere custos e ainda usa o modo de raciocínio (reasoning) para tarefas mais complexas. No final vai ter um projeto completo, testado, pronto para adaptar aos seus próprios casos de uso.

Este guia não parte do zero teórico. Assume que já sabe programar em Python, mas não assume conhecimento prévio de APIs de IA generativa. Cada passo inclui código executável, a saída esperada e os erros mais prováveis de encontrar, para que consiga acompanhar mesmo sem experiência anterior com modelos de linguagem. Vamos também cobrir aspetos que a maioria dos tutoriais ignora: gestão de custos, tratamento de falhas de rede e a diferença prática entre os dois modelos disponíveis na API.

O que é a API da DeepSeek e porque vale a pena usá-la

A DeepSeek é um laboratório de IA chinês que ganhou notoriedade internacional por publicar modelos de peso aberto com desempenho competitivo face aos grandes laboratórios ocidentais, a um custo de treino e de inferência muito mais baixo. A empresa mantém dois produtos principais acessíveis via API: a família de chat de propósito geral e a família de raciocínio, esta última pensada para problemas de matemática, lógica e programação que beneficiam de um passo de “pensamento” explícito antes da resposta final.

Na prática, a API expõe dois alias estáveis: deepseek-chat, que aponta para a geração mais recente da linha de conversação (atualmente a família DeepSeek-V4, com a variante rápida “Flash” e a variante mais capaz “Pro”), e deepseek-reasoner, que aponta para a linha de raciocínio da família DeepSeek-R1. A vantagem destes alias é simples: a DeepSeek pode atualizar o modelo por trás do nome sem que o programador tenha de mudar uma linha de código. É essa a razão pela qual este tutorial não fica desatualizado assim que sair a próxima versão.

A grande atração para quem desenvolve em Portugal é o preço. A API da DeepSeek é, historicamente, uma ordem de grandeza mais barata do que os concorrentes diretos por milhão de tokens, o que a torna atrativa para protótipos, produtos indie e projetos académicos com orçamento apertado. Isso não dispensa cuidado: como qualquer API paga por token, os custos escalam com o volume, e é por isso que este tutorial inclui uma secção inteira sobre controlo de custos.

Pré-requisitos: o que precisa antes de começar

Antes de avançar, confirme que tem os seguintes itens instalados e configurados. Não vale a pena saltar esta lista, porque os erros mais comuns neste tipo de tutorial vêm precisamente de versões desatualizadas ou de chaves de API mal configuradas.

  • Python 3.10 ou superior (recomendado 3.11+) – confirme com python3 --version
  • Node.js 20 LTS ou superior, caso prefira seguir os exemplos em JavaScript – confirme com node --version
  • Uma conta na plataforma da DeepSeek com uma chave de API ativa e crédito pré-pago carregado
  • O SDK oficial da OpenAI para Python (openai>=1.40.0) ou Node (openai@^4.50.0), já que a API da DeepSeek segue o mesmo formato
  • A biblioteca python-dotenv para gerir variáveis de ambiente com segurança
  • Um editor de código com suporte a Python (VS Code, PyCharm ou equivalente)
  • Ligação à internet estável e um terminal com acesso a pip ou npm

Se vai seguir os exemplos de integração com frameworks de agentes, adicione também langchain-deepseek e langchain-core à lista, e reserve uns 15 minutos extra para a secção de RAG (geração aumentada por recuperação) mais à frente neste artigo.

Passo 1: Criar a conta e obter a chave de API

Aceda à plataforma oficial da DeepSeek e crie uma conta com o seu email. Depois de confirmar o email, entre na secção de gestão de chaves de API e gere uma nova chave. Guarde-a imediatamente num gestor de palavras-passe: a chave só é mostrada uma vez e, se a perder, terá de gerar outra.

Aproveite este momento para dar um nome descritivo à chave (por exemplo, “dev-local” ou “producao-app-x”), sobretudo se planeia criar múltiplas chaves para separar ambientes. Isto facilita revogar uma chave específica mais tarde sem afetar as restantes, caso alguma delas seja comprometida ou deixe de ser necessária.

De seguida, carregue crédito na conta. A DeepSeek funciona com um modelo pré-pago: sem saldo, os pedidos à API falham com um erro de saturação de conta, não com um erro de autenticação, o que confunde muitos principiantes na primeira tentativa.

Passo 2: Preparar o ambiente de desenvolvimento

Crie uma pasta nova para o projeto e um ambiente virtual isolado. Isto evita conflitos entre as dependências deste tutorial e outros projetos Python que já tenha na sua máquina.

mkdir deepseek-tutorial-app
cd deepseek-tutorial-app
python3 -m venv venv
source venv/bin/activate   # No Windows: venv\Scripts\activate
pip install --upgrade pip
pip install openai python-dotenv

Confirme que a instalação correu bem executando pip show openai. Deve ver a versão instalada listada sem erros. Se aparecer “Package(s) not found”, o ambiente virtual não está ativo, volte a correr o comando source venv/bin/activate.

Passo 3: Guardar a chave de API em segurança

Nunca escreva a chave de API diretamente no código-fonte, sobretudo se o projeto vai para um repositório Git. Crie um ficheiro .env na raiz do projeto:

DEEPSEEK_API_KEY=a_sua_chave_aqui

E crie também um ficheiro .gitignore com, no mínimo, a linha .env e venv/. Isto parece um passo menor, mas é a causa número um de chaves de API expostas em repositórios públicos, um erro que já custou dinheiro real a muitos programadores que esqueceram este passo.

Passo 4: Fazer a primeira chamada à API

Como a API da DeepSeek segue o formato da OpenAI, basta apontar o cliente oficial para o endereço base correto. Crie um ficheiro primeiro_teste.py:

import os
from dotenv import load_dotenv
from openai import OpenAI

load_dotenv()

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

resposta = client.chat.completions.create(
    model="deepseek-chat",
    messages=[
        {"role": "system", "content": "És um assistente útil que responde em português de Portugal."},
        {"role": "user", "content": "Explica em duas frases o que é uma API REST."},
    ],
    temperature=0.7,
    max_tokens=200,
)

print(resposta.choices[0].message.content)

Execute com python primeiro_teste.py. Se tudo estiver correto, deve receber uma resposta em texto corrido em poucos segundos. Um exemplo de saída típica:

Uma API REST é uma interface que permite a comunicação entre sistemas através de pedidos HTTP (GET, POST, PUT, DELETE) sobre recursos identificados por URLs. Cada pedido é independente e sem estado, o que facilita a escalabilidade e a integração entre serviços diferentes.

Passo 5: Usar o modo de raciocínio para problemas complexos

Para tarefas que exigem lógica passo a passo, como problemas de matemática, depuração de código ou planeamento em várias etapas, troque o modelo para deepseek-reasoner. Este modelo devolve um campo adicional com o raciocínio interno antes da resposta final, o que é útil tanto para depurar a lógica do modelo como para mostrar transparência ao utilizador final.

resposta = client.chat.completions.create(
    model="deepseek-reasoner",
    messages=[
        {"role": "user", "content": "Um comboio parte às 14h32 e demora 3h47m a chegar. A que horas chega?"}
    ],
)

mensagem = resposta.choices[0].message
print("Raciocínio:", getattr(mensagem, "reasoning_content", "não disponível"))
print("Resposta final:", mensagem.content)

Note que o modo de raciocínio consome mais tokens e demora mais tempo a responder do que o deepseek-chat normal, precisamente porque gera esse passo intermédio de pensamento. Reserve-o para tarefas que realmente beneficiam de lógica explícita, não para conversas simples do dia a dia, sob pena de pagar mais do que precisa.

Passo 6: Implementar respostas em streaming

Para uma aplicação com interface de utilizador, esperar pela resposta completa antes de mostrar qualquer texto é uma má experiência. O streaming permite mostrar o texto token a token, à medida que é gerado, tal como acontece nas interfaces de chat mais conhecidas do mercado.

stream = client.chat.completions.create(
    model="deepseek-chat",
    messages=[{"role": "user", "content": "Escreve um parágrafo curto sobre cibersegurança."}],
    stream=True,
)

for chunk in stream:
    conteudo = chunk.choices[0].delta.content
    if conteudo:
        print(conteudo, end="", flush=True)
print()

Passo 7: Gerir histórico de conversa com múltiplas mensagens

A API não guarda o histórico da conversa automaticamente, cada pedido é independente. A responsabilidade de manter o contexto é sua, e isso significa reenviar as mensagens anteriores em cada novo pedido.

class Conversa:
    def __init__(self, sistema):
        self.historico = [{"role": "system", "content": sistema}]

    def enviar(self, texto_utilizador):
        self.historico.append({"role": "user", "content": texto_utilizador})
        resposta = client.chat.completions.create(
            model="deepseek-chat",
            messages=self.historico,
        )
        conteudo = resposta.choices[0].message.content
        self.historico.append({"role": "assistant", "content": conteudo})
        return conteudo


chat = Conversa("És um assistente técnico conciso.")
print(chat.enviar("O que é um índice de base de dados?"))
print(chat.enviar("E como é que isso afeta a velocidade de escrita?"))

Repare que a segunda pergunta (“E como é que isso afeta…”) só faz sentido porque o histórico da primeira troca foi reenviado. Sem essa gestão de estado, o modelo trataria cada pergunta como se fosse a primeira da conversa.

Passo 8: Chamadas de função (function calling) para ligar a sistemas externos

Uma das capacidades mais úteis para construir aplicações reais é deixar o modelo decidir quando chamar uma função externa, por exemplo para consultar uma base de dados, o estado do tempo ou o preço de uma criptomoeda. Defina a função com um esquema JSON e deixe o modelo escolher quando a usar.

ferramentas = [
    {
        "type": "function",
        "function": {
            "name": "obter_preco_acao",
            "description": "Devolve o preço atual de uma ação pelo seu ticker",
            "parameters": {
                "type": "object",
                "properties": {
                    "ticker": {"type": "string", "description": "Símbolo da ação, ex: AAPL"}
                },
                "required": ["ticker"],
            },
        },
    }
]

resposta = client.chat.completions.create(
    model="deepseek-chat",
    messages=[{"role": "user", "content": "Qual é o preço atual da ação da Apple?"}],
    tools=ferramentas,
)

chamada = resposta.choices[0].message.tool_calls
if chamada:
    print("Função pedida:", chamada[0].function.name)
    print("Argumentos:", chamada[0].function.arguments)

O modelo não executa a função por si só, apenas devolve o nome e os argumentos que gostaria de usar. É o seu código que interpreta esse pedido, corre a função real (por exemplo, uma chamada a uma API de bolsa) e devolve o resultado ao modelo numa segunda chamada, para que ele formule a resposta final em linguagem natural.

Passo 9: Construir um pipeline simples de RAG (geração aumentada por recuperação)

Se a sua aplicação precisa de responder com base em documentos próprios (manuais internos, FAQs, contratos), o modelo sozinho não tem esse conhecimento. A solução é o RAG: primeiro recupera-se o excerto relevante de uma base de conhecimento, depois esse excerto é injetado no prompt como contexto.

documentos = [
    "A política de reembolso permite devoluções até 30 dias após a compra.",
    "O suporte técnico está disponível de segunda a sexta, das 9h às 18h.",
    "As atualizações de segurança são lançadas todas as terças-feiras.",
]

def procurar_contexto(pergunta, documentos):
    palavras = pergunta.lower().split()
    pontuados = [(doc, sum(p in doc.lower() for p in palavras)) for doc in documentos]
    pontuados.sort(key=lambda x: x[1], reverse=True)
    return pontuados[0][0]

pergunta = "Quando são lançadas as atualizações de segurança?"
contexto = procurar_contexto(pergunta, documentos)

resposta = client.chat.completions.create(
    model="deepseek-chat",
    messages=[
        {"role": "system", "content": f"Responde apenas com base neste contexto: {contexto}"},
        {"role": "user", "content": pergunta},
    ],
)
print(resposta.choices[0].message.content)

Este exemplo usa uma procura simples por palavras-chave, suficiente para demonstrar o conceito. Numa aplicação de produção, substitua a função procurar_contexto por uma base de dados vetorial (como Chroma, Qdrant ou pgvector) que compare embeddings semânticos em vez de palavras exatas, o que devolve resultados muito mais precisos quando a pergunta usa sinónimos ou frases diferentes das do documento original.

Outro detalhe importante do RAG é o tamanho dos excertos (chunks) que divide os documentos originais. Excertos demasiado pequenos perdem contexto e obrigam o modelo a adivinhar informação em falta. Excertos demasiado grandes desperdiçam tokens e podem diluir a relevância da resposta com informação a mais. Um ponto de partida razoável para documentação técnica costuma ser entre 300 e 800 palavras por excerto, com alguma sobreposição entre excertos consecutivos para não cortar frases importantes a meio.

Passo 10: Tratamento de erros e lógica de repetição (retry)

Em produção, pedidos falham: a rede oscila, a conta fica sem saldo, ou o servidor está sob carga elevada. Uma aplicação robusta trata estes casos em vez de rebentar com uma exceção não apanhada.

import time
from openai import APIError, APIConnectionError, RateLimitError

def chamar_com_retry(mensagens, tentativas=3):
    for tentativa in range(1, tentativas + 1):
        try:
            return client.chat.completions.create(
                model="deepseek-chat",
                messages=mensagens,
                timeout=30,
            )
        except RateLimitError:
            espera = 2 ** tentativa
            print(f"Limite de taxa atingido, a aguardar {espera}s...")
            time.sleep(espera)
        except APIConnectionError:
            print("Falha de ligação, a tentar novamente...")
            time.sleep(2)
        except APIError as erro:
            print(f"Erro da API: {erro}")
            break
    raise RuntimeError("Todas as tentativas falharam")

Este padrão de backoff exponencial (esperar cada vez mais tempo entre tentativas) evita bombardear a API com pedidos repetidos quando ela já está sob pressão, o que só pioraria a situação.

Passo 11: Controlar custos e limitar o consumo de tokens

Cada pedido à API consome tokens de entrada (o que envia) e tokens de saída (o que recebe), e ambos contam para a fatura. Um erro comum de principiante é deixar o max_tokens sem limite num ambiente de produção, o que pode gerar respostas desnecessariamente longas e caras.

resposta = client.chat.completions.create(
    model="deepseek-chat",
    messages=mensagens,
    max_tokens=500,
)

uso = resposta.usage
print(f"Tokens de entrada: {uso.prompt_tokens}")
print(f"Tokens de saída: {uso.completion_tokens}")
print(f"Total: {uso.total_tokens}")

Guarde estes valores num registo (log) para acompanhar o consumo ao longo do tempo. Se a aplicação tiver muitos utilizadores, considere também aplicar um limite diário por utilizador, para evitar que uma conta isolada gere uma fatura desproporcional.

Passo 12: Publicar a aplicação como um pequeno serviço web

Para transformar os exemplos anteriores numa aplicação utilizável, embrulhe a lógica num servidor web leve com FastAPI. Instale a dependência extra:

pip install fastapi uvicorn
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Pedido(BaseModel):
    pergunta: str

@app.post("/perguntar")
def perguntar(pedido: Pedido):
    resposta = client.chat.completions.create(
        model="deepseek-chat",
        messages=[{"role": "user", "content": pedido.pergunta}],
        max_tokens=400,
    )
    return {"resposta": resposta.choices[0].message.content}

Inicie o servidor com uvicorn nome_do_ficheiro:app --reload e teste com um pedido POST para http://localhost:8000/perguntar. A partir daqui tem uma base funcional que pode ligar a uma interface web, uma extensão de browser ou uma aplicação móvel.

Passo 13: Integrar a API com LangChain para pipelines mais complexos

Para aplicações que combinam múltiplas fontes de dados, cadeias de prompts ou agentes com várias ferramentas, escrever tudo à mão com o SDK da OpenAI torna-se rapidamente difícil de manter. O LangChain resolve isso com abstrações reutilizáveis, e mantém um integração oficial para a DeepSeek através do pacote langchain-deepseek.

pip install langchain-deepseek langchain-core
from langchain_deepseek import ChatDeepSeek
from langchain_core.messages import HumanMessage, SystemMessage

modelo = ChatDeepSeek(
    model="deepseek-chat",
    api_key=os.environ["DEEPSEEK_API_KEY"],
    temperature=0.3,
)

mensagens = [
    SystemMessage(content="És um revisor técnico de documentação de software."),
    HumanMessage(content="Revê este parágrafo e aponta ambiguidades: 'O sistema processa os dados rapidamente.'"),
]

resultado = modelo.invoke(mensagens)
print(resultado.content)

A vantagem de usar o LangChain aparece quando o projeto cresce: pode encadear este passo com um recuperador de documentos, um verificador de saída estruturada e um passo de formatação final, tudo através da mesma sintaxe de composição, sem reescrever a lógica de chamada à API em cada etapa. Para projetos pequenos e médios, no entanto, o SDK direto da OpenAI mostrado nos passos anteriores costuma ser suficiente e mais fácil de depurar, porque expõe menos camadas de abstração entre o seu código e a resposta da API.

Passo 14: Calcular o custo real de um pedido antes de o enviar

Como a faturação é feita por token e não por pedido, vale a pena construir um pequeno estimador de custo antes de lançar a aplicação em produção, sobretudo se o volume de utilizadores for imprevisível. Uma forma simples é contar tokens antes de enviar o pedido, usando a biblioteca tiktoken como aproximação (a tokenização exata da DeepSeek pode variar ligeiramente, mas o valor aproximado já é suficiente para orçamentar).

import tiktoken

def estimar_tokens(texto):
    codificador = tiktoken.get_encoding("cl100k_base")
    return len(codificador.encode(texto))

prompt_sistema = "Responde de forma técnica e concisa."
prompt_utilizador = "Explica a diferença entre TCP e UDP."

total_entrada = estimar_tokens(prompt_sistema) + estimar_tokens(prompt_utilizador)
print(f"Tokens de entrada estimados: {total_entrada}")

Multiplique o número de tokens estimados pelo preço por milhão de tokens publicado na página oficial de preços da DeepSeek (os valores variam entre os modelos deepseek-chat e deepseek-reasoner e são atualizados periodicamente, por isso confirme sempre o valor corrente antes de fazer projeções financeiras para um produto em produção). Multiplicar por um fator de segurança de 1.3 a 1.5 no lado da saída é uma prática comum, porque a resposta do modelo é sempre desconhecida à partida e pode ultrapassar o valor médio esperado.

Comparação de modelos disponíveis na API da DeepSeek

Alias do modeloUso recomendadoLatência típicaCusto relativoSuporta streaming
deepseek-chatConversação geral, redação, resumosBaixaBaixoSim
deepseek-reasonerMatemática, lógica, depuração de códigoMais altaMédioSim
deepseek-chat (function calling)Agentes, integrações com sistemas externosBaixa a médiaBaixo a médioSim

Note que os valores de latência e custo são relativos entre os próprios modelos da DeepSeek, não comparações absolutas com outros fornecedores. O modo de raciocínio é sempre mais lento e mais caro do que o modo de chat normal, porque gera tokens extra de raciocínio interno antes de chegar à resposta final.

Na prática, a decisão entre os dois alias raramente é ambígua depois de testar ambos no seu próprio caso de uso. Se a resposta do deepseek-chat já resolve a tarefa com qualidade suficiente, fica-se por aí: é mais rápido e mais barato. Só vale a pena mudar para deepseek-reasoner quando notar erros de lógica repetidos, respostas inconsistentes em problemas com múltiplos passos, ou quando a tarefa envolve cálculo explícito que o modelo de chat normal tende a simplificar demasiado.

5 erros comuns a evitar

  • Não usar o modo de raciocínio para tudo: aplicar deepseek-reasoner a perguntas simples encarece e atrasa a aplicação sem ganho real de qualidade.
  • Ignorar o campo usage: não medir o consumo de tokens desde o primeiro dia torna impossível prever a fatura no fim do mês.
  • Não reenviar o histórico completo: esquecer mensagens anteriores no array messages quebra a continuidade da conversa e confunde o utilizador.
  • Guardar a chave de API no código: subir a chave para um repositório público é uma das causas mais frequentes de contas comprometidas.
  • Não tratar limites de taxa: assumir que a API nunca falha leva a aplicações que rebentam em produção assim que o tráfego aumenta.

Estes cinco erros têm uma coisa em comum: nenhum deles aparece durante os testes locais com um único utilizador. Só se tornam visíveis quando a aplicação sai do ambiente controlado do seu portátil e enfrenta tráfego real, picos de utilização ou uma rede instável. É por isso que vale a pena tratá-los desde a primeira versão do código, e não deixar para “depois, quando houver tempo”.

Segurança ao expor a API a utilizadores finais

Se a sua aplicação vai expor um campo de texto livre onde o utilizador escreve diretamente para o modelo, considere o risco de injeção de prompt: um utilizador malicioso pode tentar convencer o modelo a ignorar as instruções do sistema, revelar o prompt interno ou executar ações fora do âmbito pretendido. Nunca coloque segredos (chaves de API de outros serviços, credenciais de base de dados) dentro do prompt de sistema, porque um modelo de linguagem pode, em certas condições, ser induzido a repeti-los na resposta.

Trate a saída do modelo como input não confiável sempre que ela alimentar outro sistema automatizado, por exemplo se o texto gerado for usado para construir uma query de base de dados ou um comando de shell. Valide, sanitize e, sempre que possível, use formatos estruturados (JSON com esquema definido) em vez de texto livre para qualquer output que vá desencadear uma ação automática na sua infraestrutura. A chave de API em si deve viver apenas no lado do servidor: nunca a exponha no código de um cliente web ou móvel, porque qualquer pessoa com acesso às ferramentas de desenvolvimento do browser conseguiria extraí-la em segundos.

Dicas avançadas para produção

Depois de dominar o básico, há um conjunto de práticas que separam um protótipo de um serviço pronto para utilizadores reais. Primeiro, use caching de prompts sempre que repetir o mesmo contexto do sistema em muitos pedidos, o que reduz custos em aplicações com um prompt de sistema longo e estável. Segundo, defina temperature baixa (entre 0.0 e 0.3) para tarefas que exigem consistência, como extração de dados estruturados, e reserve valores mais altos (0.7 a 1.0) para tarefas criativas.

Terceiro, valide sempre a saída do modelo antes de a usar em lógica crítica, sobretudo quando pede dados em formato JSON. Use o parâmetro response_format={"type": "json_object"} para forçar o modelo a devolver JSON válido, e mesmo assim envolva o parsing num bloco try/except, porque nenhum modelo garante 100% de conformidade em todos os casos. Por fim, isole o tráfego de teste do tráfego real usando chaves de API diferentes para ambiente de desenvolvimento e produção, o que facilita auditar custos e detetar comportamento anómalo.

Uma quinta prática, menos óbvia mas igualmente importante, é registar não só o consumo de tokens mas também a latência de cada pedido. Picos de latência costumam ser o primeiro sinal de que a API está sob carga elevada do lado do fornecedor, ou de que a rede da sua própria infraestrutura tem um problema pontual. Ter esse histórico facilita muito diagnosticar se uma lentidão reportada por utilizadores é um problema seu ou um problema externo, e evita horas perdidas a depurar código que, afinal, está a funcionar como esperado.

Resolução de problemas: 8+ situações comuns

  • Erro 401 (não autorizado): a chave de API está incorreta, expirou ou não foi carregada do ficheiro .env. Confirme com print(os.environ.get("DEEPSEEK_API_KEY")) que a variável existe.
  • Erro 402 ou saldo insuficiente: a conta ficou sem crédito pré-pago. Aceda à plataforma e recarregue saldo antes de continuar os testes.
  • Erro 429 (limite de taxa): está a enviar pedidos demasiado depressa. Implemente o padrão de retry com backoff exponencial mostrado no Passo 10.
  • Resposta vazia ou cortada a meio: o valor de max_tokens está demasiado baixo para a resposta pedida. Aumente o limite ou peça uma resposta mais curta no prompt.
  • Streaming não mostra nada no terminal: falta o parâmetro flush=True no print, o que faz com que o buffer do terminal só mostre o texto no final.
  • reasoning_content devolve “não disponível”: está a usar o modelo deepseek-chat em vez de deepseek-reasoner. Só o modelo de raciocínio devolve esse campo.
  • Erro de módulo não encontrado (openai): o ambiente virtual não está ativo. Corra source venv/bin/activate antes de executar o script.
  • JSON inválido na resposta: mesmo com response_format definido, valide sempre com json.loads dentro de um try/except, porque respostas malformadas acontecem, sobretudo com prompts ambíguos.
  • Latência muito alta em todos os pedidos: confirme se está a usar deepseek-reasoner sem necessidade, ou se o max_tokens está definido para um valor muito elevado.

DeepSeek vs outras APIs de IA: onde é que ela se encaixa

CritérioDeepSeek APIAlternativas diretas
Formato da APICompatível com o SDK da OpenAICada fornecedor tem o seu próprio SDK ou também segue o formato OpenAI
Modelo de raciocínio dedicadoSim, alias deepseek-reasonerVaria por fornecedor
Pesos abertos disponíveisSim, publicados no Hugging FaceVaria, muitos fornecedores mantêm pesos fechados
Ideal paraProtótipos, produtos indie, tarefas de raciocínio a baixo custoCasos que exigem SLAs empresariais específicos

Se já testou a família Ollama para correr modelos localmente, ou construiu um pipeline com a API da Mistral, vai notar que a lógica de programação aqui é praticamente idêntica: o formato de mensagens, os parâmetros de temperatura e o tratamento de streaming seguem a mesma convenção que se tornou padrão de facto na indústria.

API na nuvem ou alojamento próprio: qual escolher

Uma dúvida frequente entre quem começa a explorar a DeepSeek é se compensa mais usar a API paga ou descarregar os pesos abertos e correr o modelo em hardware próprio. A resposta depende do volume de utilização e da sensibilidade dos dados. Para protótipos, produtos com poucos utilizadores ou picos de tráfego imprevisíveis, a API é quase sempre a opção mais simples e mais barata: não há custo de hardware, não há manutenção de servidor GPU e a escalabilidade é automática.

Já para aplicações com volume elevado e constante, ou que lidam com dados sensíveis que não podem sair da infraestrutura da empresa por razões de conformidade, o alojamento próprio com ferramentas como vLLM ou Ollama pode compensar a médio prazo, apesar do investimento inicial em GPUs. Se está a começar, comece sempre pela API: é possível migrar mais tarde para alojamento próprio depois de validar que o produto tem procura suficiente para justificar esse investimento, e não o contrário.

Vale ainda notar que os dois caminhos não são mutuamente exclusivos. Muitas equipas usam a API da DeepSeek em desenvolvimento e em ambientes de baixo tráfego, e reservam o alojamento próprio apenas para os componentes de maior volume ou maior sensibilidade de dados, combinando o melhor dos dois mundos consoante o caso de uso específico de cada parte da aplicação.

Projeto completo: assistente de perguntas e respostas com contexto

Juntando tudo o que foi visto, aqui fica a estrutura final do projeto, pronta a correr:

import os
import json
import time
from dotenv import load_dotenv
from openai import OpenAI, RateLimitError, APIConnectionError
from fastapi import FastAPI
from pydantic import BaseModel

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

BASE_CONHECIMENTO = [
    "O horário de suporte é das 9h às 18h, de segunda a sexta.",
    "As devoluções são aceites até 30 dias após a compra.",
]

class Pergunta(BaseModel):
    texto: str

def procurar(pergunta, docs):
    palavras = pergunta.lower().split()
    pontuados = [(d, sum(p in d.lower() for p in palavras)) for d in docs]
    pontuados.sort(key=lambda x: x[1], reverse=True)
    return pontuados[0][0]

def chamar_com_retry(mensagens, tentativas=3):
    for t in range(1, tentativas + 1):
        try:
            return client.chat.completions.create(model="deepseek-chat", messages=mensagens, max_tokens=400, timeout=30)
        except RateLimitError:
            time.sleep(2 ** t)
        except APIConnectionError:
            time.sleep(2)
    raise RuntimeError("Falha após múltiplas tentativas")

@app.post("/perguntar")
def perguntar(pedido: Pergunta):
    contexto = procurar(pedido.texto, BASE_CONHECIMENTO)
    resposta = chamar_com_retry([
        {"role": "system", "content": f"Responde apenas com base neste contexto: {contexto}"},
        {"role": "user", "content": pedido.texto},
    ])
    return {
        "resposta": resposta.choices[0].message.content,
        "tokens_usados": resposta.usage.total_tokens,
    }

Este projeto junta gestão de chave de API, um pipeline de RAG simplificado, tratamento de erros com retry e um endpoint web funcional, tudo em menos de 60 linhas. É uma base sólida para expandir com uma base de dados vetorial real, autenticação de utilizadores e um limite de consumo por conta.

Para testar o endpoint sem escrever uma interface gráfica, use o comando curl diretamente no terminal:

curl -X POST http://localhost:8000/perguntar \
  -H "Content-Type: application/json" \
  -d '{"texto": "Até quando posso devolver um produto?"}'

Uma resposta bem-sucedida devolve um objeto JSON com o texto gerado e o número total de tokens consumidos nesse pedido específico, o que já lhe dá visibilidade imediata sobre o custo de cada interação sem ter de consultar o painel da plataforma. A partir daqui, os próximos passos naturais são adicionar autenticação (por exemplo com uma chave própria da sua aplicação, distinta da chave da DeepSeek), persistir o histórico de conversas numa base de dados e colocar o serviço atrás de um proxy reverso com HTTPS antes de o expor publicamente.

Perguntas frequentes

A API da DeepSeek é gratuita?

Não. Funciona num modelo pré-pago, cobrando por milhão de tokens de entrada e saída. Novas contas podem receber crédito promocional inicial, mas o uso contínuo exige recarregar saldo na plataforma.

Preciso do SDK da OpenAI para usar a API da DeepSeek?

Não é obrigatório, mas é a via mais simples. Como a API segue o mesmo formato, basta mudar o base_url e a chave de API no SDK oficial da OpenAI para Python ou Node, sem reescrever a lógica da aplicação.

Qual a diferença entre deepseek-chat e deepseek-reasoner?

O deepseek-chat é otimizado para conversação geral, respostas rápidas e custo mais baixo. O deepseek-reasoner gera um passo de raciocínio interno antes da resposta final, o que o torna mais indicado para matemática, lógica e depuração de código, ao custo de maior latência e mais tokens consumidos.

Posso usar a API da DeepSeek em produção?

Sim, desde que implemente tratamento de erros, limites de taxa e monitorização de custos, como mostrado nos Passos 10 e 11 deste tutorial. Trate-a com o mesmo rigor de qualquer dependência externa crítica.

Os modelos DeepSeek têm pesos abertos que posso descarregar?

Sim, a DeepSeek publica pesos de vários modelos das famílias V3, V4 e R1 no Hugging Face sob licenças permissivas como MIT, o que permite descarregar e correr localmente, embora exija hardware significativo para os modelos maiores. Este tutorial foca-se na via de API, mais simples para a maioria dos projetos.

Como controlo os custos se a aplicação tiver muitos utilizadores?

Registe o campo usage de cada resposta, defina limites de max_tokens sensatos por tipo de pedido, e considere aplicar quotas diárias por utilizador ao nível da sua própria aplicação, já que a API em si não impõe esse limite automaticamente.

O que fazer se receber o erro 429 com frequência?

Implemente a lógica de retry com backoff exponencial mostrada no Passo 10, e considere agrupar pedidos ou introduzir uma fila de processamento se o volume de tráfego for elevado e constante.

Fontes e documentação oficial: documentação da API DeepSeek, repositórios oficiais no GitHub, modelos publicados no Hugging Face, SDK Python da OpenAI e integração DeepSeek no LangChain.