Alternar tema

Chamadas à API do Ollama: do curl à interface compatível com o SDK da OpenAI

Easton editorial illustration: modular AI application workbench

Aquele comando curl no terminal retornou um JSON com apenas metade de uma palavra. Depois de duas horas tentando entender o problema, descobri que a causa era a resposta em streaming. Por padrão, o Ollama entrega o conteúdo aos poucos, como um fluxo contínuo, e cada objeto JSON contém apenas alguns caracteres.

Para executar LLMs localmente, o Ollama reduziu bastante a barreira de entrada: baixar, instalar e executar — três etapas. Mas, na hora de chamar a API, é fácil se confundir. Qual é a diferença entre a API REST nativa e a interface compatível com o SDK da OpenAI? Como processar respostas em streaming?

Neste artigo, reuni os problemas que encontrei, desde comandos curl até a migração para o SDK da OpenAI sem alterar a lógica do código, além de alguns detalhes que a documentação não deixa tão explícitos.


O Ollama oferece duas APIs

Confesso que isso me confundiu por um bom tempo. Na prática, o Ollama oferece duas interfaces de API diferentes:

API REST nativa: http://localhost:11434/api/*

  • Endpoints: /api/generate para gerar texto, /api/chat para conversas e /api/tags para listar modelos
  • Resposta em streaming por padrão — exatamente o problema que encontrei às três da manhã
  • Chamada HTTP direta, sem precisar de SDK

Interface compatível com a OpenAI: http://localhost:11434/v1/*

  • Endpoints: /v1/chat/completions, /v1/completions e /v1/models
  • Compatível com os SDKs da OpenAI para Python e JavaScript
  • Funciona com o ecossistema de ferramentas da OpenAI já existente

Você pode se perguntar por que existem duas opções. A resposta é que cada uma tem seu papel. A API nativa é mais leve e direta, ideal para quem escreve o próprio cliente HTTP. Já a interface compatível com a OpenAI permite reutilizar código criado para o SDK da OpenAI: basta trocar o base_url.

Sinceramente, é uma decisão de design bem inteligente. Ela atende tanto quem quer fazer uma chamada simples quanto equipes que já têm código integrado ao ecossistema da OpenAI.


API REST nativa: começando pelo curl

Vamos começar pela API nativa. Ela é bem direta: uma interface REST padrão.

Chamada básica com curl

O exemplo mais simples é uma geração de texto:

curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "Why is the sky blue?",
  "stream": false
}'

Repare no stream: false. Por padrão, o Ollama transmite o conteúdo em streaming. Se você quiser uma resposta JSON completa, precisa desativar o streaming explicitamente. Caso contrário, verá uma sequência parecida com esta:

{"model":"llama3.2","response":"That","done":false}
{"model":"llama3.2","response":"'","done":false}
{"model":"llama3.2","response":"s","done":false}
{"model":"llama3.2","response":" a","done":false}
...
{"model":"llama3.2","response":"!","done":true}

Cada objeto JSON contém apenas alguns caracteres, enviados token por token. Esse é o formato NDJSON, sigla de Newline-Delimited JSON: um objeto JSON por linha. Naquela madrugada, eu não tinha percebido isso e tentei processar a resposta como um JSON comum. O resultado foi receber apenas o "That" do primeiro objeto.

O modo de conversa é mais útil

A geração isolada serve para tarefas simples, mas o modo de conversa é o mais usado no dia a dia:

curl http://localhost:11434/api/chat -d '{
  "model": "llama3.2",
  "messages": [
    { "role": "user", "content": "Hello!" }
  ],
  "stream": false
}'

Você pode manter um array messages e enviar todo o histórico da conversa. Assim, o modelo preserva o contexto, algo especialmente importante ao criar aplicativos de chat.

Como ver os modelos instalados

Às vezes, você só quer conferir quais modelos estão disponíveis localmente:

curl http://localhost:11434/api/tags

O JSON retornado lista todos os modelos baixados, incluindo tamanho, data de modificação e nível de quantização. É bem prático.


Como processar respostas em streaming

