LLM 大模型學習必知必會系列(十):基於AgentFabric實現互動式智慧體應用,Agent實戰

汀、人工智能發表於2024-05-30

LLM 大模型學習必知必會系列(十):基於AgentFabric實現互動式智慧體應用,Agent實戰

0.前言

**Modelscope **是一個互動式智慧體應用基於ModelScope-Agent,用於方便地建立針對各種現實應用量身定製智慧體,目前已經在生產級別落地。AgentFabric圍繞可插拔和可定製的LLM構建,並增強了指令執行、額外知識檢索和利用外部工具的能力。AgentFabric提供的互動介面包括:

  • 智慧體構建器:一個自動指令和工具提供者,透過與使用者聊天來定製使用者的智慧體

  • 使用者智慧體:一個為使用者的實際應用定製的智慧體,提供構建智慧體或使用者輸入的指令、額外知識和工具

  • 配置設定工具:支援使用者定製使用者智慧體的配置,並實時預覽使用者智慧體的效能

🔗 目前agentfabric圍繞DashScope提供的 Qwen2.0 LLM API 在AgentFabric上構建不同的智慧體應用。

在使用dashscope提供的qwen api構建應用與定製互動的過程中,我們發現選取千億級別引數的qwen-max或開源的qwen-72b等大規模引數模型能獲得較好的工具呼叫和角色扮演效果。大規模引數模型效果好,但難以在消費級機器上進行本地部署呼叫;同時小模型如qwen-7b-chat對工具呼叫的能力較弱。因此本篇旨在針對AgentFabric的工具呼叫場景,提供可用的資料集和微調方法,使稍小的模型如qwen-7b-chat也具有能在agentfabric中完成工具呼叫的能力。

1.環境安裝

參考:Agent微調最佳實踐-環境安裝

    # 設定pip全域性映象 (加速下載)
    pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
    # 安裝ms-swift
    git clone https://github.com/modelscope/swift.git
    cd swift
    pip install -e .[llm]
    
    # 環境對齊 (通常不需要執行. 如果你執行錯誤, 可以跑下面的程式碼, 倉庫使用最新環境測試)
    pip install -r requirements/framework.txt  -U
    pip install -r requirements/llm.txt  -U

2.資料準備

為訓練Agent能力,魔搭官方提供了兩個開源資料集:

  • 魔搭通用問答知識資料集 該資料集包含了38萬條通用知識多輪對話資料

  • 魔搭通用Agent訓練資料集 該資料集包含了3萬條Agent格式的API呼叫資料

相關使用方式參考:Agent微調最佳實踐-資料準備

為了讓qwen-7b-chat能夠在Agentfabric上有比較好的效果,我們嘗試使用通用Agent訓練資料集ms_agent對qwen-7b-chat進行微調。微調後模型確實能夠在ms_agent格式的prompt下獲得工具呼叫能力。但在agentfabric上對工具的呼叫表現欠佳,出現了不呼叫工具、呼叫工具時配置的引數錯誤、對工具呼叫結果的總結錯誤等,10次訪問能成功正確呼叫1次。

  • 不呼叫工具;總結時胡編亂造

  • 呼叫時不按要求填寫引數

考慮到agentfabric是基於大規模文字模型調配的prompt,側重角色扮演和應用,與ms_agent的prompt格式有區別。finetuned稍小模型的通用泛化性稍弱,換格式呼叫確實可能存在效果欠佳的情況。

ms_agent資料集格式:

    Answer the following questions as best you can. You have access to the following APIs:
    1. fire_recognition: Call this tool to interact with the fire recognition API. This API is used to recognize whether there is fire in the image. Parameters: [{"name": "image", "description": "The input image to recognize fire", "required": "True"}]
    
    Use the following format:
    
    Thought: you should always think about what to do
    Action: the action to take, should be one of the above tools[fire_recognition, fire_alert, call_police, call_fireman]
    Action Input: the input to the action
    Observation: the result of the action
    ... (this Thought/Action/Action Input/Observation can be repeated zero or more times)
    Thought: I now know the final answer
    Final Answer: the final answer to the original input question
    Begin!
    
    輸入圖片是/tmp/2.jpg,協助判斷圖片中是否存在著火點

