如何客製化企業 RAG 知識庫?— 從資料庫到知識整合的實戰技術
|

輕鬆利用OpenVINO結合LangChain與Llama2打造智慧小助手

   

作者:劉宜松、莊建

LLM大模型存在很多痛點,包括但不限於資料陳舊、無法和外部元件互動等,本文旨在使用 OpenVINO 2023.1新版本的特性加速Llama2模型,為Llama2客製化Prompt,並用LangChain 實現可連網取得最新消息的輔助搜尋功能。

本文將端對端教大家以OpenVINO結合LangChain與Llama2實現具備網際網路自動查詢的AI小助手,程式碼下載網址:https://github.com/lewis430/langchain_openvino_llama2

OpenVINO 2023.1新特性

OpenVINO 2023.1推出的新功能可簡化AI的部署和加速,此新版本為開發人員提供更多整合,最大限度減少程式碼更改。

OpenVINO提供了模型轉換工具OVC,該工具正在取代我們眾所周知的離線模型轉換任務中的模型優化器(MO)工具。該工具以OpenVINO套件形式提供,依靠內部模型前端來讀取框架格式,不需要原始框架來執行模型轉換。

將原來的 AutoModelForCausalLM 替換為 OVModelForCausalLM 即可實現模型轉換:


-from transformers import AutoModelForCausalLM
+from optimum.intel.openvino import OVModelForCausalLM
from transformers import AutoTokenizer, pipeline
 
model_id = "FlagAlpha/Llama2-Chinese-7b-Chat"
-model = AutoModelForCausalLM.from_pretrained(model_id)
+model = OVModelForCausalLM.from_pretrained(model_id, export=True)

模型選擇

因為我們是以中文為對象,而Llama2本身的中文對應能力較弱,我們需要採用中文指令集,對meta-llama/Llama-2-7b-chat-hf進行LoRA微調,使其具備較強的中文對話能力。同時也因為Llama2模型的取得需要向meta提供個人資訊,所以選擇更易取得的Llama2-Chinese-7b-Chat模型;該模型的Hugging Face連結為:https://huggingface.co/FlagAlpha/Llama2-Chinese-7b-Chat

模型轉換為 ONNX 格式

OpenVINO可用於從Hugging Face Hub載入最佳化模型,並創建管道以使用Hugging Face API透過OpenVINO Runtime執行推論。這意味著我們只需要將AutoModelForXxx類替換為相應的OVModelForXxx類,就能實現模型格式的轉換。


model_dir =  "llama-2-chat-7b/ov_model"
ov_model = OVModelForCausalLM.from_pretrained('llama-2-chat-7b', export=True, compile=False)
ov_model.half()
ov_model.save_pretrained(model_dir)

將模型部署至CPU

指定其部署推論的設備為 CPU,讓模型在英特爾(Intel)的CPU上進行推論。


ov_model=OVModelForCausalLM.from_pretrained(model_dir,device='cpu',ov_config=ov_config,config=AutoConfig.from_pretrained(model_dir,trust_remote_code=True),trust_remote_code=True)

LangChain

LangChain是一個開源的框架,可以讓AI開發人員把像是GPT-4這樣的大型語言模型和外部資料結合起來,它提供了Python或JavaScript套件,是基於大語言模型這種預測能力的應用開發工具。無論你是想要做一個聊天機器人、個人助理、問答系統,或者自助代理等等,都可以幫助我們快速地實現想法。筆者可以拍胸脯說,LangChain作為新一代AI開發框架,必將受到程式設計師的歡迎,點燃AI應用開發的新熱潮。

LangChain是一個開源框架,可把GPT-4等大型語言模型和外部資料結合起來。

Rapid API

Rapid API是一個API市集,提供了數千個API,可以幫助開發人員快速找到並使用需要的API。它包括多個類別,如人工智慧、雲端運算、區塊鏈、金融、遊戲等,每個類別下面都有大量的 API 介面可供選擇。在RapidAPI的平台上可以搜尋、篩選、訂閱和使用這些API介面,還可以查看API的文件檔和使用範例,以更充分了解與使用它們。

我們利用Rapid API平台上Bing搜尋引擎提供的API來取得瀏覽器上的最新資料,以此作為大模型的新資料來源。


url = "https://bing-web-search1.p.rapidapi.com/search"
querystring= = {"q":query,"mkt":"en-us","safeSearch":"Off","textFormat":"Raw","freshness":"Day"}
headers = {
"X-BingApis-SDK": "true",
"X-RapidAPI-Key": "Your Key",
"X-RapidAPI-Host": "bing-web-search1.p.rapidapi.com"
}
response = requests.get(url, headers=headers, params=querystring)

CustomLLM

LangChain對OpenAI ChatGPT的支援是最好的,但是在某些對資料安全性要求比較高的場合 ,我們需要將資料放在區域網路中,資料是不能出閘道器的,所以要在區域網路內部搭建本地模型,其實整個應用的成本最高的就是LLM的部署硬體需求。所以最經濟的一個方案就是一個區域網路共用一個LLM,它是統一部署後透過API的形式支援各個應用,這樣也保證了硬體的充分利用。同時,將LLM和LangChain分開部署的好處還有靈活性,LangChain對硬體的要求不高,它只是做資源的整合,任何重儲存和重運算的服務全部在遠端部署,可以將LangChain部署於硬體條件不那麼好的設備上。

我們可以透過LangChain很方便地使用OpenAI模型介面,同時LangChain內部很多邏輯程式碼都是基於ChatGPT這樣一個出色的模型來設計,當我們需要考慮使用自訂的本地模型時,需要進行轉接,其核心在於構建langchain.llms.base.LLM的子類CustomLLM,並重寫_call函數如下:


class CustomLLM(LLM):
    def _call(
        self,prompt: str,stop: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForLLMRun] = None,
    ) -> str:
        response = requests.post(f'http://127.0.0.1:8080/', {
        "ask": prompt
        })
        return response.text

自定義Prompt

因為LangChain的內部邏輯上基本是為了ChatGPT量身訂做,內建的所有Prompt都是根據 ChatGPT的參數量和聰明程度,但是對於我們本地部署、參數量小的Llama-2-7b來說就十分不契合,LangChain預設Agent中的Prompt模版無法和Llama-2-7b良好互動,雖然不是每次都失敗,但失敗機率很高,幾乎等於不可用,所以我們需要自己來定義Prompt,進行LangChain 和Llama-2-7b模型的配接。

本範例的Prompt結構中background_information是由「角色扮演」、「網路搜尋結果」、「原始問題」三者拼接而成。其中的「網路搜尋」和「原始問題」比較容易理解,而筆者發現不得不仿照LangChain加上一個角色定義,讓Llama2在做推論決策和匯總答案時扮演不同的角色,這樣可以顯著提高回答的品質。


agent_template = """
你現在是一個{role}。這裡是一些已知資訊:
{related_content}
{background_infomation}
{question_guide}:{input}
{answer_format}
"""

CustomOutputParser

LangChain的核心邏輯是Agent,而Agent的執行邏輯其實非常簡單,首先把問題和背景知識透過拼裝到原始的Prompt中,然後發給LLM,讓它回覆一個做決策的「任務表」,然後由 OutputParser處理這個任務表,它根據預設的格式,總結出LLM需要做的下一步行動,也就是選擇某個Tool繼續執行,還是就此結束直接回覆答案。

在這個專案實作中,筆者完全繼承了AgentOutptparser,它原則上是可以做到根據回覆,來多次向LLM詢問「任務表」,但因為Llama-2-7b理解力實在有限,不會再多次詢問,最多問三次。


class CustomOutputParser(AgentOutputParser):
    def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]:
        match = re.match(r'^[\s\w]*(DeepSearch)\(([^\)]+)\)', llm_output, re.DOTALL)
        if not match:
            return AgentFinish(
                return_values={"output": llm_output.strip()},
                log=llm_output,
            )
        else:
            action = match.group(1).strip()
            action_input = match.group(2).strip()
            return AgentAction(tool=action, tool_input=action_input.strip(" ").strip('"'), log=llm_output)

Custom Prompt Template和Custom Search Tool

最後,我們在這裡定義新的CustomPromptTemplate類,其實只要重寫一個format函數就行,用它來繼承了StringPromptTemplate 類,從而實現對控制推論決策、彙整答案拼裝到不同的 Prompt中。LangChain內部邏輯會自動把每次LLM回覆作為參數傳遞給format函數,只要判斷哪一個是首次向LLM詢問決策,哪一個是後續的拼裝答案。


if len(intermediate_steps) == 0:
    background_infomation = "\n"
    role = "傻瓜機器人"
    question_guide = "我現在有一個問題"
    answer_format = """請你只回答"DeepSearch("搜索詞")",並將"搜索詞"替換為你認為需要搜索的關鍵字,除此之外不要回答其他任何內容。\n\n下面請回答我上面提出的問題!"""
else:
       # 根據 intermediate_steps 中的 AgentAction 拼裝 background_infomation
    background_infomation = "\n\n你還有這些已知資訊作為參考:\n\n"
    action, observation = intermediate_steps[0]
    background_infomation += f"{observation}\n"
    role = "聰明的 AI 助手"
    question_guide = "請根據這些已知資訊回答我的問題"
    answer_format = ""

前面提到賦予LLM角色能有效提升回答品質,在這裡筆者分別賦予了推論決策和彙整答案兩個角色:「傻瓜機器人」和「聰明的AI助手」,前者只需要做簡單的分類,後者才是生成最終答案文本,筆者目測這樣的設定成功率較高,你也可以嘗試換成其他的角色,說不定有驚喜!

執行結果

  • CPU型號:Intel Xeon Gold 6248R CPU @ 3.00GHz
  • 執行環境:作業系統Ubuntu22.04,Gradio 版本>=3.47.1

 

從執行效果可以看出,對於一個資料即時性要求高的專業問題,這個Agent完全可以做到對網際網路搜尋結果的理解並回覆,整個流程可以妥善執行。但作為一個Demo還不能做到 100%的高效率回答和足夠的智慧,最大的挑戰來自三個方面,即如果想要做到極致的話,要在這三個方面花更多精力:

  1. Prompt的提煉:筆者覺得還是要設計一個更好的、配接Llama2的Prompt,確保LLM指令回應的成功率。
  2. 模型推論能力:在硬體允許的情況下,換成參數更多、推論能力更強的大模型。
  3. 網路搜尋的parser:這裡筆者是基於Bing search API 做網際網路搜尋,直接回覆結果,但還是有不少廣告等垃圾資訊,這些資訊干擾讓這個機器人顯得不那麼聰明。

 

(本文作者劉宜松為中國科學院高能物理研究所碩士研究生,莊建為英特爾邊緣運算創新大使、中國科學院高能物理研究所研究員)

OpenVINO作者群

訂閱MakerPRO知識充電報

與40000位開發者一同掌握科技創新的技術資訊!

Author: OpenVINO作者群

對於利用OpenVINO實現創新Edge AI應用充滿熱情的一群開發者,他/她們來自四面八方,時常透過社群分享他們的實作心得與成果。

Share This Post On
468 ad

Submit a Comment

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *