AI大模型探索之路-实战篇8:多轮对话与Function Calling技术应用

系列篇章💥

AI大模型探索之路-实战篇4:深入DB-GPT数据应用开发框架调研
AI大模型探索之路-实战篇5:探索Open Interpreter开放代码解释器调研
AI大模型探索之路-实战篇6:掌握Function Calling的详细流程
AI大模型探索之路-实战篇7:Function Calling技术实战自动生成函数


目录

  • 系列篇章💥
  • 一、前言
  • 二、封装调用2轮response的函数
    • 1、输出函数列表
    • 2、function函数调用封装
    • 3、定义参数数据
    • 4、测试函数tangseng_function
    • 5、测试函数sunwukong_function
    • 6、测试函数(描述中不指明信息)
  • 三、增加多轮对话的效果
    • 1、创建OpenAI客户端
    • 2、定义工具函数
    • 3、定义函数生成器
    • 4、封装大模型2次API调用
    • 5、多轮对话函数定义
    • 6、函数列表定义
    • 7、对话调用测试
  • 四、结语


一、前言

继前文深入探讨了Function Calling的操作流程并成功实验自动生成function函数之后,本文将进一步深化我们的研究,具体考察OpenAI的Function Calling技术在现实应用中的表现。此次研究的重点在于封装一个能够调用两轮response的函数,并在此基础上执行多轮对话的测试,从而全面评估该技术在实际应用中的效率和效果。

通过精心设计的实验,我们将探索这项技术的潜力及其在智能数据分析平台上的应用前景。我们的目标是为平台的顺利实施构建一个稳固且高效的技术基础。这不仅涉及到技术层面的优化,也关系到如何在实际应用中提供更流畅的用户体验和更准确的数据处理能力。

在本文中,我们将详细阐述这一过程的每个步骤,从技术选型到功能实现,再到最终的效果评估。我们希望通过对OpenAI的Function Calling技术的深入分析和应用展示,为未来相关技术的发展和应用场景的拓展提供有益的参考和启示。

二、封装调用2轮response的函数

在实现function call的过程中,我们通常需要进行两次关键的调用。
1)第一次调用:目的是让强大的大型模型协助我们识别并选择恰当的工具函数。这就像在进行一场棋局,首先需要确定使用哪个棋子。一旦选定,接下来的步骤便是实际调用该工具函数,执行具体的任务。
2)第二次调用:这一次,我们再次借助大模型的强大能力,其任务是将工具函数处理后的结果进行整合和优化,以最清晰、最易于理解的形式呈现最终输出。这可以比喻为将散落的珠子串成一串光彩夺目的项链,使其更具有观赏价值和实用价值。

在本章节中,我们将重点介绍如何将这两阶段的调用过程进行有效的封装,使其成为一个独立、可复用的模块。这种封装不仅简化了操作流程,还提高代码的可维护性和扩展性,为未来的功能拓展或技术升级提供了便利。

1、输出函数列表

继上文中,我们定义了2个工具函数

def sunwukong_function(data):
    """
    孙悟空算法函数,该函数定义了数据集计算过程
    :param data: 必要参数,表示带入计算的数据表,用字符串进行表示
    :return:sunwukong_function函数计算后的结果,返回结果为表示为JSON格式的Dataframe类型对象
    """
    data = io.StringIO(data)
    df_new = pd.read_csv(data, sep='\s+', index_col=0)
    res = df_new * 10
return json.dumps(res.to_string())

#在定义一个工具函数,一起测试
def tangseng_function(data):
    """
    唐僧算法函数,该函数定义了数据集计算过程
    :param data: 必要参数,表示带入计算的数据表,用字符串进行表示
    :return:tangseng_function函数计算后的结果,返回结果为表示为JSON格式的Dataframe类型对象
    """
    data = io.StringIO(data)
    df_new = pd.read_csv(data, sep='\s+', index_col=0)
    res = df_new * 1000000
    return json.dumps(res.to_string())
    
# 将2个函数放入函数列表
functions_list=[sunwukong_function,tangseng_function]

输出函数列表:

functions_list

输出:
在这里插入图片描述

2、function函数调用封装

def run_conversation(messages, functions_list=None, model="gpt-3.5-turbo"):
    """
    能够自动执行外部函数调用的对话模型
    :param messages: 必要参数,字典类型,输入到Chat模型的messages参数对象
    :param functions_list: 可选参数,默认为None,可以设置为包含全部外部函数的列表对象
    :param model: Chat模型,可选参数,默认模型为gpt-3.5-turbo
    :return:Chat模型输出结果
    """
    # 如果没有外部函数库,则执行普通的对话任务
    if functions_list == None:
        response = client.chat.completions.create(
                        model=model,
                        messages=messages,
                        )
        response_message = response.choices[0].message
        final_response = response_message.content
        
    # 若存在外部函数库,则需要灵活选取外部函数并进行回答
    else:
        # 创建functions对象
        tools = auto_functions(functions_list)

        # 创建外部函数库字典
        available_functions = {func.__name__: func for func in functions_list}

        # 第一次调用大模型,寻找工具函数
        response = client.chat.completions.create(
                        model=model,
                        messages=messages,
                        tools=tools,
                        tool_choice="auto", )
        response_message = response.choices[0].message


        tool_calls = response_message.tool_calls

        if tool_calls:

            messages.append(response_message) 
            for tool_call in tool_calls:
                function_name = tool_call.function.name
                function_to_call = available_functions[function_name]
                function_args = json.loads(tool_call.function.arguments)
                ## 真正执行外部函数的就是这儿的代码
                function_response = function_to_call(**function_args)
                messages.append(
                    {
                        "tool_call_id": tool_call.id,
                        "role": "tool",
                        "name": function_name,
                        "content": function_response,
                    }
                ) 
            ## 第二次调用模型,将响应结果,给到大模型进行转为为更为可视化的数据格式,再返回给用户
            second_response = client.chat.completions.create(
                model=model,
                messages=messages,
            ) 
            # 获取最终结果
            final_response = second_response.choices[0].message.content
        else:
            final_response = response_message.content
                
    return final_response

3、定义参数数据

df_str = pd.DataFrame({'x1':[1, 2], 'x2':[3, 4]}).to_string()
df_str

在这里插入图片描述

4、测试函数tangseng_function

# 定义消息列表
messages = [
        {"role": "system", "content": "数据集data:%s,数据集以字符串形式呈现" % df_str},
        {"role": "user", "content": '请在data上执行唐僧算法函数'}]


# API调用测试
run_conversation(messages = messages, functions_list = functions_list)

输出:
在这里插入图片描述

5、测试函数sunwukong_function

# 定义消息列表
messages = [
        {"role": "system", "content": "数据集data:%s,数据集以字符串形式呈现" % df_str},
        {"role": "user", "content": '请在data上执行孙悟空算法函数'}]

# API调用测试
run_conversation(messages = messages, functions_list = functions_list)

输出:
在这里插入图片描述

6、测试函数(描述中不指明信息)

# 定义消息列表
messages = [
        {"role": "system", "content": "数据集data:%s,数据集以字符串形式呈现" % df_str},
        {"role": "user", "content": '请解释一下data数据集'}]

# API调用测试
run_conversation(messages = messages, functions_list = functions_list)

输出:
在这里插入图片描述

根据结果可以看出,大模型并没有成功调用工具函数

三、增加多轮对话的效果

在实现function call技术的过程中,我们不仅需要关注单次调用的优化,还需要注重多轮对话的效果。本章节将介绍如何通过引入两个工具函数,来测试大型模型在面对涉及工具函数的问题时,是否能准确识别并调用相应的工具。

1、创建OpenAI客户端

import openai
import os
import numpy as np
import pandas as pd
import json
import io
from openai import OpenAI
import inspect
# 定义api key
openai.api_key = os.getenv("OPENAI_API_KEY")

#创建OpenAI客户端
client = OpenAI(api_key=openai.api_key )

2、定义工具函数

def sunwukong_function(data):
    """
    孙悟空算法函数,该函数定义了数据集计算过程
    :param data: 必要参数,表示带入计算的数据表,用字符串进行表示
    :return:sunwukong_function函数计算后的结果,返回结果为表示为JSON格式的Dataframe类型对象
    """
    data = io.StringIO(data)
    df_new = pd.read_csv(data, sep='\s+', index_col=0)
    res = df_new * 10
    return json.dumps(res.to_string())
    
def tangseng_function(data):
    """
    唐僧算法函数,该函数定义了数据集计算过程
    :param data: 必要参数,表示带入计算的数据表,用字符串进行表示
    :return:tangseng_function函数计算后的结果,返回结果为表示为JSON格式的Dataframe类型对象
    """
    data = io.StringIO(data)
    df_new = pd.read_csv(data, sep='\s+', index_col=0)
    res = df_new * 1000000
    return json.dumps(res.to_string())

3、定义函数生成器

def auto_functions(functions_list):
    """
    Chat模型的functions参数编写函数
    :param functions_list: 包含一个或者多个函数对象的列表;
    :return:满足Chat模型functions参数要求的functions对象
    """
    def functions_generate(functions_list):
        # 创建空列表,用于保存每个函数的描述字典
        functions = []
        # 对每个外部函数进行循环
        for function in functions_list:
            # 读取函数对象的函数说明
            function_description = inspect.getdoc(function)
            # 读取函数的函数名字符串
            function_name = function.__name__

            system_prompt = '以下是某的函数说明:%s' % function_description
            user_prompt = '根据这个函数的函数说明,请帮我创建一个JSON格式的字典,这个字典有如下5点要求:\
                           1.字典总共有三个键值对;\
                           2.第一个键值对的Key是字符串name,value是该函数的名字:%s,也是字符串;\
                           3.第二个键值对的Key是字符串description,value是该函数的函数的功能说明,也是字符串;\
                           4.第三个键值对的Key是字符串parameters,value是一个JSON Schema对象,用于说明该函数的参数输入规范。\
                           5.输出结果必须是一个JSON格式的字典,只输出这个字典即可,前后不需要任何前后修饰或说明的语句' % function_name

            response = client.chat.completions.create(
                              model="gpt-3.5-turbo",
                              messages=[
                                {"role": "system", "content": system_prompt},
                                {"role": "user", "content": user_prompt}
                              ]
                            )
            json_function_description=json.loads(response.choices[0].message.content.replace("```","").replace("json",""))
            json_str={"type": "function","function":json_function_description}
            functions.append(json_str)
        return functions
    ## 最大可以尝试4次
    max_attempts = 4
    attempts = 0

    while attempts < max_attempts:
        try:
            functions = functions_generate(functions_list)
            break  # 如果代码成功执行,跳出循环
        except Exception as e:
            attempts += 1  # 增加尝试次数
            print("发生错误:", e)
            if attempts == max_attempts:
                print("已达到最大尝试次数,程序终止。")
                raise  # 重新引发最后一个异常
            else:
                print("正在重新运行...")
    return functions

4、封装大模型2次API调用

def run_conversation(messages, functions_list=None, model="gpt-3.5-turbo"):
    """
    能够自动执行外部函数调用的对话模型
    :param messages: 必要参数,字典类型,输入到Chat模型的messages参数对象
    :param functions_list: 可选参数,默认为None,可以设置为包含全部外部函数的列表对象
    :param model: Chat模型,可选参数,默认模型为gpt-3.5-turbo
    :return:Chat模型输出结果
    """
    # 如果没有外部函数库,则执行普通的对话任务
    if functions_list == None:
        response = client.chat.completions.create(
                        model=model,
                        messages=messages,
                        )
        response_message = response.choices[0].message
        final_response = response_message.content
        
    # 若存在外部函数库,则需要灵活选取外部函数并进行回答
    else:
        # 创建functions对象
        tools = auto_functions(functions_list)

        # 创建外部函数库字典
        available_functions = {func.__name__: func for func in functions_list}

        # 第一次调用大模型
        response = client.chat.completions.create(
                        model=model,
                        messages=messages,
                        tools=tools,
                        tool_choice="auto", )
        response_message = response.choices[0].message


        tool_calls = response_message.tool_calls

        if tool_calls:

            messages.append(response_message) 
            for tool_call in tool_calls:
                function_name = tool_call.function.name
                function_to_call = available_functions[function_name]
                function_args = json.loads(tool_call.function.arguments)
                ## 真正执行外部函数的就是这儿的代码
                function_response = function_to_call(**function_args)
                messages.append(
                    {
                        "tool_call_id": tool_call.id,
                        "role": "tool",
                        "name": function_name,
                        "content": function_response,
                    }
                ) 
            ## 第二次调用模型
            second_response = client.chat.completions.create(
                model=model,
                messages=messages,
            ) 
            # 获取最终结果
            final_response = second_response.choices[0].message.content
        else:
            final_response = response_message.content
                
    return final_response

5、多轮对话函数定义

def chat_with_model(functions_list=None, 
                    prompt="你好", 
                    model="gpt-3.5-turbo", 
                    system_message=[{"role": "system", "content": "你是小智助手。"}]):
    
    messages = system_message
    messages.append({"role": "user", "content": prompt})
    
    while True:           
        answer = run_conversation(messages=messages, 
                                    functions_list=functions_list, 
                                    model=model)
        
        print(f"智能助手回答: {answer}")
        
        
        # 询问用户是否还有其他问题
        user_input = input("您还有其他问题吗?(输入退出以结束对话): ")
        if user_input == "退出":
            break

        # 记录用户回答
        messages.append({"role": "user", "content": user_input})

6、函数列表定义

functions_list=[sunwukong_function,tangseng_function]

7、对话调用测试

chat_with_model(functions_list,prompt="你好")

gpt3.5生成json schema还是会不太稳定,经常会生成失败,如下:
在这里插入图片描述

调用成功效果如下:
在这里插入图片描述
以下是我测试的对话过程
问题1:你好
问题2:1+2
问题3:什么是孙悟空函数
问题4:数据集data以字符串形式呈现如下:’ x1 x2\n0 1 3\n1 2 4’,请在数据集data上执行孙悟空算法

智能助手回复结果如下:
在这里插入图片描述

四、结语

在本文中,我们深入探讨了function call技术中对大型模型API进行两次调用的进一步封装方法,并实践了这一方法以实现多轮对话的效果。通过精心设计的技术策略和实验,我们不仅优化了API调用流程,还成功地将这些技术应用于实际的对话场景中,使得交互更加流畅和自然。这一成果不仅展示了function call技术的高级应用,也为未来更复杂的应用场景提供了可能。

在这里插入图片描述

🎯🔖更多专栏系列文章:AIGC-AI大模型探索之路

如果文章内容对您有所触动,别忘了点赞、⭐关注,收藏!加入我,让我们携手同行AI的探索之旅,一起开启智能时代的大门!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/649197.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构的直接插入排序(C语言版)

一.直接插入排序的基本概念 1.直接插入排序的基本思想 将数组分为已排序和未排序两部分。 每次从未排序部分取出一个元素,将其插入到已排序部分的合适位置,使得已排序部分保持有序。 重复步骤2,直到整个数组有序。 2.排序的工作原理 假设前 i-1 个元素已经有序,现在要将第…

基于微信小程序+ JAVA后端实现的【医院挂号预约系统】 设计与实现 (内附设计LW + PPT+ 源码+ 演示视频 下载)