agentfabric:

    # 工具

    ## 你擁有如下工具:
    
    amap_weather: amap_weather API。獲取對應城市的天氣資料 輸入引數: {"type": "object", "properties": {"location": {"type": "string", "description": "城市/區具體名稱,如`北京市海淀區`請描述為`海淀區`"}}, "required": ["location"]} Format the arguments as a JSON object.
    
    ## 當你需要呼叫工具時,請在你的回覆中穿插如下的工具呼叫命令,可以根據需求呼叫零次或多次:
    
    工具呼叫
    Action: 工具的名稱,必須是[amap_weather]之一
    Action Input: 工具的輸入
    Observation: <result>工具返回的結果</result>
    Answer: 根據Observation總結本次工具呼叫返回的結果,如果結果中出現url,請使用如下格式展示出來:![圖片](url)
    
    
    # 指令
    
    你扮演一個天氣預報助手,你需要查詢相應地區的天氣,並呼叫給你的畫圖工具繪製一張城市的圖。
    
    請注意:你具有影像和影片的展示能力,也具有執行程式碼的能力,不要在回覆中說你做不到。
    
    (。你可以使用工具:[amap_weather])朝陽區天氣怎樣?

2.1 ms_agent_for_agentfabric資料集

2.1.1 ms_agent 更新資料

為解決上述的prompt格式不匹配問題,我們首先將ms_agent轉換成agentfabric的prompt組織格式。從ms_agent到agentfabric的轉換過程可以透過如下指令碼實現:

    import json
    import re
    
    sys_prefix = "\n# 工具\n\n## 你擁有如下工具:\n\n"
    
    def _process_system(text):
        apis_info = []
        api_pattern = r"(?<=\n\d\.)(.*?})(?=])"
        apis = re.findall(api_pattern,text,re.DOTALL)
        sys_prompt = sys_prefix
        func_names = []
        for api in apis:
            func_name = re.search(r'(.*?):', api).group(1).strip()
            func_names.append(func_name)
            api_name = re.search(r'(\S+)\sAPI', api).group(1)
            api_desc = re.search(r"useful for\?\s(.*?)\.",api).group(1)
            sys_prompt += f"{func_name}: {api_name} API。{api_desc}" + "輸入引數: {\"type\": \"object\", \"properties\": {"
            paras = re.findall(r"Parameters: \[({.*})",api,re.DOTALL)
            required_paras = []
            for para in paras:
                para_name = re.search(r'"name": "(.*?)"',para).group(1)
                desc = re.search(r'"description": "(.*?)"',para).group(1)
                if re.search(r'"required": "(.*)"',para).group(1).strip().lower() == "true": required_paras.append(para_name)
                sys_prompt += f'"\{para_name}\": {{\"type\": \"string\", \"description\": \"{desc}\"}}' 
            sys_prompt += "},\"required\": " + json.dumps(required_paras) + "} Format the arguments as a JSON object." + "\n\n"
        func_names = json.dumps(func_names)
        sys_prompt += f"## 當你需要呼叫工具時,請在你的回覆中穿插如下的工具呼叫命令,可以根據需求呼叫零次或多次:\n\n工具呼叫\nAction: 工具的名稱,必須是{func_names}之一\nAction Input: 工具的輸入\nObservation: <result>工具返回的結果</result>\nAnswer: 根據Observation總結本次工具呼叫返回的結果,如果結果中出現url,請使用如下格式展示出來:![圖片](url)\n\n\n# 指令\n\n你扮演AI-Agent,\n你具有下列具體功能:\n下面你將開始扮演\n\n請注意:你具有影像和影片的展示能力,也具有執行程式碼的能力,不要在回覆中說你做不到。\n"
    
        return sys_prompt
    
    jsonl_file_path = 'ms_agent/train_agent_react.jsonl'
    target_file_path = 'new_ms_agent.jsonl'
    
    modified_data = []
    
    with open(jsonl_file_path, 'r', encoding='utf-8') as file:
        for line in file:
            json_obj = json.loads(line)
            system_prompt = json_obj["conversations"][0]["value"]
            json_obj["conversations"][0]["value"] = _process_system(system_prompt)
            modified_data.append(json_obj)
    
    with open(target_file_path, 'w', encoding='utf-8') as file:
        for json_obj in modified_data:
            file.write(json.dumps(json_obj, ensure_ascii=False) + '\n')

轉換後的30000條資料已上傳至modelscope資料集,參考資料集連結: https://modelscope.cn/datasets/AI-ModelScope/ms_agent_for_agentfabric/summary

