Ollama部署本地大模型|DeepSeek-R1-Distill-Qwen-7B支持函数调用(Function Calling)实操

想在自己的电脑上跑一个能“思考”的大模型吗?今天我就带你用Ollama,把DeepSeek最新推出的推理模型——DeepSeek-R1-Distill-Qwen-7B部署到本地,并且重点体验它强大的函数调用能力。

这个模型可不简单,它是DeepSeek-R1的蒸馏版本,专门针对推理任务进行了优化。简单来说,它不仅能回答你的问题,还能理解你的意图,调用你预先定义好的函数来完成特定任务。比如,你可以让它帮你查天气、计算数学题、甚至控制智能家居设备。

下面我就手把手教你如何从零开始部署,并展示几个实用的函数调用例子。

1. 环境准备与快速部署

1.1 安装Ollama

如果你还没安装Ollama,先去官网下载对应你操作系统的版本。安装过程很简单,基本就是一路“下一步”。

安装完成后,打开终端(Windows是命令提示符或PowerShell,Mac/Linux是Terminal),输入以下命令检查是否安装成功:

ollama --version

如果能看到版本号,说明安装成功了。

1.2 拉取DeepSeek-R1-Distill-Qwen-7B模型

接下来,我们把这个模型下载到本地。在终端里输入:

ollama pull deepseek-r1:7b

这个命令会从Ollama的模型库中下载DeepSeek-R1-Distill-Qwen-7B模型。文件大小大概在4-5GB左右,下载速度取决于你的网络。

看到“success”提示后,模型就下载完成了。你可以用下面的命令查看本地已有的模型:

ollama list

应该能看到deepseek-r1:7b出现在列表里。

1.3 启动模型服务

现在启动模型服务,开始和它对话:

ollama run deepseek-r1:7b

启动后,你会看到一个提示符,直接输入问题就可以开始对话了。比如试试:

你好,请介绍一下你自己。

模型会开始生成回答。第一次运行可能会慢一点,因为需要加载模型到内存。

2. 理解DeepSeek-R1-Distill-Qwen-7B

2.1 这个模型有什么特别?

DeepSeek-R1-Distill-Qwen-7B是DeepSeek最新推出的推理模型。你可能听说过DeepSeek之前的版本,但这个R1系列专门针对“思考”能力做了优化。

简单来说,普通的大模型是直接给出答案,而这个模型更像是在“解题”——它会一步步推理,最后得出结论。这种能力在数学计算、逻辑分析、代码调试等场景下特别有用。

2.2 为什么选择7B版本?

7B指的是70亿参数,这个大小有几个好处:

  • 对硬件要求不高:8GB内存的电脑就能跑起来
  • 推理速度快:生成回答比较快,体验流畅
  • 效果足够好:虽然比32B版本小,但在很多任务上表现已经很不错了

如果你电脑配置更好(比如有16GB以上内存),也可以试试32B版本,效果会更好一些。

3. 函数调用功能初体验

3.1 什么是函数调用?

函数调用(Function Calling)是大模型的一个高级功能。传统的大模型只能生成文本,但有了函数调用,模型可以:

  • 理解你想要做什么
  • 调用你预先定义好的函数
  • 用函数的结果来生成最终回答

举个例子,你问“北京现在天气怎么样?”,普通模型可能直接编一个答案。但支持函数调用的模型会:

  1. 识别出这是个天气查询请求
  2. 调用get_weather(city="北京")这个函数
  3. 用真实的天气数据来回答你

3.2 第一个函数调用例子

我们先从简单的开始。假设我们定义了一个计算器函数,让模型来调用它。

创建一个Python文件function_calling_demo.py

import json
import ollama

# 定义我们想让模型调用的函数
def calculator(operation, a, b):
    """执行数学运算"""
    if operation == "add":
        return a + b
    elif operation == "subtract":
        return a - b
    elif operation == "multiply":
        return a * b
    elif operation == "divide":
        return a / b if b != 0 else "错误:除数不能为0"
    else:
        return "不支持的操作"

# 告诉模型有哪些函数可用
functions = [
    {
        "name": "calculator",
        "description": "执行数学运算",
        "parameters": {
            "type": "object",
            "properties": {
                "operation": {
                    "type": "string",
                    "enum": ["add", "subtract", "multiply", "divide"],
                    "description": "要执行的操作"
                },
                "a": {
                    "type": "number",
                    "description": "第一个数字"
                },
                "b": {
                    "type": "number", 
                    "description": "第二个数字"
                }
            },
            "required": ["operation", "a", "b"]
        }
    }
]

# 用户的问题
user_query = "请计算123乘以456等于多少?"

# 调用模型,告诉它可以使用的函数
response = ollama.chat(
    model='deepseek-r1:7b',
    messages=[
        {
            'role': 'user',
            'content': user_query
        }
    ],
    functions=functions,
    function_call='auto'  # 让模型自动决定是否调用函数
)

print("模型回复:")
print(json.dumps(response['message'], ensure_ascii=False, indent=2))

# 检查模型是否想调用函数
if 'function_call' in response['message']:
    func_call = response['message']['function_call']
    print(f"\n模型想调用函数:{func_call['name']}")
    print(f"参数:{func_call['arguments']}")
    
    # 解析参数
    args = json.loads(func_call['arguments'])
    
    # 实际调用函数
    result = calculator(
        operation=args['operation'],
        a=args['a'],
        b=args['b']
    )
    
    print(f"计算结果:{result}")
    
    # 把结果返回给模型,让它生成最终回答
    follow_up = ollama.chat(
        model='deepseek-r1:7b',
        messages=[
            {
                'role': 'user',
                'content': user_query
            },
            response['message'],  # 模型的第一次回复
            {
                'role': 'function',
                'name': func_call['name'],
                'content': str(result)
            }
        ]
    )
    
    print(f"\n最终回答:{follow_up['message']['content']}")

运行这个脚本:

python function_calling_demo.py

你会看到模型先识别出这是一个乘法计算,然后调用calculator函数,最后用计算结果生成最终回答。整个过程是自动完成的!

4. 实战:构建智能天气助手

4.1 定义天气查询函数

让我们做个更实用的例子——一个能查天气的智能助手。虽然我们这里用模拟数据,但你可以很容易地替换成真实的天气API。

创建weather_assistant.py

import json
import ollama
from datetime import datetime

# 模拟的天气数据(实际使用时可以替换成真实API)
def get_weather(city, date=None):
    """获取指定城市的天气信息"""
    if date is None:
        date = datetime.now().strftime("%Y-%m-%d")
    
    # 模拟不同城市的天气数据
    weather_data = {
        "北京": {
            "temperature": "15°C",
            "condition": "晴",
            "humidity": "45%",
            "wind": "3级"
        },
        "上海": {
            "temperature": "18°C", 
            "condition": "多云",
            "humidity": "65%",
            "wind": "2级"
        },
        "广州": {
            "temperature": "25°C",
            "condition": "阵雨",
            "humidity": "85%",
            "wind": "1级"
        },
        "深圳": {
            "temperature": "26°C",
            "condition": "晴转多云",
            "humidity": "80%",
            "wind": "2级"
        }
    }
    
    if city in weather_data:
        return {
            "city": city,
            "date": date,
            **weather_data[city]
        }
    else:
        return {"error": f"未找到{city}的天气信息"}

# 定义可用的函数
functions = [
    {
        "name": "get_weather",
        "description": "获取指定城市的天气信息",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "城市名称,如北京、上海"
                },
                "date": {
                    "type": "string",
                    "description": "日期,格式为YYYY-MM-DD,默认为今天"
                }
            },
            "required": ["city"]
        }
    }
]

def chat_with_weather_assistant():
    """与天气助手对话"""
    print("天气助手已启动!输入'退出'结束对话。")
    print("-" * 50)
    
    messages = []
    
    while True:
        user_input = input("\n你:").strip()
        
        if user_input.lower() in ['退出', 'exit', 'quit']:
            print("再见!")
            break
            
        # 添加用户消息
        messages.append({
            'role': 'user',
            'content': user_input
        })
        
        # 调用模型
        response = ollama.chat(
            model='deepseek-r1:7b',
            messages=messages,
            functions=functions,
            function_call='auto'
        )
        
        assistant_message = response['message']
        messages.append(assistant_message)
        
        # 检查是否需要调用函数
        if 'function_call' in assistant_message:
            func_call = assistant_message['function_call']
            print(f"\n助手:我需要查询天气信息...")
            
            # 解析并调用函数
            args = json.loads(func_call['arguments'])
            weather_result = get_weather(**args)
            
            # 添加函数调用结果
            messages.append({
                'role': 'function',
                'name': func_call['name'],
                'content': json.dumps(weather_result, ensure_ascii=False)
            })
            
            # 让模型基于结果生成回答
            final_response = ollama.chat(
                model='deepseek-r1:7b',
                messages=messages
            )
            
            final_message = final_response['message']
            messages.append(final_message)
            
            print(f"助手:{final_message['content']}")
        else:
            print(f"助手:{assistant_message['content']}")

