引言:为什么需要掌握 Ollama 的高级功能?

在现代 AI 应用开发中,仅调用大模型生成文本已无法满足复杂需求。实际开发中,我们常需要实时交互反馈、追溯模型决策逻辑、自动化处理结构化数据、分析图像内容、实现语义检索,或是让模型自主调用工具完成复杂任务。
Ollama 提供的 Streaming、Thinking、Structured Outputs 等高级功能,正是为解决这些场景而生。掌握这些功能,能让你突破基础文本生成的局限,构建出更智能、更灵活、更贴近实际业务需求的 AI 应用。
本文将基于 Ollama 完整 API 功能,结合详细文字说明、逐行解析的示例代码和真实应用场景,帮你全面掌握每个核心模块的使用方法。

一、流式响应(Streaming):逐字渲染模型输出

1.1 什么是 Streaming?

Streaming(流式响应)是 Ollama 中一种高效的输出传递机制。与传统 “等待模型生成全部内容后一次性返回” 的方式不同,流式响应会将模型生成的内容拆分成多个小块(chunk),生成一部分就传递一部分。
这种机制的核心价值在于 “实时性”,主要适用于三类场景:
  • 实现 “打字机” 效果的 UI 界面,让用户直观看到模型的生成过程,减少等待焦虑。
  • 快速展示部分答案,对于长文本生成(如论文、报告)或复杂查询,避免用户长时间面对空白界面。
  • 降低内存占用,无需在本地缓存完整的大文本,逐块处理即可。
默认行为说明
  • REST API:默认启用 Streaming,无需额外配置。
  • Python SDK 及其他语言 SDK:默认关闭 Streaming,必须手动设置 stream=True 才能启用。

1.2 示例代码解析:Python 中实现 Streaming

以下是完整的 Python 流式响应实现代码,包含详细注释:
# 从 ollama 库中导入 chat 函数,用于发起对话请求
from ollama import chat

# 发起流式对话请求,返回可迭代的 stream 对象
stream = chat(
    model='qwen3',  # 指定使用的模型(需提前在本地通过 ollama pull qwen3 下载)
    messages=[{'role': 'user', 'content': 'What is 17 × 23?'}],  # 用户查询内容
    stream=True,  # 关键参数:开启流式输出(必须显式设置)
)
代码逐行解释
  1. from ollama import chat:导入 Ollama Python SDK 中的核心对话函数 chat,该函数是发起所有对话请求的入口。
  2. chat() 函数的核心参数:
  • model:指定要使用的模型名称,需确保模型已本地下载(可通过 ollama list 查看已下载模型)。
  • messages:对话历史列表,每个元素是包含 role(角色)和 content(内容)的字典,role 支持 user(用户)、assistant(助手)、tool(工具)三种类型。
  • stream=True:开启流式模式,此时函数返回的不再是完整响应对象,而是一个可迭代的 stream 对象,每次迭代获取一个内容块。

1.3 如何处理流式 chunk?积累字段以维持上下文

由于每个  chunk 仅包含部分内容(可能是思考过程、正式回答或工具调用指令),必须通过 “累积字段” 的方式整合完整信息,才能用于后续交互。以下是完整的处理代码及详细解释:
# 初始化状态变量和累积变量
in_thinking = False  # 标记是否正处于模型“思考”阶段(用于区分思考和正式回答)
content = ""  # 累积模型的正式回答内容
thinking = ""  # 累积模型的推理过程内容

# 迭代 stream 对象,逐块处理响应
for chunk in stream:
    # 场景1:当前 chunk 包含模型的思考过程(仅支持 Thinking 模式的模型会返回该字段)
    if chunk.message.thinking:
        # 如果是第一次收到思考内容,打印“Thinking:”标题
        if not in_thinking:
            in_thinking = True
            print('Thinking:\n', end='', flush=True)  # end='' 不自动换行,flush=True 强制立即输出
        # 实时打印当前 chunk 的思考内容,并累加到 thinking 变量中
        print(chunk.message.thinking, end='', flush=True)
        thinking += chunk.message.thinking

    # 场景2:当前 chunk 包含模型的正式回答内容
    elif chunk.message.content:
        # 如果之前处于思考阶段,先换行切换到“Answer:”标题
        if in_thinking:
            in_thinking = False
            print('\n\nAnswer:\n', end='', flush=True)
        # 实时打印当前 chunk 的正式回答,并累加到 content 变量中
        print(chunk.message.content, end='', flush=True)
        content += chunk.message.content
关键逻辑说明
  1. flush=True:这是实现 “实时打印” 的核心参数。Python 打印内容默认会缓冲,直到缓冲区满才输出,flush=True 会强制每次打印都立即输出到终端或前端,避免内容堆积延迟。
  2. 分阶段渲染:通过 in_thinking 状态变量,区分模型的 “思考过程” 和 “正式回答”,分别打印标题,让输出结构更清晰。
  3. 字段累积:thinking 和 content 变量分别存储完整的推理过程和回答内容,后续多轮对话或工具调用需依赖这些累积后的完整信息。

1.4 下一步:将累积内容加入对话历史

流式响应结束后,必须将累积的  thinkingcontent(若有  tool_calls 也需包含)添加到对话历史中,否则模型会丢失之前的上下文,影响多轮交互的连贯性。
# 构造完整的助手响应消息,包含累积的思考过程和正式回答
new_message = {
    'role': 'assistant',  # 角色为助手
    'thinking': thinking,  # 完整的推理过程
    'content': content     # 完整的正式回答
}

# 将新消息添加到原对话历史中(假设原对话历史存储在 messages 列表中)
messages.append(new_message)
重要提示:如果是涉及工具调用的场景, new_message 还需包含  tool_calls 字段(累积的工具调用指令)。若不保存  thinking 或  tool_calls,模型会丢失之前的决策路径,导致后续工具调用或推理逻辑断裂。

