Ollama: REST API Fundamentals
The REST API is Ollama's universal interface — any language, any framework, just send an HTTP request and you're connected.
⚠️ Note: The Ollama REST API has no built-in authentication — anyone who can access the service port can freely call Models and view installed Model lists. In production, you must add API Key authentication via a reverse proxy (such as Nginx/Caddy), otherwise your AI service faces risks of abuse, data leakage, and resource exhaustion.
📋 Prerequisites: You need to master the following first
- Lesson 3: CLI Basic Interaction
- Lesson 4: Model Management
1. What You Will Learn
/api/generatevs/api/chatendpoint comparison- Streaming response (NDJSON) parsing methods
- Inference parameter tuning (Temperature, Top_P, num_ctx)
- curl in practice: single-shot generation and multi-turn dialogue
- Alice's SupportBot prototype API testing
2. A Real Story from a SaaS Founder
(1) The Pain Point: Manual Replies Are Inefficient
Alice founded the GlobalShop e-commerce platform. Her 50-person customer service team handles 2,000+ tickets daily. Each ticket takes an average of 8 minutes, and customer wait times exceed 30 minutes. She needs to integrate an LLM into the customer service system via API for automatic reply drafts.
(2) The Solution: REST API Generates Replies Instantly
Using curl to call the Ollama API, customer service reply drafts are generated in 3 seconds — agents only need to review and confirm:
BASH
curl http://localhost:11434/api/chat -d '{
"model": "qwen2.5",
"messages": [{"role": "user", "content": "Refund for order #12345"}]
}'
⚠️ Warning: The Ollama API has no built-in authentication — anyone who can access the port can call it. In production, you must add API Key authentication via a reverse proxy (Nginx/Caddy). See Lesson 20 for security hardening.
💡 Tip: Streaming API (
stream: true) is suited for chat interfaces with real-time typing effects; non-streaming (stream: false) is better for batch processing and API backend integration. Non-streaming is recommended for API integration as it's simpler.
ℹ️ Info: Ollama defaults to
http://127.0.0.1:11434, accessible only from the local machine. For LAN access, set the OLLAMA_HOST environment variable, but be mindful of security risks.
3. API Endpoints Complete Guide
(1) Two Core Endpoints Comparison
| Dimension | /api/generate |
/api/chat |
|---|---|---|
| Purpose | Single-shot text generation | Multi-turn dialogue |
| Input | model + prompt |
messages array |
| Context | Single request | Supports conversation history |
| API mapping | CLI ollama run |
CLI ollama chat |
| Use case | Generation, completion, translation | Customer service, assistants, multi-turn reasoning |
sequenceDiagram
participant C as Client
participant O as Ollama Server
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) Common Request Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
model |
string | Required | Model name |
stream |
bool | true | Whether to stream output |
options |
object | — | Inference parameters (see next section) |
format |
string | — | Output format: json |
keep_alive |
string | 5m |
Model memory retention time |
▶ Example 1: Single-shot Generation Request
BASH
# 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
# }
Output:
TEXT
{"status":"ok","data":{}}
▶ Example 2: Multi-turn Dialogue Request
BASH
# 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
}'
Output:
TEXT
{"status":"ok","data":{}}
4. Streaming Response Parsing
💡 Tip: Streaming (
stream: true) and non-streaming (stream: false) each have their use cases: streaming is for real-time typing effects in chat interfaces so users see content without waiting for the full response; non-streaming is for batch processing and API backend integration where getting the complete JSON response is easier for program parsing. We recommend starting with non-streaming to validate logic, then switching to streaming to optimize UX.
(1) NDJSON Format Explained
Streaming responses use NDJSON (Newline Delimited JSON), with one JSON object per line:
TEXT
{"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}
| Field | Description |
|---|---|
message.content |
Text fragment for this chunk |
done |
Whether this is the last chunk |
total_duration |
Total Inference time (nanoseconds) |
eval_count |
Generated token count |
prompt_eval_count |
Input token count |
(2) Streaming vs Non-streaming Comparison
| Dimension | Streaming (stream: true) | Non-streaming (stream: false) |
|---|---|---|
| User experience | Real-time character-by-character output | Wait for complete response |
| First-token latency | Very low (~200ms) | Wait until all generation completes |
| Implementation complexity | Requires NDJSON parsing | Read JSON directly |
| Use case | Chat interfaces, real-time display | Batch processing, API backends |
▶ Example 3: Parsing Streaming Responses
BASH
# 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
Output:
TEXT
{"status":"ok","data":{}}
5. Inference Parameter Tuning
(1) Core Parameter Table
| Parameter | Type | Range | Default | Effect |
|---|---|---|---|---|
temperature |
float | 0-2 | 0.8 | Controls randomness; lower values are more deterministic |
top_p |
float | 0-1 | 0.9 | Nucleus sampling, limits candidate token range |
top_k |
int | 1-100 | 40 | Sample only from top-K candidates |
num_ctx |
int | 128-131072 | 2048 | Context window size |
repeat_penalty |
float | 1-2 | 1.1 | Repetition penalty coefficient |
seed |
int | Any | -1 | Random seed (-1 = random) |
(2) Parameter Tuning by Scenario
| Scenario | temperature | top_p | Notes |
|---|---|---|---|
| Code generation | 0.1-0.3 | 0.9 | Requires determinism and accuracy |
| Customer service replies | 0.3-0.5 | 0.9 | Stable but allows moderate variation |
| Creative writing | 0.7-1.0 | 0.95 | Requires diversity and creativity |
| Data analysis | 0.1-0.2 | 0.9 | Must be precise, no Hallucination allowed |
⚠️ Warning:
num_ctx directly affects memory usage. An 8B Model with num_ctx=8192 needs approximately 6GB VRAM; num_ctx=32768 needs approximately 12GB VRAM. Set it as needed — don't increase it blindly.
▶ Example 4: Parameter Tuning Comparison
BASH
# 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..."
Output:
TEXT
{"status":"ok","data":{}}
▶ Example 5: JSON Format Output
BASH
# 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"},...]}
Output:
TEXT
{"status":"ok","data":{}}
6. Comprehensive Example: SupportBot Customer Service API Prototype
💡 Tip: When calling the API in production, be sure to set the
keep_alive parameter (e.g., "keep_alive": "5m") to avoid frequent Model loading/unloading that causes response delays.
BASH
#!/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
💻 Output:
TEXT
=== 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.
❓ FAQ
Q Why does my curl request return connection refused?
A The Ollama service isn't running. Run
ollama serve or verify the systemd service is started: sudo systemctl status ollama.Q Should I choose stream: true or stream: false?
A Use
stream: true for front-end chat interfaces to get real-time typing effects. Use stream: false for backend batch processing to get complete responses directly. Non-streaming is recommended for API integration as it's simpler.Q How do I limit output length?
A Set the
num_predict parameter, e.g., "num_predict": 200 to limit generation to 200 tokens. Note this is token count, not character count.Q Does format: json guarantee valid JSON output?
A It works in most cases, but isn't 100% guaranteed. We recommend adding JSON validation at the application layer, with retry or fallback to text processing on parse failure.
Q How does multi-turn dialogue maintain context?
A The client must maintain the
messages array itself, sending the complete conversation history with each request. The Ollama server does not store session state.Q Are there concurrency limits on API calls?
A By default, only one request is processed at a time. Set the
OLLAMA_NUM_PARALLEL environment variable to increase concurrency, but this requires more VRAM. See Lesson 19 for performance tuning.📖 Summary
/api/generateis for single-shot generation;/api/chatsupports multi-turn dialogue- Streaming responses use NDJSON format, outputting chunk by chunk, ideal for chat interfaces
- temperature controls randomness — low values (0.1-0.3) for code/analysis, high values for creativity
format: jsoncan enforce structured output, but requires application-layer validation- Customer service scenarios recommend temperature=0.3-0.5, balancing stability and naturalness
- Multi-turn dialogue requires the client to maintain the messages array; the server is stateless
📝 Exercises
- Basic (Difficulty ⭐): Use curl to call
/api/generateto generate a product description, and try bothstream: trueandstream: falseto observe the difference. - Intermediate (Difficulty ⭐⭐): Use
/api/chatto implement a 3-turn dialogue, manually maintaining the messages array, outputting the complete reply each turn. - Advanced (Difficulty ⭐⭐⭐): Write a Shell script that simulates a SupportBot customer service flow — receives questions, calls the API, returns classification results (intent + reply) in JSON format, supporting real-time streaming output.