976 字
5 分钟

为使用 Ollama 部署的 DeepSeek V3 启用函数调用功能

引言#

DeepSeek V3 是一个强大的开源语言模型,而Ollama则提供了便捷的本地部署方案。本文将介绍如何通过自定义ModelfileDeepSeek V3添加函数调用功能,从而支持一些常见的agent框架。

准备工作#

Terminal window
# 确保已经安装了 Ollama
ollama --version
# 拉取 DeepSeek V3 模型
ollama pull deepseek-v3

自定义 Modelfile#

创建一个新的 Modelfile

Terminal window
vim deepseek-v3t.modelfile

把以下内容复制进去:

Terminal window
FROM deepseek-v3:latest
TEMPLATE """{{- if .Messages }}
{{- if or .System .Tools }}
{{- if .System }}
{{ .System }}
{{- end }}
{{- if .Tools }}
{{- end }}
{{- end }}
{{- range $i, $_ := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1 }}
{{- if eq .Role "user" }}<|User|>
{{- if and $.Tools $last }}
Given the following functions, please respond with a JSON for a function call with its proper arguments that best answers the given prompt.
Respond in the format {"name": function name, "parameters": dictionary of argument name and its value}. Do not use variables.
{{ $.Tools }}
{{- end }}
{{ .Content }}
{{- if $last }}<|Assistant|>{{ end }}
{{- else if eq .Role "assistant" }}
<|Assistant|>
{{- if .ToolCalls }}
<|tool▁calls▁begin|>
{{- range .ToolCalls }}
<|tool▁call▁begin|>
{"name": "{{ .Function.Name }}", "parameters": {{ .Function.Arguments }}}
<|tool▁call▁end|>
{{- end }}
<|tool▁calls▁end|>
{{- else }}
{{ .Content }}
{{- if not $last }}<|end▁of▁sentence|>{{- end }}
{{- end }}
{{- else if eq .Role "tool" }}
<|tool▁outputs▁begin|>
<|tool▁output▁begin|>
{{ .Content }}
<|tool▁output▁end|>
<|tool▁outputs▁end|>
{{- if and $last (ne .Role "assistant") }}<|Assistant|>{{- end }}
{{- end }}
{{- end }}
{{- else }}
{{- if .System }}
{{ .System }}
{{- end }}
{{- if .Prompt }}
<|User|>
{{ .Prompt }}
{{- end }}
<|Assistant|>
{{ .Response }}
{{- if .Response }}{{ end }}
{{- end }}"""

使用自定义 Modelfile#

Terminal window
ollama create deepseek-v3t -f deepseek-v3t.modelfile

使用示例#

任选一个你喜欢的agent框架,调用 openai 兼容的 sdk,就可以直接使用了。 这里以pydantic-ai为例:

from openai import AsyncOpenAI
from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIModel
openai_client = AsyncOpenAI(
api_key="test",
base_url="http://localhost:11434/v1",
)
# 如果你创建的模型名称不是 deepseek-v3t,需要自己修改
model = OpenAIModel("deepseek-v3t", openai_client=openai_client)
agent = Agent(
model
)
# 为 agent 添加一个工具函数
@agent.tool
async def get_time():
import datetime
return f"Current time is {datetime.datetime.now()}"
async def main():
response = await agent.run("What time is it?")
print(response)
if __name__ == "__main__":
import asyncio
asyncio.run(main())

只要这个代码可以运行,那就说明你已经成功为DeepSeek V3添加了函数调用功能,即使他没调用你给的工具函数

其他#

解决闪退问题#

由于DeepSeek系列模型不支持K-shift,当上下文达到一定长度时,会导致ollama闪退。目前ollama官方还没给出一个比较好的解决方案,这个问题暂时可以通过编辑Modelfile来规避,你只需要在 Modelfile 中添加下面这两行即可:

Terminal window
PARAMETER num_ctx 24576
PARAMETER num_predict 8192

修改后的完整 Modelfile 如下:

Terminal window
FROM deepseek-v3:latest
PARAMETER num_ctx 24576
PARAMETER num_predict 8192
TEMPLATE """{{- if .Messages }}
{{- if or .System .Tools }}
{{- if .System }}
{{ .System }}
{{- end }}
{{- if .Tools }}
{{- end }}
{{- end }}
{{- range $i, $_ := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1 }}
{{- if eq .Role "user" }}<|User|>
{{- if and $.Tools $last }}
Given the following functions, please respond with a JSON for a function call with its proper arguments that best answers the given prompt.
Respond in the format {"name": function name, "parameters": dictionary of argument name and its value}. Do not use variables.
{{ $.Tools }}
{{- end }}
{{ .Content }}
{{- if $last }}<|Assistant|>{{ end }}
{{- else if eq .Role "assistant" }}
<|Assistant|>
{{- if .ToolCalls }}
<|tool▁calls▁begin|>
{{- range .ToolCalls }}
<|tool▁call▁begin|>
{"name": "{{ .Function.Name }}", "parameters": {{ .Function.Arguments }}}
<|tool▁call▁end|>
{{- end }}
<|tool▁calls▁end|>
{{- else }}
{{ .Content }}
{{- if not $last }}<|end▁of▁sentence|>{{- end }}
{{- end }}
{{- else if eq .Role "tool" }}
<|tool▁outputs▁begin|>
<|tool▁output▁begin|>
{{ .Content }}
<|tool▁output▁end|>
<|tool▁outputs▁end|>
{{- if and $last (ne .Role "assistant") }}<|Assistant|>{{- end }}
{{- end }}
{{- end }}
{{- else }}
{{- if .System }}
{{ .System }}
{{- end }}
{{- if .Prompt }}
<|User|>
{{ .Prompt }}
{{- end }}
<|Assistant|>
{{ .Response }}
{{- if .Response }}{{ end }}
{{- end }}"""

然后根据上文给出的命令重新创建模型即可。

DeepSeek R1 也适用吗?#

理论上,添加了这个模板之后DeepSeek R1也可以有工具调用的能力,但是由于模型默认输出的<think>xxx</think>标签,不一定和常见的agent框架兼容,所以可能需要一些额外的处理,我也没有测试过,如果你有兴趣,可以试试看。

相关资料#

为使用 Ollama 部署的 DeepSeek V3 启用函数调用功能
https://nyanners.moe/deepseek-v3-function-calling-with-ollama
作者
Zero
发布于
2025-01-31
许可协议
CC BY-NC-SA 4.0