1.5 典型使用场景

  • 聊天机器人 UI:实现 “打字机” 效果,如网页版 AI 助手,逐字显示模型回复。
  • 长文本生成:如生成万字报告,流式输出可让用户先看到开头内容,无需等待全部生成。
  • 实时数据处理:如基于模型输出实时更新仪表盘,逐块处理避免内存溢出。

二、推理模式(Thinking):查看模型的 “内心独白”

2.1 什么是 Thinking 模式?

Thinking 模式是 Ollama 针对支持推理轨迹输出的模型提供的功能,能让模型在生成最终答案前,先输出其内部的推理过程(称为 reasoning trace)。
类比人类思维:当被问 “17×23 等于多少” 时,人类会先想 “可以拆成 (10+7)(20+3),再展开计算 200+30+140+21,最后得到 391”,这个思考过程就是推理轨迹。
开启 Thinking 模式后,模型会同时返回  thinking(推理过程)和  content(最终答案)两个字段,核心价值在于:
  • 可解释性:让开发者或用户了解模型的决策逻辑,排查 “为什么模型会给出这个答案”。
  • 审计能力:在金融、医疗等敏感场景,可记录模型推理过程用于合规审计。
  • 调试优化:通过观察推理轨迹,发现模型逻辑漏洞,优化 prompt 或模型参数。

2.2 支持 Thinking 的模型列表

并非所有 Ollama 模型都支持 Thinking 模式,以下是主流模型的支持情况:

模型名称

是否支持 Thinking

特殊要求

Qwen3

✅ 是

需在请求中设置

"think": true

DeepSeek-v3.1 / R1

✅ 是

需在请求中设置

"think": true

GPT-OSS

✅ 是

不支持布尔值,需指定等级:

"think": "low"

(简短推理)、

"medium"

(中等详细)、

"high"

(详细推理)

gemma3

❌ 否

无支持计划,无法开启

注意:GPT-OSS 模型对 think 参数有严格要求,传入 true 或 false 会报错,必须使用指定的等级字符串。

2.3 开启 Thinking 模式的 API 调用方法

方法一:cURL 请求(非流式)

适用于快速测试或不需要实时输出的场景,完整命令如下:

# 向 Ollama 本地 API 发送 POST 请求,开启 Thinking 模式
curl http://localhost:11434/api/chat -d '{
    "model": "qwen3",  # 指定支持 Thinking 的模型
    "messages": [
        { "role": "user", "content": "How many letter r are in strawberry?" }  # 用户问题:“strawberry 中有多少个字母 r?”
    ],
    "think": true,  # 开启 Thinking 模式(Qwen3/DeepSeek 专用)
    "stream": false  # 关闭流式,一次性返回完整结果
}'

响应示例:

{
  "message": {
    "role": "assistant",
    "thinking": "First, I need to spell 'strawberry' correctly: s-t-r-a-w-b-e-r-r-y. Now count the letter 'r': positions 3, 8, 9. That's 3 times.",
    "content": "There are 3 letter 'r' in 'strawberry'."
  },
  "done": true
}
方法二:Python SDK 流式 + Thinking(推荐)

结合流式输出和 Thinking 模式,既能实时看到模型的思考过程,又能获取完整答案,是最常用的方式:

# 从 ollama 库导入 chat 函数
from ollama import chat

# 发起流式对话,同时开启 Thinking 模式
stream = chat(
    model='qwen3',  # 支持 Thinking 的模型
    messages=[{'role': 'user', 'content': 'What is 17 × 23?'}],  # 用户问题
    think=True,  # 开启 Thinking 模式
    stream=True  # 开启流式输出
)

# 初始化状态变量,用于区分思考和回答阶段
in_thinking = False

# 迭代处理每个 chunk
for chunk in stream:
    # 处理思考过程的 chunk
    if chunk.message.thinking and not in_thinking:
        in_thinking = True
        print('Thinking:\n', end='')  # 打印思考阶段标题
    if chunk.message.thinking:
        print(chunk.message.thinking, end='')  # 实时打印思考内容
    
    # 处理正式回答的 chunk
    elif chunk.message.content:
        if in_thinking:
            in_thinking = False
            print('\n\nAnswer:\n', end='')  # 切换到回答阶段
        print(chunk.message.content, end='')  # 实时打印正式回答

终端输出示例:

Thinking:
I need to multiply 17 by 23. I can break it down into simpler calculations: 17 × 20 = 340, and 17 × 3 = 51. Then add the two results together: 340 + 51 = 391.

Answer:
391

2.4 CLI 快捷命令操作 Thinking

Ollama 提供了 CLI 命令,可快速开启 / 关闭 Thinking 模式,无需编写复杂代码:

# 1. 单次运行并显示推理过程(DeepSeek R1 模型)
ollama run deepseek-r1 --think "Where should I visit in Lisbon?"

# 2. 禁用推理过程(仅输出最终答案)
ollama run deepseek-r1 --think=false "Summarize this article"

# 3. 隐藏推理过程但保留推理逻辑(模型仍会思考,仅不显示)
ollama run deepseek-r1 --hidethinking "Is 9.9 bigger or 9.11?"

# 4. 交互模式中动态切换:进入交互后输入以下命令
/set think  # 开启 Thinking 模式
/set nothink  # 关闭 Thinking 模式

2.5 使用场景建议

目标

推荐做法

审计模型决策(合规场景)

保留并记录

message.thinking

字段,存储到日志或数据库

UI 动画展示 “思考中”

thinking

文本渲染为灰色斜体,配合加载动画

仅需最终答案(追求效率)

使用

--hidethinking

参数,隐藏中间推理过程

控制推理长度(GPT-OSS 模型)

根据需求设置

think: "low"

(短推理)、

"medium"

(中等)、

"high"

(详细)


三、结构化输出(Structured Outputs):让模型返回 JSON 数据

3.1 为什么要用 Structured Outputs?

传统大模型输出是自由文本,例如询问 “加拿大的信息”,模型可能返回一段段落式文字。这种输出难以直接被程序处理,如需提取 “首都”“语言” 等关键信息,还需额外解析,效率低且易出错。
结构化输出(Structured Outputs)通过预定义格式(如 JSON Schema),强制模型按照指定结构返回数据,核心优势在于:
  • 直接机器可读:返回的 JSON 数据可直接用于程序逻辑、数据库导入、API 调用等场景。
  • 数据一致性:避免模型输出格式混乱,即使多次调用,返回结构也保持统一。
  • 减少解析成本:无需手动处理自由文本,直接通过键名提取所需信息。
主要适用场景:
  • 实体信息提取(人名、地点、价格、日期等)。
  • 图像描述标准化(固定字段描述图像中的物体、场景、颜色等)。
  • 数据库批量导入(按表结构生成 JSON 数据)。
  • 确定性响应需求(配合 temperature=0,确保输出格式 100% 符合预期)。

3.2 基础用法:返回标准 JSON

无需自定义结构,仅指定输出格式为 JSON,模型会自动将回答转换为 JSON 格式(适用于简单场景):
# cURL 命令示例:返回关于加拿大的标准 JSON 数据
curl -X POST http://localhost:11434/api/chat \
-H "Content-Type: application/json" \
-d '{
    "model": "gpt-oss",  # 推荐使用支持结构化输出的模型
    "messages": [{"role": "user", "content": "Tell me about Canada in one paragraph."}],
    "stream": false,  # 结构化输出不支持流式,需关闭
    "format": "json"  # 指定输出格式为 JSON
}'

响应示例:

{
  "message": {
    "role": "assistant",
    "content": "{\"name\":\"Canada\",\"capital\":\"Ottawa\",\"languages\":[\"English\",\"French\"],\"continent\":\"North America\",\"population\":\"approximately 39 million\"}"
  },
  "done": true
}

注意:仅指定 format: "json" 时,模型可能不完全遵守预期结构(例如缺少字段、字段类型错误)。对于关键场景,推荐使用自定义 JSON Schema。

3.3 高级用法:自定义 JSON Schema

通过定义 JSON Schema,明确指定返回数据的字段名、类型、必填项等,确保模型输出完全符合需求。以下是完整示例:

步骤 1:定义 JSON Schema

需求:获取加拿大的名称、首都、官方语言,Schema 定义如下:

{
  "type": "object",  # 根节点为对象类型
  "properties": {
    "name": {"type": "string"},  # 国家名称(字符串类型)
    "capital": {"type": "string"},  # 首都(字符串类型)
    "languages": {  # 官方语言(数组类型,元素为字符串)
      "type": "array",
      "items": {"type": "string"}
    }
  },
  "required": ["name", "capital", "languages"]  # 必填字段,缺一不可
}
步骤 2:发起 cURL 请求

将自定义 Schema 传入 format 参数:

curl -X POST http://localhost:11434/api/chat \
-H "Content-Type: application/json" \
-d '{
    "model": "gpt-oss",
    "messages": [{"role": "user", "content": "Tell me about Canada."}],
    "stream": false,
    "format": {
      "type": "object",
      "properties": {
        "name": {"type": "string"},
        "capital": {"type": "string"},
        "languages": {"type": "array", "items": {"type": "string"}}
      },
      "required": ["name", "capital", "languages"]
    }
}'

响应示例(严格符合 Schema):

{
  "message": {
    "role": "assistant",
    "content": "{\"name\":\"Canada\",\"capital\":\"Ottawa\",\"languages\":[\"English\",\"French\"]}"
  },
  "done": true
}

3.4 Python 示例:使用 Pydantic 定义结构(推荐)

Pydantic 是 Python 中常用的数据验证库,可通过类定义自动生成 JSON Schema,同时支持类型验证和 IDE 自动补全,比手动编写 Schema 更高效。

示例:提取宠物信息

需求:根据用户输入的宠物描述,提取宠物名称、种类、年龄、颜色、喜欢的玩具等信息。

# 1. 导入必要的库
from ollama import chat
from pydantic import BaseModel  # Pydantic 核心类,用于定义数据结构

# 2. 定义 Pydantic 模型(自动生成 JSON Schema)
class Pet(BaseModel):
    name: str  # 宠物名称(必填,字符串)
    animal: str  # 宠物种类(必填,字符串,如 cat、dog)
    age: int  # 年龄(必填,整数)
    color: str | None = None  # 颜色(可选,字符串,默认 None)
    favorite_toy: str | None = None  # 喜欢的玩具(可选,字符串,默认 None)

# 定义包含多个宠物的列表模型
class PetList(BaseModel):
    pets: list[Pet]  # 宠物列表(必填,元素为 Pet 类型)

# 3. 发起 Ollama 请求
response = chat(
    model='gpt-oss',  # 支持结构化输出的模型
    messages=[
        {
            'role': 'user',
            'content': 'I have two cats named Luna and Loki. Luna is 3 years old, black, loves yarn. Loki is 5, orange, likes boxes.'
        }
    ],
    format=PetList.model_json_schema(),  # 自动将 Pydantic 模型转换为 JSON Schema
    options={'temperature': 0}  # 温度设为 0,确保输出完全符合结构,无随机性
)

# 4. 解析并验证返回结果
# model_validate_json 会自动验证 JSON 结构是否符合 PetList 模型,不符合则报错
pets = PetList.model_validate_json(response.message.content)

# 5. 打印结果(支持属性访问,如 pets.pets[0].name)
print(pets)

输出示例:

PetList(pets=[
    Pet(name='Luna', animal='cat', age=3, color='black', favorite_toy='yarn'),
    Pet(name='Loki', animal='cat', age=5, color='orange', favorite_toy='boxes')
])
优势解析
  • 自动类型验证:若模型返回的 age 是字符串(如 "3"),model_validate_json 会直接报错,避免后续程序逻辑出错。
  • IDE 自动补全:编写代码时,IDE 会提示 pets 对象的属性(如 pets.petspet.name),提高开发效率。
  • 可复用性:Pet 和 PetList 模型可多次用于不同请求,无需重复编写 Schema。

3.5 视觉模型 + 结构化输出:精准图像识别

结合视觉模型(Vision)和结构化输出,可实现图像信息的标准化提取,例如固定字段描述图像中的物体、场景、颜色等。
# 1. 导入必要的库和类型
from typing import Literal, Optional
from pydantic import BaseModel
from ollama import chat

# 2. 定义图像描述的结构化模型
class Object(BaseModel):
    name: str  # 物体名称(如 cat、window)
    confidence: float  # 识别置信度(0-1 之间)
    attributes: str  # 物体属性(如 black fur、wooden frame)

class ImageDescription(BaseModel):
    summary: str  # 图像概要描述
    objects: list[Object]  # 识别到的物体列表
    scene: str  # 场景描述(如 indoor living room)
    colors: list[str]  # 主要颜色列表
    time_of_day: Literal['Morning', 'Afternoon', 'Evening', 'Night']  # 时间段(仅允许指定选项)
    setting: Literal['Indoor', 'Outdoor', 'Unknown']  # 场景类型(仅允许指定选项)
    text_content: Optional[str] = None  # 图像中的文字内容(可选)

# 3. 发起带图像的结构化请求
response = chat(
    model='gemma3',  # 支持视觉功能的模型
    messages=[
        {
            'role': 'user',
            'content': 'Describe this photo and list the objects you detect.',  # 指令:描述照片并列出检测到的物体
            'images': ['path/to/cat_image.jpg']  # 本地图像路径,SDK 会自动处理
        }
    ],
    format=ImageDescription.model_json_schema(),  # 结构化输出格式
    options={'temperature': 0}  # 关闭随机性,确保格式一致
)

# 4. 解析结果
image_desc = ImageDescription.model_validate_json(response.message.content)
print(image_desc)

输出示例:

ImageDescription(
    summary='A black cat sleeping on a windowsill during evening.',
    objects=[
        Object(name='cat', confidence=0.98, attributes='black fur, closed eyes'),
        Object(name='window', confidence=0.92, attributes='wooden frame')
    ],
    scene='indoor living room',
    colors=['black', 'brown', 'white'],
    time_of_day='Evening',
    setting='Indoor',
    text_content=None
)

3.6 最佳实践建议

技巧

说明

使用 Pydantic/Zod 定义 schema

替代手动编写 JSON Schema,提高可维护性和复用性(Python 用 Pydantic,JavaScript 用 Zod)

设置

temperature=0

温度越低,模型输出越确定,结构化格式的准确率接近 100%;温度 > 0 可能导致格式错乱

在 prompt 中重复 schema

在用户指令中明确要求 “请按以下 JSON 格式输出:{schema 内容}”,增强模型的格式意识

使用 OpenAI 兼容接口

若需兼容 OpenAI 生态,可设置

response_format={"type": "json_object"}

,效果与 Ollama 的

format: "json"

一致


四、视觉模型(Vision):图文混合输入与分析

4.1 Vision 模型的核心能力

Vision 模型(支持图文混合输入的模型)能同时接收文本指令和图像数据,实现多模态理解。Ollama 中支持 Vision 的模型包括 gemma3、llava、qwen2.5vl 等,核心能力如下:
  • 图像内容描述:用自然语言详细描述图像中的场景、物体、人物动作等。
  • OCR 文字识别:提取图像中的文字内容(如海报上的文字、文档扫描件中的文字)。
  • 物体检测与分类:识别图像中的物体类别、位置及属性(如 “黑色的猫”“木质窗户”)。
  • 场景问答(VQA):根据文本指令回答与图像相关的问题(如 “这张图中有几只狗?”“图中的文字是什么意思?”)。

4.2 快速开始:CLI 方式上传图像

Ollama CLI 支持直接传入图像文件路径,快速测试视觉模型的能力,无需编写代码:
# 格式:ollama run [模型名] [图像路径] [文本指令]
ollama run gemma3 ./cat_image.jpg "What's in this image? Describe it in detail."
说明
  • 模型会自动读取本地图像文件并编码,无需手动处理。
  • 文本指令需明确,例如 “描述图像中的物体”“提取图像中的文字”“判断图像是室内还是室外”。
  • 输出为自然语言文本,若需结构化输出,需结合上一章节的 Structured Outputs 功能。

4.3 API 使用方式:Base64 编码图像

Ollama REST API 不支持直接传入文件路径,需将图像转换为 Base64 字符串后传入。以下是完整的 shell 脚本示例:
# 1. 下载测试图像(以维基百科的猫图片为例)
curl -L -o test.jpg "https://upload.wikimedia.org/wikipedia/commons/3/3a/Cat03.jpg"

# 2. 将图像转换为 Base64 字符串(去除换行符,避免 JSON 解析错误)
IMG=$(base64 < test.jpg | tr -d '\n')

# 3. 向 Ollama API 发送请求
curl -X POST http://localhost:11434/api/chat \
-H "Content-Type: application/json" \
-d '{
    "model": "gemma3",  # 支持 Vision 的模型
    "messages": [
        {
            "role": "user",
            "content": "What is in this image? Describe the animal's appearance.",  # 指令:描述图像中的动物外观
            "images": ["'"$IMG"'"]  # 传入 Base64 编码的图像字符串
        }
    ],
    "stream": false  # 视觉模型暂不支持流式输出
}'

响应示例:

{
  "message": {
    "role": "assistant",
    "content": "The image shows a cat with light-colored fur, possibly white or cream. The cat appears to be lying down, with its eyes open and looking towards the camera. Its ears are pointed, and it has a calm expression. The background is blurred, focusing attention on the cat."
  },
  "done": true
}

4.4 Python SDK 使用本地路径(更简单)

Ollama Python SDK 简化了图像处理流程,支持直接传入本地文件路径,SDK 会自动将图像转换为 Base64 编码,无需手动处理:

# 1. 导入 chat 函数
from ollama import chat

# 2. 发起带图像的请求
response = chat(
    model='gemma3',  # 支持 Vision 的模型
    messages=[
        {
            'role': 'user',
            'content': 'Describe the animal in this picture. Is it a cat or a dog?',  # 指令:描述动物并判断种类
            'images': ['test.jpg']  # 直接传入本地图像路径(相对路径或绝对路径均可)
        }
    ]
)

# 3. 打印结果
print(response.message.content)

输出示例:

The animal in the picture is a cat. It has light-colored fur, pointed ears, and a slender face. The cat is in a relaxed posture, likely resting on a soft surface. The fur appears smooth and well-groomed.

4.5 支持的数据类型

输入类型

是否支持

说明

本地文件路径

✅ Python SDK

最推荐,无需手动编码,SDK 自动处理

URL

❌ 所有方式

当前不支持直接传入远程图像 URL,需先下载到本地

Raw bytes

✅ Python SDK

支持传入图像字节流(如

open('test.jpg', 'rb').read()

Base64 string

✅ REST API

必须使用此格式,需确保去除换行符


五、嵌入向量(Embeddings):语义搜索与 RAG 的基础

5.1 什么是 Embeddings?

Embeddings(嵌入向量)是将文本(如单词、句子、段落)转换为固定长度的数值向量(通常为 384~1024 维)的过程。其核心特性是 “语义相近的文本,向量空间距离更近”。
例如:
  • “猫” 的向量与 “狗” 的向量距离较近(均为宠物)。
  • “猫” 的向量与 “汽车” 的向量距离较远(语义无关)。
这种特性使得 Embeddings 成为语义理解的基础,主要用途包括:
  • 语义相似度匹配:计算两个文本的余弦相似度(cosine similarity),判断其语义是否相近。
  • 向量数据库检索:将文本嵌入后存入向量数据库(如 Pinecone、Weaviate、Chroma),快速检索语义相关的文本。
  • RAG(Retrieval-Augmented Generation):检索与用户问题相关的知识库文本,作为上下文传入模型,提升回答的准确性和时效性。

5.2 推荐的 Embedding 模型

Ollama 支持多种专用 Embedding 模型,不同模型在性能、速度、语言支持上各有侧重:

模型

特点

适用场景

embeddinggemma

Google 出品,轻量高效,向量维度 768

英文场景、对速度要求高的应用

qwen3-embedding

阿里出品,中文语义理解能力优秀,向量维度 1024

中文场景、需要高精度语义匹配的应用

all-minilm

微软出品,通用性强,体积小,速度快

多语言场景、资源受限的设备(如边缘计算)

注意:应优先使用专用 Embedding 模型,不要用 chat 模型(如 qwen3、gemma3)生成嵌入向量,专用模型的语义表征更精准,且向量维度更统一。

5.3 生成单个文本的 Embedding

通过 Ollama API 可快速生成单个文本的嵌入向量,以下是 cURL 示例:

# 生成单个句子的 Embedding
curl -X POST http://localhost:11434/api/embed \
-H "Content-Type: application/json" \
-d '{
    "model": "embeddinggemma",  # 专用 Embedding 模型
    "input": "The quick brown fox jumps over the lazy dog."  # 要生成嵌入的文本
}'

响应示例:

{
  "embeddings": [
    0.123456, -0.456789, 0.789012, ..., 0.345678  # 768 维向量(省略中间部分)
  ],
  "total_duration": 123456789,  # 总耗时(纳秒)
  "prompt_eval_count": 9,  # 输入文本的 Token 数
  "prompt_eval_duration": 98765432  # 文本处理耗时(纳秒)
}

说明:所有 Ollama Embedding 模型返回的向量均已进行 L2 归一化(向量长度为 1),可直接用于计算余弦相似度,无需额外处理。

5.4 批量生成多个 Embeddings

支持同时传入多个文本,批量生成嵌入向量,返回的向量顺序与输入文本顺序一致:

# 批量生成多个句子的 Embedding
curl -X POST http://localhost:11434/api/chat \
-H "Content-Type: application/json" \
-d '{
    "model": "embeddinggemma",
    "input": [
        "First sentence",
        "Second sentence",
        "Third sentence"
    ]
}'

响应示例:

{
  "embeddings": [
    [0.111..., -0.222..., ...],  # 对应 "First sentence" 的向量
    [0.333..., -0.444..., ...],  # 对应 "Second sentence" 的向量
    [0.555..., -0.666..., ...]   # 对应 "Third sentence" 的向量
  ],
  "total_duration": 234567890,
  "prompt_eval_count": 15,
  "prompt_eval_duration": 187654321
}

5.5 Python 使用示例:计算语义相似度

以下示例展示如何生成文本嵌入,并计算两个句子的语义相似度:

# 1. 导入必要的库
import numpy as np
from numpy.linalg import norm  # 用于计算向量的 L2 范数
from ollama import embed

# 2. 生成嵌入向量
result = embed(
    model="embeddinggemma",  # 专用 Embedding 模型
    input=[
        "Hello world",  # 文本 1
        "Hi there",     # 文本 2(与文本 1 语义相近)
        "Goodbye everyone"  # 文本 3(与文本 1 语义无关)
    ]
)

# 3. 提取嵌入向量(result.embeddings 是列表,每个元素是一个向量)
embeddings = result.embeddings  # shape: (3, 768),3 个文本,每个 768 维

