Github上有一个很知名的项目,叫做Memos,不知道大佬们用的多不多。这是一个开源且轻量级的自托管笔记服务,我用不上太花里胡哨的功能,而Memos这种随记随走的风格我也很喜欢(说起来算是国产优秀笔记flomo的替代品)。

在用了好几年后,我瞅着这些笔记,突然一个念头油然而生,这不正是当下我最完美的 RAG (检索增强生成) 数据集吗? 如果能让 AI 来理解和检索我的笔记,我岂不是拥有了一个真正懂我的个人 AI 助手?
我的风格是说干就干,熬了几天就把它的初版给干出来了。但是我没想到,其实整个过程比我想象的要曲折,充满了各种坑。今天开这篇文章,就是要记录并分享一下我踩过的这些坑,和过程中想到的一些解决方案,希望也能给大家一点启发。另外我这里没有教程,因为代码都是AI写的,所以只谈思路,不聊代码。
第一个坑:向量模型
万事开头难,第一个难题就是向量模型(Embedding Model)的选择。最省事的方案当然是直接调用 OpenAI或者国内厂商的 Embedding API。简单、高效,效果还好。但当我估算了一下我现有笔记的量,以及未来每天增量的同步成本,我默默地看了一眼我的钱包……钱包一紧,我开始担心免费额度是否 hold 住,长期使用的成本我也估算不来,心里没底,对于我这个人项目来说,感觉是不够“经济适用”。
于是我转向了本地部署开源模型,简单的向AI询问了一下,便让AI帮我部署了一套本地支持 CUDA 加速的模型,毕竟“快”是第一生产力。在我的开发机上,一切顺利,性能杠杠的。
但是,这里总是要有个但是,当我的 Memos AI 终于跑起来时,我兴奋地问了它一个问题。我知道有一条笔记肯定能回答,但结果却让我大失所望——最相关的那条笔记内容毫无踪影。
我深入排查(深入问AI)后发现,问题出在向量搜索的局限性上。我的那条笔记,开头有几个与问题匹配的中文关键词,但笔记的主体内容是一大段代码。对于向量模型来说,它看到了开头的几个中文词,觉得有点相关,但它看到后面大段的、与问题语义完全不同的代码时,它认为这条笔记的整体“语义”和我的问题相去甚远。最终,在向量空间中,这条笔记与我的问题的“距离”被拉得很远,导致它根本没出现在喂给AI的上下文中。
这个时候,我灵机一动,有没有可能做到混合搜索。向量搜索负责找到语义最相近的笔记,但是如果最相关的一条笔记相关性的阈值过低,那就让AI先拆分问题中的关键词,拿关键词去调用传统搜索,将语义相近的笔记和传统搜索出来的笔记一股脑扔到AI上下文中,反正AI学习后肯定能帮我找出最合适的答案。
引入混合搜索后,效果立竿见影。那些“貌合神离”的笔记至少能被找到扔给AI上下文,AI也能靠谱的回答到笔记中的内容。
实际上到这里我已经很满意了,但是后面发现还能有更加优化的地方,但是,后面的坑让我在这一步的优化拖延了下来。
第二个坑:不够智能
仅仅构造一个RAG,在当下可能真的算是很简单的事情了。但问题也出在这里,RAG太简单了,基础的 RAG 流程就是“检索->提问”,流程太呆板导致不够智能。
比如我问一句「我最近几条笔记都在研究什么」,它只会傻乎乎的拿这句话去向量数据库里面检索“最近几条”这些个关键字,但显然不会有相关的笔记,而这句话的目的显然是按照笔记时间顺序找到最新的3-5条笔记再总结内容。
为了让他智能一点,我想到了 Function Call机制,让大语言模型自己决定如何更好地回答问题。当我提问的是具体问题时,还是走原来RAG那个流程;当我问的是宽泛的问题如最近、指定类型甚至不限定笔记内容时,就会去寻找更多相关笔记内容,然后返给AI上下文中,让AI参考回答。
第三个坑:笔记内容的数据安全问题
本来没有意识到这个问题的,但是上面不是加了个function call嘛,我就顺手问了一句「总结我笔记都在记些什么」,然后它给我总结了,结果内容吓我一跳,直接说我笔记里面有很多账号密码,包括信用卡的cvv信息。
这…真的吓我一跳,虽然说很多平台在线的笔记本也会记录一些账号密码信息,但是那是长期脱敏的结果,总觉得大厂怎么着也会给我笔记加密,黑客应该看不到我密码信息这些。但是AI活生生读了我笔记内容又说出来了,这个感觉又完全不一样了。
于是我意识到,需要将敏感信息过滤掉,不应该让AI能读到我的敏感内容。说干就干,在同步笔记到向量数据库的地方,和上传上下文内容给AI的过程中都加了一套过滤,确保把敏感内容都给拦截下来了。
但是…我的笔记内容已经泄过一次密了呜呜呜!

