大模型function calling多轮对话开发示例

OpenAI接口支持的function calling使得大模型能够方便的集成外部能力和数据,是实现agent(智能体)的重要基础,能让LLM和各种功能集成,从而解决复杂的问题。 对于兼容openai接口的大模型如阿里的通义千问,也是可以使用类似的方法进行调用。

模型实际上从不自行执行函数,仅生成需要调用的函数名称和调用的参数,应用自行判断执行,对于langchain等框架则把这一层封装到框架中。并且传入的函数描述,和输出的函数调用描述都是计算在token上。

如果确实想使用openai相关模型,可以通过点击我的推荐链接 https://referer.shadowai.xyz/r/1017200 ,进入CloseAI平台,该平台提供商用级OpenAI代理服务。

或者也可以使用兼容openai接口的模型,如阿里百炼 https://bailian.console.aliyun.com/

开发流程通常如下:

复制代码
步骤1:定义一个你希望模型调用的函数
步骤2:向模型描述你的函数,以便它知道如何调用它
步骤3:将您的函数定义作为可用的"工具"传递给模型,同时附上消息内容
步骤4:接收并处理模型响应
步骤5:将函数调用结果返回给模型
步骤6:流程如果尚未结束可以继续循环上述步骤.

以下我们用一个使用大模型openai的function calling并且是多轮对话的例子进行讲解。

场景如下,在用户需要查询本机内存使用情况的时候如果可用内存超过80%时,保存至文件mem_high.txt;不超过80%时,保存到mem_ok.txt。

因此我们提供了能够一个查询本机可用内存和一个保存文本到本地文件工具函数,那么我们应该怎么让大模型进行调用呢?

  1. 安装所需库:psuti、openai。psutil = process and system utilities,支持linux,mac和windows操作系统,实现系统信息获取和监控

    pip install psutil openai

  2. 准备大模型的apikey,兼容openai接口协议即可。

  3. 以下是详细的代码及解释

python 复制代码
from openai import OpenAI
from openai.types.chat.chat_completion_message_function_tool_call import ChatCompletionMessageFunctionToolCall
import psutil
import json
import os

# 可以选用兼容openai接口的相关平台base_url和api_key
client = OpenAI(
    api_key="xxxx",
    base_url="xxxx"
)


def get_memory_info():
    mem = psutil.virtual_memory()
    mem_info = {"total": mem.total, "available": mem.available, "used": mem.used, "free": mem.free}
    return json.dumps(mem_info)


def write_file(file_name, text):
    with open(file_name, "w", encoding="utf-8") as f:
        f.write(text)


def do_function_tool_call(function_tool_call: ChatCompletionMessageFunctionToolCall):
    """
    基于大模型返回的函数调用说明,进行函数调用,并且构造tool的message返回
    """
    function_call = function_tool_call.function
    name = function_call.name
    args = function_call.arguments
    if name == "get_memory_info":
        func_result = get_memory_info()
    elif name == "write_file":
        args_dict = json.loads(args)
        func_result = write_file(args_dict["file_name"], args_dict["text"])
    else:
        raise Exception("unkown function:" + name)
    if func_result is None:
        func_result = ""
    ## 需要把response的关联的function_tool_call设置tool_call_id
    tool_message = {"role": "tool", "tool_call_id": function_tool_call.id, "content": func_result}
    return tool_message


## 以下对传递给llm的工具集描述,注意在早期版本是使用functions参数进行调用格式上会有所差异,openai认为tools可以支持更加广泛的工具支持因此推荐使用tools传参
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_memory_info",
            "description": "获取系统内存,会将系统的内存情况用json格式返回",
            "parameters": {
                "type": "object",
                "properties": {},
                "required": []
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "write_file",
            "description": "将文本数据写入文件",
            "parameters": {
                "type": "object",
                "properties": {
                    "file_name": {
                        "type": "string",
                        "description": "文件名"
                    },
                    "text": {
                        "type": "string",
                        "description": "写入的文本数据"
                    }
                },
                "required": ["file_name", "text"]
            }
        }
    }]

user_input = "需要帮我计算电脑的内存使用率和具体的使用情况,如果内存使用率超过80%,将情况写到mem_high.txt文件,否则写到mem_ok.txt"
messages = [{"role": "user", "content": user_input}]
response = client.chat.completions.create(
    model="gpt-4-turbo",
    messages=messages,
    tools=tools
)

resp_msg = response.choices[0].message
# 多轮对话将大模型的返回结果,继续放回
messages.append(resp_msg)
# 实现多轮对话,首先会执行查询内存函数调用对于实际开发来说需要严格tool_calls是否为空再决定是否调用
function_tool_call = resp_msg.tool_calls[0]
# 大模型只返回需要调用的函数名称和参数,需要应用自行调用。
tool_message = do_function_tool_call(function_tool_call)
# 将函数(工具)执行结果封装成tool类型返回.
messages.append(tool_message)
response = client.chat.completions.create(
    model="gpt-4-turbo",
    messages=messages,
    tools=tools
)

# 实现多轮对话,执行写入函数的调用
resp_msg = response.choices[0].message
messages.append(resp_msg)
function_tool_call = resp_msg.tool_calls[0]
tool_message = do_function_tool_call(function_tool_call)
messages.append(tool_message)


response = client.chat.completions.create(
    model="gpt-4-turbo",
    messages=messages,
    tools=tools
)
print(response.choices[0].message.content)

最终的输出: