切换语言
切换主题

Ollama API 实战:Python 与 Node.js 客户端开发指南

凌晨一点,终端里敲下 ollama run gemma3,屏幕吐出第一句回复。挺爽的。

但你很快就开始琢磨:这玩意儿能不能接到自己项目里?不用 API Key,不用付钱,本地跑着,多香。

说实话,我一开始也这么想的。翻了一圈文档,发现官方直接给了 Python 和 JavaScript 的 SDK,甚至还能用 OpenAI 的 SDK 改两行代码就能对接。这事儿比想象中简单。

但简单不代表没坑。流式响应怎么累积?工具调用的 Agent Loop 怎么写?thinking 模式下推理和回答怎么分开?这些都是踩过的坑。

这篇文章就把这些坑填上。Python 和 Node.js 双语言对比,原生 SDK 和 OpenAI 兼容两种方案都讲清楚,给你一个完整的客户端开发指南。

对了,如果你还没装 Ollama,可以先看看我们系列的第一篇 LangChain + Ollama 集成实战,先把本地模型跑起来。


第一章:Ollama API 基础

先搞清楚 API 怎么跑的。

Ollama 默认在本地启动一个 REST API 服务,地址是 http://localhost:11434/api。你打开浏览器访问这个地址,会看到一句干巴巴的 “Ollama is running”——这就说明服务正常。

主要端点

两个核心端点你得记住:

端点用途特点
/api/chat多轮对话支持 messages 数组,能传上下文
/api/generate单轮生成简单粗暴,适合一次性任务

还有一个 /v1/chat/completions,这是 OpenAI 兼容端点。如果你手头有现成的 OpenAI 项目,改个 base_url 就能用,后面会细讲。

用 curl 试一把

先用最原始的方式试试 API:

curl http://localhost:11434/api/chat -d '{
  "model": "gemma3",
  "messages": [
    { "role": "user", "content": "天空为什么是蓝色的?" }
  ]
}'

终端里会吐出一堆 JSON。关键看 message.content 字段,那里面就是模型的回答。

响应结构大概是这样:

{
  "model": "gemma3",
  "created_at": "2026-04-18T01:23:45.678Z",
  "message": {
    "role": "assistant",
    "content": "天空呈现蓝色主要是因为..."
  },
  "done": true
}

done 字段很重要。流式响应时,每个 chunk 的 done 都是 false,最后一个 chunk 才是 true。这个后面处理流式响应时会用到。

流式响应

默认情况下,API 会等模型生成完再一次性返回。但你想让用户看到”打字机效果”,就得加 stream: true

curl http://localhost:11434/api/chat -d '{
  "model": "gemma3",
  "messages": [{ "role": "user", "content": "天空为什么是蓝色的?" }],
  "stream": true
}'

这次终端里会一行一行蹦出 JSON。每行都是一个小 chunk,你得把它们攒起来才能凑成完整回答。

嗯,手动处理这些 chunk 确实挺麻烦。这也是为什么官方给了 SDK——帮你把这些细节都封装好了。


第二章:Python SDK 完整实战

Python 的 SDK 是官方维护的,装起来特简单:

pip install ollama

装完直接用。支持 Python 3.8+,这点挺友好的。

基础调用

最简单的调用方式,一行代码搞定:

from ollama import chat

response = chat(
  model='gemma3',
  messages=[{'role': 'user', 'content': '天空为什么是蓝色的?'}]
)

print(response.message.content)

就这么简单。chat() 函数是 SDK 提供的快捷方式,内部自动创建了一个默认的 Client 连接本地的 Ollama 服务。

如果你想自定义连接参数——比如 Ollama 跑在另一台机器上——可以自己创建 Client:

from ollama import Client

client = Client(host='http://192.168.1.100:11434')
response = client.chat(model='gemma3', messages=[...])

流式响应

流式响应是重点。你得让用户看到文字一点点蹦出来,而不是等半天突然全吐出来。

from ollama import chat

stream = chat(
  model='gemma3',
  messages=[{'role': 'user', 'content': '天空为什么是蓝色的?'}],
  stream=True,
)

for chunk in stream:
  print(chunk['message']['content'], end='', flush=True)

这里有个坑:chunk 返回的是字典,不是对象。所以访问方式是 chunk['message']['content'],不是 chunk.message.content。我一开始就踩了这坑,报错半天没反应过来。

异步客户端

如果你的应用是异步架构——比如用 FastAPI 或 aiohttp——就得用异步客户端:

import asyncio
from ollama import AsyncClient

async def main():
  client = AsyncClient()
  
  # 非流式
  response = await client.chat(
    model='gemma3',
    messages=[{'role': 'user', 'content': '你好'}]
  )
  print(response.message.content)
  
  # 流式
  stream = await client.chat(
    model='gemma3',
    messages=[{'role': 'user', 'content': '天空为什么是蓝色的?'}],
    stream=True,
  )
  async for chunk in stream:
    print(chunk['message']['content'], end='', flush=True)

