簡(jiǎn)單來(lái)說(shuō),Agent 就是借助 LLM 的強(qiáng)大語(yǔ)言理解能力、邏輯推理能力調(diào)用工具來(lái)幫助人類(lèi)完成任務(wù)。但同時(shí)也存在著一些挑戰(zhàn),例如基礎(chǔ)模型的能力決定 agent 調(diào)用工具的效率,但基礎(chǔ)模型本身存在著大模型幻覺(jué)等問(wèn)題。

本文以「輸入一段指令自動(dòng)實(shí)現(xiàn)復(fù)雜任務(wù)拆分和函數(shù)調(diào)用」的場(chǎng)景為例,來(lái)構(gòu)建基礎(chǔ) Agent 流程,并側(cè)重講解如何通過(guò)「基礎(chǔ)模型選擇」、「Prompt設(shè)計(jì)」等來(lái)成功構(gòu)建「任務(wù)拆分」和「函數(shù)調(diào)用」模塊。

項(xiàng)目地址:

https://sota.jiqizhixin.com/project/smart_agent

GitHub Repo:

https://github.com/zzlgreat/smart_agent

任務(wù)拆分&函數(shù)調(diào)用 Agent 流程

對(duì)于實(shí)現(xiàn)「輸入一段指令自動(dòng)實(shí)現(xiàn)復(fù)雜任務(wù)拆分和函數(shù)調(diào)用」,項(xiàng)目構(gòu)建的 Agent 流程如下:

為了實(shí)現(xiàn)上述流程,在「任務(wù)拆分」和「函數(shù)調(diào)用」模塊中,項(xiàng)目分別設(shè)計(jì)了兩個(gè)微調(diào)模型,來(lái)實(shí)現(xiàn)將復(fù)雜任務(wù)拆分并按需調(diào)用自定義函數(shù)的功能。歸納總結(jié)的模型 solver,可以和拆分任務(wù)模型相同。

微調(diào)任務(wù)拆分&函數(shù)調(diào)用模型

2.1 微調(diào)經(jīng)驗(yàn)總結(jié)

在「任務(wù)拆分」模塊中,大模型需要具有將復(fù)雜任務(wù)分解為簡(jiǎn)單任務(wù)的能力。「任務(wù)拆分」成功與否,極大程度上取決于兩點(diǎn):

同時(shí)希望任務(wù)拆分模型在給定 prompt 模板下的輸出格式可以盡可能相對(duì)固定,但也不會(huì)過(guò)擬合喪失模型原本的推理和泛化能力,這里采取 lora 微調(diào) qv 層,對(duì)原模型的結(jié)構(gòu)改動(dòng)盡可能地少。

在「函數(shù)調(diào)用」模塊中,大模型需要具備穩(wěn)定調(diào)用工具的能力,以適應(yīng)處理任務(wù)的要求:

此外,在算力使用方面,通過(guò) lora/qlora 微調(diào)實(shí)現(xiàn)了低算力條件下大型語(yǔ)言模型的微調(diào)和推理,并采用量化部署的方式,進(jìn)一步降低推理的門(mén)檻。

2.2 基礎(chǔ)模型選擇

針對(duì)「任務(wù)拆分」模型的選擇,希望模型同時(shí)具備強(qiáng)泛化能力和一定的思維鏈能力。這里可以參考 HuggingFace 上 Open LLM Leaderboard 來(lái)選擇模型,更多關(guān)注的是衡量文本模型多任務(wù)準(zhǔn)確性的測(cè)試 MMLU 和綜合評(píng)分 Average。

本項(xiàng)目選定任務(wù)拆分模型型號(hào)為:

針對(duì)「函數(shù)調(diào)用」模型的選擇,meta 開(kāi)源的 Llama2 版代碼編程模型 CodeLlama 原始訓(xùn)練數(shù)據(jù)包含了大量的代碼數(shù)據(jù),這樣就可以嘗試自定義腳本的 qlora 微調(diào)。針對(duì)函數(shù)調(diào)用的模型,選擇 CodeLlama 模型(34b/13b/7b 均可)作為基座。

本項(xiàng)目選定函數(shù)調(diào)用模型型號(hào)為:

針對(duì)「函數(shù)調(diào)用」模型微調(diào),項(xiàng)目采用 prompt loss mask 的方式進(jìn)行 qlora 訓(xùn)練,以穩(wěn)定處理模型輸出。損失函數(shù)調(diào)整方式如下:

  1. loss_mask 是一個(gè)與輸入序列 input_ids 形狀相同的張量 (tensor)。每個(gè)元素都是 0 或 1,其中 1 表示對(duì)應(yīng)的位置的標(biāo)簽應(yīng)被考慮在損失計(jì)算中,而 0 表示不應(yīng)被考慮。
  2. 例如,如果某些標(biāo)簽是填充的(通常是因?yàn)榕幚碇械男蛄虚L(zhǎng)度不同),不想在損失的計(jì)算中考慮這些填充的標(biāo)簽。在這種情況下,loss_mask 為這些位置提供了一個(gè) 0,從而遮蔽掉了這些位置的損失。
  1. 首先,使用了 CrossEntropyLoss 來(lái)計(jì)算未 mask 的損失。設(shè)置 reduction=’none’ 來(lái)確保為序列中的每個(gè)位置都返回一個(gè)損失值,而不是一個(gè)總和或平均值。
  2. 然后,使用 loss_mask 來(lái) mask 損失。通過(guò)將 loss_mask 與 losses 相乘,得到了 masked_loss。這樣,loss_mask 中為 0 的位置在 masked_loss 中的損失值也為 0。
  1. 將所有的 masked_loss 求和,并通過(guò) loss_mask.sum() 來(lái)歸一化。這確保了你只考慮了被 mask 為 1 的標(biāo)簽的損失。為了防止除以零的情況,加一個(gè)很小的數(shù) 1e-9。
  2. 如果 loss_mask 的所有值都是 0(即 loss_mask.sum() == 0),那么直接返回一個(gè) 0 的損失值。

2.2 硬件需求:

2.3 Prompt 格式設(shè)計(jì)

對(duì)于任務(wù)拆分,項(xiàng)目采用了大型語(yǔ)言模型高效推理框架 ReWOO(Reasoning WithOut Observation)[2] 中 planner 設(shè)計(jì)的 Prompt 格式。這里只需把’Wikipedia[input]’等函數(shù)替換為的函數(shù)和描述即可,該 prompt 示例如下:

For the following tasks, make plans that can solve the problem step-by-step. 
For each plan, indicate which external tool together with tool input to retrieve evidence.
You can store the evidence into a variable #E that can be called by later tools.
(Plan, #E1, Plan, #E2, Plan, ...) Tools can be one of the following:
Wikipedia[input]: Worker that search for similar page contents from Wikipedia.
Useful when you need to get holistic knowledge about people, places, companies, historical events, or other subjects.
The response are long and might contain some irrelevant information. Input should be a search query.
LLM[input]: A pretrained LLM like yourself. Useful when you need to act with general world knowledge and common sense.
Prioritize it when you are confident in solving the problem yourself. Input can be any instruction.

對(duì)于函數(shù)調(diào)用,因?yàn)楹罄m(xù)會(huì)進(jìn)行 qlora 微調(diào),所以直接采用 huggingface 上開(kāi)源函數(shù)調(diào)用數(shù)據(jù)集 [3] 中的 prompt 樣式。請(qǐng)參見(jiàn)下文。

指令數(shù)據(jù)集準(zhǔn)備

3.1 數(shù)據(jù)來(lái)源

3.2 數(shù)據(jù)集格式

### Instruction:

<prompt> (without the <>)

### Response:
如:
### Instruction:
For the following tasks, make plans that can solve the problem step-by-step. For each plan, indicate which external tool together with tool input to retrieve evidence. You can store the evidence into a variable #E that can be called by later tools. (Plan, #E1, Plan, #E2, Plan, ...) Tools can be one of the following:get_current_time[input]: Get the current time for now. search_bing[input]: Search the web for content on Bing, and return the top 10 results. Remember, the results may not as good as Wikipedia. If you think the result will not exist in wikipedia, use it. search_wiki[input]: Search the web for content on Wikipedia, and return the top 3 results. If you think the result can exist in wikipedia, use it. search_bilibili[input]: Search for videos on Bilibili, which is a website full of ACG. It can return top 10 search results. save_file[input]: save a file in the target dir which contains the data. query_mysql[input]: Execute the sql in the local mysql database. And return the result.

What movies did the director of 'Oppenheim' direct? List the top 10 best.

### Response:
Step 1: Identify the director of "Oppenheimer" movie.
#E1 = search_wiki("Director of Oppenheimer")

Step 2: Retrieve information about the director's other works.
If the retrieved name exists in Wikipedia, proceed with searching their filmography using search_wiki. Otherwise, try searching through Bing or another source like IMDb.

For example, if Christopher Nolan is found as the director of "Oppenheimer":
#E2 = search_bing("Filmography of Christopher Nolan")

Step 3: Extract the list of films directed by this person from the retrieved information.
From the returned results, extract the titles of the top 10 best movies according to critics/audience ratings or personal preference.

這里采取 trelis 的數(shù)據(jù)集的格式。數(shù)據(jù)集量并不多,只有 55 行。結(jié)構(gòu)上其實(shí)也是 alpaca 格式。分為 systemPrompt,userPrompt,assistantResponse 分別對(duì)應(yīng) alpaca 的 Instruction,prompt,Response。示例如下:

微調(diào)過(guò)程說(shuō)明

4.1 微調(diào)環(huán)境

ubuntu 22.04 系統(tǒng),cuda 11.8,Pytorch 2.0.1,采取了 LLaMA-Efficient-Tuning 框架。Deepspeed 0.10.4

4.2 微調(diào)步驟

1)針對(duì) Marcoroni-70B 的 lora 微調(diào)

  1. LLaMA-Efficient-Tuning 框架支持 deepspeed 集成,在訓(xùn)練開(kāi)始前輸入 accelerate config 進(jìn)行設(shè)置,根據(jù)提示選擇 deepspeed zero stage 3,因?yàn)槭?6 卡總計(jì) 144G 的 VRAM 做 lora 微調(diào),offload optimizer states 可以選擇 none, 不卸載優(yōu)化器狀態(tài)到內(nèi)存。
  2. offload parameters 需要設(shè)置為 cpu,將參數(shù)量卸載到內(nèi)存中,這樣內(nèi)存峰值占用最高可以到 240G 左右。gradient accumulation 需要和訓(xùn)練腳本保持一致,這里選擇的是 4。gradient clipping 用來(lái)對(duì)誤差梯度向量進(jìn)行歸一化,設(shè)置為 1 可以防止梯度爆炸。
  3. zero.init 可以進(jìn)行 partitioned 并轉(zhuǎn)換為半精度,加速模型初始化并使高參數(shù)的模型能夠在 CPU 內(nèi)存中全部進(jìn)行分配。這里也可以選 yes。

全部選擇完成后,新建一個(gè)訓(xùn)練的 bash 腳本,內(nèi)容如下:

accelerate launch src/train_bash.py \
--stage sft \
--model_name_or_path your_model_path \
--do_train \
--dataset rewoo \
--template alpaca \
--finetuning_type lora \
--lora_target q_proj,v_proj \
--output_dir your_output_path \
--overwrite_cache \
--per_device_train_batch_size 1 \
--gradient_accumulation_steps 4 \
--lr_scheduler_type cosine \
--logging_steps 10 \
--save_steps 1000 \
--learning_rate 5e-6 \
--num_train_epochs 4.0 \
--plot_loss \
--flash_attn \
--bf16

這樣的設(shè)置需要的內(nèi)存峰值最高可以到 240G,但還是保證了 6 卡 4090 可以進(jìn)行訓(xùn)練。開(kāi)始的時(shí)候可能會(huì)比較久,這是因?yàn)?deepspeed 需要對(duì)模型進(jìn)行 init。之后訓(xùn)練就開(kāi)始了。

共計(jì)用時(shí) 8:56 小時(shí)。本次訓(xùn)練中因?yàn)橹靼迳系?NVME 插槽會(huì)和 OCULINK 共享一路 PCIE4.0 x16 帶寬。所以 6 張中的其中兩張跑在了 pcie4.0 X4 上,從上圖就可以看出 RX 和 TX 都只是 PCIE4.0 X4 的帶寬速度。這也成為了本次訓(xùn)練中最大的通訊瓶頸。如果全部的卡都跑在 pcie 4.0 x16 上,速度應(yīng)該是比現(xiàn)在快不少的。

以上是 LLaMA-Efficient-Tuning 自動(dòng)生成的 loss 曲線,可以看到 4 個(gè) epoch 后收斂效果還是不錯(cuò)的。

2)針對(duì) codellama 的 qlora 微調(diào)

根據(jù)上文所述的 prompt loss mask 方法重構(gòu)了 trainer 類(lèi)(見(jiàn)項(xiàng)目代碼倉(cāng)庫(kù) func_caller_train.py)。因?yàn)閿?shù)據(jù)集本身比較?。?5 行)。所以跑 4 個(gè) epoch 只用了兩分鐘,模型很快達(dá)到了收斂。

4.3微調(diào)完成后的測(cè)試效果

在項(xiàng)目代碼倉(cāng)庫(kù)中,提供了一個(gè)簡(jiǎn)短可用的 toolkit 示例。里面的函數(shù)包括:

  1. 必應(yīng)搜索
  2. 維基搜索
  3. bilibili 搜索
  4. 獲取當(dāng)前時(shí)間
  5. 保存文件