Esse ponto merece uma seção própria. A resposta em streaming do Ollama não chega inteira de uma vez; ela é enviada token por token.

Streaming em Python

Veja como processar o fluxo com a biblioteca requests do Python:

import requests
import json

url = "http://localhost:11434/api/chat"
payload = {
    "model": "llama3.2",
    "messages": [{"role": "user", "content": "Write a short poem"}],
    "stream": True
}

response = requests.post(url, json=payload, stream=True)
for line in response.iter_lines():
    if line:
        chunk = json.loads(line)
        print(chunk.get("message", {}).get("content", ""), end="", flush=True)

O ponto principal é response.iter_lines(), que permite ler o fluxo NDJSON linha por linha. Cada chunk pode conter apenas alguns caracteres, então é preciso acumulá-los para obter a resposta completa.

Streaming em JavaScript

No frontend, o processo com a fetch API é parecido:

const response = await fetch('http://localhost:11434/api/chat', {
  method: 'POST',
  body: JSON.stringify({
    model: 'llama3.2',
    messages: [{ role: 'user', content: 'Hello!' }],
    stream: true
  })
});

const reader = response.body.getReader();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  const chunk = new TextDecoder().decode(value);
  // Processar cada chunk...
}

É verdade que lidar com streaming dá um pouco mais de trabalho do que esperar por uma resposta completa. Em compensação, a experiência melhora bastante: o usuário vê o modelo “pensar” e responder em tempo real, em vez de esperar e receber um bloco enorme de texto de uma vez.


Interface compatível com o SDK da OpenAI: migração sem alterar a lógica

Esta é a parte de que mais gosto. O Ollama oferece uma interface compatível com a API da OpenAI, o que permite migrar código existente quase sem ajustes.

Exemplo com o SDK da OpenAI para Python

Use diretamente o SDK oficial da OpenAI:

from openai import OpenAI

client = OpenAI(
    base_url='http://localhost:11434/v1/',
    api_key='ollama'  # Não há validação local; qualquer valor serve
)

response = client.chat.completions.create(
    model="llama3.2",
    messages=[{"role": "user", "content": "Hello!"}]
)

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

Como você pode ver, as únicas mudanças são definir o base_url e fornecer qualquer valor em api_key. Todo o restante do código continua igual.

Alternando entre desenvolvimento e produção

Esse recurso é especialmente útil. Você pode usar o Ollama local no ambiente de desenvolvimento e a OpenAI em produção:

# Ambiente de desenvolvimento .env
OPENAI_API_KEY=anyrandomtext
LLM_ENDPOINT="http://localhost:11434/v1"
MODEL=llama3.2

# Ambiente de produção .env
OPENAI_API_KEY=sk-XXXXXXXXXXXXXXXXXXXXXXXX
LLM_ENDPOINT="https://api.openai.com/v1"
MODEL=gpt-3.5-turbo

No código, basta ler os valores das variáveis de ambiente:

import os
from openai import OpenAI

client = OpenAI(
    base_url=os.getenv('LLM_ENDPOINT'),
    api_key=os.getenv('OPENAI_API_KEY')
)

Assim, durante o desenvolvimento, você não precisa gastar com chamadas à API da OpenAI: os testes locais são suficientes. Na hora de publicar, basta mudar as variáveis de ambiente para usar a OpenAI de verdade.

Endpoints compatíveis

A interface do Ollama compatível com a OpenAI aceita estes endpoints:

EndpointFunçãoNível de suporte
/v1/chat/completionsGeração de conversasSuporte completo
/v1/completionsAutocompletar textoSuporte completo
/v1/modelsLista de modelosSuporte completo
/v1/embeddingsEmbeddings de textoSuporte completo
/v1/responsesNova Responses APISuporte completo

Também existe o endpoint experimental /v1/images/generations, mas ele ainda não tem a mesma estabilidade.

Alias de modelos

Um recurso útil é criar um alias para um modelo. Por exemplo, se você quiser que o código pareça chamar o GPT-3.5:

ollama cp llama3.2 gpt-3.5-turbo

Assim, quando o código usar model="gpt-3.5-turbo", quem será executado de fato é o llama3.2 local. Esse truque ajuda bastante na migração de código.


