QwenLM / Qwen-Agent

Agent framework and applications built upon Qwen>=2.0, featuring Function Calling, Code Interpreter, RAG, and Chrome extension.
https://pypi.org/project/qwen-agent/
Other
3.47k stars 348 forks source link

关于Function Calling的prompt和训练loss计算 #112

Open yangyuxiang1996 opened 7 months ago

yangyuxiang1996 commented 7 months ago

作者你好,有两个问题想咨询下:

  1. 为什么 https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/llm/function_calling.py#L271 里的prompt不是使用训练时候的react格式,有点困惑
  2. 根据Qwen的finetune_example_demo, 训练的时候工具的结果 好像被统一到observation字段,然后放在整个assistant的role下面,但是这部分我理解不应参与loss的计算,就像chatglm3那样?现在看起来是会参与loss计算的,感觉这里是否不太对? 感谢解答!
yangyuxiang1996 commented 7 months ago

另外,我在实验的过程中发现,模型会重复使用同样的参数调用同一个工具,不知道你们在开发的过程中有碰到这类现象吗

JianxinMa commented 7 months ago
  1. qwen1.5同时训练过 function_calling.py 里的 prompt 和 react prompt。但 qwen1 只训过 react。
  2. 是否参与 loss,目前这方面没有特别明确的建议,可以看下自己的场景参与 loss 是否有影响。如果需要不参与 loss,实际上也不难通过修改 finetune 的 loss masks 来实现。
  3. “模型会重复使用同样的参数调用同一个工具” —— 比较少见到,方便的话可以抛下 cases 看看,以及说明下使用的模型版本。
yangyuxiang1996 commented 7 months ago
  1. qwen1.5同时训练过 function_calling.py 里的 prompt 和 react prompt。但 qwen1 只训过 react。
  2. 是否参与 loss,目前这方面没有特别明确的建议,可以看下自己的场景参与 loss 是否有影响。如果需要不参与 loss,实际上也不难通过修改 finetune 的 loss masks 来实现。
  3. “模型会重复使用同样的参数调用同一个工具” —— 比较少见到,方便的话可以抛下 cases 看看,以及说明下使用的模型版本。

谢谢答复! 刚刚对比了直接调用dashscope的qwen1.5-14b-chat版本,没有发现这个问题,貌似是我微调后出现的,case大概如下,连续两次都预测function Calling,第三次才给出最后的回复

[["{\"name\": \"get_web_search\", \"arguments\": {\"search_query\": \"刘德华 同风格歌曲推荐\"}}"], ["{\"name\": \"get_web_search\", \"arguments\": {\"search_query\": \"刘德华 同风格歌曲推荐\"}}"]]

请问有什么好的微调建议吗?顺便问一下,想要实现一次预测多个api,可以后续并行调用,有什么建议吗

yangyuxiang1996 commented 7 months ago

还有这个疑问 image 请问当前assistant的function call和工具返回结果 放在 user 这个role是出于什么考虑的呢?试图注释掉以下代码 image 但是发现完全没有办法生成最终回复

yangyuxiang1996 commented 7 months ago

1.5的微调数据格式可以提供吗,非基于react的

JianxinMa commented 7 months ago

1.5的微调数据格式可以提供吗,非基于react的

跑一下 function call 的 example,并且在 https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/llm/function_calling.py#L48 大概这个位置,打印下 self._chat 的输入和输出(可以关掉流式输出,即配置 stream=False),就能看到qwen1.5 function call的格式了。

    def _chat_with_functions(
        ...
    ) -> Union[List[Message], Iterator[List[Message]]]:
        ...
        print('query:\n', messages)
        response = self._chat(messages, stream=stream, delta_stream=delta_stream)
        print('response:\n', response)
        return output
yangyuxiang1996 commented 7 months ago

1.5的微调数据格式可以提供吗,非基于react的

跑一下 function call 的 example,并且在 https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/llm/function_calling.py#L48 大概这个位置,打印下 self._chat 的输入和输出(可以关掉流式输出,即配置 stream=False),就能看到qwen1.5 function call的格式了。

    def _chat_with_functions(
        ...
    ) -> Union[List[Message], Iterator[List[Message]]]:
        ...
        print('query:\n', messages)
        response = self._chat(messages, stream=stream, delta_stream=delta_stream)
        print('response:\n', response)
        return output