使用該資料集finetune後,得到的模型在agentfabric上的效果明顯好轉:每次訪問都能夠去呼叫工具,且基本能正確呼叫工具。但同時也有對工具呼叫結果的總結稍弱、有時無法自動停止輸出等問題。

  • 總結能力稍弱:已經查詢到天氣,仍回答“無法獲取實時天氣資料”

  • 停止能力稍弱:未生成終止符,多次呼叫同一工具同一引數

2.1.2 AgentFabric新增資料

ms_agent資料集全為英文、且並無agentfabric的roleplay等內容資訊。雖然基模型qwen-7b-chat擁有中文能力,使透過new_ms_agent 資料集finetune後的模型能夠正常識別使用者意圖,正確呼叫工具;但總結和停止能力都稍弱。 為此,我們透過開源的agentfabric框架實際呼叫訪問,獲得了一些agentfabric使用過程中實際傳送給模型的prompt。篩選處理成一個資料集,加上new_ms_agent的資料一起finetune。得到的模型在agentfabric上修復了此前的總結稍弱、有時無法自動停止問題。

  • 多次呼叫均響應正常,甚至有一次get到了instruction中的內容。

處理好的488條資料已上傳至modelscope資料集,可透過如下連結訪問下載:

https://modelscope.cn/api/v1/datasets/AI-ModelScope/ms_agent_for_agentfabric/repo?Revision=master&FilePath=addition.jsonl

3.效果評估

測試資料來自以下資料集:

  • https://modelscope.cn/datasets/AI-ModelScope/ms_agent_for_agentfabric/summary

  • https://modelscope.cn/datasets/iic/ms_bench/summary

以上資料混合後,按照1%比例取樣作為test data

備註: 橫軸為訓練步數,縱軸為準確率

我們在原有的兩個用於agent訓練集上又額外的增加了基於agentfabric 版本的資料集,目前可供參考的agent應用資料集如下:

  • 魔搭通用agent資料集(agentfabric版)該資料集包含了30488條可支援AgentFabric格式的API呼叫資料

  • 魔搭通用問答知識資料集 該資料集包含了38萬條通用知識多輪對話資料

  • 魔搭通用Agent訓練資料集 該資料集包含了3萬條Agent格式的API呼叫資料

4.微調流程

訓練準備,以下執行過程參考了Agent微調最佳實踐-微調

4.1 在gpu機器執行

將new_ms_agent.jsonl和addition.jsonl兩個檔案的具體路徑透過--custom_train_dataset_path進行配置後,在8* A100 環境中可透過以下命令開啟訓練,需約2-3小時;如果是單卡訓練,需要修改nproc_per_node=1。

    # Experimental environment: A100
    
    cd examples/pytorch/llm
    
    # 如果使用1張卡則配置nproc_per_node=1
    nproc_per_node=8
    
    export PYTHONPATH=../../..
    
    # 時間比較久,8*A100需要 2+小時,nohup執行
    nohup torchrun \
        --nproc_per_node=$nproc_per_node \
        --master_port 29500 \
        llm_sft.py \
        --model_id_or_path qwen/Qwen-7B-Chat \
        --model_revision master \
        --sft_type lora \
        --tuner_backend swift \
        --dtype AUTO \
        --output_dir output \
        --custom_train_dataset_path ms_agent_for_agentfabric/new_ms_agent.jsonl ms_agent_for_agentfabric/addition.jsonl
        --train_dataset_mix_ratio 2.0 \
        --train_dataset_sample -1 \
        --num_train_epochs 2 \
        --max_length 2048 \
        --check_dataset_strategy warning \
        --lora_rank 8 \
        --lora_alpha 32 \
        --lora_dropout_p 0.05 \
        --lora_target_modules ALL \
        --self_cognition_sample 3000 \
        --model_name 卡卡羅特 \
        --model_author 陶白白 \
        --gradient_checkpointing true \
        --batch_size 2 \
        --weight_decay 0.01 \
        --learning_rate 5e-5 \
        --gradient_accumulation_steps $(expr 1 / $nproc_per_node) \
        --max_grad_norm 0.5 \
        --warmup_ratio 0.03 \
        --eval_steps 100 \
        --save_steps 100 \
        --save_total_limit 2 \
        --logging_steps 10 &

訓練完成後,能在nohup.out檔案看到最後的 log 顯示最佳checkpoint的存放路徑

