高级 13 分钟API

函数调用及结构化JSON输出支持 Ollama

函数调用允许大语言模型(LLM)自主决定调用您代码中的函数——例如查询天气、查询数据库、发送邮件——并以正确的格式返回参数。Ollama 函数调用基于两个核心组件:用于确保 JSON 有效的 format 参数,以及用于声明可用函数的 API tools 字段。本指南用 Python 演示这两个组件的用法,介绍哪些本地模型真正可靠,以及如何通过模式验证和重试机制提高整个流程的稳健性。

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

#为什么要在本地使用函数调用

大语言模型(LLM)生成的是文本,而不是操作。函数调用弥合了这一差距:模型不再以普通文本回答,而是返回一个结构化对象,表示“调用 get_meteo 函数,城市参数为 Paris”。您的代码执行该函数,获取实际结果,再将结果传回模型,由模型撰写最终回复。这是智能体以及与外部世界交互的助手的基础机制。

在本地,挑战是双重的。首先,确保输出是 100% 可解析的 JSON——一个话多的模型如果添加“以下是 JSON:”就会破坏您的整个管道。其次,确保模型选择正确的函数和参数,这对小模型来说变得棘手。Ollama 通过其 API 处理这两点,但需要了解一些防护措施。

保证输出JSON格式
format 参数对解码过程施加约束:模型只能生成语法有效的 JSON,甚至可以进一步限定其符合特定的模式。
函数调用
tools字段声明以OpenAI格式定义的函数;模型会返回包含需传递参数的tool_calls。
100 % 本地
所有操作都通过位于 http://localhost:11434 的 Ollama 守护进程在您的电脑上运行,无需 API 密钥,也不会泄露数据。

#前置条件及兼容模型

本地副驾驶套件

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

  • 在线空间,终身可用
  • PDF + 文件
  • 30 天内退款

JSON 模式(format 参数)适用于任何模型。而通过 tools 进行函数调用,则要求模型经过工具使用训练——否则 tool_calls 字段会保持为空。模型的表现并不都一样:一个纸面上“兼容”的 3B 模型常会弄错参数,而 14B 及以上模型在处理简单的结构规范时表现可靠。

Ollama 已安装
守护进程已启动,可通过 http://localhost:11434 访问。请使用 ollama list 检查。
Python SDK
pip install ollama pydantic — le client officiel plus Pydantic pour la validation.
可靠的工具调用模型
qwen3.5:9b、mistral-small (24B) 和 gpt-oss:20b 是 2026 年的绝佳起点。在 Q4 量化下:Qwen 3.5 9B ≈ 6.6 GB,24B 模型 ≈ 14 GB VRAM。
推荐 GPU
RTX 3060 12GB 可以顺畅运行 Qwen 3.5 9B;若要让工具调用真正可靠,建议选择 20–24B 模型(RTX 4070/4080 16 GB)。
i
JSON模式 ≠ 函数调用
format 参数保证输出有效的 JSON,但不会让模型调用函数:模型填充一个对象,由您自行解读。而 tools 字段会让模型真正选择函数。两者经常结合使用。

#通过 format 参数强制生成有效的 JSON

最简单的情况:您希望模型始终输出 JSON,而不是自由文本。在 chat 调用中传入 format: 'json'。Ollama 随后会在逐 token 解码时施加约束,以生成语法有效的 JSON 对象。重要提示:请在提示词中保留明确说明预期字段的指令,否则模型会自行编造结构。

json_mode.py
import ollama
import json

resp = ollama.chat(
    model='qwen3.5:9b',
    messages=[{
        'role': 'user',
        'content': (
            "Extrais le nom, la ville et l'age de ce texte et reponds "
            "UNIQUEMENT en JSON avec les cles nom, ville, age. "
            "Texte : Marie, 34 ans, habite a Lyon."
        ),
    }],
    format='json',  # contraint la sortie a un JSON valide
    options={'temperature': 0},
)