Qual das duas opções escolher?

Depois de tudo isso, talvez você ainda esteja se perguntando qual delas deve usar.

Quando usar a API REST nativa

Ela é indicada quando:

  • Você quer a forma mais leve possível de fazer chamadas
  • Não precisa do ecossistema do SDK da OpenAI
  • Está escrevendo seu próprio cliente HTTP, por exemplo para um dispositivo embarcado ou ambiente especial
  • Precisa controlar com precisão os detalhes da resposta em streaming

A API nativa é mais direta e trabalha em um nível mais baixo. Se você já conhece bem o protocolo HTTP, provavelmente vai se sentir à vontade com ela.

Quando usar a interface compatível com o SDK da OpenAI

Ela é indicada quando:

  • Você já tem código baseado no SDK da OpenAI
  • Precisa migrar rapidamente para uma execução local
  • Usa ferramentas do ecossistema da OpenAI, como LangChain ou LlamaIndex
  • Precisa alternar entre os ambientes de desenvolvimento e produção

Em resumo, se você quer reaproveitar o que já existe e evitar alterações no código, escolha a interface compatível com a OpenAI.

Minha recomendação

Sinceramente, durante o desenvolvimento eu prefiro usar a interface compatível com o SDK da OpenAI. Ela exige menos alterações, permite aproveitar as ferramentas existentes e facilita a depuração. Ainda assim, há cenários em que a API nativa é mais adequada — por exemplo, ao criar uma ferramenta CLI minimalista ou chamar o modelo em um ambiente sem suporte ao SDK da OpenAI.


Trechos de código para uso prático

Para encerrar, aqui estão alguns trechos que uso com frequência.

Chat em streaming com Python e o SDK da OpenAI

from openai import OpenAI

client = OpenAI(
    base_url='http://localhost:11434/v1/',
    api_key='ollama'
)

stream = client.chat.completions.create(
    model="llama3.2",
    messages=[{"role": "user", "content": "Write a poem"}],
    stream=True
)

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

Conversa completa em JavaScript com a API nativa

async function chat(messages) {
  const response = await fetch('http://localhost:11434/api/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'llama3.2',
      messages: messages,
      stream: false
    })
  });
  return await response.json();
}

// Manter o histórico da conversa
let conversation = [
  { role: 'user', content: 'Hello!' }
];

const result = await chat(conversation);
conversation.push({
  role: 'assistant',
  content: result.message.content
});

console.log(result.message.content);

Exemplo com chamada de ferramentas

O Ollama também aceita Function Calling, ou chamadas de ferramentas:

from openai import OpenAI

client = OpenAI(base_url='http://localhost:11434/v1/', api_key='ollama')

tools = [
  {
    "type": "function",
    "function": {
      "name": "get_weather",
      "description": "Get current weather",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {"type": "string"}
        },
        "required": ["location"]
      }
    }
  }
]

response = client.chat.completions.create(
  model="llama3.2",
  messages=[{"role": "user", "content": "What's the weather in Tokyo?"}],
  tools=tools
)

if response.choices[0].message.tool_calls:
  print("Model wants to call:", response.choices[0].message.tool_calls[0].function.name)

Para concluir

O design da API do Ollama encontra um bom equilíbrio: oferece a simplicidade e a leveza da API REST nativa, mas também a conveniência e a compatibilidade com o ecossistema do SDK da OpenAI. Cada opção funciona melhor em determinados cenários; a escolha depende das suas necessidades.

Se você está começando com o Ollama, recomendo testar primeiro a interface compatível com o SDK da OpenAI. Ela é fácil de adotar e exige poucas mudanças no código. Depois, quando estiver mais familiarizado, você poderá decidir se a API nativa atende melhor a algum caso específico.

E não se esqueça: respostas em streaming são o padrão e podem confundir. Se você não precisa de streaming, defina explicitamente stream: false. Caso contrário, pode acabar como eu, às três da manhã, encarando metade de uma palavra na tela.


Referências

Duas formas de chamar a API do Ollama

Fluxo completo de chamadas, desde a API nativa com curl até a interface compatível com o SDK da OpenAI

