当前位置: 首页 > news >正文

lmstdio大模型——本地大模型python函数调用设计

lmstdio大模型——本地大模型python函数调用设计

大模型的函数调用功能是指其能够根据用户需求,通过预定义或动态生成的函数接口与外部工具、API或数据库进行交互的能力。这一功能使模型不仅能生成文本,还能执行复杂任务(如计算、信息检索、数据操作),例如在回答天气查询时调用天气API获取实时数据,或在处理数学问题时激活计算工具。通过解析用户指令中的意图和参数,模型自动选择并触发相应函数,随后将返回结果整合到自然语言回复中,从而突破纯文本生成的限制,实现更高效的自动化服务。这种能力显著扩展了大模型的应用场景,使其在智能助手、数据分析、跨系统集成等场景中具备实际任务处理能力,提升了交互的实用性和准确性。

本文将介绍如何利用lmstdio以及python实现本地大模型的函数调用功能。

Step1:安装lmstdio及模型

lmstdio官网:lmstudio.ai

lmstdio 是一个面向大语言模型(LLM)开发的轻量级工具库,专注于简化模型交互中的输入输出处理、上下文管理及复杂任务调度。其核心目标是通过标准化接口和实用功能,帮助开发者更高效地构建基于大模型的应用程序,尤其是在涉及多轮对话、函数调用和外部工具集成的场景中。
在这里插入图片描述

主要功能与特点:

  1. 输入输出标准化
    lmstdio 提供统一的接口规范,可将用户输入的文本或结构化指令(如自然语言命令)自动解析为模型可处理的格式,同时将模型的生成结果(如文本回复或函数调用请求)转换为开发者友好的结构化数据。例如,用户提问“明早北京天气如何?”可被解析为调用天气API的标准化参数。

  2. 上下文管理
    支持对多轮对话上下文的持久化存储和动态更新,通过智能缓存和关键信息提取(如实体识别、意图分类),减少重复计算并提升长对话场景下的连贯性。例如,自动关联前文提到的地点和时间,避免用户反复澄清需求。

  3. 函数调用支持
    深度集成大模型的“工具调用”能力,允许开发者预定义外部函数(如数据库查询、API请求),并自动将模型生成的函数调用请求(如 {"function": "get_weather", "params": {"city": "北京"}})映射到实际代码执行,最后将结果融入自然语言回复中。这一过程大幅降低了代码开发复杂度。

  4. 性能优化
    通过请求批处理、流式响应和错误重试机制,优化高并发场景下的资源利用率,同时内置提示词(prompt)模板和缓存策略,减少模型调用延迟与成本。

与类似工具(如 LangChain、LlamaIndex)相比,lmstdio 更强调轻量化和灵活性,适合需要快速落地原型或对定制化要求较高的项目。其设计哲学是通过“约定优于配置”降低开发门槛,同时保留扩展性,是中小规模LLM应用的理想选择。

下载好lmstdio安装后,点击搜索图标,即可选择合适的大模型进行安装:
在这里插入图片描述

点击文件夹图标可以对模型位置进行管理:
在这里插入图片描述

如果遇到模型无法下载的问题,可以尝试更换镜像源,参考以下文章:https://blog.csdn.net/mervyn0318/article/details/144468568

我们使用Q4_K_M量化的gemma-2-9b-it模型进行函数调用的演示设计,该模型大约占用9G显存:

在这里插入图片描述

选择聊天图标,点击加载模型即可将模型加载到显存和内存中,此时就可以开始问答了:
在这里插入图片描述

由于我们使用python进行调用,因此我们将使用lmstdio的服务器模式。选择开发者图标,点击启动服务器:
在这里插入图片描述

利用下方代码,即可检测是否与lmstdio服务连接成功。注意代码中client = OpenAI(base_url="http://127.0.0.1:1234/v1", api_key="lm-studio"),base_url需要选择lmstdio提供的地址,由于本文为http://127.0.0.1:1234,因此base_url=“http://127.0.0.1:1234/v1”

python需要首先安装openai库,安装命令为pip install openai,安装完成后即可运行下方代码:

# 在终端中与智能助手聊天
from openai import OpenAI
 
# 指向本地服务器
client = OpenAI(base_url="http://127.0.0.1:1234/v1", api_key="lm-studio")
 