data = json.loads(resp['message']['content'])
print(data)  # {'nom': 'Marie', 'ville': 'Lyon', 'age': 34}
→
始终将 temperature 设为 0
进行结构化提取时,将 temperature 设为 0。您需要的是确定性和符合要求的输出,而不是创造性。这能显著减少字段幻觉。

#按模式约束的 JSON 结构化输出(structured outputs)

自2024年底起,Ollama也接受在format中传入完整的JSON Schema(而不只是字符串'json')。此时,解码会受到约束,必须遵守该模式规定的类型、必填字段和枚举值。这比单独使用'json'稳健得多,因为模型在结构上无法生成不符合该模式的对象。使用Pydantic可以自动生成该模式。

structured_output.py
import ollama
from pydantic import BaseModel

class Personne(BaseModel):
    nom: str
    ville: str
    age: int

resp = ollama.chat(
    model='mistral-small',
    messages=[{'role': 'user',
               'content': 'Marie, 34 ans, habite a Lyon.'}],
    format=Personne.model_json_schema(),  # schema JSON complet
    options={'temperature': 0},
)

# validation stricte : leve une erreur si non conforme
personne = Personne.model_validate_json(resp['message']['content'])
print(personne)  # nom='Marie' ville='Lyon' age=34

这里的解码被约束为符合 Personne 的结构,model_validate_json 会在 Python 端再执行一次验证。双重保障:确保输出既可解析,又符合声明的类型。这是本地生产环境中所有数据提取任务推荐采用的模式。

#用 Python 逐步使用 tools API

接下来介绍真正的函数调用。在 tools 字段中按 OpenAI 格式声明函数(包含 name、description,以及采用 JSON Schema 的 parameters)。模型读取这些定义后,如果认为调用函数有帮助,就会返回一个或多个 tool_calls,而不是文本消息。您需要执行函数并将结果返回。

  1. 01
    描述函数
    为每个函数提供清晰的 name、准确的 description(模型会据此选择函数),以及采用 JSON Schema 格式的 parameters,列出各个参数,并通过 required 指明哪些参数必填。
  2. 02
    发送带有 tools 的请求
    将tools列表传递给ollama.chat。模型将自行决定是调用函数还是直接回答。
  3. 03
    读取 tool_calls
    检查 resp['message'].get('tool_calls')。如果存在,说明模型希望调用一个带有指定参数的函数。
  4. 04
    执行并返回
    调用真正的 Python 函数,然后将结果作为 'tool' 角色消息传递给模型,由模型生成最终回复。
tools_definition.py
def get_meteo(ville: str) -> str:
    # ici un vrai appel API ; on simule
    return f"Il fait 22 C et ensoleille a {ville}."

tools = [{
    'type': 'function',
    'function': {
        'name': 'get_meteo',
        'description': "Renvoie la meteo actuelle d'une ville donnee.",
        'parameters': {
            'type': 'object',
            'properties': {
                'ville': {
                    'type': 'string',
                    'description': 'Nom de la ville, ex: Paris',
                },
            },
            'required': ['ville'],
        },
    },
}]

#调用 → 执行 → 响应的循环

函数调用涉及往返操作。第一次调用:模型返回一个tool_call,您执行该函数。第二次调用:您将结果返回给模型,模型随后生成自然语言响应。这是完整的循环,可重复用于多个函数。

boucle_tools.py
import ollama

dispatch = {'get_meteo': get_meteo}

messages = [{'role': 'user',
             'content': 'Quel temps fait-il a Marseille ?'}]

resp = ollama.chat(model='mistral-small',
                   messages=messages, tools=tools)
msg = resp['message']
messages.append(msg)

for call in msg.get('tool_calls') or []:
    fn = call['function']['name']
    args = call['function']['arguments']
    resultat = dispatch[fn](**args)  # execution reelle
    messages.append({
        'role': 'tool',
        'name': fn,
        'content': resultat,
    })

# second appel : le modele redige la reponse finale
final = ollama.chat(model='mistral-small', messages=messages)
print(final['message']['content'])
!
切勿盲目按参数执行操作
函数名及其参数由模型控制。请使用分发字典(白名单),而不是 eval 或动态 getattr,并在执行前验证每个参数。即使模型被攻陷或产生幻觉,也不能让它随意调用函数。