asyncio.run(main())

异步流式返回的是 async generator,用 async for 遍历。跟同步版本的逻辑一样,就是加了 awaitasync

Cloud Models

有意思的是,Ollama SDK 还支持云端模型。有些大模型本地跑不动——比如那个 120B 的 gpt-oss——但云端有。

from ollama import chat

response = chat(
  model='gpt-oss:120b-cloud',
  messages=[{'role': 'user', 'content': '你好'}]
)

模型名带 -cloud 后缀就会走云端 API。当然你得有 Ollama 的云端账户和 API Key,配置方式跟本地不太一样,感兴趣的可以看官方文档。

说实话,这个功能挺实用的。小模型本地跑省钱,大模型云端跑省硬件。混合方案挺香。


第三章:Node.js SDK 完整实战

Node.js 的 SDK 也一样简洁:

npm i ollama

注意这包同时支持 Node.js 和浏览器环境。浏览器版本要单独导入:

// Node.js
import ollama from 'ollama'

// 浏览器
import ollama from 'ollama/browser'

基础调用

Node.js 里默认就是异步的,写起来更顺手:

import ollama from 'ollama'

const response = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: '天空为什么是蓝色的?' }],
})

console.log(response.message.content)

跟 Python 版对比一下:Python 用字典传 messages,Node.js 用对象。参数名基本一致,换语言不用重新学习概念。

流式响应

Node.js 的流式处理天生就是异步 generator:

import ollama from 'ollama'

const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: '天空为什么是蓝色的?' }],
  stream: true,
})

for await (const chunk of stream) {
  process.stdout.write(chunk.message.content)
}

这里用 process.stdout.write 而不是 console.log,因为 console.log 会自动换行,你不想每蹦一个字就换行吧?

自定义配置

SDK 支持自定义 host 和 headers:

import ollama from 'ollama'

// 自定义 host
const client = new ollama.Ollama({ host: 'http://192.168.1.100:11434' })

// 或者用全局配置
ollama.setDefaultHost('http://192.168.1.100:11434')

// 添加 headers(比如认证)
const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: '你好' }],
  headers: { Authorization: 'Bearer xxx' },
})

headers 参数挺有用。如果你的 Ollama 服务前面加了认证代理,可以在这里传 token。

取消流式生成

有个 abort() 方法可以取消正在进行的流式生成:

import ollama from 'ollama'

const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: '写一篇长文...' }],
  stream: true,
})

// 用户点击了停止按钮
ollama.abort()

for await (const chunk of stream) {
  // abort 后循环会提前结束
  process.stdout.write(chunk.message.content)
}

这个功能做聊天界面时必用。用户不想等模型写完废话,点个按钮就能停。

浏览器版本

浏览器里用法类似,但有些差异:

import ollama from 'ollama/browser'

// 浏览器里只能用流式,因为原生 API 不支持非流式跨域请求
const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: '你好' }],
  stream: true,
})

for await (const chunk of stream) {
  document.getElementById('output').textContent += chunk.message.content
}

浏览器版本有个限制:必须用流式模式。因为 Ollama API 的非流式请求会一次性返回大 JSON,跨域请求容易超时或被拦截。流式请求是分 chunk 的,问题少很多。

这个设计挺合理的。浏览器里做聊天 UI,本来就需要流式显示效果。


第四章:工具调用实战

工具调用是做 Agent 的基础。Ollama 支持让模型调用你定义的函数,然后根据函数返回结果继续生成回答。

Python SDK 有个很方便的特性:可以直接传 Python 函数作为工具,SDK 会自动解析函数的 docstring 和参数类型。

Python 函数自动解析

def get_weather(city: str) -> str:
  """获取指定城市的天气信息

  Args:
    city: 城市名称,如"北京"、"上海"

  Returns:
    天气描述字符串
  """
  # 模拟数据
  weather_data = {
    '北京': '晴,温度 18°C',
    '上海': '多云,温度 22°C',
    '广州': '雨,温度 26°C',
  }
  return weather_data.get(city, f'未找到 {city} 的天气数据')

from ollama import chat

response = chat(
  model='qwen3',
  messages=[{'role': 'user', 'content': '北京今天天气怎么样?'}],
  tools=[get_weather],
)

print(response.message.content)

SDK 自动把函数转成了工具定义格式:名字从函数名取,描述从 docstring 取,参数从类型注解取。省了自己手写 JSON Schema 的麻烦。

Agent Loop 模式

但事情没那么简单。模型可能调用多个工具,或者调用工具后还想继续调用。你需要一个循环来处理。