项目名称 项目名称&#xff1a; 《基于微信小程序的医院挂号预约系统设计与实现》 项目技术栈 该项目采用了以下核心技术栈&#xff1a; 后端框架/库&#xff1a; Java, SSM框架数据库&#xff1a; MySQL前端技术&#xff1a; 微信小程序, uni-app 项目展示 全文概括 本…

Linux_应用篇(09) 进程

本章将讨论进程相关的知识内容&#xff0c; 虽然在前面章节内容已经多次向大家提到了进程这个概念&#xff0c;但并未真正地向大家解释这个概念&#xff1b;在本章&#xff0c;我们将一起来学习 Linux 下进程相关的知识内容&#xff0c;虽然进程的基本概念比较简单&#xff0c;…

Tensors张量操作

定义Tensor 下面是一个常见的tensor&#xff0c;包含了里面的数值&#xff0c;属性&#xff0c;以及存储位置 tensor([[0.3565&#xff0c;0.1826&#xff0c;0.6719],[0.6695&#xff0c;0.5364&#xff0c;0.7057]]&#xff0c;dtypetorch.float32,devicecuda:0)Tensor的属…

【动态规划】零基础解决路径问题(C++)

目录 62.路径问题 解法&#xff08;动态规划&#xff09;&#xff1a; 1. 状态表⽰&#xff1a; 2. 状态转移⽅程&#xff1a; 3. 初始化&#xff1a; 4. 填表顺序&#xff1a; 5. 返回值&#xff1a; 不同路径2.0 解法&#xff08;动态规划&#xff09;&#xff1a; …

LLM中的RoPE位置编码代码解析与RoPE的性质分析(一)

本博客需要对位置编码有一定了解&#xff0c;但不熟悉代码实现的老哥看。 正弦位置编码&#xff08;sinusoidal&#xff09; 在介绍RoPE之前&#xff0c;先回顾一下正弦位置编码。 数学表达 P E ( p o s , 2 i ) s i n ( p o s 1000 0 2 i / d m o d e l ) PE(pos, 2i) sin…

行转列——kettle开发14

一、行转列 如图所示&#xff0c;行转列就是把数据字段的字段名转换为一列&#xff0c;把数据行变成数据列。即我们将昨天输出的张三在周一至周日的工作小时转换为7行数据。对应7行数据分别为张三在周一工作多个小时&#xff0c;在周二工作多少个小时等等。 我们来看下行转列组…

怎么设置电脑锁屏密码?一键给你的电脑“上锁”

在保护个人电脑安全方面&#xff0c;设置锁屏密码是一种简单而有效的方法。无论是在家里还是在公共场所&#xff0c;锁屏密码都可以有效防止他人未经授权访问您的电脑&#xff0c;保护您的隐私和数据安全。 然而&#xff0c;对于一些新手用户来说&#xff0c;怎么设置电脑锁屏…

期货学习笔记-横盘行情学习1

横盘行情的特征及分类 横盘行情的概念 横盘行情时中继形态的一种&#xff0c;一般常出现在大涨或大跌之后出现横盘行情是对当前趋势行情的修正&#xff0c;是对市场零散筹码的清理&#xff0c;是为了集中筹码更便于后期行情的展开 横盘行情的特征 1.水平运动&#xff1a;该…

Java基础-反射原理

总结放前面&#xff1a; 反射是可以通过一个类对象或类名称获取到该类的全部信息&#xff08;属性和方法&#xff09;&#xff0c;包括为权限为private。 要使用反射第一步&#xff0c;要获取的类的Class对象&#xff0c;该Class对象存放在堆区&#xff0c;于类加载时创建&…

互联网政务应用安全管理规定:使用安全连接方式访问

