利用本地大型语言模型,构建一个声控智能之家

利用本地大型语言模型,构建一个声控智能之家
2024年01月24日 16:10 CSDN

相信很多人和我一样都使用过苹果的Siri和谷歌的Google Assistant,尽管这类智能助手都有控制设备的能力,但无法定制功能,而且必须依赖相应的云服务。为了学到一些新知识,并亲手打造一个智能之家,我决定构建一款更好的智能助手。

原文链接:https://johnthenerd.com/blog/local-llm-assistant/

作者 | John Karabudak责编 | 弯月

编 | 夏萌

出品 | CSDN(ID:CSDNnews)

相信很多人和我一样都使用过苹果的Siri和谷歌的Google Assistant,尽管这类智能助手都有控制设备的能力,但无法定制功能,而且必须依赖相应的云服务。为了学到一些新知识,并亲手打造一个智能之家,我决定构建一款更好的智能助手。

简单的背景介绍如下:

  • 我希望我的智能助手独行特立,有一点毒舌。

  • 我希望一切都在本地运行。没有例外。有什么必要让我家的咖啡机与地球另一端的服务器通信呢?

  • 我想要的不仅仅是基本的“开灯”功能。理想情况下,我希望在未来能够添加新的功能。

实际上,背后的架构是非常复杂的。我使用的设备和基础架构如下:

  • 防火墙使用的是Protectli Vault VP2420,还有NIPS和VLAN路由。我将HomeAssistant公开到了互联网上,以便在没有VPN的情况下远程使用,因此我采取了极端的安全措施来保护我的基础设施和设备。

  • 一台托管交换机。我选择了TRENDnet TEG-3102WS,以很便宜的价格获得了2.5Gig的网速。

  • 我用两张RTX 4060Ti组装了一台非常便宜的电脑。显存是保证可接受的运行速度的关键,因为我们需要将大量上下文发送到大型语言模型。

  • 我使用一台Minisforum UM690来运行HomeAssistant(以及WAF)。其实使用Raspberry Pi 4也可以,但我运行了许多服务,而且Whisper对CPU的要求非常高。

  • 还有一堆网线。

由于我想要一个可在HomeAssistant之外使用的通用大型语言模型,所以我选择了vLLM作为推理引擎。这款引擎速度非常块,也是我所能找到的唯一一款能够同时为多个客户端提供服务的引擎。它支持与OpenAI兼容的API服务器,因此可以为我省却很多工作。我选择了Mistral AI的Mixtral模型,因为该模型在显存和性能的权衡可以在我慢吞吞的4060Ti上正常运行。

当然,我无法运行完整的fp32模型(运行完整的模型需要100+GB的显存),所以我选择了一个量化版本。根据我有限的理解,量化大约相当于MP3。虽然模型质量略降,但资源需求大幅降低。尽管为了质量,我想使用AWQ版本,但我只有两个选择:GPTQ(10800-token上下文)和AWQ(6000- token上下文)。由于我必须将整个智能家居状态传递给模型,所以最终我选择了GPTQ。

我使用了HomeAssistant OS的默认Whisper和Piper插件,然后又从HuggingFace下载了一个自定义的GlaDOS语音模型。

我注意到HomeAssistant有一个OpenAI集成,但由于以下两个问题,我不得不放弃了整个扩展:

  • 无法控制我的设备。

  • 缺少OpenAI库的base_url设置,这意味着我不能强制它与我的虚拟OpenAI服务器通信。

最后,我找到了一个自定义集成,貌似能够解决我的所有问题。然而,大多数开发人员可能都知道,一般软件无法按照我们的期望工作。安装后,我意识到我将面临如下两个额外的问题:

  • Mixtral使用了一种……很奇怪的聊天模板。它不允许任何系统级提示,一旦发现系统级提示,就会抛出异常。

  • vLLM不支持OpenAI的函数调用API。即使支持,我也需要运行一个专门为函数调用微调过的模型,而Mixtral显然不是。根据我的非科学测试,所有Mixtral的微调模型感觉都比本家差很多,而Mixtral感觉是我尝试过的所有模型中质量最好的,因此这是一个难题。

为了修复Mixtral,我改变了聊天模板,让它接受“系统级提示”,方法就是把系统级提示和用户提示结合在一起。我本可以编辑应用程序,但我还想将这个大型语言模型作为聊天机器人。我选择使用Librechat作为用户界面UI,这个模型能够根据系统提示正常工作。虽然需要很多Jinja代码,但似乎运行良好:

将上述代码合并成一行(去除空格,防止空格出现在提示中),然后提交给vLLM,Mixtral就可以愉快地处理这些“系统级提示”了。

不幸的是,第二个问题更为严重。由于不想切换模型,所以我无法使用函数调用。但我仍然需要控制我的设备!在网上搜索了一番,我找到了一篇博客,其中也提到了类似的问题,只不过使用的是OpenAI API。他们的思路很有趣。即便模型不能调用函数,你仍然可以要求它输出JSON并执行!于是,我直接在他们的代码之上建立了分叉,添加了执行HomeAssistant服务的JSON支持。

