Ollama: Fundamentos da API REST
A API REST é a interface universal do Ollama — qualquer linguagem, qualquer framework, basta enviar uma requisição HTTP e você está conectado.
📋 Pré-requisitos: Você precisa dominar o seguinte primeiro
- Aula 3: Interação Básica via CLI
- Aula 4: Gerenciamento de Modelos
1. O Que Você Vai Aprender
- Comparação dos endpoints
/api/generatevs/api/chat - Métodos de parsing de resposta streaming (NDJSON)
- Ajuste de parâmetros de Inferência (Temperature, Top_P, num_ctx)
- curl na prática: geração single-shot e diálogo de múltiplas rodadas
- Teste de API do protótipo SupportBot da Alice
2. Uma História Real de Uma Fundadora de SaaS
(1) O Problema: Respostas Manuais São Ineficientes
Alice fundou a plataforma de e-commerce GlobalShop. Sua equipe de 50 agentes de atendimento lida com mais de 2.000 tickets diariamente. Cada ticket leva em média 8 minutos, e o tempo de espera dos clientes excede 30 minutos. Ela precisa integrar um LLM no sistema de atendimento via API para rascunhos de respostas automáticas.
(2) A Solução: API REST Gera Respostas Instantaneamente
Usando curl para chamar a API do Ollama, rascunhos de respostas ao cliente são gerados em 3 segundos — agentes apenas precisam revisar e confirmar:
curl http://localhost:11434/api/chat -d '{
"model": "qwen2.5",
"messages": [{"role": "user", "content": "Refund for order #12345"}]
}'
stream: true) é adequada para interfaces de chat com efeito de digitação em tempo real; não-streaming (stream: false) é melhor para processamento em lote e integração de back-end de API. Não-streaming é recomendado para integração de API por ser mais simples.
http://127.0.0.1:11434, acessível apenas a partir da máquina local. Para acesso LAN, defina a variável de ambiente OLLAMA_HOST, mas esteja ciente dos riscos de segurança.
3. Guia Completo dos Endpoints da API
(1) Comparação dos Dois Endpoints Centrais
| Dimensão | /api/generate |
/api/chat |
|---|---|---|
| Finalidade | Geração de texto single-shot | Diálogo de múltiplas rodadas |
| Entrada | model + prompt |
Array messages |
| Contexto | Requisição única | Suporta histórico de conversa |
| Mapeamento de API | CLI ollama run |
CLI ollama chat |
| Caso de uso | Geração, complemento, tradução | Atendimento ao cliente, assistentes, raciocínio de múltiplas rodadas |
sequenceDiagram
participant C as Cliente
participant O as Servidor Ollama
C->>O: POST /api/chat {messages, model, stream}
O-->>C: NDJSON {message, done: false}
O-->>C: NDJSON {message, done: false}
O-->>C: NDJSON {message, done: true, stats}
(2) Parâmetros Comuns de Requisição
| Parâmetro | Tipo | Padrão | Descrição |
|---|---|---|---|
model |
string | Obrigatório | Nome do Modelo |
stream |
bool | true | Se a saída é streaming |
options |
object | — | Parâmetros de Inferência (veja próxima seção) |
format |
string | — | Formato de saída: json |
keep_alive |
string | 5m |
Tempo de retenção do Modelo na memória |
▶ Exemplo 1: Requisição de Geração Single-shot
# Non-streaming generate request
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "Write a haiku about coding",
"stream": false
}'
# Response (abbreviated)
# {
# "model": "llama3.2",
# "response": "Lines of logic flow,\nBug hides in the deep syntax—\nSemicolon found.",
# "done": true,
# "total_duration": 2500000000,
# "eval_count": 18
# }
Saída:
{"status":"ok","data":{}}
▶ Exemplo 2: Requisição de Diálogo de Múltiplas Rodadas
# Chat with message history
curl http://localhost:11434/api/chat -d '{
"model": "qwen2.5",
"messages": [
{"role": "system", "content": "You are a helpful customer service agent."},
{"role": "user", "content": "I want to return my order #12345"},
{"role": "assistant", "content": "I can help with that. May I ask the reason for the return?"},
{"role": "user", "content": "The product arrived damaged"}
],
"stream": false
}'
Saída:
{"status":"ok","data":{}}
4. Parsing de Resposta Streaming
stream: true) e não-streaming (stream: false) cada um tem seus casos de uso: streaming é para efeitos de digitação em tempo real em interfaces de chat para que os usuários vejam conteúdo sem esperar a resposta completa; não-streaming é para processamento em lote e integração de back-end de API onde obter a resposta JSON completa é mais fácil para parsing programático. Recomendamos começar com não-streaming para validar a lógica, depois mudar para streaming para otimizar a UX.
(1) Formato NDJSON Explicado
Respostas streaming usam NDJSON (Newline Delimited JSON), com um objeto JSON por linha:
{"model":"llama3.2","message":{"role":"assistant","content":"I"},"done":false}
{"model":"llama3.2","message":{"role":"assistant","content":" can"},"done":false}
{"model":"llama3.2","message":{"role":"assistant","content":" help"},"done":false}
{"model":"llama3.2","message":{"role":"assistant","content":""},"done":true,"total_duration":1500000000}
| Campo | Descrição |
|---|---|
message.content |
Fragmento de texto deste chunk |
done |
Se este é o último chunk |
total_duration |
Tempo total de Inferência (nanosegundos) |
eval_count |
Contagem de tokens gerados |
prompt_eval_count |
Contagem de tokens de entrada |
(2) Comparação Streaming vs Não-streaming
| Dimensão | Streaming (stream: true) | Não-streaming (stream: false) |
|---|---|---|
| Experiência do usuário | Saída caractere por caractere em tempo real | Espera pela resposta completa |
| Latência do primeiro token | Muito baixa (~200ms) | Espera até toda geração completar |
| Complexidade de implementação | Requer parsing NDJSON | Lê JSON diretamente |
| Caso de uso | Interfaces de chat, exibição em tempo real | Processamento em lote, back-ends de API |
▶ Exemplo 3: Parsing de Respostas Streaming
# Streaming request with real-time output
curl http://localhost:11434/api/chat -d '{
"model": "llama3.2",
"messages": [{"role": "user", "content": "Hello!"}],
"stream": true
}' | while read -r line; do
# Extract content field from each NDJSON line
echo "$line" | python3 -c "
import sys, json
data = json.load(sys.stdin)
if data.get('message', {}).get('content'):
print(data['message']['content'], end='', flush=True)
"
done
Saída:
{"status":"ok","data":{}}
5. Ajuste de Parâmetros de Inferência
(1) Tabela de Parâmetros Centrais
| Parâmetro | Tipo | Faixa | Padrão | Efeito |
|---|---|---|---|---|
temperature |
float | 0-2 | 0.8 | Controla aleatoriedade; valores mais baixos são mais determinísticos |
top_p |
float | 0-1 | 0.9 | Amostragem por núcleo, limita faixa de tokens candidatos |
top_k |
int | 1-100 | 40 | Amostra apenas dos top-K candidatos |
num_ctx |
int | 128-131072 | 2048 | Tamanho da janela de contexto |
repeat_penalty |
float | 1-2 | 1.1 | Coeficiente de penalização por repetição |
seed |
int | Qualquer | -1 | Semente aleatória (-1 = aleatório) |
(2) Ajuste de Parâmetros por Cenário
| Cenário | temperature | top_p | Observações |
|---|---|---|---|
| Geração de código | 0.1-0.3 | 0.9 | Requer determinismo e precisão |
| Respostas de atendimento | 0.3-0.5 | 0.9 | Estável mas permite variação moderada |
| Escrita criativa | 0.7-1.0 | 0.95 | Requer diversidade e criatividade |
| Análise de dados | 0.1-0.2 | 0.9 | Deve ser preciso, Alucinação não permitida |
num_ctx afeta diretamente o uso de memória. Um Modelo 8B com num_ctx=8192 precisa de aproximadamente 6GB VRAM; num_ctx=32768 precisa de aproximadamente 12GB VRAM. Defina conforme necessário — não aumente cegamente.
▶ Exemplo 4: Comparação de Ajuste de Parâmetros
# Low temperature: deterministic output
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "What is 2+2?",
"stream": false,
"options": {"temperature": 0.1}
}'
# Response: "2+2 equals 4."
# High temperature: creative output
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "What is 2+2?",
"stream": false,
"options": {"temperature": 1.5}
}'
# Response: "In the realm of mathematics, 2+2 opens the door to 4..."
Saída:
{"status":"ok","data":{}}
▶ Exemplo 5: Saída em Formato JSON
# Force JSON output format
curl http://localhost:11434/api/chat -d '{
"model": "llama3.2",
"messages": [
{"role": "system", "content": "You are a product catalog API. Return JSON only."},
{"role": "user", "content": "List 3 laptops under $500"}
],
"format": "json",
"stream": false,
"options": {"temperature": 0.3}
}'
# Response is valid JSON
# {"products":[{"name":"Acer Aspire 5","price":449,"spec":"8GB RAM, 256GB SSD"},...]}
Saída:
{"status":"ok","data":{}}
6. Exemplo Abrangente: Protótipo de API do SupportBot de Atendimento ao Cliente
keep_alive (por exemplo, "keep_alive": "5m") para evitar carregamento/descarregamento frequente do Modelo que causa atrasos na resposta.
#!/bin/bash
# ============================================
# Comprehensive: SupportBot API prototype
# Multi-turn customer service via REST API
# ============================================
API="http://localhost:11434/api/chat"
MODEL="qwen2.5"
# Function: Send a chat message and extract response
chat() {
local system_prompt="$1"
local user_msg="$2"
local temp="${3:-0.4}"
curl -s "$API" -d "$(cat <<EOF
{
"model": "$MODEL",
"messages": [
{"role": "system", "content": "$system_prompt"},
{"role": "user", "content": "$user_msg"}
],
"stream": false,
"options": {"temperature": $temp, "num_ctx": 4096}
}
EOF
)" | python3 -c "import sys,json; print(json.load(sys.stdin)['message']['content'])"
}
# Customer service system prompt
SYSTEM="You are SupportBot, a customer service agent for an e-commerce store. Be polite, concise, and helpful. If you cannot answer, say 'Let me connect you with a human agent.'"
# Simulate customer interactions
echo "=== Query 1: Order Status ==="
chat "$SYSTEM" "Where is my order #88765? It has been 5 days."
echo ""
echo "=== Query 2: Return Request ==="
chat "$SYSTEM" "I received a damaged item. Order #12345. I want a refund."
echo ""
echo "=== Query 3: Product Question ==="
chat "$SYSTEM" "Does the wireless headphone support Bluetooth 5.3?"
echo ""
echo "=== Benchmark ==="
time chat "$SYSTEM" "Hello" > /dev/null
=== Query 1: Order Status ===
I'd be happy to check on your order #88765. Based on our tracking system, your order is currently in transit and expected to arrive within 2-3 business days. You can track it at track.example.com/88765.
=== Query 2: Return Request ===
I'm sorry to hear about the damaged item. For order #12345, I've initiated a return request. You'll receive a prepaid shipping label via email within 24 hours. Once we receive the item, a full refund will be processed within 3-5 business days.
=== Query 3: Product Question ===
Yes, our wireless headphones support Bluetooth 5.3 with a range of up to 15 meters. They also feature active noise cancellation and 30-hour battery life.
❓ Perguntas Frequentes
P: Por que minha requisição curl retorna connection refused? R: O serviço Ollama não está rodando. Execute
ollama serveou verifique se o serviço systemd está iniciado:sudo systemctl status ollama.
P: Devo escolher stream: true ou stream: false? R: Use
stream: truepara interfaces de chat front-end para obter efeito de digitação em tempo real. Usestream: falsepara processamento em lote no back-end para obter respostas completas diretamente. Não-streaming é recomendado para integração de API por ser mais simples.
P: Como limito o comprimento da saída? R: Defina o parâmetro
num_predict, por exemplo,"num_predict": 200para limitar a geração a 200 tokens. Note que isso é contagem de tokens, não caracteres.
P: format: json garante saída JSON válida? R: Funciona na maioria dos casos, mas não é 100% garantido. Recomendamos adicionar validação JSON na camada da aplicação, com retry ou fallback para processamento de texto em caso de falha de parsing.
P: Como o diálogo de múltiplas rodadas mantém o contexto? R: O cliente deve manter o array
messagespor conta própria, enviando o histórico completo de conversa com cada requisição. O servidor Ollama não armazena estado de sessão.
P: Há limites de concorrência nas chamadas de API? R: Por padrão, apenas uma requisição é processada por vez. Defina a variável de ambiente
OLLAMA_NUM_PARALLELpara aumentar a concorrência, mas isso requer mais VRAM. Veja a Aula 19 para ajuste de desempenho.
📖 Resumo
/api/generateé para geração single-shot;/api/chatsuporta diálogo de múltiplas rodadas- Respostas streaming usam formato NDJSON, saindo chunk por chunk, ideal para interfaces de chat
- temperature controla aleatoriedade — valores baixos (0.1-0.3) para código/análise, valores altos para criatividade
format: jsonpode impor saída estruturada, mas requer validação na camada da aplicação- Cenários de atendimento recomendam temperature=0.3-0.5, equilibrando estabilidade e naturalidade
- Diálogo de múltiplas rodadas requer que o cliente mantenha o array messages; o servidor é stateless
📝 Exercícios
- Básico (Dificuldade ⭐): Use curl para chamar
/api/generatepara gerar uma descrição de produto, experimentestream: trueestream: falsepara observar a diferença. - Intermediário (Dificuldade ⭐⭐): Use
/api/chatpara implementar um diálogo de 3 rodadas, mantendo manualmente o array messages, exibindo a resposta completa a cada rodada. - Avançado (Dificuldade ⭐⭐⭐): Escreva um script Shell que simule um fluxo de atendimento SupportBot — recebe perguntas, chama a API, retorna resultados de classificação (intenção + resposta) em formato JSON, suportando saída streaming em tempo real.