前几日&#xff0c;由中央网络安全和信息化委员会办公室、中央机构编制委员会办公室、工业和信息化部、公安部等4部门联合制定的《互联网政务应用安全管理规定》&#xff08;以下简称规定&#xff09;发布了&#xff0c;规定定义了互联网政务应用&#xff0c;也对互联网政务应用…

[GDB] GDB调试

目录 一 简介 二 功能: 三 命令: 四 调试准备: 五 开始调试: 5.1 添加断点&#xff1a; 5.2 条件编译 5.3 断点查看 5.4 断点删除: 5.5 查看源码 5.6 单步调试(逐过程)&#xff1a; 5.7 断点调试: 5.8 单步跟踪(逐语句): 5.9 调试过程&#xff1a; 5.9.1 开始调…

一屏万象,场景无限:蓝牙墨水屏标签多功能多场景应用带您领略未来

在数字化浪潮汹涌澎湃的今天&#xff0c;智能科技产品层出不穷&#xff0c;它们不仅极大地改变了我们的生活方式&#xff0c;更在无形中拓宽了我们的视野。而今&#xff0c;一款融合了创新技术与实用性于一体的蓝牙墨水屏标签&#xff0c;正以其多功能多场景应用的特性&#xf…

【wiki知识库】02.wiki知识库SpringBoot后端的准备

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 一、&#x1f525;今日目标 二、&#x1f4c2;打开SpringBoot项目 2.1 导入所需依赖 2.2修改application.yml配置文件 2.3导入MybatisPlus逆向工程工具 2.4创建一个公用的返回值 2.5创建CopyUtil工具类 2.6创建…

固定Linux的ip地址,通过图形化界面操作,简单易上手

目录 1、查看Linux的网络 2、修改设置 3、修改Windows网络设置 1、查看Linux的网络 2、修改设置 3、修改Windows网络设置 Microsoft Windows [版本 10.0.19045.3996] (c) Microsoft Corporation。保留所有权利。C:\Users\dgq>ipconfigWindows IP 配置无线局域网适配器 WLAN:…

DataGrip软件执行已将创建好的sql文件步骤

一、在需要导入sql文件上右击找到SQLScript &#xff0c;然后点击 Run SQL Script 二、找到sql文件&#xff0c;点击OK就可以了

【编译原理复习笔记】正则表达式与自动机

正则表达式 正则表达式是一种用来描述正则语言的更紧凑的表达方法 e.g. r a ( a ∣ b ) ∗ ( ϵ ∣ ( . ∣ ) ( a ∣ b ) ) ra(a|b)^*(\epsilon|(.|\\_ )(a|b)) ra(a∣b)∗(ϵ∣(.∣)​(a∣b)) 正则表达式可以由较小的正则表达式按照特定的规则递归地构建。每个正则表达式定义…

【软件设计师】程序语言

1.程序设计语言基本概念 1.1 低级语言与高级语言 低级语言&#xff1a;机器语言和汇编语言称为低级语言 机器语言指0.&#xff0c;1组成的机器指令序列 汇编语言指用符号表示指令的语言&#xff0c;如MOV AX&#xff0c;2 高级语言&#xff1a;从人类的逻辑角度出发&#xff0…

蓝卓入选工信部2023年度“揭榜挂帅”项目

蓝卓“面向多元异构和应用快速开发演化的智能工厂操作系统解决方案”&#xff0c;凭借行业领先的平台技术能力以及数智赋能的硬核实力成功揭榜挂帅。 本次入选不仅代表了蓝卓又一次获得工信部权威专家及国家认可&#xff0c;更是“工厂操作系统”首次在国家层面获得表彰。 智能…

听说京东618裁员?所以日常准备很重要呀

文末有最少必要的面试题&#xff0c;还准备了离线 PDF 版本。 京东也要向市场输送人才了? 这几天看到技术群里不少朋友在讨论京东裁员相关的信息。 我去看了下京东近期的操作&#xff0c;京东内部考勤调整和午休时间缩短&#xff0c;以及强化打卡机制等管理调整&#xff1b;有…