关于chatglm3 function calling的理解

ChatGLM3-6B开源了工具调用,好奇他是怎么实现的,所以写了这个文章记录。

一、测试官方的示例

官方给的示例很简单,只不过给的两个函数 track 和 text-to-speech 没有具体的实现,模型的输出也只是给出了需要调用的函数名和参数。剩下的需要自己去实现..

我更换了tools中的函数:

tools = [{"name": "go_ahead","description": "小车前进","parameters": {"type": "object","properties": {"distance": {"description": "前进的距离,单位为米"}},"required": ['distance']}},{"name": "back","description": "小车后退","parameters": {"type": "object","properties": {"distance": {"description": "后退的距离,单位为米"}},"required": ['distance']}},{"name": "turn_left","description": "小车左转","parameters": {"type": "object","properties": {"angle": {"description": "左转角度,单位为°"}},"required": ['angle']}},{"name": "turn_right","description": "小车右转","parameters": {"type": "object","properties": {"angle": {"description": "右转角度,单位为°"}},"required": ['angle']}}
]

测试下来出现以下问题:

        1. 输入多个操作只能执行一个操作

        2. 会出现输出不存在的函数的情况

        3. 当已有的函数不能实现用户的操作时,会调用已有函数强行输出

二、代码解析

现在让我们来看看具体实现的代码。下载chatglm3-6b权重的时候也会下载modeling_chatglm.py和tokenization_chatglm.py这两个python文件,chatglm3实现function calling也是在这里面实现的。

1. 输入的处理

首先工具调用跟一般的对话的输入差在有一个 system_info ,他是作为history输入到model.chat函数中的。

system_info = {"role": "system", "content": "Answer the following questions as best as you can. You have access to the following tools:", "tools": tools}

我们可以在modeling_chatglm.py文件中找到chat的实现

@torch.inference_mode()
def chat(self, tokenizer, query: str, history: List[Tuple[str, str]] = None, role: str = "user",max_length: int = 8192, num_beams=1, do_sample=True, top_p=0.8, temperature=0.8, logits_processor=None,**kwargs):if history is None:history = []if logits_processor is None:logits_processor = LogitsProcessorList()logits_processor.append(InvalidScoreLogitsProcessor())gen_kwargs = {"max_length": max_length, "num_beams": num_beams, "do_sample": do_sample, "top_p": top_p,"temperature": temperature, "logits_processor": logits_processor, **kwargs}inputs = tokenizer.build_chat_input(query, history=history, role=role)inputs = inputs.to(self.device)eos_token_id = [tokenizer.eos_token_id, tokenizer.get_command("<|user|>"),tokenizer.get_command("<|observation|>")]outputs = self.generate(**inputs, **gen_kwargs, eos_token_id=eos_token_id)outputs = outputs.tolist()[0][len(inputs["input_ids"][0]):-1]response = tokenizer.decode(outputs)history.append({"role": role, "content": query})response, history = self.process_response(response, history)return response, history

在chat函数中,history又被作为参数送到tokenizer.build_chat_input中,然后得到input。

那很明显需要查看tokenizer.build_chat_input的实现,tokenizer.build_chat_input函数在tokenization_chatglm中:

def build_chat_input(self, query, history=None, role="user"):if history is None:history = []input_ids = []for item in history:content = item["content"]if item["role"] == "system" and "tools" in item:content = content + "\n" + json.dumps(item["tools"], indent=4, ensure_ascii=False)input_ids.extend(self.build_single_message(item["role"], item.get("metadata", ""), content))input_ids.extend(self.build_single_message(role, "", query))input_ids.extend([self.get_command("<|assistant|>")])return self.batch_encode_plus([input_ids], return_tensors="pt", is_split_into_words=True)

根据上面的代码看得出来,他是直接用json.dumps把tools拼接到content中,然后塞给大模型的。

2. 输出的处理

输出的处理在chat函数中的process_response函数

def process_response(self, output, history):content = ""history = deepcopy(history)for response in output.split("<|assistant|>"):metadata, content = response.split("\n", maxsplit=1)if not metadata.strip():content = content.strip()history.append({"role": "assistant", "metadata": metadata, "content": content})content = content.replace("[[训练时间]]", "2023年")else:history.append({"role": "assistant", "metadata": metadata, "content": content})if history[0]["role"] == "system" and "tools" in history[0]:content = "\n".join(content.split("\n")[1:-1])def tool_call(**kwargs):return kwargsparameters = eval(content)content = {"name": metadata.strip(), "parameters": parameters}else:content = {"name": metadata.strip(), "content": content}return content, history

这里需要注意一点,chatglm3-6b应该是有针对工具调用进行训练,输出的结果很稳定,基本上都是下面的结构:

'turn_right\n```python\ntool_call(angle=30)\n```'

第一行是调用的函数名,然后下面是执行函数的代码(代码中函数名统一为tool_call)。再通过split('\n')得到代码,eval执行tool_call函数得到函数的变量字典,然后返回字典如下:

{'name': 'turn_right', 'parameters': {'angle': 30}}

3.  openai_api_demo.py

官方还给出了openai_api_demo.py这个文件,他实现了完整的 输入自然语言->得到函数和函数参数->执行函数 这一套流程。虽然不知道为什么没有在readme中写出来

openai_api_demo.py主要依靠tool_register.py下的get_tools和dispatch_tool

1. register_tool用于注册函数,它接受一个可调用对象 func 作为参数。该函数将 func 注册为一个工具,并返回 func 本身。2. dispatch_tool用于执行函数,它接受一个函数名和函数参数,返回函数的返回。

三、尝试在百川上实现

我是在baichaun-13B上进行测试的,相对于chatglm3-6b每次稳定的输出,baichaun-13B的输出就不是那么好了。所以我们需要设计一个prompt如下:

prompt = '''
输出必须是带有markdown格式的python代码:
```python
工具的name(parameters)
```
例如:
```python
back(distance=10)
```'''

那么输入到百川模型的messages如下:

system_info = {"role": "system", "content": "尽可能回答以下问题。您可以使用以下工具:\n tools:" + json.dumps(tools, indent=4, ensure_ascii=False) + prompt} query = "23加69等于多少"messages = [system_info,{"role": "user", "content": query}
]

没有意外的话模型会生成一个被```python```包裹的代码,使用eval()执行代码就可以了

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】指针详解(四)

目录 1.assert断言 2.指针的使用和传址调用 2.1strlen的模拟使用 2.2传值调用和传址调用 1.assert断言 assert.h头文件定义了宏 assert()&#xff0c;用于在运行时确保程序符合指定条件&#xff0c;如果不符合&#xff0c;就报错终止运行。这个宏常常被称为“断言”。 例如…

多模态——CLIP:Contrastive Language-Image Pre-training解读

前言 随着人工智能技术的不断进步&#xff0c;多模态成为备受瞩目的研究方向。多模态技术旨在融合不同类型的数据和信息&#xff0c;以实现更准确、高效的人工智能应用。有学者认为它代表了所有模型发展的最终趋势。这类模型旨在接受多种不同的输入方式&#xff0c;例如图像、…

OpenStack搭建和部署

Centos官网qcow2镜像修改root账号密码&#xff0c;开启ssh等 wget http://172.16.20.10/vmtemplate/KVM/wangrui/Debian/debian-10.2.0-openstack-amd64.qcow2 一、查看镜像文件信息 [debian-10.2-cloud] nameDebian 10.2.0 (Buster) Cloud osinfodebian10 archx86_64 fi…

Linux Debian12使用podman安装upload-labs靶场环境

一、upload-labs简介 PHP语言编写&#xff0c;持续收集渗透测试和CTF中针对文件上传漏洞的靶场&#xff0c;总共21关&#xff0c;每一关都包含着不同的上传绕过方式。 二、安装podman环境 Linux Debian系统如果没有安装podman容器环境&#xff0c;可以参考这篇文章先安装pod…

透过许战海矩阵洞察安记食品增长战略

引言&#xff1a;安记食品如果想实施增长战略&#xff0c;建议深耕招牌产品,走向全国市场,目前招牌产品咖哩和复合调味粉市场空间没有被全面释放出来,需要科学的产品战略作为支撑。安记食品选择功能性产品方向是正确的,但“功能性”需要一个大品类作为载体,牛奶,饮料是最大的载…

网站被恶意扫描怎么办(上WAF)

在网络安全领域&#xff0c;有一大类工具被广泛使用&#xff0c;且作用不可忽视&#xff0c;它就是网络安全扫描器。扫描器是一种专门设计用来评估计算机、网络或者应用中已知的弱点的计算机程序&#xff0c;但是很多人恶意使用&#xff0c;找到网站弱点进行攻击。 扫描器的种…

K8S理论

kubernetes&#xff1a;8个字母省略&#xff0c;就是k8s 自动部署自动扩展和管理容器化部署的应用程序的一个开源系统 k8s是负责自动化运维管理多个容器化程序的集群&#xff0c;是一个功能强大的容器编排工具 分布式和集群化的方式进行容器化管理 版本有1.15 .1.18 .1.20 …

问答区故意在结题前回答混赏金的狗

此贴专记录CSDN问答社区里面&#xff0c;一些回答者在临近结题时胡乱回答&#xff0c;只为分取结题赏金的人。 所有图片均为事实&#xff0c;绝无半点虚假。各位看官可以自行搜索问题题目或者通过查看此人回答求证 所有图片均为事实&#xff0c;绝无半点虚假。各位看官可以自行…

c语言中数据结构

