开发者实战 | 基于 OpenVINO™ + LangChain + LLama2 打造智能小助手

本文介绍了如何使用OpenVINO™2023.1的新特性,特别是OVC工具,来加速Llama2模型并实现中文对话能力。通过LangChain和自定义Prompt,作者展示了如何将Llama2模型部署到CPU,并结合RapidAPI获取实时数据,创建了一个具备联网查询功能的AI小助手。
摘要由CSDN通过智能技术生成

点击蓝字

关注我们,让开发变得更有趣

作者:刘宜松

中国科学院高能物理研究所 硕士研究生

指导老师:庄建 

英特尔边缘计算创新大使

中国科学院高能物理研究所 研究员

594497950699da8ae81b5f4d6f09f9ba.png

本文目的

LLM 大模型存在很多痛点,包括但不限于数据陈旧,无法和外部组件进行交互,本文旨在使用 OpenVINO™  2023,利用其新版本的特性加速 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 模型,以下是模型的 Huggingface 链接:

https://huggingface.co/FlagAlpha/Llama2-Chinese-7b-Chat

(复制链接到浏览器打开)

模型转换为 ONNX 格式

OpenVINO™ 可用于从 Hugging Face Hub 加载优化模型,并创建管道以使用 Hugging FaceAPI 通过 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,让模型在英特尔的 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 这样的大型语言模型(LLM)和外部数据结合起来。它提供了 Python 或 JavaScript 的包。它是基于大语言模型这种预测能力的应用开发工具。无论你是想要做一个聊天机器人、个人助理、问答系统,或者自助代理等等,都可以帮助我们快速地实现想法。我可以拍胸脯地说,LangChain 作为新一代 AI 开发框架,必将受到程序员的追捧,点燃 AI 应用开发的新热潮。

7fa6b4238c51a5c48bf1de8b6e99204e.png

LangChain 的精髓是 agent 机制,学习了解 Agent 就像探索迷宫一样有趣。langchain 的 Agent 实在是非常聪明的设计。什么是 Agent,简单讲 Agent 利用 LLM 的理解推理能力来简化原本十分复杂的逻辑判断,决定什么问题由什么工具来解决,最后汇总成一个“答案”返回给用户。LangChain 把这个过程用一个非常经典的 Prompt 模板定义了出来,这个模板中包括四个环节:Thought(LLM 的思考过程和决定)、Action(要采取的行动以及要给他的输入)、Observation(执行 Action 后预计的输出结果)、Tools(Action 行动的调用函数)。

67e780d85a4b403899c787a1c8b3cc57.png

Rapid API

RapidAPI 是一个 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_infomation = 角色扮演 + 网络检索结果 + 原始问题这三者拼接起来的。其中的“网络检索结果”和“原始问题”比较理解理解,而我发现不得不仿照 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

6e3e7542bb51be6141bf129c77c25049.png

从运行效果可以看出,对于一个数据实时性要求高的专业问题,这个 Agent 完全可以做到对互联网检索的结果的理解并返回。整个流程是可以很好执行起来。但作为一个 Demo 还不能做到 100% 的高效回答和足够的智能,最大的挑战来自三个方面,即如果想要做到极致的话,要在这三个方面花更多精力:

1、Prompt 的提炼:我觉得还是要设计一个更优的适配 Llama2 的 Prompt,确保 LLM 指令响应的成功率。

2、模型推理能力:在硬件允许的情况下换成参数更多,推理能力更强的大模型。

3、网络检索的 parser:这里我是基于 bing search API 做联网检索,直接返回结果,还是有不少广告等垃圾信息,所以这些信息干扰让 这个机器人显得不那么聪明。

OpenVINO™

--END--

你也许想了解(点击蓝字查看)⬇️➡️ 开发者实战 | 介绍OpenVINO™ 2023.1:在边缘端赋能生成式AI➡️ 基于 ChatGLM2 和 OpenVINO™ 打造中文聊天助手➡️ 基于 Llama2 和 OpenVINO™ 打造聊天机器人➡️ OpenVINO™ DevCon 2023重磅回归!英特尔以创新产品激发开发者无限潜能➡️ 5周年更新 | OpenVINO™  2023.0,让AI部署和加速更容易➡️ OpenVINO™5周年重头戏!2023.0版本持续升级AI部署和加速性能➡️ OpenVINO™2023.0实战 | 在 LabVIEW 中部署 YOLOv8 目标检测模型➡️ 开发者实战系列资源包来啦!➡️ 以AI作画,祝她节日快乐;简单三步,OpenVINO™ 助你轻松体验AIGC
➡️ 还不知道如何用OpenVINO™作画?点击了解教程。➡️ 几行代码轻松实现对于PaddleOCR的实时推理,快来get!➡️ 使用OpenVINO 在“端—边—云”快速实现高性能人工智能推理
扫描下方二维码立即体验 
OpenVINO™ 工具套件 2023.1

点击 阅读原文 立即体验OpenVINO 2023.1

d14487c939177d697778e580e27a40a4.png

文章这么精彩,你有没有“在看”?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值