现在位置: 首页 > Ollama 教程 > 正文

Ollama 六大模型能力实战

流式输出、思考模式、结构化输出、视觉理解、向量嵌入、工具调用,加上联网搜索,构成 Ollama 模型能力的完整版图。

本章节用官方 Python 库逐个实战每一项能力,所有示例可直接运行。

首先,我们需要安装 Ollama 的 Python SDK。

可以使用 pip 安装:

pip install ollama

确保你的环境中已安装了 Python 3.x,并且网络环境能够访问 Ollama 本地服务。

在使用 Python SDK 之前,确保 Ollama 本地服务已经启动。

你可以使用命令行工具来启动它:

ollama serve

启动本地服务后,Python SDK 会与本地服务进行通信,执行模型推理等任务。


能力一:流式输出

流式让回答逐字出现在界面上,是聊天应用体验的基础。

SDK 中把 stream 设为 True,然后迭代处理每个数据块:

实例

from ollama import chat

# 开启流式,逐块接收响应
stream = chat(
    model='qwen3.5',
    messages=[{'role': 'user', 'content': '用三句话介绍 RUNOOB 菜鸟教程'}],
    stream=True,
)

# 逐块打印,同时拼接完整内容
content = ''
for chunk in stream:
    print(chunk.message.content, end='', flush=True)
    content += chunk.message.content

# 拼接后的 content 可用于保存历史、入库存档

关键点:流式的每个数据块只是"片段",必须自己在客户端累积完整内容。后续要把这轮回答放进对话历史时,用的就是拼接后的完整文本。


能力二:思考模式

推理模型会先输出一段思考过程再给答案,SDK 里通过 think 参数控制,思考和正文分属两个字段。

实例

from ollama import chat

response = chat(
    model='qwen3.5',
    messages=[{'role': 'user', 'content': '9.9 和 9.11 谁大?'}],
    think=True,
    stream=False,
)

# 思考过程与最终答案分属两个字段
print('思考:', response.message.thinking)
print('答案:', response.message.content)

流式场景下,thinking 与 content 会在数据块中交替出现,用状态机方式切换渲染区域:

实例

from ollama import chat

stream = chat(
    model='qwen3.5',
    messages=[{'role': 'user', 'content': '17 乘 23 等于多少?'}],
    think=True,
    stream=True,
)

in_thinking = False
for chunk in stream:
    if chunk.message.thinking:
        if not in_thinking:
            in_thinking = True
            print('【思考中】', end='', flush=True)
        print(chunk.message.thinking, end='', flush=True)
    elif chunk.message.content:
        if in_thinking:
            in_thinking = False
            print('\n【答案】', end='', flush=True)
        print(chunk.message.content, end='', flush=True)

UI 实现建议:把 thinking 渲染成可折叠的灰色区域,content 渲染成正文;gpt-oss 系列只接受 low / medium / high 三档思考强度,传布尔值无效。


能力三:结构化输出

结构化输出让模型返回严格符合 JSON Schema 的数据,配合 Pydantic 校验,是程序消费模型输出的标准姿势。

实例

from ollama import chat
from pydantic import BaseModel

# 用 Pydantic 定义期望的数据结构
class Site(BaseModel):
    name: str
    category: str
    free: bool

response = chat(
    model='qwen3.5',
    messages=[{'role': 'user', 'content': '介绍一下 RUNOOB 菜鸟教程'}],
    format=Site.model_json_schema(),
)

# 返回内容是符合 schema 的 JSON 字符串,直接校验解析
site = Site.model_validate_json(response.message.content)
print(site.name, site.category, site.free)

这个模式是所有数据抽取类应用的基石:从简历抽字段、从工单提要素、从图片抽信息(配合视觉能力)都用它。

两个稳定性技巧:把 options 的 temperature 设为 0;提示词里同时描述一遍字段含义,与 schema 双重约束。


能力四:视觉理解

多模态模型(如 qwen3.5)可以接收图片,SDK 支持直接传文件路径,比 REST API 的 base64 编码省事得多。

实例

from ollama import chat

response = chat(
    model='qwen3.5',
    messages=[{
        'role': 'user',
        'content': '这张截图是什么页面?列出主要功能。',
        'images': ['screenshot.png'],
    }],
)

print(response.message.content)