# 初始化历史记录列表,其中包含系统和用户的角色和内容
history = [
    {"role": "system", "content": "你是一个聪明的助手。你总是提供合理、准确且有帮助的答案。总是用中文简体回答"},
    {"role": "user", "content": "什么是python"},
]
# 创建聊天完成请求,指定模型、历史消息和其他参数
completion = client.chat.completions.create(
    model="gemma-2-9b-it",
    messages=history,
    temperature=0.7,
    stream=True,
)
# 初始化新消息字典,用于存储助手的回答
new_message = {"role": "assistant", "content": ""}
# 遍历完成请求的结果,并打印内容
for chunk in completion:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
        new_message["content"] += chunk.choices[0].delta.content
# 将新消息添加到历史记录列表中
history.append(new_message)
Python是一种解释型、高层次的通用编程语言。它以其清晰易读的语法而闻名,因此非常适合初学者学习。 

以下是 Python 的一些关键特点:

* **解释型:** Python 代码不需要事先编译,而是直接在运行时被解释执行。这使得开发和调试更加方便。
* **高层次:** Python 提供了许多内置函数和模块,可以帮助开发者简化代码编写,提高效率。
* **通用:** Python 可以用于多种领域,包括网站开发、数据分析、机器学习、人工智能等。
* **开源:** Python 是免费且开源的,这意味着任何人可以使用、修改和分发它。
* **活跃的社区:** Python 拥有庞大的用户社区,提供丰富的资源和支持。

总而言之,Python 是一种功能强大、易于学习和使用的编程语言,适合各种应用场景。

Step2:函数调用设计

本节将结合lmstdio官方文档:https://lm-studio.cn/docs/api/tools ,进行示例讲解设计,下方是一段函数调用的示例代码。

from datetime import datetime, timedelta
import json
import random
from openai import OpenAI

# 连接lmstdio服务器并选择模型
client = OpenAI(base_url="http://127.0.0.1:1234/v1", api_key="lm-studio")  # 连接lmstdio服务器
model = "gemma-2-9b-it"  # 选择模型


# 设计需要调用的函数
def get_delivery_date(order_id: str) -> datetime:
    # 生成一个随机的交付日期,从今天开始到14天内的任意一天
    today = datetime.now()
    random_days = random.randint(1, 14)
    delivery_date = today + timedelta(days=random_days)
    return delivery_date


tools = [
    {
        "type": "function",
        "function": {
            "name": "get_delivery_date",
            "description": "根据订单号获取预计的交付日期,当顾客询问订单的预计交付日期时,调用此函数,比如当用户问'我的订单什么时候能送达?'时,调用此函数",
            "parameters": {
                "type": "object",
                "properties": {
                    "order_id": {
                        "type": "string",
                        "description": "顾客的订单号ID",
                    },
                },
                "required": ["order_id"],
                "additionalProperties": False,
            },
        },
    }
]

messages = [
    {
        "role": "system",
        "content": "您是一位乐于助人的客户支持助理。使用提供的工具协助用户。",
    },
    {
        "role": "user",
        "content": "给我1017号订单的交货日期和时间",
    },
]

# LM Studio
response = client.chat.completions.create(
    model=model,
    messages=messages,
    tools=tools,
)

# 获取顾客输入的参数
# 请注意,下方代码假设我们已经确定模型生成了一个函数调用。
tool_call = response.choices[0].message.tool_calls[0]
arguments = json.loads(tool_call.function.arguments)

order_id = arguments.get("order_id")

# 使用提取的order_id调用get_delivery_date函数
delivery_date = get_delivery_date(order_id)

assistant_tool_call_request_message = {
    "role": "assistant",
    "tool_calls": [
        {
            "id": response.choices[0].message.tool_calls[0].id,
            "type": response.choices[0].message.tool_calls[0].type,
            "function": response.choices[0].message.tool_calls[0].function,
        }
    ],
}

# 创建一条包含函数调用结果的消息
function_call_result_message = {
    "role": "tool",
    "content": json.dumps(
        {
            "order_id": order_id,
            "delivery_date": delivery_date.strftime("%Y-%m-%d %H:%M:%S"),
        }
    ),
    "tool_call_id": response.choices[0].message.tool_calls[0].id,
}

# 准备聊天完成回调装载内容,包括历史消息、助手工具调用请求消息和函数调用结果消息
completion_messages_payload = [
    messages[0],
    messages[1],
    assistant_tool_call_request_message,
    function_call_result_message,
]

