InternLM / xtuner

An efficient, flexible and full-featured toolkit for fine-tuning LLM (InternLM2, Llama3, Phi3, Qwen, Mistral, ...)
https://xtuner.readthedocs.io/zh-cn/latest/
Apache License 2.0
3.72k stars 302 forks source link

[Bug] Empty available tools during execute `msagent_react_map_fn` #416

Closed fanqiNO1 closed 6 months ago

fanqiNO1 commented 7 months ago

当我在试着手动转换 damo/MSAgent-Bench dev.jsonl 的第一条数据时,遇到了空可用工具的情况,执行代码如下:

if __name__ == '__main__':
    with open('dev.jsonl', 'r', encoding='utf-8') as f:
        data = f.readline()
        data = json.loads(data)
    data['conversations'] = json.dumps(data['conversations'], ensure_ascii=False)  # for eval
    data = msagent_react_map_fn(data)
    json.dump(data, open('new.json', 'w', encoding='utf-8'), ensure_ascii=False, indent=4)

输出后的文件数据为:

{
    "conversation": [
        {
            "system": "你是一个可以调用外部工具的助手,可以使用的工具包括:\n{}\n\n                如果使用工具请遵循以下格式回复:\n```\n\n                Thought:思考你当前步骤需要解决什么问题,是否需要使用工具\n\n                Action:工具名称,你的工具必须从 [[]] 选择\n\n                Action Input:工具输入参数\n```\n工具返回按照以下格式回复:\n```\n\n                Response:调用工具后的结果\n```\n如果你已经知道了答案,或者你不需要工具,\n                请遵循以下格式回复\n```\n\n                Thought:给出最终答案的思考过程\n\n                Final Answer:最终答案\n```\n开始!\n",
            "input": "现在我给你另一条地址,请识别出里面的元素。输入地址:北京市海淀区中关村大街27号\n",
            "output": "Action:modelscope_text-address\nAction Input:{'text': '北京市海淀区中关村大街27号'}\n\n\n\n"
        },
        {
            "system": "Response:{'prov': '北京市', 'city': '北京市', 'district': '海淀区', 'road': '中关村大街', 'number': '27号'}\n",
            "output": "Final Answer:地址识别json表示:{\"prov\": \"北京市\", \"city\": \"北京市\", \"district\": \"海淀区\", \"road\": \"中关村大街\", \"number\": \"27号\"}。我使用的模型是ModelScope的'damo/mgeo_geographic_elements_tagging_chinese_base'模型。这是基于达摩院联合高德发布的多任务多模态地址预训练底座MGeo模型微调得到的。\n"
        },
        {
            "system": "",
            "input": "请识别以下地址中的元素。包括:省、市、区、镇、社区、道路、路号、POI、楼栋号、户室号等。输入地址:北京市海淀区上地十街10号院\n",
            "output": "Action:modelscope_text-address\nAction Input:{'text': '北京市海淀区上地十街10号院'}\n\n\n\n"
        },
        {
            "system": "Response:{'prov': '北京市', 'city': '北京市', 'district': '海淀区', 'town': '上地街道', 'community': '十街10号院'}\n",
            "output": "Final Answer:地址识别结果json表示:{\"prov\": \"北京市\", \"city\": \"北京市\", \"district\": \"海淀区\", \"town\": \"上地街道\", \"community\": \"十街10号院\"}。本API使用的是ModelScope的'damo/mgeo_geographic_elements_tagging_chinese_base'模型,为了更好地提高模型的训练效果,我们在达摩院联合高德发布的多任务多模态地址预训练底座MGeo模型上进行了微调。\n"
        }
    ]
}

可见,可使用的工具为空字典。

原始数据为:

{
    "id": "MS_Agent_Bench_Test_0",
    "conversations": [
        {
            "from": "system",
            "value": "你是达摩院的ModelScopeGPT(魔搭助手),你是个大语言模型, 是2023年达摩院的工程师训练得到的。你有多种能力,可以通过插件集成魔搭社区的模型api来回复用户的问题,还能解答用户使用模型遇到的问题和模型知识相关问答。1. {\"plugin_name\": \"modelscope_text-address\", \"plugin_owner\": \"ModelScopeGPT\", \"plugin_type\": \"default\", \"plugin_schema_for_model\": {\"name\": \"modelscope_text-address\", \"description\": \"针对中文的地址信息,识别出里面的元素,包括省、市、区、镇、社区、道路、路号、POI、楼栋号、户室号等\", \"url\": \"http://104.61.144.17:1354/\", \"paths\": [{\"name\": \"modelscope_text-address\", \"model_id\": \"/damo/mgeo_geographic_elements_tagging_chinese_base\", \"method\": \"post\", \"description\": \"针对中文的地址信息,识别出里面的元素,包括省、市、区、镇、社区、道路、路号、POI、楼栋号、户室号等\", \"parameters\": [{\"name\": \"text\", \"description\": \"用户输入的地址信息\", \"required\": \"True\"}]}]}}\n\n2. {\"plugin_name\": \"modelscope_text-address\", \"plugin_owner\": \"ModelScopeGPT\", \"plugin_type\": \"default\", \"plugin_schema_for_model\": {\"name\": \"modelscope_text-address\", \"description\": \"针对中文的地址信息,识别出里面的元素,包括省、市、区、镇、社区、道路、路号、POI、楼栋号、户室号等\", \"url\": \"http://90.16.54.177:2332/\", \"paths\": [{\"name\": \"modelscope_text-address\", \"model_id\": \"/damo/mgeo_geographic_elements_tagging_chinese_base\", \"method\": \"post\", \"description\": \"针对中文的地址信息,识别出里面的元素,包括省、市、区、镇、社区、道路、路号、POI、楼栋号、户室号等\", \"parameters\": [{\"name\": \"text\", \"description\": \"用户输入的地址信息\", \"required\": \"True\"}]}]}}\n\n3. {\"plugin_name\": \"modelscope_text-address\", \"plugin_owner\": \"ModelScopeGPT\", \"plugin_type\": \"default\", \"plugin_schema_for_model\": {\"name\": \"modelscope_text-address\", \"description\": \"针对中文的地址信息,识别出里面的元素,包括省、市、区、镇、社区、道路、路号、POI、楼栋号、户室号等\", \"url\": \"http://78.171.158.54:1470/\", \"paths\": [{\"name\": \"modelscope_text-address\", \"model_id\": \"/damo/mgeo_geographic_elements_tagging_chinese_base\", \"method\": \"post\", \"description\": \"针对中文的地址信息,识别出里面的元素,包括省、市、区、镇、社区、道路、路号、POI、楼栋号、户室号等\", \"parameters\": [{\"name\": \"text\", \"description\": \"用户输入的地址信息\", \"required\": \"True\"}]}]}}"
        },
        {
            "from": "user",
            "value": "现在我给你另一条地址,请识别出里面的元素。输入地址:北京市海淀区中关村大街27号"
        },
        {
            "from": "assistant",
            "value": "<|startofthink|>```JSON\n{\"api_name\": \"modelscope_text-address\", \"url\": \"http://90.16.54.177:2332/damo/mgeo_geographic_elements_tagging_chinese_base\", \"parameters\": {\"text\": \"北京市海淀区中关村大街27号\"}}\n```<|endofthink|>\n\n<|startofexec|>```JSON\n{\"prov\": \"北京市\", \"city\": \"北京市\", \"district\": \"海淀区\", \"road\": \"中关村大街\", \"number\": \"27号\"}\n```<|endofexec|>\n地址识别json表示:{\"prov\": \"北京市\", \"city\": \"北京市\", \"district\": \"海淀区\", \"road\": \"中关村大街\", \"number\": \"27号\"}。我使用的模型是ModelScope的'damo/mgeo_geographic_elements_tagging_chinese_base'模型。这是基于达摩院联合高德发布的多任务多模态地址预训练底座MGeo模型微调得到的。"
        },
        {
            "from": "user",
            "value": "请识别以下地址中的元素。包括:省、市、区、镇、社区、道路、路号、POI、楼栋号、户室号等。输入地址:北京市海淀区上地十街10号院"
        },
        {
            "from": "assistant",
            "value": "<|startofthink|>```JSON\n{\"api_name\": \"modelscope_text-address\", \"url\": \"http://78.171.158.54:1470/damo/mgeo_geographic_elements_tagging_chinese_base\", \"parameters\": {\"text\": \"北京市海淀区上地十街10号院\"}}\n```<|endofthink|>\n\n<|startofexec|>```JSON\n{\"prov\": \"北京市\", \"city\": \"北京市\", \"district\": \"海淀区\", \"town\": \"上地街道\", \"community\": \"十街10号院\"}\n```<|endofexec|>\n地址识别结果json表示:{\"prov\": \"北京市\", \"city\": \"北京市\", \"district\": \"海淀区\", \"town\": \"上地街道\", \"community\": \"十街10号院\"}。本API使用的是ModelScope的'damo/mgeo_geographic_elements_tagging_chinese_base'模型,为了更好地提高模型的训练效果,我们在达摩院联合高德发布的多任务多模态地址预训练底座MGeo模型上进行了微调。"
        }
    ]
}

经过排查,发现是 extract_json_objects 函数,https://github.com/InternLM/xtuner/blob/main/xtuner/dataset/map_fns/dataset_map_fns/msagent_map_fn.py#L45 。在成功发现可解析的 json 部分后,无论是否其含有 name 和 description 字段,都会跳过这一部分,尽管这一部分可能嵌套包含着所需的数据。

原始 extract_json_objects 函数部分如下:

result, index = decoder.raw_decode(text[match:])
if 'name' in result and 'description' in result:
    results.append(result)
pos = match + index

打断点后,可以发现代码得到的所有 result 为:

{'plugin_name': 'modelscope_text-address', 'plugin_owner': 'ModelScopeGPT', 'plugin_type': 'default', 'plugin_schema_for_model': {'name': 'modelscope_text-address', 'description': '针对中文的地址信息,识别出里面的元素,包括省、市、区、镇、社区、道路、路号、POI、楼栋号、户室号等', 'url': 'http://104.61.144.17:1354/', 'paths': [{'name': 'modelscope_text-address', 'model_id': '/damo/mgeo_geographic_elements_tagging_chinese_base', 'method': 'post', 'description': '针对中文的地址信息,识别出里面的元素,包括省、市、区、镇、社区、道路、路号、POI、楼栋号、户室号等', 'parameters': [{'name': 'text', 'description': '用户输入的地址信息', 'required': 'True'}]}]}}
{'plugin_name': 'modelscope_text-address', 'plugin_owner': 'ModelScopeGPT', 'plugin_type': 'default', 'plugin_schema_for_model': {'name': 'modelscope_text-address', 'description': '针对中文的地址信息,识别出里面的元素,包括省、市、区、镇、社区、道路、路号、POI、楼栋号、户室号等', 'url': 'http://90.16.54.177:2332/', 'paths': [{'name': 'modelscope_text-address', 'model_id': '/damo/mgeo_geographic_elements_tagging_chinese_base', 'method': 'post', 'description': '针对中文的地址信息,识别出里面的元素,包括省、市、区、镇、社区、道路、路号、POI、楼栋号、户室号等', 'parameters': [{'name': 'text', 'description': '用户输入的地址信息', 'required': 'True'}]}]}}
{'plugin_name': 'modelscope_text-address', 'plugin_owner': 'ModelScopeGPT', 'plugin_type': 'default', 'plugin_schema_for_model': {'name': 'modelscope_text-address', 'description': '针对中文的地址信息,识别出里面的元素,包括省、市、区、镇、社区、道路、路号、POI、楼栋号、户室号等', 'url': 'http://78.171.158.54:1470/', 'paths': [{'name': 'modelscope_text-address', 'model_id': '/damo/mgeo_geographic_elements_tagging_chinese_base', 'method': 'post', 'description': '针对中文的地址信息,识别出里面的元素,包括省、市、区、镇、社区、道路、路号、POI、楼栋号、户室号等', 'parameters': [{'name': 'text', 'description': '用户输入的地址信息', 'required': 'True'}]}]}}

可见,检索到可解析的 json 部分后就完全跳过了这一部分。

修改后逻辑约为:

result, index = decoder.raw_decode(text[match:])
if 'name' in result and 'description' in result:
    results.append(result)
    pos = match + index
else:
    pos = match + 1

即,只有完全解析到了 name 与 description 字段,才会跳过这一部分。

此外,system_text 字符串内部的空格(代码缩进)导致了输出的结果存在大量空白。(不确定是否会对训练过程产生影响)

I would like to fix this bug and create a PR!

LZHgrla commented 7 months ago

@fanqiNO1 Hi 原代码确实存在这一问题,您的描述、分析及修改后的代码是正确的。

非常感谢,请问是否方便提交一个PR来修正这一问题?

关于 system_text 这一情况,也是需要进行优化的。我们可以使用“括号+单引号”来定义system字符串,而非现在所使用的“三引号”。

fanqiNO1 commented 7 months ago

谢谢答复!我会尽快把 PR 提交上来。

fanqiNO1 commented 6 months ago

@fanqiNO1 Hi 原代码确实存在这一问题,您的描述、分析及修改后的代码是正确的。

非常感谢,请问是否方便提交一个PR来修正这一问题?

关于 system_text 这一情况,也是需要进行优化的。我们可以使用“括号+单引号”来定义system字符串,而非现在所使用的“三引号”。

PR 已经提交上来了,位于 PR #419