作者:
智能體 AI Agent 作為大模型的衍生應用,具有對任務的理解、規劃與行動能力。它可以通過將一個復雜的用戶請求拆分成不同的子任務,并依次調用外部工具來解決這些任務,并將其中每個任務步驟的執行結果,按預先規劃的邏輯串聯起來,從而達成最終的目的。
接下來我們就通過一個例子,演示如何利用 OpenVINO 工具套件在你的電腦上的一步步搭建本地智能體流水線。
1轉換壓縮LLM
首先要需要利用 Hugging Face 的 Optimum-intel 命令行工具將原始模型轉化為 OpenVINO 的 IR 格式,并對其進行 int4 量化壓縮,以實現本地部署的目的。這里我們選擇通義千問團隊近期發布的 Qwen2.5 大語言模型為例,它可以支持多種不同語言。其中最小3B參數版本的模型便可以對本示例進行復現。
!optimum-cli export openvino --model "Qwen/Qwen2.5-3B-Instruct"--task text-generation-with-past --trust-remote-code --weight-format int4 --group-size 128 --ratio 1.0 --sym “Qwen2.5-3B-Instruct-int4-ov”
其中"Qwen/Qwen2.5-3B-Instruct"為模型的 HuggingFace 的模型 ID,如果在訪問 Hugging Face 模型倉庫時,發現網絡限制,也可以通過 ModelScope 將原始模型下載到本地,并將該模型 ID 替換為模型的本地路徑,例如:"./model/Qwen2.5-3B-Instruct"。
2創建LLM任務
第二步同樣可以利用 Optimum-intel 提供的 OpenVINO API 接口將模型部署在指定的硬件平臺,這里可以通過指定 device=”gpu” 將模型加載到任意一個 Intel 的獨顯或是集顯上,以最大化模型推理性能。
tokenizer = AutoTokenizer.from_pretrained(llm_model_path, trust_remote_code=True) ov_config = {hints.performance_mode(): hints.PerformanceMode.LATENCY, streams.num(): "1", props.cache_dir(): ""} llm = OVModelForCausalLM.from_pretrained( llm_model_path, device=llm_device.value, ov_config=ov_config, config=AutoConfig.from_pretrained(llm_model_path, trust_remote_code=True), trust_remote_code=True, )
除了對模型對象進行初始化以外,還需要創建針對模型推理輸出的后處理函數,主要目的是為了實現流式輸出,以及設置停止字符,讓 LLM 在調用工具前停止推理任務。
def text_completion(prompt: str, stop_words) -> str: im_end = "<|im_end|>" if im_end not in stop_words: stop_words = stop_words + [im_end] streamer = TextStreamer(tokenizer, timeout=60.0, skip_prompt=True, skip_special_tokens=True) stopping_criteria = StoppingCriteriaList([StopSequenceCriteria(stop_words, tokenizer)]) input_ids = torch.tensor([tokenizer.encode(prompt)]) generate_kwargs = dict( input_ids=input_ids, streamer=streamer, stopping_criteria=stopping_criteria, ) output = llm.generate(**generate_kwargs) output = output.tolist()[0] output = tokenizer.decode(output, errors="ignore") assert output.startswith(prompt) output = output[len(prompt) :].replace("<|endoftext|>", "").replace(im_end, "") for stop_str in stop_words: idx = output.find(stop_str) if idx != -1: output = output[: idx + len(stop_str)] return output
3定義智能體Prompt模板
這一步也是決定智能體工作模式的關鍵,通過 Prompt 模板,我們將教會 LLM 一個常規任務的解決路徑,以及有哪些類別的外部工具可能幫助它解決特定問題。可以看到在下面這個典型 ReAct 類 Prompt 模板中,我們定義外部工具的具體信息模板,以及 LLM 在執行任務過程中的輸出模板,其中 “Observation” 后內容為外部工具調用后返回的結果,并非由 LLM 直接生成。可以看到在該模板中, LLM 可能會被執行多次,直到上下文中的信息足夠回答用戶請求。
TOOL_DESC = """{name_for_model}: Call this tool to interact with the {name_for_human} API. What is the {name_for_human} API useful for? {description_for_model} Parameters: {parameters}""" PROMPT_REACT = """Answer the following questions as best you can. You have access to the following APIs: {tools_text} Use the following format: Question: the input question you must answer Thought: you should always think about what to do Action: the action to take, should be one of [{tools_name_text}] 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! Question:{query}"""
4輸出過濾與工具定義
由于智能體需要和外部工具頻繁交互,發出指令并獲取工具反饋結果,因此我們需要在 LLM 輸出時,判斷哪些關鍵詞代表模型需要調用工具,哪些關鍵詞代表收集工具反饋結果。在這里例子中,當 LLM 輸出 “Action:" 后的字符,代表接下來需要調用的工具函數名稱,輸出 “Action Input” 后的字符,代表輸入給該工具的輸入參數,以及 “Observation” 代表接下來需要直接輸出工具的執行結果,因此它也是終止當前 LLM 推理任務的特殊字符。
def parse_latest_tool_call(text): tool_name, tool_args = "", "" i = text.rfind(" Action:") j = text.rfind(" Action Input:") k = text.rfind(" Observation:") if 0 <= i < j: # If the text has `Action` and `Action input`, if k < j: # but does not contain `Observation`, # then it is likely that `Observation` is ommited by the LLM, # because the output text may have discarded the stop word. text = text.rstrip() + " Observation:" # Add it back. k = text.rfind(" Observation:") tool_name = text[i + len(" Action:") : j].strip() tool_args = text[j + len(" Action Input:") : k].strip() text = text[:k] ????return?tool_name,?tool_args,?text
為了告訴 LLM 什么時候該調用什么工具,以及這些工具的基本輸入和輸入參數格式,我們在完成工具函數的編寫后,還需要以字典的形式,將這些信息送入先前定義的 Prompt 模板中,參考示例如下:
tools = [ { "name_for_human": "get weather", "name_for_model": "get_weather", "description_for_model": 'Get the current weather in a given city name."', "parameters": [ { "name": "city_name", "description": "City name", "required": True, "schema": {"type": "string"}, } ], }, { "name_for_human": "image generation", "name_for_model": "image_gen", "description_for_model": "AI painting (image generation) service, input text description, and return the image URL drawn based on text information.", "parameters": [ { "name": "prompt", "description": "describe the image", "required": True, "schema": {"type": "string"}, } ], }, ]
在這個例子中,我們定義一個天氣查詢工具以及一個文生圖工具,他們分別會調用響應的 API 服務完成響應任務。
5構建智能體
接下來我們需要將以上定義的函數串聯起來,構建一個簡單的智能體流水線。第一步會將用戶請求經 Prompt 模板格式化后送入 LLM,接下來解析 LLM 輸出,并判斷是否需要調用外部工具 “Action” 。如果需要調用外部工具,則智能體會運行該工具函數,獲得運行結果,最后將結果數據合并到下一輪的輸入 Prompt 中,由 LLM 判斷是否還需要再次調用其他工具,再進行一次循環,如果不需要調用工具,并且當前得到的信息已經可以滿足用戶請求,那 LLM 將整合并基于這個過程中所有的 “Observation” 信息,輸出最終答案 “Final Answer”。
while True: output = text_completion(planning_prompt + text, stop_words=["Observation:", "Observation: "]) action, action_input, output = parse_latest_tool_call(output) if action: observation = call_tool(action, action_input) output += f" Observation: = {observation} Thought:" observation = f"{observation} Thought:" print(observation) text += output else: text += output break
該示例的運行效果如下,這里我們讓智能體“根據當前倫敦的天氣,生成一張大本鐘的照片”。可以看到智能體按照我們既定的 Prompt 策略,將用戶問題拆分后,分別調用預先定義的不同工具,根據用戶要求得到最終結果。當然你也可以用中文向它發出請求。
query = "get the weather in London, and create a picture of Big Ben based on the weather information" response,history=llm_with_tool(prompt=query,history=history,list_of_tool_info=tools)
“Thought: First, I need to use the get_weather API to get the current weather in London.
Action: get_weather
Action Input: {"city_name": "London"}
Observation:
{'current_condition': {'temp_C': '11', 'FeelsLikeC': '10', 'humidity': '94', 'weatherDesc': [{'value': 'Overcast'}], 'observation_time': '12:23 AM'}}
Thought:
Now that I have the weather information, I will use the image_gen API to generate an image of Big Ben based on the weather conditions.
Action: image_gen
Action Input: {"prompt": "Big Ben under overcast sky with temperature 11°C and humidity 94%"}
Observation:
{"image_url": "https://image.pollinations.ai/prompt/Big%20Ben%20under%20overcast%20sky%20with%20temperature%2011%C2%B0C%20and%20humidity%2094%25"}
Thought:
The image has been generated successfully.
Final Answer: The current weather in London is overcast with a temperature of 11°C and humidity of 94%. Based on this information, here is the image of Big Ben under an overcast sky: ![](https://image.pollinations.ai/prompt/Big%20Ben%20under%20overcast%20sky%20with%20temperature%2011%C2%B0C%20and%20humidity%2094%25)“
6總結
該示例以 OpenVINO 作為 LLM 的推理后端,一步步構建起了一個簡單的智能體流水線,可以看到這個示例中除了 Optimum-intel,沒有其他外部依賴需要安裝,因此它也是一個非常基礎的的智能體構建過程。除此以外,該示例使用 3B 大小 SLM 便可以實現該智能體的構建,同時帶來不錯的性能表現,是非常適合在本地構建的智能體示例。
-
流水線
+關注
關注
0文章
120瀏覽量
25737 -
AI
+關注
關注
87文章
30887瀏覽量
269069 -
模型
+關注
關注
1文章
3243瀏覽量
48836 -
OpenVINO
+關注
關注
0文章
93瀏覽量
201
原文標題:從0到1構建 OpenVINO? 智能體流水線|開發者實戰
文章出處:【微信號:英特爾物聯網,微信公眾號:英特爾物聯網】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論