if __name__ == "__main__":
    chat_with_weather_assistant()

4.2 运行天气助手

运行上面的脚本:

python weather_assistant.py

然后试试这些对话:

  • “北京今天天气怎么样?”
  • “帮我查一下上海明天的天气”
  • “广州和深圳哪个更热?”

你会发现模型能正确识别你的意图,调用天气查询函数,然后用真实(模拟)的数据回答你。

5. 高级应用:多函数协同工作

5.1 定义多个功能函数

真正的智能助手通常需要多个函数协同工作。我们来看一个更复杂的例子——一个能同时处理计算、天气查询和单位转换的助手。

创建multi_function_assistant.py

import json
import ollama

# 定义多个函数
def calculator(operation, a, b):
    """数学计算器"""
    operations = {
        "add": lambda x, y: x + y,
        "subtract": lambda x, y: x - y,
        "multiply": lambda x, y: x * y,
        "divide": lambda x, y: x / y if y != 0 else "错误:除数不能为0"
    }
    
    if operation in operations:
        return operations[operation](a, b)
    return "不支持的操作"

def get_weather(city):
    """获取天气(简化版)"""
    weather_map = {
        "北京": "晴,15°C",
        "上海": "多云,18°C",
        "广州": "阵雨,25°C"
    }
    return weather_map.get(city, f"未找到{city}的天气信息")

def convert_units(value, from_unit, to_unit):
    """单位转换"""
    conversions = {
        ("km", "mile"): lambda x: x * 0.621371,
        ("mile", "km"): lambda x: x * 1.60934,
        ("kg", "lb"): lambda x: x * 2.20462,
        ("lb", "kg"): lambda x: x * 0.453592,
        ("celsius", "fahrenheit"): lambda x: x * 9/5 + 32,
        ("fahrenheit", "celsius"): lambda x: (x - 32) * 5/9
    }
    
    key = (from_unit.lower(), to_unit.lower())
    if key in conversions:
        result = conversions[key](value)
        return f"{value}{from_unit} = {result:.2f}{to_unit}"
    return "不支持的单位转换"

# 所有可用函数
functions = [
    {
        "name": "calculator",
        "description": "执行数学运算",
        "parameters": {
            "type": "object",
            "properties": {
                "operation": {
                    "type": "string",
                    "enum": ["add", "subtract", "multiply", "divide"]
                },
                "a": {"type": "number"},
                "b": {"type": "number"}
            },
            "required": ["operation", "a", "b"]
        }
    },
    {
        "name": "get_weather",
        "description": "获取城市天气",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string"}
            },
            "required": ["city"]
        }
    },
    {
        "name": "convert_units",
        "description": "单位转换",
        "parameters": {
            "type": "object",
            "properties": {
                "value": {"type": "number"},
                "from_unit": {"type": "string"},
                "to_unit": {"type": "string"}
            },
            "required": ["value", "from_unit", "to_unit"]
        }
    }
]

def process_query(query):
    """处理用户查询"""
    response = ollama.chat(
        model='deepseek-r1:7b',
        messages=[{"role": "user", "content": query}],
        functions=functions,
        function_call='auto'
    )
    
    message = response['message']
    
    if 'function_call' in message:
        func_call = message['function_call']
        args = json.loads(func_call['arguments'])
        
        # 根据函数名调用对应的函数
        if func_call['name'] == 'calculator':
            result = calculator(**args)
        elif func_call['name'] == 'get_weather':
            result = get_weather(**args)
        elif func_call['name'] == 'convert_units':
            result = convert_units(**args)
        else:
            result = "未知函数"
        
        # 获取最终回答
        final_response = ollama.chat(
            model='deepseek-r1:7b',
            messages=[
                {"role": "user", "content": query},
                message,
                {
                    "role": "function",
                    "name": func_call['name'],
                    "content": str(result)
                }
            ]
        )
        
        return final_response['message']['content']
    else:
        return message['content']

