Ollama API 调用:从 curl 到 OpenAI SDK 兼容接口
凌晨三点。我盯着终端里那条 curl 命令,脑子里全是刚才踩过的坑——明明按照官方文档写的,怎么返回的 JSON 里只有半个单词?
原来是流式响应。Ollama 默认会像流水一样一点点吐出内容,每个 JSON 对象只包含几个字符。这事儿折腾了我两个小时。
说实话,本地部署 LLM 这块,Ollama 真算是把门槛降下来了。你不用折腾 Docker 配置,也不用操心 GPU 驱动——下载、安装、运行,三步搞定。但调用 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 的两种方式
从 curl 原生 API 到 OpenAI SDK 兼容接口的完整调用流程
⏱️ 预计耗时: 10 分钟
- 1
步骤1: 确认 Ollama 已安装并运行
先检查 Ollama 是否正常运行:
• 终端执行:ollama list(查看已下载模型)
• 或访问:http://localhost:11434(应返回 Ollama is running)
• 默认端口:11434 - 2
步骤2: 选择调用方式
根据你的场景选择:
• 原生 REST API:适合轻量调用、自定义客户端
• OpenAI SDK 兼容:适合已有 OpenAI 代码、快速迁移 - 3
步骤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
步骤4: 使用 OpenAI SDK 兼容接口
Python OpenAI SDK 调用:
• 设置 base_url='http://localhost:11434/v1/'
• api_key 可随便填(本地不验证)
• 其他代码与 OpenAI 完全相同
• 环境切换:改 base_url 即可(开发用本地,生产用 OpenAI) - 5
步骤5: 处理流式响应
流式响应处理要点:
• Python:response.iter_lines() 逐行读取 NDJSON
• JavaScript:response.body.getReader() 流式读取
• 每个 chunk 只包含几个字符,需累积完整回复
• 非流式:设置 stream: false 得到完整 JSON
常见问题
Ollama 的原生 API 和 OpenAI SDK 兼容接口有什么区别?
为什么我调用 Ollama API 只返回了半个单词?
• 设置 stream: false 禁用流式,得到完整 JSON
• 或正确处理 NDJSON 流:逐行读取并累积内容
如何在开发环境用本地 Ollama,生产环境用 OpenAI?
Ollama 支持哪些 OpenAI 端点?
可以给 Ollama 模型起别名吗?
Ollama 支持工具调用(Function Calling)吗?
参考资料
- Ollama API Introduction
- Ollama OpenAI Compatibility
- Ollama Streaming Guide
- KodeKloud OpenAI Compatibility Guide
8 分钟阅读 · 发布于: 2026年4月3日 · 修改于: 2026年4月4日

评论
使用 GitHub 账号登录后即可评论