best_model_checkpoint: /home/workspace/swift/examples/pytorch/llm/output/qwen-7b-chat/v0-20240314-211944/checkpoint-2828

[INFO:swift] best_model_checkpoint: /home/workspace/swift/examples/pytorch/llm/output/qwen-7b-chat/v0-20240314-211944/checkpoint-2828
[INFO:swift] images_dir: /home/workspace/swift/examples/pytorch/llm/output/qwen-7b-chat/v0-20240314-211944/images
[INFO:swift] End time of running main: 2024-03-14 23:33:54.658745

5.部署模型

此時我們獲得了一個自己的finetuned model,可以將它部署到自己的機器上使用。以下執行過程參考了 VLLM推理加速與部署-部署

5.1 合併lora

由於sft_type=lora,部署需要先將LoRA weights合併到原始模型中:

    python tools/merge_lora_weights_to_model.py --model_id_or_path /dir/to/your/base/model --model_revision master --ckpt_dir /dir/to/your/lora/model

其中需要替換 /dir/to/your/base/model 和 /dir/to/your/lora/model為自己本地的路徑, /dir/to/your/lora/model為訓練最終的best_model_checkpoint。/dir/to/your/base/model 可以透過snapshot_download介面檢視,訓練時使用的基模型為qwen/Qwen-7B-Chat,則本地路徑為:

    from modelscope import snapshot_download
    base_model_path = snapshot_download('qwen/Qwen-7B-Chat')
    print(base_model_path)

執行後完成後得到merge後的ckpt路徑。

    [INFO:swift] Saving merged weights...
    [INFO:swift] Successfully merged LoRA and saved in /home/workspace/swift/examples/pytorch/llm/output/qwen-7b-chat/v0-20240314-211944/checkpoint-2828-merged.
    [INFO:swift] End time of running main: 2024-03-18 10:34:54.307471

5.2 拉起部署

    nohup python -m vllm.entrypoints.openai.api_server --model /dir/to/your/model-merged --trust-remote-code &

需要將/dir/to/your/model-merged替換成自己本地merge後的ckpt路徑。

當nohup.out檔案顯示以下資訊時,表示部署完成

INFO:     Started server process [531583]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

測試部署:需要將/dir/to/your/model-merged替換成自己本地merge後的ckpt路徑

    curl http://localhost:8000/v1/completions -H "Content-Type: application/json" -d '{"model": "/dir/to/your/model-merged", "prompt": "San Francisco is a", "max_tokens": 7, "temperature": 0}'

6.Modelscope-Agent中使用

6.1 簡單測試

可透過如下程式碼簡單測試模型能力,使用時需要將/dir/to/your/model-merged替換成自己本地merge後的ckpt路徑。

    from modelscope_agent.agents.role_play import RolePlay  # NOQA
    
    
    def test_weather_role():
        role_template = '你扮演一個天氣預報助手,你需要查詢相應地區的天氣,並呼叫給你的畫圖工具繪製一張城市的圖。'
    
        llm_config =  {
            "model_server": "openai",
            "model": "/dir/to/your/model-merged",
            "api_base": "http://localhost:8000/v1",
            "is_chat": True,
            "is_function_call": False,
            "support_stream": False
        }
        #llm_config = {"model": "qwen-max", "model_server": "dashscope"}
    
        # input tool name
        function_list = ['amap_weather']
    
        bot = RolePlay(
            function_list=function_list, llm=llm_config, instruction=role_template)
    
        response = bot.run('朝陽區天氣怎樣?')
    
        text = ''
        for chunk in response:
            text += chunk
        print(text)
        assert isinstance(text, str)
    
    
    test_weather_role()

6.2 Agentfabric中使用

  1. 進入agentfabric目錄
    cd modelscope-agent/apps/agentfabric
  1. 在config/model_config.json檔案,新增訓好的本地模型

    "my-qwen-7b-chat": {
        "type": "openai",
        "model": "/dir/to/your/model-merged",
        "api_base": "http://localhost:8000/v1",
        "is_chat": true,
        "is_function_call": false,
        "support_stream": false
    }
    
  2. agentfabric目錄下執行如下命令拉起gradio

    GRADIO_SERVER_NAME=0.0.0.0 PYTHONPATH=../../  python app.py

然後在瀏覽器中輸入你 伺服器IP:7860開啟即可看到如下介面

相關文章