# 4. 定义余弦相似度计算函数
def cosine_sim(a, b):
    """计算两个向量的余弦相似度,结果范围 [-1, 1],越接近 1 语义越相近"""
    return np.dot(a, b) / (norm(a) * norm(b))

# 5. 计算相似度
sim1_2 = cosine_sim(embeddings[0], embeddings[1])  # "Hello world" 与 "Hi there" 的相似度
sim1_3 = cosine_sim(embeddings[0], embeddings[2])  # "Hello world" 与 "Goodbye everyone" 的相似度

# 6. 打印结果
print(f"Similarity between 'Hello world' and 'Hi there': {sim1_2:.3f}")
print(f"Similarity between 'Hello world' and 'Goodbye everyone': {sim1_3:.3f}")

输出示例:

Similarity between 'Hello world' and 'Hi there': 0.892
Similarity between 'Hello world' and 'Goodbye everyone': 0.123

说明:余弦相似度结果越接近 1,说明两个文本语义越相近;越接近 0 或负数,语义越无关。

5.6 最佳实践

建议

说明

使用相同模型进行索引和查询

索引知识库文本和查询文本时,必须使用同一个 Embedding 模型,否则向量空间不一致,相似度计算无效

存储归一化后的向量

Ollama 返回的向量已 L2 归一化,存储时直接保存即可,后续计算相似度可简化为

np.dot(a, b)

优先选用专用 Embedding 模型

专用模型(如 embeddinggemma、qwen3-embedding)的语义表征能力远优于 chat 模型,避免混用

控制输入文本长度

过长的文本会导致 Token 数过多,影响生成速度和语义精准度,建议单段文本不超过 512 Token


六、工具调用(Tool Calling):让模型调用外部函数

6.1 什么是 Tool Calling?

Tool Calling(工具调用)是 Ollama 让模型与外部工具(如 API、数据库、计算器、文件系统)交互的核心功能。模型可根据用户问题,自主判断是否需要调用工具,以及调用哪个工具,再将工具返回的结果整合为自然语言回答。
例如:
  • 用户问 “纽约现在的气温是多少?”,模型会调用天气 API 获取实时数据,再返回 “纽约当前气温为 22°C”。
  • 用户问 “(11434+12341)×412 等于多少?”,模型会调用计算器工具分步计算,再返回最终结果。
Tool Calling 是构建 AI Agent 的核心环节,让模型从 “只能生成文本” 升级为 “能执行动作、获取实时数据、解决实际问题”。

6.2 单次工具调用(Single-shot)

单次工具调用是指模型仅调用一次工具就完成回答,适用于简单场景(如查询单个城市的气温、计算单个公式)。
步骤 1:定义工具描述
需明确工具的名称、功能描述和参数格式,让模型知道如何调用:
{
  "type": "function",
  "function": {
    "name": "get_temperature",  # 工具名称(需与实际函数名一致)
    "description": "Get current temperature for a city",  # 工具功能描述
    "parameters": {
      "type": "object",
      "required": ["city"],  # 必填参数
      "properties": {
        "city": {"type": "string", "description": "City name"}  # 参数说明:城市名称(字符串)
      }
    }
  }
}
步骤 2:发起 API 请求

通过 cURL 发起工具调用请求,模型会返回工具调用指令:

curl -s http://localhost:11434/api/chat \
-H "Content-Type: application/json" \
-d '{
    "model": "qwen3",  # 支持工具调用的模型
    "messages": [{"role": "user", "content": "What is the temperature in New York?"}],  # 用户问题
    "tools": [
        {
            "type": "function",
            "function": {
                "name": "get_temperature",
                "description": "Get current temperature for a city",
                "parameters": {
                    "type": "object",
                    "required": ["city"],
                    "properties": {
                        "city": {"type": "string", "description": "City name"}
                    }
                }
            }
        }
    ],
    "stream": false
}'
步骤 3:模型返回工具调用指令

模型会判断需要调用 get_temperature 工具,并传入参数 city: "New York":

{
  "message": {
    "role": "assistant",
    "tool_calls": [
      {
        "type": "function",
        "function": {
          "name": "get_temperature",
          "arguments": {"city": "New York"}
        }
      }
    ]
  },
  "done": false  # done 为 false,表示需要继续工具调用
}

6.3 执行工具并返回结果

拿到模型的工具调用指令后,需执行对应的外部工具(如调用天气 API),再将工具返回的结果传入模型,让模型生成最终回答。

# 执行工具后,将结果加入对话历史,发起第二次请求
curl -s http://localhost:11434/api/chat \
-H "Content-Type: application/json" \
-d '{
    "model": "qwen3",
    "messages": [
        {"role": "user", "content": "What is the temperature in New York?"},  # 原用户问题
        {"role": "assistant", "tool_calls": [{"type": "function", "function": {"name": "get_temperature", "arguments": {"city": "New York"}}}]},  # 模型的工具调用指令
        {"role": "tool", "tool_name": "get_temperature", "content": "22°C"}  # 工具返回的结果
    ],
    "stream": false
}'

模型返回最终回答:

{
  "message": {
    "role": "assistant",
    "content": "The temperature in New York is 22°C."
  },
  "done": true
}

6.4 并行工具调用

模型支持同时调用多个工具,一次性获取多个结果后综合回答,适用于需要多源数据的场景(如查询 “纽约的气温和天气状况”)。

curl -s http://localhost:11434/api/chat \
-H "Content-Type: application/json" \
-d '{
    "model": "qwen3",
    "messages": [{"role": "user", "content": "What is the temperature and weather condition in New York?"}],
    "tools": [
        {
            "type": "function",
            "function": {
                "name": "get_temperature",
                "description": "Get current temperature for a city",
                "parameters": {"type": "object", "required": ["city"], "properties": {"city": {"type": "string"}}}
            }
        },
        {
            "type": "function",
            "function": {
                "name": "get_weather_condition",
                "description": "Get current weather condition (sunny/rainy/cloudy) for a city",
                "parameters": {"type": "object", "required": ["city"], "properties": {"city": {"type": "string"}}}
            }
        }
    ],
    "stream": false
}'