# 调用OpenAI API的聊天完成端点,将工具调用结果发送回模型
response = client.chat.completions.create(
    model=model,
    messages=completion_messages_payload,
)

print(response.choices[0].message.content, flush=True)
订单1017的预计交货日期是2025年3月1日 下午10点56分。   

接下来,我们分步介绍一下函数调用的代码逻辑:

函数定义

def get_delivery_date(order_id: str) -> datetime:

这个函数是我们要调用的函数,它接受一个参数order_id,并返回一个datetime对象,表示预计的交付日期。在用户与大模型交互时,我们希望当用户询问订单的预计交付日期时,调用此函数。

工具列表定义

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_delivery_date",
            "description": "根据订单号获取预计的交付日期,当顾客询问订单的预计交付日期时,调用此函数,比如当用户问'我的订单什么时候能送达?'时,调用此函数",
            "parameters": {
                "type": "object",
                "properties": {
                    "order_id": {
                        "type": "string",
                        "description": "顾客的订单号ID",
                    },
                },
                "required": ["order_id"],
                "additionalProperties": False,
            },
        },
    }
]
  • tools列表定义了我们要调用的函数。在这个例子中,我们只定义了一个函数,即get_delivery_date
    • 每个函数都有一个namedescriptionparameters字段。
      • parameters字段定义了函数的参数类型和描述。
      • "required"字段指定了函数的必需参数。
      • "additionalProperties"字段指定了函数是否接受额外的参数。
    • 该部分在整个函数调用过程中较为重要,大模型需要结合tools中的函数描述以及用户的消息内容,判断是否需要调用该函数,当需要调用函数时返回函数调用的参数。

对话历史

messages = [
    {"role": "system", "content": "您是一位乐于助人的客户支持助理。使用提供的工具协助用户。"},
    {"role": "user", "content": "给我1017号订单的交货日期和时间"},
]

这个列表定义了用户和模型的对话历史。在这个例子中,我们只定义了两条消息:

  • 一条是用户的消息:“给我1017号订单的交货日期和时间”。
  • 另一条是模型的回复(虽然在这里没有直接给出,但会在后续步骤中生成)。

模型调用与响应

response = client.chat.completions.create(model=model, messages=messages, tools=tools)

这行代码调用了OpenAI API的聊天完成端点,将用户的消息和函数列表发送给模型。模型会根据用户的消息和函数列表生成回复。

提取函数调用信息

tool_call = response.choices[0].message.tool_calls[0]

这行代码从模型的回复中提取了函数调用信息。模型的回复中可能包含多个函数调用,我们只取第一个函数调用。

参数转换

arguments = json.loads(tool_call.function.arguments)

这行代码将函数调用的参数从JSON字符串转换为Python字典。函数调用的参数是一个JSON字符串,我们需要将其转换为Python字典,以便提取参数的值。

提取订单ID

order_id = arguments.get("order_id")

这行代码从函数调用的参数中提取了order_id的值。我们假设函数调用的参数中包含一个名为order_id的参数,我们使用get方法从字典中提取该参数的值。

调用函数并获取交付日期

delivery_date = get_delivery_date(order_id)

这行代码调用get_delivery_date函数,并将order_id作为参数传递给它。函数会返回一个datetime对象,表示预计的交付日期。

助手工具调用请求消息

assistant_tool_call_request_message = {
    "role": "assistant",
    "tool_calls": [
        {
            "id": response.choices[0].message.tool_calls[0].id,
            "type": response.choices[0].message.tool_calls[0].type,
            "function": response.choices[0].message.tool_calls[0].function,
        }
    ],
}

这个字典定义了助手工具调用请求消息。这个消息包含了函数调用的信息,包括函数调用的ID、类型和函数。我们使用模型的回复中的函数调用信息来创建这个消息。

函数调用结果消息

function_call_result_message = {
    "role": "tool",
    "content": json.dumps({
        "order_id": order_id,
        "delivery_date": delivery_date.strftime("%Y-%m-%d %H:%M:%S"),
    }),
    "tool_call_id": response.choices[0].message.tool_calls[0].id,
}

这个字典定义了函数调用结果消息。这个消息包含了函数调用的结果,包括order_iddelivery_date。我们使用get_delivery_date函数的返回值来创建这个消息。

聊天完成回调装载内容