#Schema 验证与重试策略

本地部署时,小模型有时会出现参数缺失、类型错误或函数不存在等问题。切勿依赖原始输出。每个 tool_call 均需通过 Pydantic 验证,若验证失败,则应结合错误信息重新调用——通常模型在第二次尝试时会自动修正。

retry_validation.py
from pydantic import BaseModel, ValidationError

class MeteoArgs(BaseModel):
    ville: str

def valider_appel(call):
    fn = call['function']['name']
    if fn not in dispatch:
        raise ValueError(f"Fonction inconnue: {fn}")
    args = MeteoArgs.model_validate(call['function']['arguments'])
    return fn, args

def appel_avec_retry(messages, max_essais=3):
    for essai in range(max_essais):
        resp = ollama.chat(model='mistral-small',
                           messages=messages, tools=tools)
        try:
            calls = resp['message'].get('tool_calls') or []
            return [valider_appel(c) for c in calls], resp
        except (ValidationError, ValueError) as e:
            messages.append({
                'role': 'user',
                'content': f"Erreur: {e}. Corrige et reessaie.",
            })
    raise RuntimeError('Echec apres retries')
执行前需验证
为每个函数定义一个 Pydantic 模型,就能在参数传入您的代码之前,检测出参数缺失或类型错误。
带反馈的重试
将错误消息重新加入上下文,可以引导模型进行修正。几乎总是尝试 2 至 3 次就足够了。
函数白名单
拒绝任何不在 dispatch 中的函数名。这既是一项安全措施,也是防止幻觉的保护机制。
优雅的降级
失败 N 次后,请向用户返回一条清晰的说明,而不是让程序崩溃——使用小模型时尤其如此。

#小模型在工具使用中的陷阱

工具使用对模型的认知能力要求较高:模型必须理解意图、选择合适的函数、映射参数并遵守格式。参数量低于 7B 时,结果往往不够可靠。以下是在本地运行时最常出现的问题及解决方法。

tool_calls 为空
模型以文本形式响应,而非调用函数。通常是因为模型未经过工具使用训练,或函数描述过于模糊。请改用 Qwen 3.5 或 Mistral Small,并完善函数描述。
参数错误
模型会编造或遗漏字段。请在 schema 中用 required 将这些字段设为必填,减少同时提供给模型的函数数量,并在每次执行前进行验证。
模型虚构的函数
模型调用了一个不存在的函数。分发端必须配置白名单。
JSON 中混入额外内容
未指定格式时,小型模型会在 JSON 前后添加其他文本。对于只需提取数据的任务,请始终使用 format='json' 或指定一个模式(schema)。
功能过多
工具数量超过5–6个时,小模型就容易混乱。请按子任务拆分,或采用两阶段路由。
→
本地运行的合理折中
要在没有高端 GPU 的情况下实现可靠的函数调用,Q4 量化的 mistral-small(24B,约需 14 GB 显存)在 RTX 4080 上通常能提供最佳的质量与资源占用平衡。资源更少时,qwen3.5:9b(约 6.6 GB)可以应付少量描述清楚的函数,gpt-oss:20b 则是一个速度很快的替代选择。对于明确以智能体为主的用途,如果您有 24 GB 显存,glm-4.7-flash(MoE 30B-A3B,约 19 GB)表现出色。

#深入了解

函数调用是智能体和高级集成的基础组件。本网站的以下指南进一步延伸了本篇指南的内容:

用 Python 通过 REST API 集成 Ollama
在实际的 FastAPI/Flask 应用中使用 :11434 端口上的 OpenAI 兼容端点、流式传输和 JSON 模式。
使用 LangChain 和 Ollama 创建本地 AI 智能体
从基础的函数调用过渡到一个能够串联工具、记忆和推理的完整智能体。
MCP 与本地 LLM:将 MCP 服务器连接到 Ollama
通过模型上下文协议(Model Context Protocol)统一对工具(文件、网络、数据库)的访问方式,而不是手动定义每个函数。
这份指南对您有帮助吗?

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