模型返回并行工具调用指令:

{
  "message": {
    "role": "assistant",
    "tool_calls": [
      {"type": "function", "function": {"name": "get_temperature", "arguments": {"city": "New York"}}},
      {"type": "function", "function": {"name": "get_weather_condition", "arguments": {"city": "New York"}}}
    ]
  },
  "done": false
}

执行工具后返回结果:

{
  "message": {
    "role": "assistant",
    "content": "The temperature in New York is 22°C and the weather condition is sunny."
  },
  "done": true
}

6.5 多轮 Agent 循环(Multi-turn Tool Calling)

多轮工具调用是指模型需要多次调用工具(可能是同一个或不同工具),逐步推进问题解决,适用于复杂任务(如多步计算、多条件查询)。

以下是 Python 实现的多轮工具调用示例,解决 “(11434+12341)×412 等于多少?” 的问题:

# 1. 导入必要的库
from ollama import chat

# 2. 定义可用的工具函数
def add(a: int, b: int) -> int:
    """Add two numbers(加法函数)"""
    return a + b

def multiply(a: int, b: int) -> int:
    """Multiply two numbers(乘法函数)"""
    return a * b

# 3. 存储可用工具(键为工具名称,值为工具函数)
available_functions = {
    'add': add,
    'multiply': multiply
}

# 4. 初始化对话历史
messages = [{'role': 'user', 'content': 'What is (11434+12341)*412?'}]

# 5. 多轮工具调用循环
while True:
    # 发起对话请求,传入可用工具和思考模式
    response = chat(
        model='qwen3',
        messages=messages,
        tools=[add, multiply],  # 传入工具函数,模型会自动解析名称、参数
        think=True,  # 开启思考模式,查看模型的推理过程
    )

    # 将模型响应加入对话历史
    messages.append(response.message)

    # 检查是否需要调用工具
    if response.message.tool_calls:
        # 遍历每个工具调用指令
        for tc in response.message.tool_calls:
            # 获取对应的工具函数
            func = available_functions.get(tc.function.name)
            if func:
                # 执行工具函数(传入参数)
                result = func(**tc.function.arguments)
                # 将工具执行结果加入对话历史
                messages.append({
                    'role': 'tool',
                    'tool_name': tc.function.name,
                    'content': str(result)  # 工具结果需转为字符串
                })
    else:
        # 没有更多工具调用,退出循环
        break

# 6. 打印最终结果
print("Final Answer:", response.message.content)

输出示例:

Final Answer: (11434 + 12341) = 23775, then 23775 × 412 = 9795300. So the result is 9795300.
循环过程解析
  1. 第一轮:模型判断需要先计算 11434+12341,调用 add 工具,结果为 23775。
  2. 第二轮:模型获取 add 结果后,判断需要计算 23775×412,调用 multiply 工具,结果为 9795300。
  3. 第三轮:模型获取 multiply 结果后,无需再调用工具,生成最终回答。

6.6 流式 + 工具调用:完整 Accumulation 示例

结合流式输出和工具调用,需累积  thinkingcontenttool_calls 三个字段,确保上下文完整:
# 1. 导入库
from ollama import chat

# 2. 定义工具函数
def add(a: int, b: int) -> int:
    return a + b

available_functions = {'add': add}

# 3. 初始化对话历史和累积变量
messages = [{'role': 'user', 'content': 'What is 123 + 456?'}]
thinking = ""  # 累积思考过程
content = ""   # 累积正式回答
tool_calls = []  # 累积工具调用指令

# 4. 发起流式请求
stream = chat(
    model='qwen3',
    messages=messages,
    tools=[add],
    think=True,
    stream=True
)

# 5. 处理流式 chunk
for chunk in stream:
    # 累积思考过程
    if chunk.message.thinking:
        thinking += chunk.message.thinking
    # 累积正式回答
    if chunk.message.content:
        content += chunk.message.content
    # 累积工具调用指令
    if chunk.message.tool_calls:
        tool_calls.extend(chunk.message.tool_calls)

# 6. 将完整响应加入对话历史
messages.append({
    'role': 'assistant',
    'thinking': thinking,
    'content': content,
    'tool_calls': tool_calls
})

# 7. 执行工具并获取结果
if tool_calls:
    tc = tool_calls[0]
    func = available_functions.get(tc.function.name)
    result = func(**tc.function.arguments)
    messages.append({
        'role': 'tool',
        'tool_name': tc.function.name,
        'content': str(result)
    })

# 8. 生成最终回答
final_response = chat(model='qwen3', messages=messages)
print("Final Answer:", final_response.message.content)

输出示例:

Final Answer: 123 + 456 = 579.

七、Web Search & Fetch:赋予模型实时信息获取能力

7.1 为什么需要 Web Search & Fetch?

普通大模型的知识库存在 “知识截止日期”,无法获取训练数据之后的新信息(如 2025 年的新闻、最新产品发布、实时事件)。Web Search(网络搜索)和 Web Fetch(网页内容抓取)功能,能让模型突破这一限制,实时获取网络上的最新信息。
核心用途:
  • 实时新闻查询(如 “2025 年世界杯冠军是谁?”)。
  • 最新数据获取(如 “当前比特币价格是多少?”)。
  • 网页内容解析(如 “Ollama 官网最新发布的功能有哪些?”)。

7.2 Web Search API:执行网络搜索

Ollama 提供  web_search 函数,可直接发起网络搜索,返回相关搜索结果(标题、链接、摘要)。
# 1. 导入 ollama 库
import ollama