2024-04-07 10:35:52,221 - function_calling.py - 48 - INFO - ===== chat input ===== [Message({'role': 'system', 'content': 'xxx'}), Message({'role': 'user', 'content': '周杰伦是谁\n\n\n✿FUNCTION✿: get_knowledgegraph_retrieve\n✿ARGS✿: {"entity": "周杰伦"}\n✿RESULT✿: {"data": {"result": [{"name": "周杰伦", "entitys": [{"中文名": "周杰伦", "职业": "歌手、音乐人、演员、导演、编剧", "星座": "摩羯座", "entityType": "person.literature_art_entertainment.singer[歌手]", "entityDesc": "华语流行乐男歌手、音乐人、演员、导演、编剧", "外文名": "Jay Chou、Chou Jie Lun、\xa0、Chow Chieh-lun、", "主要成就": "获得十五座金曲奖、两届台湾金曲奖最佳国语男歌手奖、四届世界音乐大奖最畅销中华区艺人奖、两届MTV亚洲大奖最受欢迎艺人奖、四届新加坡金曲奖最受欢迎男歌手奖、展开、主要成就、获得十五座金曲奖、两届台湾金曲奖最佳国语男歌手奖、四届世界音乐大奖最畅销中华区艺人奖、两届MTV亚洲大奖最受欢迎艺人奖、四届新加坡金曲奖最受欢迎男歌手奖、两次获得台湾金曲奖最佳年度歌曲奖、四次获得台湾金曲奖最佳国语专辑奖、第7届音乐风云榜颁奖盛典港台最佳男歌手奖、第7届音乐风云榜颁奖盛典港台最受欢迎男歌手奖、第13届音乐风云榜年度盛典港台最受欢迎男歌手奖、第27届香港十大中文金曲全国最受欢迎歌手奖男歌手银奖、第28届香港十大中文金曲全年最高销量歌手大奖男歌手奖、大中华区8次年度唱片销量冠军、连续7年获得IFPI香港唱片销量大奖十大销量国语唱片、三次获得台湾金曲奖最佳作曲人奖、台湾金曲奖最佳专辑制作人奖、\xa0、2010年MP3下载量全球第三、2009年悉尼演唱会票房公告牌全球第二、台湾电影金马奖最佳新演员奖、香港电影金像奖最佳新演员奖、入选美国有线电视新闻网亚洲25位最具影响力人物、《Fast Company》全球百大创意人物、第19届全球华语榜中榜暨亚洲影响力大典亚洲影响力最受欢迎全能华语艺人奖、第19届全球华语榜中榜暨亚洲影响力大典华语乐坛跨时代实力唱作人奖、2021年福布斯中国名人榜第5名、\xa0、收起", "别名": "周董、President Chou、\xa0、小公举、", "出生地": "台湾省新北市", "entityId": "7f89295836ebec23db51062b395c0d33", "代表作品": "七里香;青花瓷;双截棍;简单爱;夜曲;以父之名;稻香;龙卷风;一路向北;晴天;夜的第七章;东风破;爱在西元前;轨迹;床边故事;头文字D;不能说的秘密;满城尽带黄金甲;大灌篮;天台爱情", "经纪公司": "杰威尔音乐有限公司", "民族": "汉族", "entityName": "周杰伦", "entityUrl": "/item/%E5%91%A8%E6%9D%B0%E4%BC%A6/129156", "出生日期": "1979年1月18日", "entityAbstract": "周杰伦(Jay Chou),1979年1月18日出生于台湾省新北市,祖籍福建省泉州市永春县,中国台湾流行乐男歌手、音乐人、演员、导演、编剧,毕业于淡江中学", "毕业院校": "淡江中学", "标签": "华语流行乐男歌手、音乐人、演员、导演、编剧", "国籍": "中国", "血型": "O型血", "身高": "175 cm", "entityPv": 92852303}]}], "timeConsumer": 6}, "code": 0}\n✿RETURN✿'})]

2024-04-07 10:36:01,298 - function_calling.py - 50 - INFO - ===== chat output ===== [Message({'role': 'assistant', 'content': '周杰伦是一位著名的华语流行乐男歌手、音乐人、演员、导演和编剧。他出生于1979年1月18日,来自中国台湾省新北市,祖籍福建省泉州市永春县,摩羯座。他的音乐作品丰富多样,包括《七里香》、《青花瓷》、《双截棍》等经典歌曲。周杰伦以其独特的创作风格和多才多艺在华语乐坛享有很高声誉,曾多次获得金曲奖、台湾金曲奖和世界音乐大奖等重要奖项。他的演艺事业也相当成功,获得过电影奖项如金马奖和金像奖的最佳新演员奖。在粉丝心中,他还有“小公举”和“周董”的昵称。'})]

刚刚看了下格式,按照这个输入输出构造样例就可以了是吧,还有回到我第一个问题,其实这里把前一轮的observation都放到了user里面,这也是不会参与loss计算的吧,我理解Qwen1.5的实现就是这样的,但是提供的Qwen1的finetune demo是把observation放到assistant里面,会参与loss计算,这是区别之一吗,不知道我理解的对不对

JianxinMa commented 7 months ago

是的,理解没问题。但Observation放user好还是放assistnat好,我们并没有定论。Observation放user其实是为了方便兼容 openai api(只有对话/chat接口,没有续写/generate接口)。

LianxinRay commented 5 months ago

1.5的微调数据格式可以提供吗,非基于react的

跑一下 function call 的 example,并且在 https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/llm/function_calling.py#L48 大概这个位置,打印下 self._chat 的输入和输出(可以关掉流式输出,即配置 stream=False),就能看到qwen1.5 function call的格式了。

    def _chat_with_functions(
        ...
    ) -> Union[List[Message], Iterator[List[Message]]]:
        ...
        print('query:\n', messages)
        response = self._chat(messages, stream=stream, delta_stream=delta_stream)
        print('response:\n', response)
        return output

2024-04-07 10:35:52,221 - function_calling.py - 48 - INFO - ===== chat input ===== [Message({'role': 'system', 'content': 'xxx'}), Message({'role': 'user', 'content': '周杰伦是谁\n\n\n✿FUNCTION✿: get_knowledgegraph_retrieve\n✿ARGS✿: {"entity": "周杰伦"}\n✿RESULT✿: {"data": {"result": [{"name": "周杰伦", "entitys": [{"中文名": "周杰伦", "职业": "歌手、音乐人、演员、导演、编剧", "星座": "摩羯座", "entityType": "person.literature_art_entertainment.singer[歌手]", "entityDesc": "华语流行乐男歌手、音乐人、演员、导演、编剧", "外文名": "Jay Chou、Chou Jie Lun、\xa0、Chow Chieh-lun、", "主要成就": "获得十五座金曲奖、两届台湾金曲奖最佳国语男歌手奖、四届世界音乐大奖最畅销中华区艺人奖、两届MTV亚洲大奖最受欢迎艺人奖、四届新加坡金曲奖最受欢迎男歌手奖、展开、主要成就、获得十五座金曲奖、两届台湾金曲奖最佳国语男歌手奖、四届世界音乐大奖最畅销中华区艺人奖、两届MTV亚洲大奖最受欢迎艺人奖、四届新加坡金曲奖最受欢迎男歌手奖、两次获得台湾金曲奖最佳年度歌曲奖、四次获得台湾金曲奖最佳国语专辑奖、第7届音乐风云榜颁奖盛典港台最佳男歌手奖、第7届音乐风云榜颁奖盛典港台最受欢迎男歌手奖、第13届音乐风云榜年度盛典港台最受欢迎男歌手奖、第27届香港十大中文金曲全国最受欢迎歌手奖男歌手银奖、第28届香港十大中文金曲全年最高销量歌手大奖男歌手奖、大中华区8次年度唱片销量冠军、连续7年获得IFPI香港唱片销量大奖十大销量国语唱片、三次获得台湾金曲奖最佳作曲人奖、台湾金曲奖最佳专辑制作人奖、\xa0、2010年MP3下载量全球第三、2009年悉尼演唱会票房公告牌全球第二、台湾电影金马奖最佳新演员奖、香港电影金像奖最佳新演员奖、入选美国有线电视新闻网亚洲25位最具影响力人物、《Fast Company》全球百大创意人物、第19届全球华语榜中榜暨亚洲影响力大典亚洲影响力最受欢迎全能华语艺人奖、第19届全球华语榜中榜暨亚洲影响力大典华语乐坛跨时代实力唱作人奖、2021年福布斯中国名人榜第5名、\xa0、收起", "别名": "周董、President Chou、\xa0、小公举、", "出生地": "台湾省新北市", "entityId": "7f89295836ebec23db51062b395c0d33", "代表作品": "七里香;青花瓷;双截棍;简单爱;夜曲;以父之名;稻香;龙卷风;一路向北;晴天;夜的第七章;东风破;爱在西元前;轨迹;床边故事;头文字D;不能说的秘密;满城尽带黄金甲;大灌篮;天台爱情", "经纪公司": "杰威尔音乐有限公司", "民族": "汉族", "entityName": "周杰伦", "entityUrl": "/item/%E5%91%A8%E6%9D%B0%E4%BC%A6/129156", "出生日期": "1979年1月18日", "entityAbstract": "周杰伦(Jay Chou),1979年1月18日出生于台湾省新北市,祖籍福建省泉州市永春县,中国台湾流行乐男歌手、音乐人、演员、导演、编剧,毕业于淡江中学", "毕业院校": "淡江中学", "标签": "华语流行乐男歌手、音乐人、演员、导演、编剧", "国籍": "中国", "血型": "O型血", "身高": "175 cm", "entityPv": 92852303}]}], "timeConsumer": 6}, "code": 0}\n✿RETURN✿'})]

