进阶 15 分钟API

通过API将 Ollama 集成到Python应用程序中 REST

Ollama 在 11434 端口提供两个 HTTP API:原生 API(/api/generate、/api/chat)和兼容 OpenAI 的 API(/v1/chat/completions)。后者是在 Python 中集成 Ollama API 的首选方式:您的代码使用与调用 GPT-4 完全相同的 SDK,但运行在您自己的机器上。本指南介绍具体的实现模式——流式输出、结构化 JSON、函数调用——并提供可直接粘贴到项目中的 FastAPI 和 Flask 示例。

作者: Mohamed Meguedmi·更新于 2026-08-27·已在 Windows、macOS 和 Linux 上测试

#为何选择REST API

CLI 工具 ollama run est 适合测试,但并非为应用程序调用而设计。REST API 则是为此而设计:支持标准 HTTP 请求,输入输出为 JSON,通过 Server-Sent Events 实现流式传输。所有界面(Open WebUI、Cline、LangChain)底层均采用此方案。

兼容 OpenAI
端点 /v1/chat/completions 接受与 api.openai.com/v1/chat/completions 完全相同的请求体。您只需更改 URL 和密钥,现有代码即可正常运行。
无需重复造轮子
Python 版官方 openai SDK(或任意 HTTP 客户端)可以直接与 Ollama 通信。无需学习使用专用客户端。
运行时解耦
您的 Python 应用和 Ollama 分别在各自的容器中运行。将来切换到 vLLM 或 LM Studio 时,只需更改 base_url。
支持多客户端同时连接
多个 Python 脚本、一个 Jupyter 笔记本和 Open WebUI 可以同时访问同一个 Ollama 实例。守护进程会自动管理请求队列。
i
原生API与OpenAI兼容API
Ollama 同时维护这两种 API。原生 API(/api/chat)提供专有参数(num_ctx、num_predict、mirostat),但可移植性较差。OpenAI 兼容 API 能满足 95% 的需求,换用任何其他提供商时也能继续使用。默认建议选择后者。

#先决条件

本地副驾驶套件

本指南带你上手模型。工具包则帮你用上能在你的编辑器中编写代码的编程助手。

  • 在线空间,终身可用
  • PDF + 文件
  • 30 天内退款
Ollama已安装并启动
守护进程必须在 http://localhost:11434 上监听。运行 curl http://localhost:11434 进行检查——您应看到 "Ollama is running"。
Python 3.10+
较新的 SDK(openai 1.x)要求至少使用 Python 3.8,但使用现代注解需要 Python 3.10 或更高版本。
支持聊天模式的模型
ollama pull qwen3.5:9b ou gemma4:12b. Pour le function calling, choisissez un modèle qui le supporte : Qwen 3.5, Granite 4.2, Mistral Small 24B, Devstral.
足够的VRAM
一个9B Q4模型(如 Qwen 3.5 9B)约需6-7GB显存,一个12B模型(如 Gemma 4 12B)约需8GB。无GPU也可运行,但速度仅为5-10个token/秒。

#1. Ollama 端的两种 API

在编写Python代码之前,先通过终端查看端点以了解具体运行情况。使用curl可直接与守护进程通信,无需任何抽象层。

原生API — /api/chat
curl http://localhost:11434/api/chat -d '{
  "model": "qwen3.5:9b",
  "messages": [{"role": "user", "content": "Bonjour"}],
  "stream": false
}'
OpenAI API — /v1/chat/completions
curl http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3.5:9b",
    "messages": [{"role": "user", "content": "Bonjour"}]
  }'

第二个会返回与 OpenAI 完全相同的载荷,包含 choices[0].message.content、id、model、usage 字段。正是这种一致性使得直接替换成为可能。

→
API 密钥被忽略但为必填项
OpenAI SDK 要求提供 api_key 参数。Ollama 不进行任何验证——请填写 "ollama" 或任意非空字符串。如果出于习惯填写真实的 OpenAI 密钥,该密钥仍会保留在本地设备上,但建议使用中立字符串以避免混淆。

#2. 指向 Ollama 的 OpenAI SDK

基础的Ollama API Python集成仅需五行代码:安装OpenAI SDK,使用本地base_url进行实例化,然后像平常一样调用chat.completions.create。

安装
pip install openai
client.py — 基础调用
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="ollama",  # ignoré, mais requis par le SDK
)

reponse = client.chat.completions.create(
    model="qwen3.5:9b",
    messages=[
        {"role": "system", "content": "Tu réponds en français, de façon concise."},
        {"role": "user", "content": "Explique en une phrase ce qu'est un LLM."},
    ],
    temperature=0.3,
)

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

运行脚本。如果 Ollama 正常启动且模型已下载,将生成一句话。若出现 ConnectionRefusedError,请使用 ollama ps 检查守护进程是否正常运行。

model
ollama list列出的精确名称(如qwen3.5:9b, gemma4:12b, mistral-small等)
messages
对话轮次列表。支持的角色:system、user、assistant、tool。
temperature
0 表示确定性,0.7 表示创造性。进行数据提取时,请保持在 0 或 0.1。
max_tokens
响应上限。可选 — Ollama 设置合理的 num_predict 默认值。

#3. 通过 SSE 逐个 token 进行流式传输

为获得良好的用户体验(如聊天机器人、长文本生成),建议实时显示 token 而非等待生成完成。Ollama 通过 Server-Sent Events 实现流式传输,OpenAI SDK 可将其封装为一个简单的 Python 循环。

streaming.py
from openai import OpenAI

client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")

flux = client.chat.completions.create(
    model="qwen3.5:9b",
    messages=[{"role": "user", "content": "Raconte une courte histoire de robot."}],
    stream=True,
)

for chunk in flux:
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)
print()

每个分块包含一个增量(新增的文本片段)。最后一个分块的delta.content为None,finish_reason已填充——这是停止信号。

!
不要忘记设置 flush=True
未设置 flush=True 时,Python 会按行缓冲 stdout,终端中的流式效果将消失。而对于 HTTP API 来说,是 Web 服务器(uvicorn、gunicorn)负责刷新输出——您无需手动处理。

#4. 使用 JSON 模式生成结构化输出

当需要解析回复(如提取、分类、生成payload)时,仅在提示中要求"返回JSON"是不够的——模型常常在JSON周围插入额外文本。JSON模式会强制解码器仅输出有效的JSON内容。

json_mode.py
from openai import OpenAI
import json

client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")

reponse = client.chat.completions.create(
    model="qwen3.5:9b",
    messages=[
        {"role": "system", "content": (
            "Tu extrais des informations structurées. "
            "Réponds uniquement avec un objet JSON contenant les clés : "
            "nom (string), age (int), ville (string)."
        )},
        {"role": "user", "content": "Marie a 34 ans, elle habite à Lyon."},
    ],
    response_format={"type": "json_object"},
    temperature=0,
)

donnees = json.loads(reponse.choices[0].message.content)
print(donnees)
# {'nom': 'Marie', 'age': 34, 'ville': 'Lyon'}

response_format={"type": "json_object"} 启用了 JSON 模式。在 Ollama 侧,这会在采样器层面施加约束:任何生成无效 JSON 的 token 都会被拒绝。相比提示 "以 JSON 格式回答" 再祈祷,这种方式更可靠。

→
提示中请注明 "JSON"
如同OpenAI一样,JSON模式要求在系统或用户提示中至少提及一次'JSON'一词。否则,部分模型会生成空对象。请在系统提示中描述预期的JSON结构——这将指导内容生成,JSON模式仅确保语法正确。

#5. 函数调用(工具使用)

函数调用功能使模型能够指示其需要调用 Python 函数,而非直接作答。并非所有模型都支持该功能——请访问 ollama.com/library 检查模型能力中是否包含 "tools"。Qwen 3.5、Granite 4.2、Mistral Small 24B 和 Devstral 原生支持该功能。