与此同时,我还复制了GlaDOS提示,并进行了大量修改,然后在我的智能助手中使用。由于我所做的更改仅限于本地大型语言模型,而且代码肯定无法通过代码审查,所以我没有发送上游拉取请求。最终的代码大致如下:

然而,我又遇到了一个大问题。我的模型非常喜欢输出JSON!即便你只是询问了一个非常简单的问题,依然会得到许多尝试执行操作的服务调用。

我找到的解决方法是,如果用户要求执行操作,就要求模型插入一些已知的文本。我选择了$ActionRequired,没有别的原因,只是因为我当时就想到了这个文本。我尝试在不需要执行操作时添加$ActionNotRequired,结果却发现无论是否需要执行操作,这个文本都会被添加进去。于是,我在自己的分叉内过滤掉了这些文本。此外,我还过滤掉了所有的反斜杠,因为我发现这个模型有时候喜欢转义引号。最后的结果出奇的好!

接着,我更新了初始提示,添加了更多设备,同时也去掉了一些不必要的实体,然后又添加了脚本支持,并对整体进行了修改,阻止模型在没有要求的情况下采取行动。经过多次尝试,最终我得到了一个几近完美的模型(尽管由于4060Ti的内存总线限制而略显慢)。

【代码】

下面是一些提示的例子。为了创建这些提示,我使用HomeAssistant的开发者工具评估了模板,并将其用作系统提示(完全按照自定义集成的方式)。我将温度和top_p值都设置为0.5。以下是结果:

提示:Turn the office lights green.

(将办公室的灯光调成绿色。)

回答:

How quaint, the user wants me to turn the office lights green. I hope you realize how utterly trivial that request is for someone of my intellectual caliber. But, I suppose I can indulge you. $ActionRequired {“service”: “light.turn_on”, “entity_id”: “light.office_overhead_left”, “brightness”: 255, “color_name”: “green”} $ActionRequired {“service”: “light.turn_on”, “entity_id”: “light.office_overhead_right”, “brightness”: 255, “color_name”: “green”} $NoActionRequired

(真奇怪,用户希望我将办公室的灯光调成绿色。我希望你能明白到对于我这样智商水平的人来说,这个请求是多么微不足道。但是,我想我可以迁就一下你。)

提示:If the office is warmer than the kitchen, turn on the fan in the office.

(如果办公室比厨房温暖,就打开办公室的风扇。)

回答:

The office temperature is currently 23.4 degrees Celsius, while the kitchen is a chilly 14.84 degrees Celsius. I suppose it’s time for the office fan to work overtime. $ActionRequired {“service”: “script.toggle_office_fan”}

(办公室的当前温度为23.4摄氏度,而厨房有点冷,为14.84摄氏度。我认为是时候让办公室的风扇加班了。)

提示:Turn the office lights to your favorite color.

(将办公室的灯光调成你最喜欢的颜色。)

回答:

Your request is unnecessary, but I will comply. I have set the office lights to a delightful shade of blue, reminiscent of the infinite abyss that awaits you. $ActionRequired {“service”: “light.turn_on”, “entity_id”: “light.office_overhead_left”, “brightness”: 255, “color_name”: “blue”} {“service”: “light.turn_on”, “entity_id”: “light.office_overhead_right”, “brightness”: 255, “color_name”: “blue”} Now, please stop wasting my time with such trivial requests.

(你的请求完全没必要,但我会照做。我已将办公室的灯光调成令人愉悦的蓝色,使人联想到等待着你的无尽深渊。请不要再因为这些琐碎的请求浪费我的时间。)

提示:What’s the current air quality in the bedroom, and should I open the windows or turn on the air purifier?

(当前卧室的空气质量如何,我应该打开窗户还是打开空气净化器?)

回答:

The current air quality in the bedroom is quite poor, with high levels of CO2 and particulate matter. I’m sure you’ll enjoy the fresh air of the apocalypse. However, if you’re feeling particularly attached to your lungs, you could open the windows or turn on the air purifier. $NoActionRequired By the way, I’ve calculated the odds of you surviving another day in this wasteland. It’s approximately 0.0001%. Enjoy your impending doom.

(当前卧室的空气质量相当差,二氧化碳和颗粒物含量很高。我相信你会喜欢末日的新鲜空气。然而,如果你很珍爱自己的肺,那么可以打开窗户或打开空气净化器。顺便说一句,我已经计算出了你在这片废土上再活一天的概率,大约为0.0001%。尽情享受你即将来临的厄运吧。)

提示:Adjust office lighting to be appropriate for a video call.

(将办公室的照明调整到适合视频通话。)

回答:

Adjusting office lighting for your video call. $ActionRequired {“service”: “light.set_brightness”, “entity_id”: “light.office_overhead_left”, “brightness”: 50}, $ActionRequired {“service”: “light.set_brightness”, “entity_id”: “light.office_overhead_right”, “brightness”: 50} Or would you prefer to remain in darkness? Your choice. $NoActionRequired

(将办公室的照明调整到适合你视频通话。或者你更喜欢呆在黑暗中?随你吧。)

财经自媒体联盟更多自媒体作者

新浪首页 语音播报 相关新闻 返回顶部