切换语言
切换主题

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 APIhttp://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

    步骤1: 确认 Ollama 已安装并运行

    先检查 Ollama 是否正常运行:

    • 终端执行:ollama list(查看已下载模型)
    • 或访问:http://localhost:11434(应返回 Ollama is running)
    • 默认端口:11434
  2. 2

    步骤2: 选择调用方式

    根据你的场景选择:

    • 原生 REST API:适合轻量调用、自定义客户端
    • OpenAI SDK 兼容:适合已有 OpenAI 代码、快速迁移
  3. 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

    步骤4: 使用 OpenAI SDK 兼容接口

    Python OpenAI SDK 调用:

    • 设置 base_url='http://localhost:11434/v1/'
    • api_key 可随便填(本地不验证)
    • 其他代码与 OpenAI 完全相同
    • 环境切换:改 base_url 即可(开发用本地,生产用 OpenAI)
  5. 5

    步骤5: 处理流式响应

    流式响应处理要点:

    • Python:response.iter_lines() 逐行读取 NDJSON
    • JavaScript:response.body.getReader() 流式读取
    • 每个 chunk 只包含几个字符,需累积完整回复
    • 非流式:设置 stream: false 得到完整 JSON

常见问题

Ollama 的原生 API 和 OpenAI SDK 兼容接口有什么区别?
原生 API 更轻量直接,默认流式响应(NDJSON 格式),适合自定义 HTTP 客户端。OpenAI SDK 兼容接口完全兼容 OpenAI SDK,只需改 base_url,适合已有 OpenAI 代码的快速迁移。
为什么我调用 Ollama API 只返回了半个单词?
这是流式响应的默认行为。Ollama 默认使用 NDJSON 格式逐个 token 输出,每个 JSON 对象只包含几个字符。解决方法:

• 设置 stream: false 禁用流式,得到完整 JSON
• 或正确处理 NDJSON 流:逐行读取并累积内容
如何在开发环境用本地 Ollama,生产环境用 OpenAI?
使用环境变量切换:开发时设置 LLM_ENDPOINT="http://localhost:11434/v1",生产时设置为 "https://api.openai.com/v1"。代码中只需从环境变量读取 base_url,其他代码完全不变。
Ollama 支持哪些 OpenAI 端点?
完全支持:/v1/chat/completions、/v1/completions、/v1/models、/v1/embeddings、/v1/responses。实验性支持:/v1/images/generations(稳定度还不够)。
可以给 Ollama 模型起别名吗?
可以。使用命令:ollama cp llama3.2 gpt-3.5-turbo,这样代码里写 model="gpt-3.5-turbo" 实际用的是本地 llama3.2。迁移代码时这个技巧很有用。
Ollama 支持工具调用(Function Calling)吗?
支持。可以通过 OpenAI SDK 兼容接口使用 tools 参数,定义函数 schema,模型会返回 tool_calls 字段指示要调用的函数。

参考资料

8 分钟阅读 · 发布于: 2026年4月3日 · 修改于: 2026年4月4日

评论

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

相关文章