tools.py
from openai import OpenAI
import json

client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")

# 1. Une fonction Python réelle
def meteo(ville: str) -> dict:
    # En vrai, vous appelleriez Open-Meteo ou autre
    return {"ville": ville, "temperature_c": 18, "conditions": "nuageux"}

# 2. Sa description au format OpenAI
outils = [{
    "type": "function",
    "function": {
        "name": "meteo",
        "description": "Donne la météo actuelle d'une ville française.",
        "parameters": {
            "type": "object",
            "properties": {
                "ville": {"type": "string", "description": "Nom de la ville"},
            },
            "required": ["ville"],
        },
    },
}]

messages = [{"role": "user", "content": "Quel temps fait-il à Bordeaux ?"}]

# 3. Premier appel : le modèle décide d'appeler la fonction
reponse = client.chat.completions.create(
    model="qwen3.5:9b",
    messages=messages,
    tools=outils,
)

appel = reponse.choices[0].message.tool_calls[0]
args = json.loads(appel.function.arguments)
resultat = meteo(**args)

# 4. Second appel : on renvoie le résultat au modèle pour la réponse finale
messages.append(reponse.choices[0].message)
messages.append({
    "role": "tool",
    "tool_call_id": appel.id,
    "content": json.dumps(resultat),
})

finale = client.chat.completions.create(model="qwen3.5:9b", messages=messages)
print(finale.choices[0].message.content)

这个循环有两轮:第一轮返回tool_calls(模型表示“调用meteo,参数为ville=Bordeaux”);第二轮在您执行函数并注入其结果后,返回自然语言回答。在生产环境中,只要tool_calls非空,就继续循环。

!
模型的能力并不都一样
如果模型对工具调用的支持较差(如旧版 Llama 2、Mistral 7B v0.1),就会出现格式错误的调用或凭空编造的参数。如果遇到这种情况:(1)确认模型官方支持工具调用,(2)将温度降至 0,(3)简化参数模式。

#6. 通过FastAPI暴露 Ollama

典型场景:您的前端调用 Python 后端,后端调用 Ollama。FastAPI 正确处理异步操作,且通过 StreamingResponse 将流式数据传输至浏览器。

依赖项
pip install fastapi uvicorn openai
main.py
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from openai import OpenAI

app = FastAPI()
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")

class Question(BaseModel):
    message: str
    model: str = "qwen3.5:9b"

@app.post("/chat")
def chat(q: Question):
    reponse = client.chat.completions.create(
        model=q.model,
        messages=[{"role": "user", "content": q.message}],
    )
    return {"reponse": reponse.choices[0].message.content}

@app.post("/chat/stream")
def chat_stream(q: Question):
    def generateur():
        flux = client.chat.completions.create(
            model=q.model,
            messages=[{"role": "user", "content": q.message}],
            stream=True,
        )
        for chunk in flux:
            delta = chunk.choices[0].delta.content
            if delta:
                yield delta
    return StreamingResponse(generateur(), media_type="text/plain")
启动服务器
uvicorn main:app --reload --port 8000
命令行测试
curl -N -X POST http://localhost:8000/chat/stream \
  -H "Content-Type: application/json" \
  -d '{"message": "Écris un haïku sur Paris."}'

curl命令的-N(--no-buffer)选项会禁用客户端缓冲,以实现实时流式输出。前端JS中,您会读取fetch响应的ReadableStream——与OpenAI API的处理方式相同。

#7. 带历史记录的Flask聊天机器人

要实现完整的聊天机器人,需要在各轮对话之间保留消息历史。下面是一个极简 Flask 版本,它将对话存储在内存中(生产环境中应改用真正的会话或数据库)。

依赖项
pip install flask openai
app.py
from flask import Flask, request, jsonify, Response
from openai import OpenAI
from collections import defaultdict

app = Flask(__name__)
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")

# Historiques par session — en prod : Redis, Postgres, etc.
historiques: dict[str, list] = defaultdict(lambda: [
    {"role": "system", "content": "Tu es un assistant en français, concis et utile."},
])

