DR – 核心要点
- Ollama 提供两种 API:原生 REST API 和 OpenAI SDK 兼容接口
- 原生 API 默认流式响应(NDJSON 格式),需设置 stream: false 禁用
- OpenAI SDK 兼容接口只需改 base_url,其他代码完全不变
- 开发环境可用本地 Ollama,生产环境切换到 OpenAI(零成本迁移)
- 两种方式各有适用场景:原生 API 更轻量,OpenAI SDK 更便利
终端里那条 curl 命令,返回的 JSON 里只有半个单词——折腾了两小时才发现是流式响应。Ollama 默认像流水一样一点点吐出内容,每个 JSON 对象只包含几个字符。
本地部署 LLM 这块,Ollama 把门槛降下来了:下载、安装、运行,三步搞定。但调用 API 这块容易迷糊:原生 REST API 和 OpenAI SDK 兼容接口有什么区别?流式响应怎么处理?
这篇文章整理踩过的坑,从 curl 命令到 OpenAI SDK 的零代码迁移,还有文档里没明说的小细节。
Ollama API 有两种接口
哎,这点真的让我困惑了好一阵。Ollama 实则提供了两套完全不同的 API 接口:
原生 REST API:
http://localhost:11434/api/*
- 端点:/api/generate(文本生成)、/api/chat(对话)、/api/tags(模型列表)
- 默认流式响应(这就是我凌晨三点遇到的问题)
- 直接 HTTP 调用,不需要任何 SDK
OpenAI 兼容接口:
http://localhost:11434/v1/*
- 端点:/v1/chat/completions、/v1/completions、/v1/models
- 完全兼容 OpenAI SDK(Python、JavaScript 都能直接用)
- 支持现有的 OpenAI 工具生态
你可能会想:为什么要有两套?实则各有用处。原生 API 更轻量、更直接,适合你自己写 HTTP 客户端;OpenAI 兼容接口则让你能直接用已有的 OpenAI SDK 代码,连改都不用改——改个 base_url 就行。
说实话,这种设计挺机智的。既照顾了想简单调用的开发者,又照顾了已经有 OpenAI 生态代码的团队。
原生 REST API:从 curl 开始
先说原生 API。这块实则挺直接的,就是个标准的 REST 接口。
基础的 curl 调用
最简单的例子——文本生成:
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "Why is the sky blue?",
"stream": false
}'
嗯,注意那个 stream: false。默认情况下 Ollama 会流式返回内容,如果你想要完整的 JSON 响应,就得显式禁用流式。不然你会看到一堆这样的输出:
{"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}
每个 JSON 对象只包含几个字符,逐个 token 输出。这就是所谓的 NDJSON(Newline-Delimited JSON)格式——每行一个 JSON 对象。凌晨三点那次,我就是没注意到这个,直接按普通 JSON 解析,结果只拿到了第一个对象里的 “That”。
对话模式更实用
单次生成适合简单任务,但对话模式才是真正常用的:
curl http://localhost:11434/api/chat -d '{
"model": "llama3.2",
"messages": [
{ "role": "user", "content": "Hello!" }
],
"stream": false
}'
你可以维护一个 messages 数组,把历史对话都传进去,这样模型就能记住上下文。这点对于构建聊天应用特别重大。
查看已安装的模型
有时候你想看看本地有哪些模型:
curl http://localhost:11434/api/tags
返回的 JSON 会列出所有已下载的模型,包括大小、修改时间、量化等级这些信息。挺方便的。
流式响应的处理
这块需要专门聊聊。Ollama 的流式响应有个特点:它不是一次性返回完整内容,而是逐个 token 输出。
Python 处理流式
用 Python 的 requests 库处理流式响应:
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)
关键点是 response.iter_lines()——这能让你逐行读取 NDJSON 流。每个 chunk 里可能只有几个字符,你得累积起来才能得到完整回复。
JavaScript 的流式处理
前端用 fetch API 也类似:
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);
// 处理每个 chunk...
}
说实话,流式处理比非流式麻烦一些,但用户体验好多了——你能实时看到模型在”思考”和输出,而不是等半天突然蹦出一大段文字。
OpenAI SDK 兼容接口:零代码迁移
这块是我最喜爱的部分。Ollama 提供了完整的 OpenAI API 兼容接口,你几乎可以无缝迁移现有代码。
Python OpenAI SDK 示例
直接用 OpenAI 的官方 SDK:
from openai import OpenAI
client = OpenAI(
base_url='http://localhost:11434/v1/',
api_key='ollama' # 本地不验证,随意填
)
response = client.chat.completions.create(
model="llama3.2",
messages=[{"role": "user", "content": "Hello!"}]
)
print(response.choices[0].message.content)
你看,唯一的改动就是设置 base_url 和随意填个 api_key。其他代码完全不变。
开发和生产环境切换
这个特性特别实用。你可以在开发环境用本地 Ollama,生产环境用 OpenAI:
# 开发环境 .env
OPENAI_API_KEY=anyrandomtext
LLM_ENDPOINT="http://localhost:11434/v1"
MODEL=llama3.2
# 生产环境 .env
OPENAI_API_KEY=sk-XXXXXXXXXXXXXXXXXXXXXXXX
LLM_ENDPOINT="https://api.openai.com/v1"
MODEL=gpt-3.5-turbo
代码里只需要从环境变量读取:
import os
from openai import OpenAI
client = OpenAI(
base_url=os.getenv('LLM_ENDPOINT'),
api_key=os.getenv('OPENAI_API_KEY')
)
这样一来,你开发时不用花钱调用 OpenAI API,本地测试够了;上线时改改环境变量就能切换到真正的 OpenAI。
支持的端点
Ollama 的 OpenAI 兼容接口支持这些端点:
|
端点 |
功能 |
支持程度 |
|
/v1/chat/completions |
对话生成 |
完全支持 |
|
/v1/completions |
文本补全 |
完全支持 |
|
/v1/models |
模型列表 |
完全支持 |
|
/v1/embeddings |
文本嵌入 |
完全支持 |
|
/v1/responses |
新响应 API |
完全支持 |
还有个实验性的 /v1/images/generations 端点,不过稳定度还不够。
模型别名
有个小技巧:你可以给模型起别名。列如你想让代码看起来像在调用 GPT-3.5:
ollama cp llama3.2 gpt-3.5-turbo
这样你的代码里写 model=”gpt-3.5-turbo”,实际上用的是本地的 llama3.2。迁移代码时这个技巧挺有用的。
两种方式怎么选?
说了这么多,你可能会想:那我该用哪种?
原生 REST API 的场景
适合这些情况:
- 你想要最轻量的调用方式
- 不需要 OpenAI SDK 的生态
- 自己写 HTTP 客户端(列如嵌入式设备、特殊环境)
- 需要准确控制流式响应的细节
原生 API 更直接、更底层。如果你对 HTTP 协议熟悉,用它会很顺手。
OpenAI SDK 兼容接口的场景
适合这些情况:
- 你已经有基于 OpenAI SDK 的代码
- 需要快速迁移到本地部署
- 用了 OpenAI 工具链(LangChain、LlamaIndex 这些)
- 需要在开发/生产环境间切换
说白了,如果你是”拿来主义者”,不想改代码,那就用 OpenAI 兼容接口。
我的提议
老实讲,我开发时更喜爱用 OpenAI SDK 兼容接口——代码改得少,工具链能用,调试也方便。但有些场景下原生 API 的确 更合适,列如你要写一个极简的 CLI 工具,或者需要在某个不支持 OpenAI SDK 的环境里调用。
实战代码片段
最后分享几个我常用的代码片段。
Python 流式聊天(OpenAI SDK)
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)
JavaScript 完整对话(原生 API)
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();
}
// 维护对话历史
let conversation = [
{ role: 'user', content: 'Hello!' }
];
const result = await chat(conversation);
conversation.push({
role: 'assistant',
content: result.message.content
});
console.log(result.message.content);
带工具调用的示例
Ollama 还支持 Function Calling(工具调用):
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)
说了这么多
实则 Ollama 的 API 设计挺平衡的——既给了你原生 REST API 的直接和轻量,又给了你 OpenAI SDK 的便利和生态兼容。两种方式各有适用场景,关键是看你的需求。
如果你刚开始用 Ollama,我提议先试试 OpenAI SDK 兼容接口——上手快,改代码少。等你熟悉了,再根据具体需求决定要不要用原生 API。
对了,还有一点:流式响应处理这块的确 容易踩坑。记得默认是流式的,如果不需要流式就显式设置 stream: false,不然你会像我一样凌晨三点盯着半个单词发呆。
参考资料
- Ollama API Introduction
- Ollama OpenAI Compatibility
- Ollama Streaming Guide
- KodeKloud OpenAI Compatibility Guide
总结
调用 Ollama API 的两种方式
从 curl 原生 API 到 OpenAI SDK 兼容接口的完整调用流程
⏱️ 预计耗时: 10 分钟
- 步骤1: 确认 Ollama 已安装并运行
- 先检查 Ollama 是否正常运行: • 终端执行:ollama list(查看已下载模型) • 或访问:http://localhost:11434(应返回 Ollama is running) • 默认端口:11434
- 步骤2: 选择调用方式
- 根据你的场景选择: • 原生 REST API:适合轻量调用、自定义客户端 • OpenAI SDK 兼容:适合已有 OpenAI 代码、快速迁移
- 步骤3: 使用原生 REST API(curl 方式)
- 最基础的 curl 调用: • 文本生成:curl http://localhost:11434/api/generate -d '{“model”: “llama3.2”, “prompt”: “…”, “stream”: false}' • 对话模式:curl http://localhost:11434/api/chat -d '{“model”: “llama3.2”, “messages”: […], “stream”: false}' • 注意:默认流式响应,需设置 stream: false 禁用
- 步骤4: 使用 OpenAI SDK 兼容接口
- Python OpenAI SDK 调用: • 设置 base_url='http://localhost:11434/v1/' • api_key 可随意填(本地不验证) • 其他代码与 OpenAI 完全一样 • 环境切换:改 base_url 即可(开发用本地,生产用 OpenAI)
- 步骤5: 处理流式响应
- 流式响应处理要点: • Python:response.iter_lines() 逐行读取 NDJSON • JavaScript:response.body.getReader() 流式读取 • 每个 chunk 只包含几个字符,需累积完整回复 • 非流式:设置 stream: false 得到完整 JSON