# 2. 配置 API 密钥(需在 Ollama 官网申请,设置环境变量或传入 headers)
# 方式 1:设置环境变量(推荐)
# import os
# os.environ['OLLAMA_API_KEY'] = 'your_api_key'

# 3. 发起网络搜索
response = ollama.web_search("What is Ollama's new engine in 2025?")  # 搜索关键词:2025 年 Ollama 的新引擎

# 4. 打印搜索结果
print("Search Results:")
for result in response.results:
    print(f"Title: {result.title}")
    print(f"URL: {result.url}")
    print(f"Summary: {result.summary[:100]}...")  # 打印摘要前 100 字符
    print("-" * 50)

输出示例:

Search Results:
Title: Ollama 2025 New Engine: Faster, More Efficient Model Serving
URL: https://ollama.com/blog/new-engine-2025
Summary: Ollama announced its new engine in 2025, featuring improved inference speed (2x faster than previous versions) and lower memory usage...
--------------------------------------------------
Title: Ollama's New Engine Supports Multi-Modal Real-Time Processing
URL: https://techcrunch.com/2025/03/15/ollama-new-engine/
Summary: The new engine from Ollama integrates real-time web search with multi-modal models, enabling AI agents to process text, images, and...
--------------------------------------------------

说明:web_search 函数返回的结果包含 title(标题)、url(网页链接)、summary(内容摘要),模型可基于这些信息生成回答。

7.3 Web Fetch API:抓取网页内容

Web Fetch 用于获取指定 URL 的完整网页内容(去除 HTML 标签后的纯文本),适用于需要详细解析网页内容的场景。

# 1. 导入 ollama 库
import ollama

# 2. 抓取网页内容(以 Ollama 官网为例)
result = ollama.web_fetch('https://ollama.com/blog/new-engine-2025')

# 3. 打印网页信息
print("Page Title:", result.title)
print("Page Content (First 500 chars):", result.content[:500], "...")

输出示例:

Page Title: Ollama 2025 New Engine: Faster, More Efficient Model Serving
Page Content (First 500 chars): Ollama is excited to announce the launch of its new engine in 2025, designed to revolutionize AI model serving. The new engine delivers 2x faster inference speed compared to the previous version, thanks to optimized GPU acceleration and model quantization techniques. It also reduces memory usage by 30%, making it possible to run large models on low-resource devices. Additionally, the new engine integrates seamlessly with web search and tool calling, enabling developers to build more powerful AI agents...

7.4 构建搜索 Agent(Search Agent)

结合 Web Search、Web Fetch 和 Tool Calling,可构建能自主搜索网络、解析网页内容、生成回答的搜索 Agent。

# 1. 导入库
import ollama

# 2. 定义可用工具(网络搜索和网页抓取)
def web_search(query: str) -> str:
    """Perform web search and return summary of results"""
    response = ollama.web_search(query)
    # 整合搜索结果为字符串
    summaries = [f"Title: {r.title}\nSummary: {r.summary}" for r in response.results[:3]]
    return "\n\n".join(summaries)

def web_fetch(url: str) -> str:
    """Fetch web page content and return plain text"""
    result = ollama.web_fetch(url)
    return f"Page Title: {result.title}\nContent: {result.content[:2000]}"  # 限制内容长度

available_tools = {
    'web_search': web_search,
    'web_fetch': web_fetch
}

# 3. 初始化对话历史
messages = [{'role': 'user', 'content': "What is Ollama's new engine in 2025? What features does it have?"}]

# 4. 多轮 Agent 循环
while True:
    # 发起对话请求
    response = chat(
        model='qwen3:4b',  # 推荐使用 32K 上下文模型,容纳更多搜索结果
        messages=messages,
        tools=[web_search, web_fetch],
        think=True
    )

    messages.append(response.message)

    # 处理工具调用
    if response.message.tool_calls:
        for tc in response.message.tool_calls:
            func = available_tools.get(tc.function.name)
            if func:
                result = func(**tc.function.arguments)
                messages.append({
                    'role': 'tool',
                    'tool_name': tc.function.name,
                    'content': result
                })
    else:
        break

# 5. 打印最终回答
print("Final Answer:\n", response.message.content)

输出示例:

Final Answer:
 Ollama's new engine, launched in 2025, focuses on speed, efficiency, and integration capabilities. Key features include:

1. Faster Inference: 2x faster than previous versions, enabled by optimized GPU acceleration and model quantization.
2. Lower Memory Usage: 30% reduction in memory consumption, allowing large models to run on low-resource devices.
3. Seamless Integrations: Integrates with web search and tool calling, supporting multi-modal real-time processing (text, images, etc.).
4. Improved Agent Support: Enhances AI agent capabilities by enabling real-time information retrieval and complex task execution.

The information is based on recent web search results from Ollama's official blog and tech news coverage.

建议:构建搜索 Agent 时,推荐使用 32K 上下文的模型(如 qwen3:4b:32k),确保能容纳大量搜索结果和网页内容,避免上下文溢出。


结语:构建下一代 AI 应用的基石

通过本文的学习,你已掌握 Ollama 的七大核心高级功能,它们各自的核心价值如下:

模块

核心价值

Streaming

实时反馈体验,提升用户交互感

Thinking

可解释性与审计能力,让模型决策透明化

Structured Outputs

数据自动化提取,降低程序处理成本

Vision

多模态理解,支持图文混合输入分析

Embeddings

语义检索基础,赋能 RAG 和相似度匹配

Tool Calling

构建真正智能 Agent,让模型具备行动能力

Web Search

打破知识截止日期限制,获取实时信息

这些功能并非孤立存在,结合使用能产生更强的协同效应。例如:
  • Vision + Structured Outputs:精准提取图像中的结构化信息。
  • Embeddings + RAG + Tool Calling:构建具备知识库检索和工具使用能力的智能客服。
  • Web Search + Tool Calling + Thinking:打造能实时搜索、自主推理、解决复杂问题的 AI Agent。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