这就是 Agent Loop:

from ollama import chat

def add(a: int, b: int) -> int:
  """加法运算"""
  return a + b

def multiply(a: int, b: int) -> int:
  """乘法运算"""
  return a * b

tools = [add, multiply]
tool_map = {'add': add, 'multiply': multiply}

messages = [{'role': 'user', 'content': '计算 (3 + 5) * 2'}]

while True:
  response = chat(model='qwen3', messages=messages, tools=tools)

  if response.message.tool_calls:
    # 模型想调用工具
    for call in response.message.tool_calls:
      func_name = call.function.name
      func_args = call.function.arguments
      result = tool_map[func_name](**func_args)

      # 把工具调用结果加进消息历史
      messages.append({
        'role': 'tool',
        'content': str(result),
        'tool_name': func_name,
      })
  else:
    # 模型没调用工具,说明结束了
    print(response.message.content)
    break

逻辑是这样的:

  1. 发消息给模型,带上工具定义
  2. 如果模型返回了 tool_calls,就执行对应的函数
  3. 把函数结果塞回消息历史,再发给模型
  4. 循环直到模型不再调用工具

这个模式做 Agent 时必用。你定义好一堆工具函数,模型自己决定什么时候调用、调用哪些、调用顺序。

thinking 模式

有些模型——比如 qwen3——支持 thinking 模式。模型会先”思考”,再给出回答。

from ollama import chat

stream = chat(
  model='qwen3',
  messages=[{'role': 'user', 'content': '为什么天空是蓝色的?'}],
  stream=True,
  think=True,
)

thinking = ''
content = ''

for chunk in stream:
  if chunk.message.thinking:
    thinking += chunk.message.thinking
  elif chunk.message.content:
    content += chunk.message.content

print('=== 思考过程 ===')
print(thinking)
print('=== 最终回答 ===')
print(content)

thinking 模式下,chunk 里会多一个 thinking 字段。你得分别累积思考内容和最终回答。

这个功能挺有意思的。你能看到模型是怎么一步步推导出答案的。做教育类应用或者调试 Prompt 时很有用。


第五章:原生 SDK vs OpenAI 兼容 API

现在你有两种选择:

  1. 用 Ollama 原生 SDK(前面讲的那些)
  2. 用 OpenAI SDK,改个地址就能对接 Ollama

哪种更好?看你的情况。

OpenAI 兼容方案

如果你手头有现成的 OpenAI 项目,迁移成本最低的方式就是改 base_url

from openai import OpenAI

client = OpenAI(
  base_url='http://localhost:11434/v1',
  api_key='ollama',  # 必填,但会被忽略
)

response = client.chat.completions.create(
  model='gemma3',
  messages=[{'role': 'user', 'content': '天空为什么是蓝色的?'}],
)

print(response.choices[0].message.content)

就这么简单。OpenAI SDK 完全不知道背后跑的是 Ollama,它只知道自己在跟一个 “OpenAI API” 说话。

Node.js 版本也一样:

import OpenAI from 'openai'

const client = new OpenAI({
  baseURL: 'http://localhost:11434/v1',
  apiKey: 'ollama',
})

const completion = await client.chat.completions.create({
  model: 'gemma3',
  messages: [{ role: 'user', content: '天空为什么是蓝色的?' }],
})

console.log(completion.choices[0].message.content)

两种方案对比

方面原生 SDKOpenAI 兼容
安装pip install ollama已有 OpenAI SDK 即可
工具调用自动解析函数 docstring手写 JSON Schema
流式响应字典格式 chunk标准 OpenAI 格式
Cloud Models支持不支持
迁移成本新项目无成本现有项目成本极低

选择建议

新项目:用原生 SDK。

理由:

  • 工具调用更方便,Python 函数直接当工具传
  • 支持更多特性(Cloud Models、thinking 模式)
  • 文档和示例都是官方的,遇到问题容易查

现有 OpenAI 项目迁移:用 OpenAI 兼容方案。

理由:

  • 改两行代码就能跑
  • 不用重写任何逻辑
  • 后续想切换回 OpenAI 也简单

一句话总结:原生 SDK 功能更全,OpenAI 兼容迁移更快。看你需求。

说实话,两个方案我都试过。原生 SDK 的工具调用确实省事不少——不用自己写 JSON Schema 定义,函数 docstring 写清楚就行。但如果你的项目已经跑在 OpenAI 上,没必要为了用 Ollama 全部重构。


最后

说了这么多,总结几个要点:

基础调用:Python 和 Node.js SDK 都封装得很好,几行代码就能跑。流式响应记得用 stream=True 开启。

工具调用:Agent Loop 是核心模式——循环处理 tool_calls 直到模型不再调用。Python SDK 能直接传函数当工具,省了写 JSON Schema 的麻烦。