# 测试多个功能
test_queries = [
    "100公里等于多少英里?",
    "北京天气怎么样?",
    "计算一下256乘以128等于多少",
    "20摄氏度转换成华氏度是多少?",
    "上海和广州哪里更热?"  # 这个可能需要多次函数调用
]

print("多功能助手测试:")
print("=" * 50)

for i, query in enumerate(test_queries, 1):
    print(f"\n测试 {i}: {query}")
    print(f"回答: {process_query(query)}")
    print("-" * 30)

5.2 运行测试

运行这个多函数助手:

python multi_function_assistant.py

你会看到模型能正确识别不同类型的请求,并调用相应的函数。比如:

  • “100公里等于多少英里?” → 调用convert_units
  • “北京天气怎么样?” → 调用get_weather
  • “计算一下256乘以128等于多少” → 调用calculator

6. 实用技巧与注意事项

6.1 提升函数调用准确率

有时候模型可能不太确定该调用哪个函数,或者参数提取不准确。这里有几个小技巧:

1. 给函数写清楚的描述 函数的description字段很重要,要写得具体明确。比如:

{
    "name": "book_restaurant",
    "description": "预订餐厅,需要提供餐厅名称、用餐时间、人数和联系方式",
    # ... 其他参数
}

2. 参数描述也要详细 每个参数的描述都要写清楚,帮助模型理解:

"parameters": {
    "restaurant_name": {
        "type": "string",
        "description": "餐厅的全名,如'海底捞火锅(中关村店)'"
    },
    "time": {
        "type": "string", 
        "description": "用餐时间,格式为'YYYY-MM-DD HH:MM',如'2024-01-15 18:30'"
    }
}

3. 提供示例对话 在系统提示中给一些例子:

system_prompt = """你是一个智能助手,可以帮我调用各种函数。
例如:
用户:我想订今晚6点半海底捞的位子,3个人
你应该:调用book_restaurant函数,参数为restaurant_name='海底捞', time='今晚6点半', people=3

用户:北京今天多少度?
你应该:调用get_weather函数,参数为city='北京'
"""

6.2 处理复杂请求

有时候用户的问题需要多个函数配合。比如“帮我查一下北京天气,然后计算如果去上海出差3天要带多少衣服”,这就需要:

  1. 先查北京天气
  2. 再查上海天气
  3. 根据温差给建议

你可以这样处理:

def handle_complex_query(query):
    """处理需要多个步骤的复杂查询"""
    # 第一步:让模型分解任务
    planning_response = ollama.chat(
        model='deepseek-r1:7b',
        messages=[{
            "role": "user",
            "content": f"请把这个任务分解成几个步骤:{query}"
        }]
    )
    
    steps = planning_response['message']['content']
    print(f"任务分解:{steps}")
    
    # 第二步:逐步执行
    # ... 实际执行每个步骤

6.3 错误处理

函数调用可能会失败,要做好错误处理:

try:
    result = some_function(**args)
except Exception as e:
    # 告诉模型出错了
    error_message = f"调用函数失败:{str(e)}"
    
    # 让模型基于错误信息重新回答
    recovery_response = ollama.chat(
        model='deepseek-r1:7b',
        messages=[
            {"role": "user", "content": original_query},
            {"role": "assistant", "content": "我尝试调用函数但失败了"},
            {"role": "function", "name": func_name, "content": error_message}
        ]
    )
    return recovery_response['message']['content']

7. 总结

通过今天的实操,你应该已经掌握了:

1. 快速部署DeepSeek-R1-Distill-Qwen-7B

  • 用Ollama一键拉取和运行模型
  • 本地部署,数据完全在你自己电脑上

2. 理解函数调用的价值

  • 让大模型不只是生成文本,还能执行具体操作
  • 把AI的“思考”能力和实际功能结合起来

3. 实际开发函数调用应用

  • 从简单的计算器到复杂的多函数助手
  • 学会了如何定义函数、处理参数、整合结果

4. 掌握了实用技巧

  • 如何提升函数调用的准确率
  • 如何处理复杂请求和错误情况

这个模型的函数调用能力真的很实用。你可以基于这个框架,开发出各种智能应用:

  • 个人助手:管理日程、查询信息、控制智能设备
  • 工作工具:自动生成报告、分析数据、处理文档
  • 教育应用:解题辅导、知识问答、学习规划

最重要的是,这一切都在你本地运行,不需要联网,数据完全私有。你可以放心地处理敏感信息,不用担心数据泄露。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