該解決方案基於大語言模型(LLM)的意圖識別技術,能夠從海量的資料中學習到複雜的語言規律和使用者行為模式,實現對使用者意圖的更精準識別和更自然流暢的互動體驗。本方案以千問1.5(Qwen1.5)大語言模型為基礎,為您介紹基於LLM的意圖識別解決方案的完整開發流程。
背景資訊
什麼是意圖識別
即AI智能體通過理解人們用自然語言所表達的需求,來執行相應的操作或提供相應的資訊,它是智能互動系統中不可或缺的一環。目前,基於大語言模型(LLM)的意圖識別技術已經得到業界的廣泛關注,並被廣泛應用。
意圖識別技術的典型情境樣本
-
在智能語音助手領域,使用者通過簡單的語音命令與語音助手進行互動。例如,當使用者對語音助手說“我想聽音樂”時,系統需要準確識別出使用者的需求是播放音樂,然後執行相應操作。
-
在智能客服情境中,挑戰則體現在如何處理各種客戶服務請求,並將它們快速準確地分類至例如退貨、換貨、投訴等不同的處理流程中。例如,在電子商務平台上,使用者可能會表達“我收到的商品有瑕疵,我想要退貨”。在這裡,基於LLM的意圖識別系統要能夠迅速捕捉到使用者的意圖是“退貨”,並且自動觸發退貨流程,進一步引導使用者完成後續操作。
使用流程
前提條件
在開始執行操作前,請確認您已完成以下準備工作:
-
已開通PAI(DLC、EAS)後付費,並建立預設工作空間,詳情請參見開通PAI並建立預設工作空間。
-
已建立OSS儲存空間(Bucket),用於儲存訓練資料和訓練獲得的模型檔案。關於如何建立儲存空間,詳情請參見控制台快速入門。
準備訓練資料
支援使用以下兩種方式準備訓練資料:
-
方式二:依據資料準備策略,使用iTAG平台進行資料標註。適用於大規模資料情境,顯著提升標註效率。
資料準備策略
為了提升訓練的有效性和穩定性,您可以參考以下策略準備資料:
-
對於單意圖識別情境,確保每類意圖的標註數量至少為50至100條,當模型微調效果不佳時,您可以考慮增加標註資料量。同時,您需要注意每類意圖的標註資料量盡量均衡,不宜出現某類意圖的標註資料量過多的情況。
-
對於多意圖識別情境或多輪對話情境,建議標註資料量在單意圖識別情境資料量的20%以上,同時多意圖識別情境或多輪對話情境涉及的意圖需要在單意圖識別情境中出現過。
-
意圖描述需要覆蓋儘可能豐富的問法和情境。
資料格式要求
訓練資料格式要求為:JSON格式的檔案,包含instruction和output兩個欄位,分別對應輸入的指令和模型預測的意圖以及對應的關鍵參數。對於不同的意圖識別情境,相應的訓練資料樣本如下:
-
對於單意圖識別情境,您需要針對特定的業務情境,準備相應的業務資料,用於大語言模型(LLM)的微調訓練。以智能家居的單輪對話為例,訓練資料樣本如下:
[ { "instruction": "我想聽音樂", "output": "play_music()" }, { "instruction": "太吵了,把聲音開小一點", "output": "volume_down()" }, { "instruction": "我不想聽了,把歌關了吧", "output": "music_exit()" }, { "instruction": "我想去杭州玩,幫我查下天氣預報", "output": "weather_search(杭州)" }, ] -
對於多意圖識別情境或多輪對話情境,使用者的意圖可能會在多個對話輪次中表達。在這種情況下,您可以準備多輪對話資料,並對多輪使用者的輸入進行標註。以語音助手為例,給定一個多輪對話流:
User:我想聽音樂。 Assistant:什麼類型的音樂? User:給我放個***的音樂吧。 Assistant:play_music(***)相應的多輪對話訓練資料格式如下:
[ { "instruction": "我想聽音樂。給我放個***的音樂吧。", "output": "play_music(***)" } ]
由於多輪對話模型訓練的長度明顯提升,而且在實際應用中,多輪對話意圖識別情境數量有限。建議您僅當單輪對話的意圖識別無法滿足實際業務需求時,考慮應用多輪對話的模型訓練方式。本方案將以單輪對話為例,為您展示該解決方案的整個使用流程。
使用iTAG平台進行資料標註
您也可以參考以下操作步驟,使用PAI-iTAG平台對資料進行標註,以產生滿足特定要求的訓練資料集。
-
將用於iTAG標註的資料註冊到PAI資料集。
-
參考資料準備策略,準備manifest格式的資料檔案,內容樣本如下。
{"data":{"instruction": "我想聽音樂"}} {"data":{"instruction": "太吵了,把聲音開小一點"}} {"data":{"instruction": "我不想聽了,把歌關了吧"}} {"data":{"instruction": "我想去杭州玩,幫我查下天氣預報"}} -
進入AI資產管理>資料集頁面,選擇目標工作空間,並單擊進入資料集。
-
單擊新建数据集,並配置以下關鍵參數,其他參數配置詳情,請參見建立及管理資料集。
參數
描述
存储类型
選擇对象存储(OSS)。
导入格式
選擇文件。
OSS路径
選擇已建立的OSS目錄,按照以下操作步驟上傳已準備好的manifest檔案:
-
單擊
按鈕,並在选择OSS文件對話方塊,單擊上传文件。 -
單擊查看本地文件或拖拽上传文件,根據提示上傳manifest檔案。
-
-
-
進入資料準備>智能標註(iTAG)頁面,單擊前往管理页,並切換到模版管理頁簽。
-
單擊新建模版,選擇自定义模版 > 基础模版,並單擊编辑,完成相關參數配置後,單擊保存模版名称。其中關鍵配置說明如下,更多配置詳情,請參見範本管理員。
配置
描述
基礎模版畫布區
-
選擇文本,並單擊產生內容卡片。
-
單擊文本地區,在导入数据集對話方塊中,選擇已有資料集。然後在右側的基礎模版配置地區,選擇数据集字段名 > instruction。
基礎模版答題區
選擇输入框,並單擊生成题目卡片。然後將标题修改為output。
-
-
在左側導覽列選擇,然後在右側的任务管理頁簽單擊创建任务。在建立標註任務頁面配置相關參數後,單擊创建。關鍵配置說明如下,其他參數配置詳情,請參見建立標註任務。
參數
描述
输入数据集
選擇上述步驟已建立的資料集。
說明請注意,輸入的資料和使用的模板對應。
模版类型
選擇自定义模板,並在已有模板下拉框中,選擇已建立的模板。
-
標註任務建立完成後,開始標註資料。具體操作,請參見處理標註任務。
-
完成資料標註後,將標註結果匯出至OSS目錄中。具體操作,請參見匯出標註結果資料。
在本方案中,輸出的manifest檔案的內容樣本如下,資料格式說明,請參見標註資料格式概述。
{"data":{"instruction":"我想聽音樂","_itag_index":""},"label-1947839552568066048-system":{"fixedFlag":0,"results":[{"MarkResultId":"1947839554911772672","MarkTitle":"基礎模版","MarkResult":"{\"tabId\":\"CommonExtensions\",\"annotations\":[{\"id\":null,\"labels\":{\"output\":\"play_music()\"},\"exif\":null}],\"type\":\"CommonExtensions\",\"version\":\"v2\"}","QuestionId":"CommonExtensions","ResultType":"OPEN_GROUP","Progress":null,"Version":"1753236185165","MarkTime":"Wed Jul 23 10:03:05 CST 2025","UserMarkResultId":null,"IsNeedVoteJudge":false}],"abandonFlag":0},"label-1947839552568066048":{"results":[{"MarkResultId":"1947839554911772672","MarkTitle":"基礎模版","MarkResult":"{\"tabId\":\"CommonExtensions\",\"annotations\":[{\"id\":null,\"labels\":{\"output\":\"play_music()\"},\"exif\":null}],\"type\":\"CommonExtensions\",\"version\":\"v2\"}","QuestionId":"CommonExtensions","ResultType":"OPEN_GROUP","Progress":null,"Version":"1753236185165","MarkTime":"Wed Jul 23 10:03:05 CST 2025","UserMarkResultId":"1947839763671740416","IsNeedVoteJudge":false}]},"abandonFlag":0,"abandonRemark":null} {"data":{"instruction":"太吵了,把聲音開小一點","_itag_index":""},"label-1947839552568066048-system":{"fixedFlag":0,"results":[{"MarkResultId":"1947839554891464704","MarkTitle":"基礎模版","MarkResult":"{\"tabId\":\"CommonExtensions\",\"annotations\":[{\"id\":null,\"labels\":{\"output\":\"volume_down()\"},\"exif\":null}],\"type\":\"CommonExtensions\",\"version\":\"v2\"}","QuestionId":"CommonExtensions","ResultType":"OPEN_GROUP","Progress":null,"Version":"1753236198979","MarkTime":"Wed Jul 23 10:03:19 CST 2025","UserMarkResultId":null,"IsNeedVoteJudge":false}],"abandonFlag":0},"label-1947839552568066048":{"results":[{"MarkResultId":"1947839554891464704","MarkTitle":"基礎模版","MarkResult":"{\"tabId\":\"CommonExtensions\",\"annotations\":[{\"id\":null,\"labels\":{\"output\":\"volume_down()\"},\"exif\":null}],\"type\":\"CommonExtensions\",\"version\":\"v2\"}","QuestionId":"CommonExtensions","ResultType":"OPEN_GROUP","Progress":null,"Version":"1753236198979","MarkTime":"Wed Jul 23 10:03:19 CST 2025","UserMarkResultId":"1947839868520656896","IsNeedVoteJudge":false}]},"abandonFlag":0,"abandonRemark":null} {"data":{"instruction":"我不想聽了,把歌關了吧","_itag_index":""},"label-1947839552568066048-system":{"fixedFlag":0,"results":[{"MarkResultId":"1947839554992373760","MarkTitle":"基礎模版","MarkResult":"{\"tabId\":\"CommonExtensions\",\"annotations\":[{\"id\":null,\"labels\":{\"output\":\"music_exit()\"},\"exif\":null}],\"type\":\"CommonExtensions\",\"version\":\"v2\"}","QuestionId":"CommonExtensions","ResultType":"OPEN_GROUP","Progress":null,"Version":"1753236212152","MarkTime":"Wed Jul 23 10:03:32 CST 2025","UserMarkResultId":null,"IsNeedVoteJudge":false}],"abandonFlag":0},"label-1947839552568066048":{"results":[{"MarkResultId":"1947839554992373760","MarkTitle":"基礎模版","MarkResult":"{\"tabId\":\"CommonExtensions\",\"annotations\":[{\"id\":null,\"labels\":{\"output\":\"music_exit()\"},\"exif\":null}],\"type\":\"CommonExtensions\",\"version\":\"v2\"}","QuestionId":"CommonExtensions","ResultType":"OPEN_GROUP","Progress":null,"Version":"1753236212152","MarkTime":"Wed Jul 23 10:03:32 CST 2025","UserMarkResultId":"1947839936657285120","IsNeedVoteJudge":false}]},"abandonFlag":0,"abandonRemark":null} {"data":{"instruction":"我想去杭州玩,幫我查下天氣預報","_itag_index":""},"label-1947839552568066048-system":{"fixedFlag":0,"results":[{"MarkResultId":"1947839554971426816","MarkTitle":"基礎模版","MarkResult":"{\"tabId\":\"CommonExtensions\",\"annotations\":[{\"id\":null,\"labels\":{\"output\":\"weather_search(杭州)\"},\"exif\":null}],\"type\":\"CommonExtensions\",\"version\":\"v2\"}","QuestionId":"CommonExtensions","ResultType":"OPEN_GROUP","Progress":null,"Version":"1753236218730","MarkTime":"Wed Jul 23 10:03:39 CST 2025","UserMarkResultId":null,"IsNeedVoteJudge":false}],"abandonFlag":0},"label-1947839552568066048":{"results":[{"MarkResultId":"1947839554971426816","MarkTitle":"基礎模版","MarkResult":"{\"tabId\":\"CommonExtensions\",\"annotations\":[{\"id\":null,\"labels\":{\"output\":\"weather_search(杭州)\"},\"exif\":null}],\"type\":\"CommonExtensions\",\"version\":\"v2\"}","QuestionId":"CommonExtensions","ResultType":"OPEN_GROUP","Progress":null,"Version":"1753236218730","MarkTime":"Wed Jul 23 10:03:39 CST 2025","UserMarkResultId":"1947839975890939904","IsNeedVoteJudge":false}]},"abandonFlag":0,"abandonRemark":null} -
在終端中,使用如下Python指令碼,將上述產生的manifest格式的資料標註結果檔案,轉換為適用於快速開始(QuickStart)的訓練資料格式。
import json # 輸入檔案路徑和輸出檔案路徑 input_file_path = 'test_json.manifest' output_file_path = 'train.json' converted_data = [] with open(input_file_path, 'r', encoding='utf-8') as file: for line in file: try: # 解析每一行的JSON資料 data = json.loads(line) # 提取instruction instruction = data['data']['instruction'] # 遍曆所有以 "label-" 開頭的鍵 for key in data.keys(): if key.startswith('label-'): # 提取MarkResult並解析其內容 mark_result_str = data[key]['results'][0]['MarkResult'] mark_result = json.loads(mark_result_str) # 將 MarkResult 字串解析為 JSON # 提取annotations中的labels["output"] output = mark_result['annotations'][0]['labels']['output'] # 構建新的資料結構 converted_data.append({ 'instruction': instruction, 'output': output }) break except Exception as e: print(f"Error processing line: {line.strip()}. Error: {e}") # 將轉換後的資料寫入輸出檔案 with open(output_file_path, 'w', encoding='utf-8') as outfile: json.dump(converted_data, outfile, ensure_ascii=False, indent=4) print(f"Conversion completed. Output saved to {output_file_path}")輸出結果為JSON格式的檔案。
訓練及離線評測模型
訓練模型
快速開始(QuickStart)彙集了優秀的AI開源社區預訓練模型。您可以在快速開始(QuickStart)中,實現從訓練到部署再至推理的完整流程,無需編寫代碼,極大簡化了模型的開發過程。
本方案以Qwen1.5-1.8B-Chat模型為例,為您介紹如何使用已準備好的訓練資料,在快速開始(QuickStart)中進行模型訓練。具體操作步驟如下:
-
進入Model Gallery頁面。
-
登入PAI控制台。
-
在頂部左上方根據實際情況選擇地區。
-
在左側導覽列選擇工作空间列表,單擊指定工作空間名稱,進入對應工作空間內。
-
在左側導覽列選擇快速开始 > Model Gallery。
-
-
在快速開始頁面右側的模型列表中,搜尋並單擊通義千問1.5-1.8B-Chat模型卡片,進入模型詳情頁面。
-
在模型詳情頁面,單擊右上方的训练。然後在训练配置面板中,配置以下關鍵參數,其他參數取預設配置。
參數
描述
训练方式
-
全參微調:資源要求高,訓練時間長,效果一般更好。
說明參數量較小的模型支援全參數微調,請根據您的情境需要進行選擇。
-
QLoRA:表示輕量化微調。相較於全參數微調,資源要求更低,訓練時間更短,效果一般會差一些。
-
LoRA:同QLoRA。
数据集配置
训练数据集
參照以下操作步驟,選擇已準備好的訓練資料集。
-
在下拉式清單中選擇OSS文件或目录。
-
單擊
按鈕,選擇已建立的OSS目錄。 -
在选择OSS文件對話方塊中,單擊上傳文件,拖拽上傳已準備好的訓練資料集檔案,並單擊确定。
输出配置
模型输出路径
選擇OSS目錄,用來存放訓練輸出的設定檔和模型檔案。
Tensorboard輸出路徑
超参数配置
關於超參數詳細介紹,請參見表1.全量超參數說明。
建議您按照以下超參數配置策略進行配置,針對不同的訓練方式,關鍵超參數推薦配置,請參見表2.超參數推薦配置。
-
注意根據不同的訓練方式配置超參數。
-
全域批次大小=卡數*per_device_train_batch_size*gradient_accumulation_steps-
為了最大化訓練效能,優先調大卡數和per_device_train_batch_size。
-
一般將全域批次大小設定為64至256,當訓練資料量很少時,可以適當調小。
-
-
序列長度(seq_length)可以根據實際情境進行調整。例如,資料集中本文序列最大長度為50,則可以將序列長度設定為64(一般設定為2的次冪數)。
-
當訓練loss下降過慢或者不收斂時,建議您適當調大學習率(learning_rate)。同時,需要確認訓練資料的資料品質是否有保證。
-
-
單擊训练按鈕,在计费提醒對話方塊中單擊确定。
系統自動跳轉到訓練任務詳情頁面,訓練任務啟動成功,您可以在該頁面查看訓練任務狀態和訓練日誌。訓練任務建立成功後,系統跳轉到訓練任務詳情頁面,任務狀態顯示為運行中。頁面展示三階段進度:建立中、環境準備中、運行中。基本資料包括預訓練模型qwen1.5-1.8b-chat、訓練方式為SFT 監督微調: LoRA、任務分類為產生式AI / 大語言模型。頁面提供任務詳情、任務日誌、任務監控三個Tab頁簽,可查看輸入路徑、輸出路徑及超參數配置等詳細資料。
離線評測模型
當模型訓練結束後,您可以在終端使用Python指令碼,來評測模型效果。
-
準備評測資料檔案testdata.json,內容樣本如下:
[ { "instruction": "想知道的十年是誰唱的?", "output": "music_query_player(十年)" }, { "instruction": "今天杭州的天氣怎麼樣?", "output": "weather_search(杭州)" } ] -
在終端中,使用如下Python指令碼來離線評測模型。
#encoding=utf-8 from transformers import AutoModelForCausalLM, AutoTokenizer import json from tqdm import tqdm device = "cuda" # the device to load the model onto # 修改模型路徑 model_name = '/mnt/workspace/model/qwen14b-lora-3e4-256-train/' print(model_name) model = AutoModelForCausalLM.from_pretrained( model_name, torch_dtype="auto", device_map="auto" ) tokenizer = AutoTokenizer.from_pretrained(model_name) count = 0 ecount = 0 # 修改訓練資料路徑 test_data = json.load(open('/mnt/workspace/data/testdata.json')) system_prompt = '你是一個意圖識別專家,可以根據使用者的問題識別出意圖,並返回對應的函數調用和參數。' for i in tqdm(test_data[:]): prompt = '<|im_start|>system\n' + system_prompt + '<|im_end|>\n<|im_start|>user\n' + i['instruction'] + '<|im_end|>\n<|im_start|>assistant\n' gold = i['output'] gold = gold.split(';')[0] if ';' in gold else gold model_inputs = tokenizer([prompt], return_tensors="pt").to(device) generated_ids = model.generate( model_inputs.input_ids, max_new_tokens=64, pad_token_id=tokenizer.eos_token_id, eos_token_id=tokenizer.eos_token_id, do_sample=False ) generated_ids = [ output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids) ] pred = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0] if gold.split('(')[0] == pred.split('(')[0]: count += 1 gold_list = set(gold.strip()[:-1].split('(')[1].split(',')) pred_list = set(pred.strip()[:-1].split('(')[1].split(',')) if gold_list == pred_list: ecount += 1 else: pass print("意圖識別準確率:", count/len(test_data)) print("參數識別準確率:", ecount/len(test_data))說明如果代碼執行結果返回提示資訊
Using low_cpu_mem_usage=True or a device_map requires Accelerate: pip install accelerate,請按照提示執行pip install accelerate安裝依賴庫。
部署及調用模型服務
部署模型服務
當評測模型效果符合預期時,您可以按照以下操作步驟,將訓練獲得的模型部署為EAS線上服務。
-
在任务详情頁面右上方單擊部署,系統已預設配置了基本資料和資源資訊,部署方式選擇vLLM加速部署,您也可以根據需要進行修改,參數配置完成後單擊部署按鈕。
-
在计费提醒對話方塊中,單擊确定。
系統自動跳轉到部署任務頁面,當状态為运行中時,表示服務部署成功。
調用模型服務
以下提供一個API調用樣本,展示如何通過用戶端發起Request調用:
-
擷取服務訪問地址和Token。
-
在服务详情頁面的基本信息地區,單擊查看调用信息。
-
在调用信息對話方塊中,查詢服務訪問地址和Token,並儲存到本地。
-
-
以vLLM加速部署為例,調用程式碼範例如下。您可以在終端中執行此代碼調用服務。
from openai import OpenAI ##### API 配置 ##### openai_api_key = "<EAS_SERVICE_TOKEN>" openai_api_base = "<EAS_SERVICE_URL>/v1/" client = OpenAI( api_key=openai_api_key, base_url=openai_api_base, ) models = client.models.list() model = models.data[0].id print(model) def main(): stream = True chat_completion = client.chat.completions.create( messages=[ { "role": "system", "content": [ { "type": "text", "text": "你是一個意圖識別專家,可以根據使用者的問題識別出意圖,並返回對應的意圖和參數。", } ], }, { "role": "user", "content": [ { "type": "text", "text": "我想聽音樂", } ], } ], model=model, max_completion_tokens=2048, stream=stream, ) if stream: for chunk in chat_completion: print(chunk.choices[0].delta.content, end="") else: result = chat_completion.choices[0].message.content print(result) if __name__ == "__main__": main()其中:
-
<EAS_SERVICE_URL>:配置為已擷取的服務訪問地址。
-
<EAS_SERVICE_TOKEN>:配置為已擷取的服務Token。
-
相關文檔
-
更多關於iTAG的使用流程以及標註資料格式要求,請參見智能標註(iTAG)。
-
更多關於EAS產品的內容介紹,請參見模型線上服務(EAS)。
-
使用快速開始(QuickStart)功能,您可以輕鬆完成更多情境的部署與微調任務,包括Llama-3、Qwen1.5、Stable Diffusion V1.5等系列模型。詳情請參見Model Gallery使用案例匯總。