thinking 模式:qwen3 等模型支持,能看到模型的思考过程。chunk 里要分别处理 thinking 和 content 字段。

方案选择:新项目用原生 SDK,功能更全;现有 OpenAI 项目用兼容方案,改个地址就行。

下一步建议:

  • 如果你还没把 Ollama 装起来,先看系列第一篇把本地模型跑起来
  • 挑一个适合你项目的方案(原生或 OpenAI 兼容),动手试一试
  • 官方文档持续更新,新功能会不断加进去,有空可以翻翻看

本地跑 LLM 这事儿,门槛越来越低了。Ollama 把复杂的东西都藏在了简单 API 背后。你只需要知道怎么调用,剩下的交给它。

这就是我们这个系列的第二篇。下一篇会讲 Modelfile 定制——怎么把模型调教成你想要的样子。

Ollama API 客户端开发

使用 Python 或 Node.js SDK 调用 Ollama 本地模型 API 的完整指南

⏱️ 预计耗时: 45 分钟

  1. 1

    步骤1: 安装 SDK 并测试基础调用

    Python 用户执行 `pip install ollama`,Node.js 用户执行 `npm i ollama`。

    安装完成后,用最简单的代码测试连接:
    ```python
    from ollama import chat
    response = chat(model='gemma3', messages=[{'role': 'user', 'content': '你好'}])
    print(response.message.content)
    ```

    确保 Ollama 服务已启动(默认端口 11434),且已下载对应模型。
  2. 2

    步骤2: 实现流式响应

    开启流式模式,让用户看到逐字输出效果:

    ```python
    from ollama import chat
    stream = chat(model='gemma3', messages=[...], stream=True)
    for chunk in stream:
    print(chunk['message']['content'], end='', flush=True)
    ```

    注意 chunk 返回的是字典,用 `chunk['message']['content']` 访问。
  3. 3

    步骤3: 配置工具调用(可选)

    定义 Python 函数作为工具,SDK 自动解析 docstring 和类型注解:

    ```python
    def get_weather(city: str) -> str:
    """获取城市天气信息"""
    return f'{city}: 晴'

    response = chat(model='qwen3', messages=[...], tools=[get_weather])
    ```

    实现 Agent Loop 循环处理多次工具调用,直到模型返回最终答案。
  4. 4

    步骤4: 选择原生或 OpenAI 兼容方案

    新项目推荐原生 SDK,功能更全(Cloud Models、thinking 模式)。

    现有 OpenAI 项目只需改两行:
    ```python
    client = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')
    ```

    迁移成本极低,随时切回 OpenAI。

常见问题

Ollama API 的默认端口和地址是什么?
Ollama 默认在 localhost:11434 启动 REST API 服务。核心端点包括 /api/chat(多轮对话)和 /api/generate(单轮生成),还有 /v1/chat/completions 用于 OpenAI 兼容。
Python SDK 流式响应返回的是什么类型?
Python SDK 流式响应返回的是字典类型,不是对象。访问内容要用 chunk['message']['content'],而不是 chunk.message.content。异步客户端返回的是 async generator,用 async for 遍历。
Node.js SDK 在浏览器环境有什么限制?
浏览器版本必须使用流式模式(stream: true),因为非流式请求会一次性返回大 JSON,跨域请求容易超时或被拦截。导入方式也有区别:浏览器用 import ollama from 'ollama/browser'。
什么是 Agent Loop 模式?
Agent Loop 是处理工具调用的循环模式:发送消息给模型 → 检查是否返回 tool_calls → 执行对应函数 → 将结果塞回消息历史 → 再次调用模型 → 循环直到模型不再调用工具。这个模式是构建 Agent 的基础。
thinking 模式下如何分别获取思考过程和最终回答?
thinking 模式下,流式响应的 chunk 会多一个 thinking 字段。需要分别累积:if chunk.message.thinking 则累积思考内容,elif chunk.message.content 则累积最终回答。目前 qwen3 等模型支持此功能。
原生 SDK 和 OpenAI 兼容方案如何选择?
新项目推荐原生 SDK:工具调用支持函数 docstring 自动解析、支持 Cloud Models 和 thinking 模式。现有 OpenAI 项目推荐兼容方案:只需改 base_url 即可,迁移成本极低,后续切回 OpenAI 也方便。

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

当前属于系列阅读 第 12 / 12 篇

Ollama 本地 LLM 实战指南

如果你是从搜索进入这篇文章,建议顺手补上上一篇或继续下一篇,这样更容易把同一主题读完整。

查看系列总览

相关文章

BetterLink

想持续收到这个主题的更新?

你可以直接关注作者更新、订阅 RSS,或者继续沿着系列入口往下读,避免下次又回到搜索结果重新找。

关注公众号

评论

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