⏱️ Estimated time: 10 min

  1. 1

    Step 1: Confirme que o Ollama está instalado e em execução

    Primeiro, verifique se o Ollama está funcionando:

    • Execute no terminal: ollama list (para ver os modelos baixados)
    • Ou acesse: http://localhost:11434 (a resposta deve ser Ollama is running)
    • Porta padrão: 11434
  2. 2

    Step 2: Escolha a forma de chamada

    Escolha de acordo com seu cenário:

    • API REST nativa: ideal para chamadas leves e clientes personalizados
    • Compatibilidade com o SDK da OpenAI: ideal para código OpenAI existente e migrações rápidas
  3. 3

    Step 3: Use a API REST nativa com curl

    Chamada mais básica com curl:

    • Geração de texto: curl http://localhost:11434/api/generate -d '{"model": "llama3.2", "prompt": "...", "stream": false}'
    • Modo de conversa: curl http://localhost:11434/api/chat -d '{"model": "llama3.2", "messages": [...], "stream": false}'
    • Atenção: a resposta é transmitida em streaming por padrão; defina stream: false para desativar
  4. 4

    Step 4: Use a interface compatível com o SDK da OpenAI

    Chamada com o SDK da OpenAI para Python:

    • Defina base_url='http://localhost:11434/v1/'
    • O api_key pode ter qualquer valor (não há validação local)
    • O restante do código é exatamente igual ao usado com a OpenAI
    • Para trocar de ambiente, basta alterar o base_url: Ollama local em desenvolvimento e OpenAI em produção
  5. 5

    Step 5: Processe respostas em streaming

    Pontos principais do processamento em streaming:

    • Python: use response.iter_lines() para ler o NDJSON linha por linha
    • JavaScript: use response.body.getReader() para ler o fluxo
    • Cada chunk contém apenas alguns caracteres; é preciso acumulá-los para obter a resposta completa
    • Sem streaming: defina stream: false para receber um JSON completo

FAQ

Qual é a diferença entre a API nativa do Ollama e a interface compatível com o SDK da OpenAI?
A API nativa é mais leve e direta, responde em streaming por padrão no formato NDJSON e é indicada para clientes HTTP personalizados. A interface compatível com a OpenAI funciona com o SDK da OpenAI; basta alterar o base_url, o que facilita a migração de código existente.
Por que a chamada à API do Ollama retornou apenas metade de uma palavra?
Esse é o comportamento padrão da resposta em streaming. O Ollama envia cada token em um objeto JSON separado no formato NDJSON, e cada objeto pode conter apenas alguns caracteres. Há duas soluções:

• Defina stream: false para desativar o streaming e receber um JSON completo
• Ou processe corretamente o fluxo NDJSON, lendo e acumulando as linhas
Como usar o Ollama local em desenvolvimento e a OpenAI em produção?
Use variáveis de ambiente para alternar: em desenvolvimento, defina LLM_ENDPOINT="http://localhost:11434/v1"; em produção, use "https://api.openai.com/v1". No código, basta ler o base_url da variável de ambiente; todo o restante permanece igual.
Quais endpoints da OpenAI são compatíveis com o Ollama?
Há suporte completo para /v1/chat/completions, /v1/completions, /v1/models, /v1/embeddings e /v1/responses. O endpoint /v1/images/generations tem suporte experimental e ainda não oferece a mesma estabilidade.
É possível criar um alias para um modelo do Ollama?
Sim. Use o comando ollama cp llama3.2 gpt-3.5-turbo. Assim, quando o código usar model="gpt-3.5-turbo", o modelo local llama3.2 será chamado. Esse recurso é útil ao migrar código.
O Ollama aceita chamadas de ferramentas (Function Calling)?
Sim. Você pode usar o parâmetro tools pela interface compatível com o SDK da OpenAI, definir o schema da função e receber no campo tool_calls a indicação de qual função o modelo deseja chamar.

9 min de leitura · Publicado em: 3 abr 2026 · Atualizado em: 4 set 2026

Comentários

Entre com GitHub para comentar

Easton BlogEaston Blog