问题描述
本地通过ollama调用的时候可能会遇到toolcalling调用失败的情况
http://localhost:11434/api/chat
{
"model": "ttt",
"messages": [
{
"role": "user",
"content": "What is the weather today in Paris?"
}
],
"stream": false,
"tools": [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The location to get the weather for, e.g. San Francisco, CA"
},
"format": {
"type": "string",
"description": "The format to return the weather in, e.g. 'celsius' or 'fahrenheit'",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location", "format"]
}
}
}
]
}
返回
{
"error": "registry.ollama.ai/library/deepseek-r1:latest does not support tools"
}
这种代表模型不支持工具调用.
这种情况可能有以下几个原因
原因 1.模型本身不支持toolcalling.
判断方法:前往ollama的网站,直接搜索模型名称,看模型中是否带有tools的标志,如果带有这个标志代表模型支持工具调用.
目前2025年6月.deepseek-R1 不支持工具调用.
原因2:启动大模型ollama版本不支持,但是鉴于目前的时间,应该不存在
原因3:模型导入时modelfile编写问题.
问题原因
如果是使用ollama内置命令拉取的模型,不会遇到这个问题.
内置命令如:
ollama run qwen3
这种直接从ollama仓库拉取模型运行的情况.
我的模型是使用modefile导入的.命令是
ollama create 模型名字 -f modelfile.txt
最原始的modefile过于简单,
FROM "D:\model\gguf\qwen3\Qwen3-8B-Q4_K_M.gguf"
TEMPLATE """{{- if .System }}
<|im_start|>system {{ .System }}<|im_end|>
{{- end }}
<|im_start|>user
{{ .Prompt }}<|im_end|>
<|im_start|>assistant
"""
SYSTEM """"""
PARAMETER stop <|im_start|>
PARAMETER stop <|im_end|>
这种modelfile是不支持的.
解决方案
先用ollama的命令拉取一个官方相同的模型,我在本地用的qwen3,那么我可以拉取下面这个模型
ollama run qwen3:0.6b
至于为什么用0.6b因为我们只要官方的modelfile,所以选择0.6b会减少模型拉取的时间
模型拉倒本地之后,使用list命令获取刚刚拉取下来的模型叫什么
ollama list
接着使用可以使用如下命令获取官方模型的modefile,我这里模型名称叫做qwen3:0.6B
ollama show --modelfile qwen3:0.6b
返回结果如下:
D:\model\gguf\llama>ollama show --modelfile qwen3:0.6b
# Modelfile generated by "ollama show"
# To build a new Modelfile based on this, replace FROM with:
# FROM qwen3:0.6b
FROM d:\OLLAMA_MODELS\blobs\sha256-7f4030143c1c477224c5434f8272c662a8b042079a0a584f0a27a1684fe2e1fa
TEMPLATE """
{{- $lastUserIdx := -1 -}}
{{- range $idx, $msg := .Messages -}}
{{- if eq $msg.Role "user" }}{{ $lastUserIdx = $idx }}{{ end -}}
{{- end }}
{{- if or .System .Tools }}<|im_start|>system
{{ if .System }}
{{ .System }}
{{- end }}
{{- if .Tools }}
# Tools
You may call one or more functions to assist with the user query.
You are provided with function signatures within <tools></tools> XML tags:
<tools>
{{- range .Tools }}
{"type": "function", "function": {{ .Function }}}
{{- end }}
</tools>
For each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:
<tool_call>
{"name": <function-name>, "arguments": <args-json-object>}
</tool_call>
{{- end -}}
<|im_end|>
{{ end }}
{{- range $i, $_ := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1 -}}
{{- if eq .Role "user" }}<|im_start|>user
{{ .Content }}
{{- if and $.IsThinkSet (eq $i $lastUserIdx) }}
{{- if $.Think -}}
{{- " "}}/think
{{- else -}}
{{- " "}}/no_think
{{- end -}}
{{- end }}<|im_end|>
{{ else if eq .Role "assistant" }}<|im_start|>assistant
{{ if (and $.IsThinkSet (and .Thinking (or $last (gt $i $lastUserIdx)))) -}}
<think>{{ .Thinking }}</think>
{{ end -}}
{{ if .Content }}{{ .Content }}
{{- else if .ToolCalls }}<tool_call>
{{ range .ToolCalls }}{"name": "{{ .Function.Name }}", "arguments": {{ .Function.Arguments }}}
{{ end }}</tool_call>
{{- end }}{{ if not $last }}<|im_end|>
{{ end }}
{{- else if eq .Role "tool" }}<|im_start|>user
<tool_response>
{{ .Content }}
</tool_response><|im_end|>
{{ end }}
{{- if and (ne .Role "assistant") $last }}<|im_start|>assistant
{{ if and $.IsThinkSet (not $.Think) -}}
<think>
</think>
{{ end -}}
{{ end }}
{{- end }}"""
PARAMETER repeat_penalty 1
PARAMETER stop <|im_start|>
PARAMETER stop <|im_end|>
PARAMETER temperature 0.6
PARAMETER top_k 20
PARAMETER top_p 0.95
LICENSE """ Apache License
Version 2.0, January 2004
omit........
"""
上面就是ollama给的modefile,我们只需要把第三行的from地址改成自己本地gguf文件地址,然后重新导入自己本地模型就可以了
比如我本地文件模型在D:\model\gguf\qwen3\0.6\Qwen3-0.6B-Q8_0.gguf那么我的modelfile文件内容如下;
FROM "D:\model\gguf\qwen3\0.6\Qwen3-0.6B-Q8_0.gguf"
TEMPLATE """
{{- $lastUserIdx := -1 -}}
{{- range $idx, $msg := .Messages -}}
{{- if eq $msg.Role "user" }}{{ $lastUserIdx = $idx }}{{ end -}}
{{- end }}
{{- if or .System .Tools }}<|im_start|>system
{{ if .System }}
{{ .System }}
{{- end }}
{{- if .Tools }}
# Tools
You may call one or more functions to assist with the user query.
You are provided with function signatures within <tools></tools> XML tags:
<tools>
{{- range .Tools }}
{"type": "function", "function": {{ .Function }}}
{{- end }}
</tools>
For each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:
<tool_call>
{"name": <function-name>, "arguments": <args-json-object>}
</tool_call>
{{- end -}}
<|im_end|>
{{ end }}
{{- range $i, $_ := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1 -}}
{{- if eq .Role "user" }}<|im_start|>user
{{ .Content }}
{{- if and $.IsThinkSet (eq $i $lastUserIdx) }}
{{- if $.Think -}}
{{- " "}}/think
{{- else -}}
{{- " "}}/no_think
{{- end -}}
{{- end }}<|im_end|>
{{ else if eq .Role "assistant" }}<|im_start|>assistant
{{ if (and $.IsThinkSet (and .Thinking (or $last (gt $i $lastUserIdx)))) -}}
<think>{{ .Thinking }}</think>
{{ end -}}
{{ if .Content }}{{ .Content }}
{{- else if .ToolCalls }}<tool_call>
{{ range .ToolCalls }}{"name": "{{ .Function.Name }}", "arguments": {{ .Function.Arguments }}}
{{ end }}</tool_call>
{{- end }}{{ if not $last }}<|im_end|>
{{ end }}
{{- else if eq .Role "tool" }}<|im_start|>user
<tool_response>
{{ .Content }}
</tool_response><|im_end|>
{{ end }}
{{- if and (ne .Role "assistant") $last }}<|im_start|>assistant
{{ if and $.IsThinkSet (not $.Think) -}}
<think>
</think>
{{ end -}}
{{ end }}
{{- end }}"""
PARAMETER repeat_penalty 1
PARAMETER stop <|im_start|>
PARAMETER stop <|im_end|>
PARAMETER temperature 0.6
PARAMETER top_k 20
PARAMETER top_p 0.95
使用导入命令(注意替换modelname和modelfilepath)
ollama create modename -f modelfilepath
接下来就可以调用成功了,content为空,tool_calls代表需要调用的tool
模型返回
{
"model": "ttt",
"created_at": "2025-06-11T03:18:48.3569896Z",
"message": {
"role": "assistant",
"content": "",
"tool_calls": [
{
"function": {
"name": "get_current_weather",
"arguments": {
"format": "fahrenheit",
"location": "Paris"
}
}
}
]
},
"done_reason": "stop",
"done": true,
"total_duration": 2440101400,
"load_duration": 1229006400,
"prompt_eval_count": 203,
"prompt_eval_duration": 173670700,
"eval_count": 156,
"eval_duration": 1036884700
}