作者:
智能體 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: “
6總結
該示例以 OpenVINO 作為 LLM 的推理后端,一步步構建起了一個簡單的智能體流水線,可以看到這個示例中除了 Optimum-intel,沒有其他外部依賴需要安裝,因此它也是一個非常基礎的的智能體構建過程。除此以外,該示例使用 3B 大小 SLM 便可以實現該智能體的構建,同時帶來不錯的性能表現,是非常適合在本地構建的智能體示例。
-
流水線
+關注
關注
0文章
127瀏覽量
27229 -
AI
+關注
關注
91文章
39793瀏覽量
301382 -
模型
+關注
關注
1文章
3752瀏覽量
52102 -
OpenVINO
+關注
關注
0文章
118瀏覽量
767
原文標題:從0到1構建 OpenVINO? 智能體流水線|開發者實戰
文章出處:【微信號:英特爾物聯網,微信公眾號:英特爾物聯網】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
流水線基本結構
FPGA中的流水線設計
周期精確的流水線仿真模型
流水線中的相關培訓教程[4]
FPGA之流水線練習(3):設計思路
FPGA之為什么要進行流水線的設計
如何選擇合適的LED生產流水線輸送方式
嵌入式_流水線
利用OpenVINO搭建本地智能體流水線
評論