为ChatGLM3添加新的工具

ChatGLM3 prompt格式简介

ChatGLM3已经发布一段时间了,相较于ChatGLM2,它的一个重大更新是支持了工具和代码的调用,我们只需要将工具的输入输出定义完整,ChatGLM3会选择最可能满足用户诉求的工具,调用它,并依据返回的结果生成更好地答复。

根据官方描述,为了统一多项任务上的prompt格式以及防止prompt注入,ChatGLM3的prompt分为两部分,第一部分为system_prompt,用于描述当前任务下ChatGLM3的身份以及特点,第二部分为对话中不同角色role的发言,

<|system|>
You are ChatGLM3, a large language model trained by Zhipu.AI. Follow the user's instructions carefully. Respond using markdown.
<|user|>
Hello
<|assistant|>
Hello, I'm ChatGLM3. What can I assist you today?

在不同任务下,role的取值范围不同:

  • 多轮对话:<|user|><|assistant|>
  • 工具调用和代码执行:<|user|><|observation|><|assistant|>

其中的observation为工具调用的结果,或者代码的执行结果。对于工具调用,在用户提出query后,ChatGLM3会首先以assistant身份输出选择的工具和参数,然后需要将工具的调用结果以<|observation|>身份输入模型,最终模型再以<|assistant|>身份输出最终结果。对于代码调用,模型会以<|assistant|>的身份并携带单词"interpreter"输出代码,然后需要将执行结果以<|observation|>身份输入模型,之后可能发生若干轮“输出代码 -> 输入结果”的循环,最终模型会以<|assistant|>身份但是不携带单词"interpreter"输出最终的答案。

官方代码改写

ChatGLM3的项目中携带了一个简单实现的工具调用示例,即composite_demo/demo_tool.py文件,而可以访问的工具定义则在composite_demo/tool_registry.py中实现。通过阅读代码和文档,我们知道,它是通过装饰函数register_tool获取函数的钩子、注释、以及参数说明,因此,我们只需要参照其他工具的定义完成以下工作:

  1. 开发一个新工具
  2. 在函数头下添加注释
  3. 在工具上方添加装饰函数register_tool
  4. 对工具的每个参数通过Annotated函数增加参数类型、参数含义、是否必须三个信息

为了演示,设计了一个获取明天天气的函数,具体实现是通过调用丫丫天气的api,具体参数含义请参见它们的api介绍,然后完成以上4步,最终的代码如下:

_CITY_ID_DICT = []

def get_city_id(city_name):
    def _dfs(d, _city_name):
        if 'list' in d:
            for item in d['list']:
                city_id = _dfs(item, _city_name)
                if city_id is not None:
                    return city_id
        else:
            if d['en'] == _city_name or d['name'] == _city_name:
                return d['city_id']
            else:
                return None

    global _CITY_ID_DICT
    if len(_CITY_ID_DICT) == 0:
        with open('../composite_demo/city_id.json', 'r', encoding='utf8') as fp:
            _CITY_ID_DICT = json.load(fp)
    city_id = _dfs(_CITY_ID_DICT, city_name)
    if city_id is None:
        raise ValueError('您提供的城市名不在列表中')

    return city_id

@register_tool
def get_tomorrow_weather(
        city_name: Annotated[str, 'The name of the city to be queried', True],
) -> str:
    """
    Get the weather for `city_name` of tomorrow
    """
    city_id = get_city_id(city_name)
    print(f'http://api.yytianqi.com/forecast7d?city={city_id}&key=e6g6eq1blkiqq01i')

    import requests
    try:
        resp = requests.get(f'http://api.yytianqi.com/forecast7d?city={city_id}&key=你的api key')
        resp.raise_for_status()
        resp = resp.json()
        print(resp)
        data = resp['data']['list'][1]
        ret = ''
        # "tq1": "多云",  //白天天气
        ret += f'白天天气:{data["tq1"]}\n'

        # "tq2": "晴",  //夜间天气,当与白天天气相同时,两者可合并为一个
        if 'tq2' not in data:
            ret += f'夜间天气:{data["tq1"]}\n'
        else:
            ret += f'夜间天气:{data["tq2"]}\n'

        # "numtq1": "01",  //白天天气编码
        # "numtq2": "00",  //夜间天气编码

        # "qw1": "6",  //白天气温
        ret += f'白天气温:{data["qw1"]}℃\n'

        # "qw2": "-5",  //夜间气温
        ret += f'夜间气温:{data["qw2"]}℃\n'

        # "fl1": "3-4级",  //白天风力
        ret += f'白天风力:{data["fl1"]}\n'

        # "numfl1": "1",  //白天风力编码
        # "fl2": "微风",  //夜间风力
        ret += f'夜间风力:{data["fl2"]}\n'

        # "numfl2": "0",  //夜间风力编码
        # "fx1": "北风",  //白天风向
        ret += f'白天风向:{data["fx1"]}\n'

        # "numfx1": "8",  //白天风向编码
        # "fx2": "无持续风向",  //夜间风向,如白天风力风向与夜间风力风向一致,可合并为一行
        if 'fx2' not in data:
            ret += f'夜间风向:{data["fx1"]}\n'
        else:
            ret += f'夜间风向:{data["fx2"]}\n'
        # "numfx2": "0",  //夜间风向编码
        # "date": "2016-03-09"  //预报日期

    except:
        import traceback
        ret = "Error encountered while fetching weather data!\n" + traceback.format_exc()
    return ret

其中,city_id.json可以从丫丫天气城市ID编码列表,直接复制下来保存到本地即可,同时还需要在官网注册将你的api key替换到代码中去。

效果

在未增加工具之前,我们如果询问模型“北京明天的天气”,由于系统中只有一个官方提供的查询当前天气的工具,因此模型只能选择该工具,并返回当前的时间,这与用户的实际诉求是不一致的。而我们新增工具后,理论上,模型应该会选择新工具并提供明天的天气情况的简介。实际运行与此预估相符。

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值