completion_messages_payload = [
    messages[0],
    messages[1],
    assistant_tool_call_request_message,
    function_call_result_message,
]

这个列表定义了聊天完成回调装载内容。这个列表包含了历史消息、助手工具调用请求消息和函数调用结果消息。我们将这个列表作为参数传递给OpenAI API的聊天完成端点,将函数调用结果发送回模型。

最终模型调用

response = client.chat.completions.create(model=model, messages=completion_messages_payload)

这行代码调用了OpenAI API的聊天完成端点,将函数调用结果发送回模型。模型会根据函数调用结果生成回复。

接下来,我们设计一个更加多样的函数调用,在下方的代码中,我们写了5个函数,分别计算两数相加、相减、相乘、相除以及比较两数大小:

import json
from openai import OpenAI

# 连接lmstdio服务器并选择模型
client = OpenAI(base_url="http://127.0.0.1:1234/v1", api_key="lm-studio")  # 连接lmstdio服务器
model = "gemma-2-9b-it"  # 选择模型


# 设计需要调用的函数
def add_data(num1: float, num2: float) -> float:
    return num1 + num2

def minus_data(num1: float, num2: float) -> float:
    return num1 - num2

def multiply_data(num1: float, num2: float) -> float:
    return num1 * num2

def divide_data(num1: float, num2: float) -> float:
    return num1 / num2

def compare_data(num1: float, num2: float) -> str:
    if num1 > num2:
        return True
    else:
        return False