2024-04-07 10:36:01,298 - function_calling.py - 50 - INFO - ===== chat output ===== [Message({'role': 'assistant', 'content': '周杰伦是一位著名的华语流行乐男歌手、音乐人、演员、导演和编剧。他出生于1979年1月18日,来自中国台湾省新北市,祖籍福建省泉州市永春县,摩羯座。他的音乐作品丰富多样,包括《七里香》、《青花瓷》、《双截棍》等经典歌曲。周杰伦以其独特的创作风格和多才多艺在华语乐坛享有很高声誉,曾多次获得金曲奖、台湾金曲奖和世界音乐大奖等重要奖项。他的演艺事业也相当成功,获得过电影奖项如金马奖和金像奖的最佳新演员奖。在粉丝心中,他还有“小公举”和“周董”的昵称。'})]

刚刚看了下格式,按照这个输入输出构造样例就可以了是吧,还有回到我第一个问题,其实这里把前一轮的observation都放到了user里面,这也是不会参与loss计算的吧,我理解Qwen1.5的实现就是这样的,但是提供的Qwen1的finetune demo是把observation放到assistant里面,会参与loss计算,这是区别之一吗,不知道我理解的对不对

大佬,有个问题想咨询下,我们想用GPT4o来整理训练语料,但是遇到个数据细节问题。比如: user:我想打开xxx买xx assistant:(打开xx的function call) {xxx111} assistant: 现在我需要在xxx下单买xx。(下单的function call) {xxx222} assistant: 已帮你完成 根据如上对话在构建训练语料的时候,有如下: user1: 我想打开xxx买xx. {xxx111} assistant1: 现在我需要在xxx下单买xx user2: 现在我需要在xxx下单买xx。{xxx222} assistant2: 已帮你完成

上述对话,user2讲 现在我需要在xxx下单买xx。 当做输入数据构建进user角色里的,但是他的口吻是assistant,会不会造成问题?或者应该按照什么格式处理这种数据呢

zhoujz10 commented 4 months ago

https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/llm/function_calling.py

请问这个文件里function call的prompt为什么会包含"result"和"return"呢,我理解assistant应该只会输出function name和arguments?

JianxinMa commented 4 months ago

https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/llm/function_calling.py

请问这个文件里function call的prompt为什么会包含"result"和"return"呢,我理解assistant应该只会输出function name和arguments?

result和return中间的内容是工具返回的结果。prompt里包含工具结果的目的是:让模型根据这次的工具结果判断接下来是要 总结工具结果就结束、还是继续调用其他工具。

zhoujz10 commented 4 months ago

https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/llm/function_calling.py

请问这个文件里function call的prompt为什么会包含"result"和"return"呢,我理解assistant应该只会输出function name和arguments?

result和return中间的内容是工具返回的结果。prompt里包含工具结果的目的是:让模型根据这次的工具结果判断接下来是要 总结工具结果就结束、还是继续调用其他工具。

嗯嗯,谢谢,不过我在使用这个prompt直接call模型(Qwen2-72B-Instruct-GPTQ-Int4)的时候,发现模型会直接想象一个结果填写到result后面,可能是我打开方式不对?我是把如下prompt format之后拼在system_prompt里,与qwen_agent/llm/function_calling.py中的拼接方式相同。

FN_CALL_TEMPLATE_FMT_EN = """## When you need to call a tool, please insert the following command in your reply, which can be called zero or multiple times according to your needs:

%s: The tool to use, should be one of [{tool_names}]
%s: The input of the tool
%s: Tool results
%s: Reply based on tool results. Images need to be rendered as ![](url)""" % (
    FN_NAME,
    FN_ARGS,
    FN_RESULT,
    FN_EXIT,
)

可能是因为我没有用FN_STOP_WORDS控制模型在FN_RESULT token之后停止输出?

JianxinMa commented 4 months ago

https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/llm/function_calling.py

请问这个文件里function call的prompt为什么会包含"result"和"return"呢,我理解assistant应该只会输出function name和arguments?

result和return中间的内容是工具返回的结果。prompt里包含工具结果的目的是:让模型根据这次的工具结果判断接下来是要 总结工具结果就结束、还是继续调用其他工具。

嗯嗯,谢谢,不过我在使用这个prompt直接call模型(Qwen2-72B-Instruct-GPTQ-Int4)的时候,发现模型会直接想象一个结果填写到result后面,可能是我打开方式不对?我是把如下prompt format之后拼在system_prompt里,与qwen_agent/llm/function_calling.py中的拼接方式相同。

FN_CALL_TEMPLATE_FMT_EN = """## When you need to call a tool, please insert the following command in your reply, which can be called zero or multiple times according to your needs:

%s: The tool to use, should be one of [{tool_names}]
%s: The input of the tool
%s: Tool results
%s: Reply based on tool results. Images need to be rendered as ![](url)""" % (
    FN_NAME,
    FN_ARGS,
    FN_RESULT,
    FN_EXIT,
)

可能是因为我没有用FN_STOP_WORDS控制模型在FN_RESULT token之后停止输出?

是的,需要配置stop word