当前位置:   article > 正文

[DL]ChatGLM3_chatglm3 function calling

chatglm3 function calling

ChatGLM3训练数据更多样、训练步数更充分、训练策略更合理,在语义、数学、推理、代码、知识等不同角度的数据集上表现出色,目前在44个中英文公开数据集测试国内第一。

在这里插入图片描述

I-ChatGLM3的功能变化

1.全新的多消息模式

从一问一答的对话模式转为多角色问答模型,如下图

在这里插入图片描述

2.史诗级的更新点 – Function Calling

2023年6月Function Calling功能首次由OpenAI宣布在Chat Completion模型中进行使用,代表着Chat模型不再需要LangChain框架就可以直接在模型内部调用外部工具API,从而更便捷的使用LLM,进行AI Agent的开发。

LangChain框架

LangChain是一个用于开发由语言模型驱动的应用程序的框架。

主要功能:

  1. 调用语言模型
  2. 将不同的数据源接到语言模型的交互中
  3. 允许语言模型与运行环境交互

提供的模块:

  1. Modules:支持的模型类型和集成
  2. Prompt:提示词管理、优化和序列
  3. Memory:在链/代理调用之间持续存在的状态
  4. Indexes:加载、查询和更新外部数据的接口和集成
  5. Chain:结构化的调用序列
  6. Agents:链,其中LLM在给定高级指令和一组工具的情况下,反复决定操作,执行操作并观察结果,直到高级指令完成
  7. Callbacks:回调允许记录和流式传输任何链的中间步骤,从而轻松观察、调试和评估应用程序内部

基于LangChain+ChatGLM的本地知识库问答实现原理流程图

在这里插入图片描述

Function Calling功能可以弥补LLM的一些缺点,比如实时信息的缺乏、特定领域能力,使得能够进一步利用LLM的逻辑推理能力,可以将问题进行分解处理,解决问题能力更加强大。

基于Function Calling可以开发什么AI Agent

简单类AI Agent项目:

  • Function Calling + OpenWeather:智能查询天气信息的应用
  • Function Calling + 谷歌邮箱API:智能收发邮件的应用

进阶类AI Agent项目:

  • Function Calling + 谷歌搜索API + 爬虫:智能搜索问答机器人
  • Function Calling + pymysql + MySQL:定制化SQL代码解释器
  • Function Calling + python:代码解释器(code interpreter)
  • Function Calling + python+算法库:机器学习/深度学习助手

II-ChatGLM3的使用

类OpenAI Chat模型的调用方法

ChatGLM3模型提供了基于openai框架的调用使用方法,对于使用OpenAI API创建的应用而言,想要将基础模型更改为ChatGLM3,只需要将model参数修改为‘chatglm3-6b’即可。一个统一的调用方式对开发者来说是重大利好的。

import openai

if __name__ == "__main__":
    openai.api_base = "http://localhost:8000/v1"
    openai.api_key = "none"
    for chunk in openai.ChatCompletion.create(
    	model = "chatglm3-6b",
        messages = [
            {"role": "user", "content": "你好"}
        ],
        stream = True
    ):
        if hasatter(chunk.choices[0].delta, "content"):
            print(chunk.choices[0].delta.content, end="", flush=True)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
1.ChatGLM3调用流程及返回结果说明
response_glm3 = openai.ChatCompletion.create(
    model = "chatglm3-6b",
    messages = [
        {"role": "user", "content": "你好"}
    ]
)
print(response_glm3['choices'][0]['message']['content'])
# 输出为:你好!我是人工智能助手ChatGLM3-6B,很高兴见到你,欢迎问我任何问题。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

- messages:基本构成元素为字典的列表,每一个字典都代表一条独立的消息。role表示某条消息的作者,content表示消息的具体内容。

- choices:返回答案是一个列表,通过参数的设置,可以返回不止一条答案。

返回结果response_glm3是高度结构化的json对象,其结构如下图所示

在这里插入图片描述

- metadata:为调用的工具名。(Code Interpreter固定为interpreter。)

2.messages参数结构及功能解释

messages是一种用于描述ChatCompletion模型与用户之间通信信息的高级抽象,从表示形式上来看,一个messages是一个列表,包含多个字典,每一个字典都代表一条独立的消息。role表示某条消息的作者,content表示消息的具体内容。

- role:某条消息的作者。角色身份:system(系统提示词,指明模型扮演的角色信息),user(用户输入),assistant(模型回复),observation(工具调用、代码执行结果)。

- content:消息的具体内容。

为LLM模型指定某种虚拟身份,更便于激活模型能力。设置身份的方法主要有两种:

  • 一是在content中直接假设

    response_glm3 = openai.ChatCompletion.create(
        model = "chatglm3-6b",
        messages = [
            {"role": "user", "content": "假设你是一名资深的大学教授,请问机器学习是什么?"}
        ]
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 二是使用system role

    response_glm3 = openai.ChatCompletion.create(
        model = "chatglm3-6b",
        messages = [
            {"role": "system", "content": "假设你是一名资深的大学教授。"},
            {"role": "user", "content": "请问机器学习是什么?"}
        ]
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

III-ChatGLM3的Function Calling功能及示例

Function Calling功能的本质是让LLM调用外部函数,即Chat模型不再仅仅根据自身的数据库知识进行回答,而是可以额外挂载一个函数库,根据用户提问进行函数库检索,根据实际需求调用外部函数并获取函数运行结果,再基于函数运行结果进行回答。基本过程如下图所示:

在这里插入图片描述

智能查询天气信息的应用

1.查询天气函数实现(获取查询天气工具的API key,如OpenWeather)
import requests

def get_weather(loc):
    """
    查询即时天气预报
    param loc:当前需要查询城市的名称,中国城市要用对应城市的英文名称。
    :return:OpenWeather API查询即时天气的结果,返回结果对象类型为解析之后的JSON格式对象。
    """
    # step1 构建请求
    URL = "https://api.openweathermaporg/data/2.5/weather" 
    
    # step2 设置查询参数
    params = {
        "q": loc,
        "appid": open_weather_key,  # 获取的API key
        "units": "metric",  # 使用摄氏度而不是华氏度
        "lang": "zh_cn"  # 输出语言为简体中文
    }
    
    # step3 发送get请求
    response = requests.get(URL, params=params)
    
    # step4 解析响应
    data = response.json()
    return json.dumps(data)

# 测试函数是否能使用
weather = get_weather("Hangzhou")
print(weather)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

正常运行时,上述输出如下图所示

在这里插入图片描述

最后需要创建get_weather函数的functions参数

weather_api_spec = [
    {
        'name': 'get_weather',
        'description': '输入城市名称,查询即时天气函数。',
        'parameters': {
            'type': 'object',
            'properties': {
                'loc': {
                    'description': '城市名称,中国城市要用对应城市的英文名称。',
                    'type': 'string',
                    'required': True
                }
            }
        }
    }
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
2.实时查询天气的Function Calling实现

将get_weather函数放入函数库(写入functions_list函数列表),然后启用外链函数库之后的多伦对话机器人chat_with_model,查看对话效果。下面对整个对话流程进行简要的说明。

第一步:构建消息内容

# 设定LLM身份
system_info = {
    "role": "system",
    "content": "Answer the following questions a best as you can. You have access to the following tools:",
    "tools": weather_api_spec
}

# 用户提问消息内容
messages = [
    system_info,
    {
        "role": "user",
    	"content": "请问今天北京天气如何?" 
    }
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

第二步:首次调用LLM

# 第一次调用LLM
first_response = openai.ChatCompletion.create(
    model = "chatglm3-6b",
    messages = messages,
    return_function_call = True
)
first_response_message = first_response['choices'][0]['message']
print(first_response_message)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输出结果如下图所示

在这里插入图片描述

这表明想要获得问题的答案需要调用外部函数。

对first_response_message内容进行解析

function_call = json.loads(first_response_message.content)
print(function_call)
  • 1
  • 2

输出结果如下图所示

在这里插入图片描述

该解析结果中包含了需要调用的外部函数的名称以及所需参数。

第三步:外部函数调用

# 获取函数名及参数
function_name = function_call["name"]
function_args = function_call["parameters"]
# 获取外部函数
functions_list = [get_weather]
available_functions = {func.__name__: func for func in functions_list}
function_to_call = available_functions[function_name]
# 运行外部函数
function_response = function_to_call(**function_args)
print(function_response)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

输出结果如下图所示

在这里插入图片描述

得到的是外部函数运行的结果,接下来需要再一次使用LLM对上述结果进行解析并输出最初问题的答案。

第四步:第二次调用LLM

# messages中拼接first_response_message消息
messages.append(first_response_message)
# messages中拼接外部函数输出结果
messages.append(
    {
		"role": "observation",  # 角色为observation,表示为外部函数发的消息
        "name": function_name,
    	"content": function_response
    }
)

# 第二次调用LLM
second_response = openai.ChatCompletion.create(
    model = "chatglm3-6b",
    messages = messages
)
final_response = second_response['choices'][0]['message']['content']
print(final_response)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

输出结果如下图所示

在这里插入图片描述

3.函数封装

对上述过程进行函数封装,实现自动执行外部函数的LLM对话功能。

def run_conv_glm(messages, functions_list=None, functions=None, model="chatglm3-6b", return_function_call = True):
    """
    能够自动执行外部函数调用的Chat对话模型
    :param messages:必要参数,输入到对话模型的messages参数对象
    :param functions_list:可选参数,默认为None,可以设置为包含全部外部函数的函数列表
    :param functions:外部函数的说明
    :param model:可选参数,LLM模型,默认为chatglm3-6b
    :return:
    """
    def is_json_string(s):
        try:
            json_object = json.loads(s)
        except ValueError as e:
            retrun False
        return True
    
    user_messages = messages
    
    # 如果没有外部函数库,则执行普通的对话任务
    if functions_list == None:
        response = openai.ChatCompletion.create(
                        model = model,
                        messages = user_messages
                    )
        response_message = response['choices'][0]['message']
        final_response = response_message['content']
    # 有外部函数库
	else:
        # 创建外部函数的system_message
        system_info = {
            "role": "system",
            "content": "Answer the following questions a best as you can. You have access to the following tools:",
            "tools": functions
        }
        # 创建外部函数库字典
        available_functions = {func.__name__: func for func in functions_list}
        # 创建包含用户问题的messages
        messages = system_info + user_messages
        # first response
        first_response = openai.ChatCompletion.create(
            model = "chatglm3-6b",
            messages = messages,
            return_function_call = return_function_call
        )
        first_response_message = first_response['choices'][0]['message']
        # 判断返回结果是否为json格式对象,即是否需要调用外部函数
        if is_json_string(first_response_message['content']):  # 需要调用
            function_call = json.loads(first_response_message.content)
            # 获取函数名及参数
            function_name = function_call["name"]
            function_args = function_call["parameters"]
            # 获取外部函数
            function_to_call = available_functions[function_name]
            # 运行外部函数
            function_response = function_to_call(**function_args)
    		# messages中拼接first_response_message消息
            messages.append(first_response_message)
            # messages中拼接外部函数输出结果
            messages.append(
                {
                    "role": "observation",  # 角色为observation,表示为外部函数发的消息
                    "name": function_name,
                    "content": function_response
                }
            )
            # 第二次调用LLM
            second_response = openai.ChatCompletion.create(
                model = "chatglm3-6b",
                messages = messages
            )
            final_response = second_response['choices'][0]['message']['content']
        else:
            final_response = first_response_message['content']
    return final_response
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

上述实现为单轮对话,下面基于上述函数实现多轮对话函数。

def chat_with_glm(messages, functions_list=None, functions=None, model="chatglm3-6b", return_function_call = True):
    messages = [{"role": "system", "content": question}]
    while True:
        answer = run_conv_glm(messages, 
                              functions_list=None, 
                              functions=None, 
                              model="chatglm3-6b", 
                              return_function_call = True
                             )
        print(f"模型回答:{answer}")
        
        question = input("您还有其他问题吗?(输入退出以结束对话)")
        if question == "退出":
            break
            
        message.append({"role": "assistant", "content": answer})
        message.append({"role": "user", "content": question})
        
    del messages
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

多轮对话功能测试如下图所示

在这里插入图片描述


ChatGLM3保姆级教程

ChatGLM3-6B部署和微调

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/538890
推荐阅读
相关标签
  

闽ICP备14008679号