目录

Ollama 工具调用教程:使用工具扩展模型能力

语言模型不知道今天的天气、你的数据库里有什么,也不擅长精确计算。工具调用(tool calling,也叫 function calling)让模型可以“请你的程序帮忙执行某个函数”,再根据结果回答。

只有支持工具的模型才能使用此功能。在 ollama.com 的模型页面上会标注 tools,例如 qwen3、llama3.1、gpt-oss、mistral。

工作流程

1. 你:问题 + 可用工具的说明 ──────────▶ 模型
2. 模型:「请调用 get_weather(city="台北")」◀──
3. 你的程序执行 get_weather("台北") → "24°C,多云"
4. 你:把结果发回 ─────────────────────▶ 模型
5. 模型:「台北现在 24 度、多云,建议带件薄外套。」

模型本身不会执行任何程序,它只是决定要调用哪个工具、传入什么参数。真正执行的是你的程序,所以你可以完全控制它能做什么。

Python 示例

ollama Python 包可以直接把 Python 函数作为工具传入,它会自动根据函数的类型标注和 docstring 生成工具说明:

from ollama import chat


def get_weather(city: str) -> str:
    """
    查询城市当前的天气。

    Args:
        city: 城市名称,例如“台北”

    Returns:
        天气描述
    """
    fake_data = {"台北": "24°C,多云", "高雄": "29°C,晴天"}
    return fake_data.get(city, "没有查询到数据")


tools = {"get_weather": get_weather}
messages = [{"role": "user", "content": "台北和高雄现在天气如何?"}]

response = chat(model="qwen3:8b", messages=messages, tools=[get_weather])
messages.append(response.message)

# 模型可能一次要求调用多个工具
for call in response.message.tool_calls or []:
    fn = tools[call.function.name]
    result = fn(**call.function.arguments)
    print(f"调用 {call.function.name}({call.function.arguments}) → {result}")
    messages.append({"role": "tool", "tool_name": call.function.name, "content": str(result)})

final = chat(model="qwen3:8b", messages=messages)
print(final.message.content)

要点:

  1. 把模型的响应(包括 tool_calls)添加回 messages。
  2. 将每个工具的执行结果以 role: "tool" 添加回去。
  3. 再调用一次 chat,模型就会根据结果回答。

让模型自行决定调用次数

有些问题需要连续调用多个工具,例如“先查汇率,再计算金额”。可以用循环处理,直到模型不再要求调用工具:

from ollama import chat


def get_exchange_rate(currency: str) -> float:
    """获取 1 单位外币兑换新台币的汇率。currency 例如 USD、JPY。"""
    return {"USD": 32.1, "JPY": 0.21}.get(currency.upper(), 0.0)


def multiply(a: float, b: float) -> float:
    """计算 a 乘以 b。"""
    return a * b


tools = {f.__name__: f for f in [get_exchange_rate, multiply]}
messages = [{"role": "user", "content": "350 美元大约是多少新台币?"}]

while True:
    response = chat(model="qwen3:8b", messages=messages, tools=list(tools.values()))
    messages.append(response.message)
    if not response.message.tool_calls:
        break
    for call in response.message.tool_calls:
        result = tools[call.function.name](**call.function.arguments)
        messages.append({"role": "tool", "tool_name": call.function.name, "content": str(result)})

print(response.message.content)

实际使用时,请设置最多调用次数,避免模型陷入无限循环。

使用 REST API 定义工具

不使用 Python 包时,可以通过 JSON Schema 描述工具:

curl http://localhost:11434/api/chat -d '{
  "model": "qwen3:8b",
  "messages": [{ "role": "user", "content": "台北天气如何?" }],
  "stream": false,
  "tools": [{
    "type": "function",
    "function": {
      "name": "get_weather",
      "description": "查询城市当前的天气",
      "parameters": {
        "type": "object",
        "properties": {
          "city": { "type": "string", "description": "城市名称" }
        },
        "required": ["city"]
      }
    }
  }]
}'

响应中的 message.tool_calls:

"tool_calls": [
  { "function": { "name": "get_weather", "arguments": { "city": "台北" } } }
]

执行后,将结果以 {"role": "tool", "tool_name": "get_weather", "content": "24°C,多云"} 的形式添加到 messages,再发送一次。

编写清晰的工具说明

模型完全根据名称和说明来判断何时使用工具、如何填写参数:

  • 函数名称要清楚表达用途:search_orders 比 query1 好。
  • 在说明中写清楚什么情况下该使用、参数格式和示例。
  • 参数尽量少,类型要明确;能使用枚举(enum)就使用枚举。
  • 工具数量不要太多,小模型面对十几个工具时容易选错。

安全注意事项

  • 模型会根据用户输入触发工具。如果用户可以控制输入,就等于用户可以间接调用你的工具。
  • 不要提供可执行任意代码、任意 SQL 或删除数据的工具。
  • 付款、发邮件、删除等有副作用的操作,应在执行前让用户确认。
  • 检查模型提供的参数,不要直接信任。

更新于 2026年10月12日