976 字
5 分钟
为使用 Ollama 部署的 DeepSeek V3 启用函数调用功能
引言
DeepSeek V3 是一个强大的开源语言模型,而Ollama则提供了便捷的本地部署方案。本文将介绍如何通过自定义Modelfile为DeepSeek V3添加函数调用功能,从而支持一些常见的agent框架。
准备工作
# 确保已经安装了 Ollamaollama --version
# 拉取 DeepSeek V3 模型ollama pull deepseek-v3自定义 Modelfile
创建一个新的 Modelfile
vim deepseek-v3t.modelfile把以下内容复制进去:
FROM deepseek-v3:latestTEMPLATE """{{- 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
ollama create deepseek-v3t -f deepseek-v3t.modelfile使用示例
任选一个你喜欢的agent框架,调用 openai 兼容的 sdk,就可以直接使用了。
这里以pydantic-ai为例:
from openai import AsyncOpenAIfrom pydantic_ai import Agentfrom 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.toolasync 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 中添加下面这两行即可:
PARAMETER num_ctx 24576PARAMETER num_predict 8192修改后的完整 Modelfile 如下:
FROM deepseek-v3:latestPARAMETER num_ctx 24576PARAMETER num_predict 8192TEMPLATE """{{- 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