第四个坑:群晖的“坏环境”
我的memos部署在群晖上,利用的是群晖自带的docker环境,memos笔记的内容存在sqlite文件上,当初正是看到sqlite文件易读写,所以觉得RAG这事能干,才起心动念了的。
但是在群晖上同步笔记内容到向量数据库时就出问题了。首先,群晖 系统自带的 Python 版本是 3.8。这个版本在今天看来,已经有些“年迈”了。很多新的 AI 相关的库都要求 Python 3.9+,安装依赖一直都在报错。
在我强行升级系统python版本到3.9之后,真正的麻烦又来了。虽然一切信息都表明群晖里面cuda是正常的,但是同步脚本就是跑不起来。就在我一筹莫展时,我突然想到:我真的需要 GPU 级别的性能来向量化我的笔记吗?
我的笔记大多是几百字以内的短文本,同步任务也是后台异步执行的,对实时性要求并不高。经过与AI友好交流并测试后,我发现即使用 CPU 来进行向量化,速度也完全可以接受。
想通了这一点,我果断修改了方案:强制指定模型使用 CPU 运行,同步脚本终于算是跑起来了。
同步脚本在宿主机上运行我觉得还好,但是web服务那一大块我就不想在宿主机上跑了,于是在折腾同步脚本的同时我也在打着docker镜像,结果…
Docker 镜像巨大!!!一个带了 CUDA 环境的 PyTorch 镜像,再加上模型本身,打包出来的 Docker 镜像足足有 7.33G!对于 NAS 这种资源环境来说,简直是庞然大物。
好在同步脚本都用CPU跑了,那镜像还用啥CUDA,马上也全部改成CPU版本,镜像也变成了700多兆。也算是开眼了,7.33G的镜像,打包都打了半个小时。
然后部署docker的时候又出问题了,我docker镜像是存在内网的,群晖不认可非https环境的镜像。以往docekr都可以通过配置文件添加insecure-registries项即可解决,结果群晖对 Docker 进行了“魔改”,把配置文件藏在了一个极其奇葩的路径下:/var/packages/ContainerManager/etc/dockerd.json。
到这里真是长舒一口气,总算是大小的坑踩完了。
最后终于顺利跑起来
所有服务终于顺利跑起来了,使用了一会,又有了新的不满意。作为一个memos外挂的AI,每次用的时候单开一个网页,总感觉不得劲。
于是我想了一下,决定用油猴脚本定制一个悬浮窗,打开memos网页时,固定右小角显示一个悬浮按钮,点击就可以与memos AI对话,效果如下:

做了好几天,准备歇歇了,其实还有一个可以优化的地方,那就是项目中用的是“all-MiniLM-L6-v2”这个向量模型,但其实它对中文的处理能力并不优秀,还可以升级成更好的中文向量模型,应该能有更好的效果。但是我累了,没想到这么简单一个项目还挺折腾,就先放项目出来让大家观摩观摩吧。
观前提示:代码全部AI生成,本人不对代码质量负责,仅仅提供一个思路,这个 Memos AI 项目我还会不断完善(前提是要歇一歇)。
github地址:https://github.com/DemoJ/memos-ai