@app.post("/chat/<session_id>")
def chat(session_id: str):
    message = request.json["message"]
    historique = historiques[session_id]
    historique.append({"role": "user", "content": message})

    reponse = client.chat.completions.create(
        model="qwen3.5:9b",
        messages=historique,
    )
    contenu = reponse.choices[0].message.content
    historique.append({"role": "assistant", "content": contenu})
    return jsonify({"reponse": contenu})

@app.post("/chat/<session_id>/stream")
def chat_stream(session_id: str):
    message = request.json["message"]
    historique = historiques[session_id]
    historique.append({"role": "user", "content": message})

    def generateur():
        morceaux = []
        flux = client.chat.completions.create(
            model="qwen3.5:9b",
            messages=historique,
            stream=True,
        )
        for chunk in flux:
            delta = chunk.choices[0].delta.content
            if delta:
                morceaux.append(delta)
                yield delta
        historique.append({"role": "assistant", "content": "".join(morceaux)})

    return Response(generateur(), mimetype="text/plain")

@app.delete("/chat/<session_id>")
def reset(session_id: str):
    historiques.pop(session_id, None)
    return "", 204

if __name__ == "__main__":
    app.run(port=5000, debug=True)
i
上下文长度限制
历史记录越长,每次调用消耗的 token 就越多。对于 Qwen 3.5,Ollama 端的默认上下文窗口为 2048 个 token——超过这一长度时,旧消息会被截断,且不会有任何提示。可以通过原生 API,或使用 Modelfile 覆盖设置来增大窗口(num_ctx 8192 或 32768)。

#用于生产环境

让网络上的设备能够访问 Ollama
默认情况下,守护进程仅监听 127.0.0.1。若要允许其他机器访问,请设置 OLLAMA_HOST=0.0.0.0 后启动,并在其前面部署带身份验证的反向代理,否则网络上的任何人都能调用您的模型。
并发与请求队列
Ollama 对每个模型的请求进行串行处理。要同时服务多个用户,请启动多个实例,或切换到原生支持动态批处理的 vLLM。
客户端超时
未加载模型的请求可能需要10-30秒(VRAM加载过程)。请将OpenAI客户端的超时时间设置为OpenAI(..., timeout=120),而非库默认的10分钟,通常反向代理端的超时时间会更短。
保持模型处于加载状态
默认情况下,Ollama 会在闲置 5 分钟后卸载模型。使用 API 时,可通过原生 /api/chat 接口传入 keep_alive="30m",或定期发送 ping 请求,避免首个用户请求遇到冷启动。
可观测性
始终记录 model、prompt_tokens、completion_tokens(位于 reponse.usage 中)。这些是您的推理指标,有助于发现模型变慢或提示词长度暴增的情况。
→
从OpenAI API迁移
如果您已有调用 api.openai.com 的代码,切换至 Ollama 仅需两行:将 base_url="https://api.openai.com/v1" 修改为 base_url="http://localhost:11434/v1",并调整模型名称。其余功能——流式传输、JSON 模式、工具调用——均保持一致。这是兼容 OpenAI 接口端点的核心优势。

#深入了解

您已具备基础组件。根据具体使用场景,有三条进阶方向:

构建一个能够独立决策的智能体
关于使用 LangChain 在 Python 中构建本地 AI 智能体的指南,将函数调用扩展为完整的智能体循环,涵盖多个工具的管理和多步推理。
为您的文档添加 RAG 功能
若要使您的应用程序基于内部知识库(PDF、笔记、代码)进行回答,请配置一个向量数据库。本地RAG入门指南将为您建立基础。
自定义模型行为
与其每次调用都重复系统提示,不如通过Modelfile创建一个模型变体。Ollama Modelfile定制指南介绍了如何将法语助手或编程模式的设置固定下来,并保存为一个可重复使用的模型名称。
这份指南对您有帮助吗?

有反馈、发现了错误,或想补充说明?请告诉我们,让这份指南对每个人都更有帮助。