tools = [
    {
        "type": "function",
        "function": {
            "name": "add_data",
            "description": "将两个数字相加,当用户询问某两个数字相加求结果时,调用此函数",
            "parameters": {
                "type": "object",
                "properties": {
                    "num1": {
                        "type": "number",
                        "description": "第一个数字",
                    },
                    "num2": {
                        "type": "number",
                        "description": "第二个数字",
                    },
                },
                "required": ["num1", "num2"],
                "additionalProperties": False,
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "minus_data",
            "description": "将两个数字相减,当用户询问某两个数字相减求结果时,调用此函数",
            "parameters": {
                "type": "object",
                "properties": {
                    "num1": {
                        "type": "number",
                        "description": "第一个数字",
                    },
                    "num2": {
                        "type": "number",
                        "description": "第二个数字",
                    },
                },
                "required": ["num1", "num2"],
                "additionalProperties": False,
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "multiply_data",
            "description": "将两个数字相乘,当用户询问某两个数字相乘求结果时,调用此函数",
            "parameters": {
                "type": "object",
                "properties": {
                    "num1": {
                        "type": "number",
                        "description": "第一个数字",
                    },
                    "num2": {
                        "type": "number",
                        "description": "第二个数字",
                    },
                },
                "required": ["num1", "num2"],
                "additionalProperties": False,
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "divide_data",
            "description": "将两个数字相除,当用户询问某两个数字相除求结果时,调用此函数",
            "parameters": {
                "type": "object",
                "properties": {
                    "num1": {
                        "type": "number",
                        "description": "第一个数字",
                    },
                    "num2": {
                        "type": "number",
                        "description": "第二个数字",
                    },
                },
                "required": ["num1", "num2"],
                "additionalProperties": False,
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "compare_data",
            "description": "将两个数字相比较,当用户询问某两个数字比较大小时,调用此函数,当函数返回True时,表示第一个数字大于第二个数字,否则表示第一个数字小于或等于第二个数字",
            "parameters": {
                "type": "object",
                "properties": {
                    "num1": {
                        "type": "number",
                        "description": "第一个数字",
                    },
                    "num2": {
                        "type": "number",
                        "description": "第二个数字",
                    },
                },
                "required": ["num1", "num2"],
                "additionalProperties": False,
            },
        },
    }
]

messages = [
    {
        "role": "system",
        "content": "您是一位乐于助人的客户支持助理。使用提供的工具协助用户。",
    },
    {
        "role": "user",
        "content": "8.9和8.11相比较谁更大",
    },
]

# LM Studio
response = client.chat.completions.create(
    model=model,
    messages=messages,
    tools=tools,
)

下方函数 process_tool_calls 的设计目的是处理从模型返回的工具调用(tool calls)信息,并执行相应的函数操作:

首先,函数从模型的响应中提取工具调用信息,并将其封装为一个包含工具调用详细信息的字典,随后将该信息添加到消息列表 messages 中。接着,函数遍历每个工具调用,解析其参数并调用相应的函数(如 add_datamultiply_data 等),将函数执行结果封装为工具调用结果消息,并同样添加到消息列表中。最后,函数将更新后的消息列表发送回模型以获取最终的响应。整个过程实现了对工具调用的解析、执行和结果反馈的完整流程,确保模型能够动态调用外部函数并处理复杂任务。

def process_tool_calls(response, messages):
    """此处我们定义一个函数,用于处理工具调用"""
    # 我们首先需要从模型返回的响应中提取出函数调用的信息。
    tool_calls = response.choices[0].message.tool_calls

    # 创建一个字典,用于存储工具调用的信息
    assistant_tool_call_message = {
        "role": "assistant",
        "tool_calls": [
            {
                "id": tool_call.id,
                "type": tool_call.type,
                "function": tool_call.function,
            }
            for tool_call in tool_calls
        ],
    }

    # 将工具调用信息添加到消息列表中
    messages.append(assistant_tool_call_message)

    # 创建一个空列表,用于存储工具调用的结果
    tool_results = []
    for tool_call in tool_calls:
        # 获取工具调用的参数
        arguments = (
            json.loads(tool_call.function.arguments)
            if tool_call.function.arguments.strip()
            else {}
        )

        # 确定要调用的函数
        fun_name = tool_call.function.name
        if fun_name == "add_data":
            result = add_data(**arguments)
        elif fun_name == "multiply_data":
            result = multiply_data(**arguments)
        elif fun_name == "divide_data":
            result = divide_data(**arguments)
        elif fun_name == "compare_data":
            result = compare_data(**arguments)
        else:
            result = "未知函数"

        # 添加工具调用的结果到工具调用结果列表中
        tool_result_message = {
            "role": "tool",
            "content": json.dumps(result),
            "tool_call_id": tool_call.id,
        }
        tool_results.append(tool_result_message)
        messages.append(tool_result_message)

    # 得到最终结果
    final_response = client.chat.completions.create(
        model=model,
        messages=messages,
    )

    return final_response

前文中我们询问到:“8.9和8.11相比较谁更大”,来看看最终的输出结果吧!

final_response = process_tool_calls(response, messages)
print(final_response.choices[0].message.content)
8.9 是更大的数。 

在不断实验中我们发现,当询问内容与tools中函数的description描述越接近,越容易触发工具调用,因此建议在询问中尽量出现与description相同或相近的语句,这样会更容易触发工具调用。

相关文章:

  • Python中有哪些基本数据类型?
  • 软考~系统规划与管理师考试——真题篇——2021年5月——论文——纯享题目版
  • ClickHouse 的分区、分桶和分片详解
  • 计算机毕业设计SpringBoot+Vue.js学科竞赛管理系统(源码+文档+PPT+讲解)
  • qt5的中文乱码问题,QString、QStringLiteral 为 UTF-16 编码
  • 状态模式
  • RK3588部署YOLOv8(1):YOLOv8和YOLOv8-pose转ONNX及Python后处理代码实现
  • 人工智能定义
  • AI学习第五天-python的基础使用-趣味图形
  • DeepSeek:面向效率与垂直领域的下一代大语言模型技术解析
  • 2025年电气工程与智能系统国际学术会议(IC2EIS 2025)
  • order by布尔盲注、时间盲注
  • 【算法通关村 Day11】位运算
  • 计算机三级网络技术备考(2)
  • vue测试:单元测试、组件测试、端到端测试
  • Cuckoo Hashing的变体:多哈希表多槽位版本
  • SOME/IP-SD -- 协议英文原文讲解4
  • 为AI聊天工具添加一个知识系统 之123 详细设计之64 人类文化和习俗,即文化上的差异-根本差异
  • 如何搭建起成熟的团队知识文档管理系统
  • 仿真环境下实现场景切换、定位物体和导航行走
  • 移动互联网未成年人模式正式发布
  • 民营经济促进法出台,自今年5月20日起施行
  • 五月院线片单:就看五一档表现了
  • 大理杨徐邱再审上诉案宣判:驳回上诉,维持再审一审判决
  • 中消协发布“五一”消费提示:践行“光盘行动”,抵制餐饮浪费
  • 国家税务总局:“二套转首套”可以享受贷款利息个税专项扣除