视觉与结构化输出组合,可以做"图片转数据":

实例

from ollama import chat
from pydantic import BaseModel

# 定义从图片中抽取的目标结构
class Receipt(BaseModel):
    merchant: str
    total: float
    date: str

response = chat(
    model='qwen3.5',
    messages=[{
        'role': 'user',
        'content': '从这张票据照片提取商家、金额、日期',
        'images': ['receipt.jpg'],
    }],
    format=Receipt.model_json_schema(),
    options={'temperature': 0},
)

print(Receipt.model_validate_json(response.message.content))

能力五:向量嵌入

embed 接口批量产出文本向量,配合余弦相似度即可实现最小可用语义搜索。

实例

import ollama

# 批量生成文档向量
docs = [
    'Python 是一门解释型语言',
    'JavaScript 主要运行在浏览器',
    'RUNOOB 提供免费编程教程',
]
result = ollama.embed(model='embeddinggemma', input=docs)
vectors = result['embeddings']
print(len(vectors), len(vectors[0]))  # 3 条向量及其维度

# 查询向量与文档向量做余弦相似度即可排序检索
query = ollama.embed(model='embeddinggemma', input='学 python 难吗')

索引和查询必须使用同一个嵌入模型,否则向量空间不一致,检索结果没有意义。完整的知识库实战在 RAG 项目章节展开。


能力六:工具调用

工具调用让模型学会"喊帮助":它判断需要外部信息时返回 tool_calls,程序执行真正的函数,把结果回传后模型再总结作答。

先看完整的 Agent loop 时序,理解消息在四方之间的流动:

工具调用 Agent loop 时序图

Python SDK 允许直接把函数当工具传入,函数签名和 docstring 会自动解析成 schema:

实例

from ollama import chat

# 本地工具函数:docstring 会成为模型看到的工具说明
def get_weather(city: str) -> str:
    """查询指定城市的当前气温

    Args:
        city: 城市名称

    Returns:
        当前气温描述
    """

    temperatures = {"北京": "22°C", "上海": "26°C", "纽约": "18°C"}
    return temperatures.get(city, "未知城市")

messages = [{'role': 'user', 'content': '纽约现在多少度?'}]

# Agent loop:循环直到模型不再请求工具
while True:
    response = chat(
        model='qwen3.5',
        messages=messages,
        tools=[get_weather],
    )

    # 把模型消息(含 tool_calls)追加进历史
    messages.append(response.message)

    if not response.message.tool_calls:
        # 没有工具请求了,输出最终回答
        print(response.message.content)
        break

    # 有工具请求:执行并把结果以 tool 角色回传
    for call in response.message.tool_calls:
        result = get_weather(**call.function.arguments)
        messages.append({
            'role': 'tool',
            'tool_name': call.function.name,
            'content': result,
        })

三个工程要点:其一,每次的 response.message 必须原样追加回 messages,工具结果用 tool 角色回传;其二,并行工具调用时模型可能一次返回多个 tool_calls,逐个执行逐个追加;其三,真实项目中工具结果可能很长,注意截断以保护上下文窗口。


能力七:联网搜索

Ollama 官方提供 web_search 和 web_fetch 两个联网接口,可以作为工具挂给模型,让它回答训练数据之外的新信息。

实例

from ollama import chat, web_search, web_fetch

# 把联网能力作为工具挂载
available_tools = {'web_search': web_search, 'web_fetch': web_fetch}

messages = [{'role': 'user', 'content': "Ollama 最近有什么新特性?"}]

while True:
    response = chat(
        model='qwen3.5',
        messages=messages,
        tools=[web_search, web_fetch],
        think=True,
    )
    messages.append(response.message)

    if not response.message.tool_calls:
        print(response.message.content)
        break

    for call in response.message.tool_calls:
        func = available_tools.get(call.function.name)
        if func:
            # 工具结果可能很长,截断保护上下文
            result = str(func(**call.function.arguments))
            messages.append({
                'role': 'tool',
                'tool_name': call.function.name,
                'content': result[:2000],
            })

联网接口需要在 ollama.com 创建 API Key;搜索结果动辄数千 token,官方建议此类 Agent 场景把上下文开到 32K 以上。它也有现成的 MCP Server 实现,可以接入 Cline、Codex 等工具,集成细节见生态章节。