一、结构体的由来 1. 数据类型的不足 C语言中&#xff0c;基本数据类型只有整型、字符型、浮点型等少数几种&#xff0c;无法满足复杂数据类型的需要。 2. 数组的限制 虽然数组可以存储多个同类型的数据&#xff0c;但是数组中的元素个数是固定的&#xff0c;无法动态地改变…

渗透测试——1.3计算机网络基础

一、黑客术语 1、肉鸡&#xff1a;被黑客攻击电脑&#xff0c;可以受黑客控制不被发现 2、端口&#xff08;port&#xff09;&#xff1a;数据传输的通道 3、弱口令&#xff1a;强度不高&#xff0c;容易被猜到的口令、密码 4、客户端&#xff1a;请求申请电脑&#xff08;…

10. UVM Environment

环境为agents, scoreboards和其他验证组件&#xff08;包括有助于在 SoC 级别重用块级环境组件的其他环境类&#xff09;提供良好的层次结构和容器。用户定义的 env 类必须从 uvm_env 类扩展。 10.1 uvm_env class hierarchy 类声明&#xff1a; virtual class uvm_env extend…

k8s的二进制部署(一)

k8s的二进制部署&#xff1a;源码包部署 环境&#xff1a; k8smaster01: 20.0.0.71 kube-apiserver kube-controller-manager kube-schedule ETCD k8smaster02: 20.0.0.72 kube-apiserver kube-controller-manager kube-schedule Node节点01: 20.0.0.73 kubelet kube-pr…

nodejs+vue+ElementUi大学新生入学系统的设计与实现1hme0

采用B/S模式架构系统&#xff0c;开发简单&#xff0c;只需要连接网络即可登录本系统&#xff0c;不需要安装任何客户端。开发工具采用VSCode&#xff0c;前端采用VueElementUI&#xff0c;后端采用Node.js&#xff0c;数据库采用MySQL。 涉及的技术栈 1&#xff09; 前台页面…

Stable Diffusion模型原理

1 Stable Diffusion概述 1.1 图像生成的发展 在Stable Diffusion诞生之前&#xff0c;计算机视觉和机器学习方面最重要的突破是 GAN&#xff08;Generative Adversarial Networks 生成对抗网络&#xff09;。GAN让超越训练数据已有内容成为可能&#xff0c;从而打开了一个全新…

Elasticsearch8.x结合OpenAI CLIP模型实现图搜图及文搜图功能

前言 在当今大数据时代&#xff0c;搜索引擎已经是许多应用的核心组件之一&#xff0c;近年随着大模型以及AI技术&#xff08;如&#xff1a;自然语言处理NLP&#xff09;的流行&#xff0c;这些技术的结合将会创造出更多的应用场景&#xff0c;比如&#xff1a;电商商品搜索、…

系列十五(面试)、RocketMQ消息重复消费问题

一、RocketMQ消息重复消费问题 1.1、官网 1.2、消息重复被消费原因 通过上述官网的描述我们可以知道&#xff0c;RocketMQ中的消息是存在重复消费的情况的。那么消息为什么会被重复消费呢&#xff1f;先来回顾一下RocketMQ的消息是怎么发送和接收的&#xff1a; 从上图可以看出…

c++primer—读书笔记【全能详细版】

第1章 开始 1.1 编写一个简单的c程序 1.1.1 编译.运行程序 ​ int类型是一种内置类型&#xff0c;即语言自身定义的类型 1.2 初识输入输出 ​ 输入流和输出流而言&#xff0c;一个流就是一个字符序列。术语“流”的意思表示&#xff0c;随时间的推移&#xff0c;字符是顺序…

dl转置卷积

转置卷积 转置卷积&#xff0c;顾名思义&#xff0c;通过名字我们应该就能看出来&#xff0c;其作用和卷积相反&#xff0c;它可以使得图像的像素增多 上图的意思是&#xff0c;输入是22的图像&#xff0c;卷积核为22的矩阵&#xff0c;然后变换成3*3的矩阵 代码如下 import…

Django(三)

1.快速上手 确保app已注册 【settings.py】 编写URL和视图函数对应关系 【urls.py】 编写视图函数 【views.py】 启动django项目 命令行启动python manage.py runserverPycharm启动 1.1 再写一个页面 2. templates模板 2.1 静态文件 2.1.1 static目录 2.1.2 引用静态…

【三维生成】稀疏重建、Image-to-3D方法(汇总)

系列文章目录 总结一下近5年的三维生成算法&#xff0c;持续更新 文章目录 系列文章目录一、LRM&#xff1a;单图像的大模型重建&#xff08;2023&#xff09;摘要1.前言2.Method3.实验 二、SSDNeRF&#xff1a;单阶段Diffusion NeRF的三维生成和重建&#xff08;ICCV 2023&am…