現(xiàn)在有一個(gè) 70B 和一個(gè) 34B 的模型,在實(shí)際使用中,用 6 張 4090 同時(shí)以 bf16 精度運(yùn)行這兩個(gè)模型是不現(xiàn)實(shí)的。但是可以通過(guò)量化的方法壓縮模型大小,同時(shí)提升模型推理速度。這里采用高性能 LLM 推理庫(kù) exllamav2 運(yùn)用 flash_attention 特性來(lái)對(duì)模型進(jìn)行量化并推理。在項(xiàng)目頁(yè)面中作者介紹了一種獨(dú)特的量化方式,本文不做贅述。按照其中的轉(zhuǎn)換機(jī)制可以將 70b 的模型按照 2.5-bit 量化為 22G 的大小,這樣一張顯卡就可以輕松加載。

1)測(cè)試方法

給定一段不在訓(xùn)練集中的復(fù)雜任務(wù)描述,同時(shí)在 toolkit 中添加訓(xùn)練集中不包含的函數(shù)和對(duì)應(yīng)描述。如果 planner 可以完成對(duì)任務(wù)進(jìn)行拆分,distributor 可以調(diào)用函數(shù),solver 可以根據(jù)整個(gè)流程對(duì)結(jié)果進(jìn)行總結(jié)。

2)測(cè)試結(jié)果

任務(wù)拆分:先使用 text-generation-webui 快速測(cè)試一下任務(wù)拆分模型的效果,如圖所示:

這里可以寫(xiě)一個(gè)簡(jiǎn)單的 restful_api 接口,方便在 agent 測(cè)試環(huán)境下的調(diào)用(見(jiàn)項(xiàng)目代碼 fllama_api.py)。

函數(shù)調(diào)用:在項(xiàng)目中已經(jīng)寫(xiě)好了一個(gè)簡(jiǎn)單的 planner-distributor-worker-solver 的邏輯。接下來(lái)就讓測(cè)試一下這個(gè)任務(wù)。輸入一段指令:what movies did the director of ‘Killers of the Flower Moon’ direct?List one of them and search it in bilibili.

調(diào)用過(guò)程如下視頻所示:


「搜索 bilibili 」這個(gè)函數(shù)是不包含在項(xiàng)目的函數(shù)調(diào)用訓(xùn)練集中的。同時(shí)這部電影也是一部還沒(méi)有上映的新電影,不確定模型本身的訓(xùn)練數(shù)據(jù)有沒(méi)有包含??梢钥吹?a href="http://www.dlbhg.com/wiki/what-is-a-large-model-understand-the-basic-concepts-of-ai/">模型很好地將輸入指令進(jìn)行拆分:

同時(shí)進(jìn)行函數(shù)調(diào)用得到了以下結(jié)果:點(diǎn)擊結(jié)果是 Goodfellas,和該部電影的導(dǎo)演匹配得上。

總結(jié)

本項(xiàng)目以「輸入一段指令自動(dòng)實(shí)現(xiàn)復(fù)雜任務(wù)拆分和函數(shù)調(diào)用」場(chǎng)景為例,設(shè)計(jì)了一套基本 agent 流程:toolkit-plan-distribute-worker-solver 來(lái)實(shí)現(xiàn)一個(gè)可以執(zhí)行無(wú)法一步完成的初級(jí)復(fù)雜任務(wù)的 agent。通過(guò)基礎(chǔ)模型的選型和 lora 微調(diào)使得低算力條件下一樣可以完成大模型的微調(diào)和推理。并采用量化部署的方式,進(jìn)一步降低推理的門(mén)檻。最后通過(guò)該 pipeline 實(shí)現(xiàn)了一個(gè)搜索電影導(dǎo)演其他作品的示例,實(shí)現(xiàn)了基礎(chǔ)的復(fù)雜任務(wù)完成。

局限性:本文只是基于搜索和基本操作的 toolkit 設(shè)計(jì)了函數(shù)調(diào)用和任務(wù)拆分。使用的工具集非常簡(jiǎn)單,并沒(méi)有太多設(shè)計(jì)。針對(duì)容錯(cuò)機(jī)制也沒(méi)有太多考慮。通過(guò)本項(xiàng)目,大家也可以繼續(xù)向前一步探索 RPA 領(lǐng)域上的應(yīng)用,進(jìn)一步完善 agent 流程,實(shí)現(xiàn)更高程度的智能自動(dòng)化提升流程的可管理性。

本文章轉(zhuǎn)載微信公眾號(hào)@機(jī)器之心SOTA模型

上一篇:

從0到1搭建本地RAG問(wèn)答系統(tǒng):Langchain+Ollama+RSSHub技術(shù)全解析

下一篇:

LangChain 的問(wèn)題所在
#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊(cè)

多API并行試用

數(shù)據(jù)驅(qū)動(dòng)選型,提升決策效率

查看全部API→
??

熱門(mén)場(chǎng)景實(shí)測(cè),選對(duì)API

#AI文本生成大模型API

對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)

#AI深度推理大模型API

對(duì)比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)