我的案头摆着一枚铭牌:“工具是开发者方法论的固化”。
本篇介绍的clawsqlite-knowledge是一款为OpenClaw环境量身开发的个人知识库skill,也是我在文章收纳与搜索召回领域探索之后的一次方法论固化。

我一直有一种好奇心焦虑:好玩、有趣的东西太多了,于是不停地剪藏网页,保存长文,转存观点,收藏链接。Evernote、Notion、OneNote、Joplin、Obsidian,装了一个又一个,库越攒越大,心里也似乎越来越踏实。可真正需要它们的时候,问题就来了:明明记得自己看过那篇文章,也大概记得它讲了什么,但就是搜不出来。
我想找“爬虫抓取”,那篇文章标题却叫“网页数据采集”;我想找“模型量化”,收藏时用的词却是“模型压缩”;我记得它讲过 RWA,但文章真正写的"资产代币化"。传统搜索靠的是字面匹配,只认词,不认意思。结果就是存的时候很轻松,用的时候大海捞针。久而久之,收藏夹就不再像知识库,而更像一座“数字坟墓”。东西全都在,真正能被重新调出来的却很少。
这正是我做 clawsqlite-knowledge 这个 OpenClaw skill 的原因。我想解决一个实际问题:已经存下来的东西,怎样才能在需要的时候重新被找回来。
为什么你的笔记总是“搜不到”?
很多笔记软件最大的问题在缺乏有效维护时,无法完成真正有意义的召回。原因很简单:第一,大多数人没有耐心在保存时认真整理。我们以为以后会补标签、补分类、补摘要,但现实往往是:存完就结束了。第二,人类回忆信息时,想起来的常常不是原词,而是一个模糊概念。你脑子里浮现的是“那个讲社交预测市场的文章”,但原文标题可能完全不是这个说法。传统全文检索这时就很吃力,因为它只会问一句:你输入的字,和原文里的字,到底有没有重合。
可见“收纳”和“召回”根本不是同一个问题。前者追求顺手,后者需要理解。那么有没有什么方法可以只管一键收藏。过后只需要模糊地表达意向,总是能找回当初收纳的文章,提供灵感和参考呢?我开发clawsqlite-knowledge 就是尽量让这两件事无缝衔接起来。
Embedding与向量匹配
传传统关键词搜索的逻辑,本质上更像“查字典”。它只能处理“你刚好说对了原词”这类情况。这种基于字面匹配的搜索,无法感知文字背后的语义。比如你搜索“网页抓取”,而文章里写的是“网页采集”;你搜索“量化模型”,而文章里讨论的是“压缩推理成本”;你搜索“社交预测”,而文章真正写的是某个具体的机制。只要字面偏一点,普通搜索就会漏掉。但人类回忆信息,本来就不是按精确标题回忆的。我们记住的常常是主题、场景、印象和关联。一个真正有用的知识库,不能只有全文检索,还需要有更接近语义层面的召回能力。
向量匹配则重构了这种搜索方式。它不再只关注字符本身,而是通过一种被称为“嵌入(Embedding)”的方式,将每一段笔记、每一个词汇投影到一个高维空间里。在我们的 clawsqlite 实现中,这个空间的维度是 1024。你可以把它想象成一座深邃的宇宙,每一条笔记都是一颗悬浮的星球。在这个宇宙中,星球的位置不是由名字决定的,而是由它的含义决定的。当模型处理“量化交易”这个词时,它会分析这个词携带的金融属性、算法属性、自动化属性,并在 1024 个维度上给出一组空间坐标。换句话说,向量匹配不只看字面是否重合,而是试图把“意思相近”的内容放得更近。这样一来,即便查询和原文的措辞不一样,系统也还有机会把你真正需要的那篇文章拉回来。
无论你说的是“番茄”“西红柿”还是 tomato,尽管它们的拼写几乎没有重叠,但因为它们所代表的核心含义高度一致,模型就会把它们放在距离很近的位置上。这就是向量匹配能够实现“模糊搜索”的底层逻辑。它识别的是概念的接近程度,而不是拼写表面的相似程度。哪怕你的查询词写得支离破碎,或者使用了完全不同的语言,只要它们在语义层面足够接近,系统就有机会在海量数据中捕捉到那条关联信号。这种从“字符对比”到“空间定位”的转变,让笔记搜索拥有了更接近人类直觉的联想能力。
BM25的精确制导
不过,如果只用向量检索,另一个问题又会出现:它容易找出一堆“差不多”的文章,却不一定“够准确”地发现你真正想要的那个精确匹配结果。尤其是在技术场景里,很多关键信息并不是一个模糊主题,而是一个具体名词、一个协议名、一个型号、一个缩写。像 STM32F103、nRF24L01、RWA、BM25、LoRA 这种东西,字面本身就很重要。你不能只靠“语义大概相近”来判断它是不是正确结果。
这时,关键词搜索里的 BM25 算法恰好可以弥补这一点。它的一个关键技术叫作 IDF,也就是“逆文档频率”。你可以把 IDF 想象成一种“物以稀为贵”的打分标准。在搜索时,不是每个词的地位都一样。
如果你在知识库里搜索“量化交易的原理”,系统会扫视一眼你的所有笔记。“的”这种词几乎到处都会出现,对系统来说,它就像空气一样普通,几乎不能帮助定位任何具体笔记,所以分数会非常低,甚至被直接忽略。但“量化交易”这种专业词就不一样了。它可能只在你 146 篇笔记中的 5 篇里出现过。正因为它稀缺,所以它的辨识度很强。系统会认为:既然你提到了这么少见的词,那你找的大概率就是那几篇文章之一。因此,这个词的得分会明显更高。
这就是“逆文档频率”的基本逻辑:一个词在库里出现得越频繁,它在搜索时的价值就越低;反过来,一个词越罕见、越独特,它越可能代表文章的核心,得分也就越高。它就像一个自动过滤器,帮你过滤掉那些没什么区分度的虚词,把搜索的聚光灯集中到真正有含金量的关键词上。这样,即便你搜的是一句比较长的话,系统也能很快抓出其中最值钱的部分,帮你定位结果。
在 clawsqlite-knowledge 里,BM25 是向量搜索最好的搭档。向量搜索负责解决“大概是什么”,而 BM25 负责守住“到底写了什么”。前者给你联想能力,后者给你精确锚点。
混合搜索:组合的升华
既然 BM25 见树不见林,而向量搜索恰恰相反,那么最自然的思路,就是把它们组合起来,以同时获得两边的优点。当然,这种组合不是简单的线性拼接。
当我们收录一篇文章以后,会先对全文做一次“取头留尾”。具体来说,就是取文章前 1200 字和最后一段,生成一个“长摘要”。这个长摘要会生成一个 1024 维向量,同时也会建立一个 BM25 的 FTS 索引。接着,这个长摘要还会交给 LLM 模型生成一个关键词列表。
如果没有配置 LLM,则降级为使用 jieba 分词结合 TextRank 来生成关键词列表。jieba 不仅是目前非常稳健的中文分词工具,更重要的是,它还能通过 TextRank 这样的算法,从一堆文字里尽量抓出更有代表性的关键词。你可以把这个过程理解成一种降级但可用的替代方案:它当然不如 LLM 那样灵活,但在没有模型可用的时候,仍然能提供不错的标签抽取效果。这个关键词列表随后也会再生成一个 1024 维向量。
这些关键词会被整理成“标签(tags)”,既写回数据库字段,也作为“标签向量”的输入。实际入库时,clawsqlite-knowledge 会构建出几条不同的信号:
- 长摘要向量:把文章长摘要 embed 成 1024 维向量(
articles_vec); - 标签向量:把
tags这一行文字 embed 成另一条 1024 维向量(articles_tag_vec); - 全文 FTS:对标题、标签、摘要建立 BM25 索引;
- 标签 FTS:对
tags做更轻量的字面匹配,增加一个额外打分通道。
搜索时,就是围绕这几条信号做一场加权投票:语义相似(摘要向量 + 标签向量)负责“找对人”;FTS + 标签字面负责“确保那个人真的说了这些字”。
在实际工程里,我们不会让任何一个通道“独裁”。当前版本的默认权重结构,大致是语义向量占 75%:其中 45% 给标签,30% 给摘要;字面匹配占 20%:其中 10% 是标签,10% 是全文 FTS;另有约 5% 用于人工 priority 和时间衰减。这个权重是可以人工调节的,你可以在.env环境变量中定义自己喜欢的权重比例。
这套结构的好处在于,“开源硬件 / open source hardware” 这种中英文同义词,可以通过标签向量较容易地对齐;而像 STM32F103、nRF24L01 这种硬编码型号,仍然由 BM25 和标签 FTS 来把关,不会被语义通道淹没。
补上OpenClaw的分词短板
原生状态下的 OpenClaw,在面对庞大的中文知识库时,会有一个比较明显的短板:它缺乏足够强的 CJK 字符流分词能力,无法像处理英文那样,天然依赖空格去识别词边界。这会带来什么问题?很简单:当你搜索“量化交易”时,数据库有可能只能识别出一些零碎片段,最后返回一堆包含“量化”或者“交易”的噪音结果,甚至直接找不到你真正想要的东西。OpenClaw的github上有一条发布自2月19日的issues,memorySearch BM25 (FTS5) does not work for CJK text #20730,就是抱怨并且期待这个问题能修复。每隔几天就有人过来刷一下这个issues,防止它被锁。
求人不求已,我自己维护了一个打好分词补丁的 Docker 镜像:ernestyu/openclaw-patched。它把 libsimple.so 和 vec0.so 这两个关键补丁提前准备好了。其中,libsimple.so 更像是给全文搜索装上了一套更适合中文的分词能力。它的作用,是把原本连成一片的中文字符流切成更合理的词元,让核心关键词能够更好地进入索引系统。这样一来,字面搜索才真正有机会在中文场景里发挥作用。而 vec0.so 则是向量检索这一侧的基础支撑。作为 sqlite-vec 扩展的核心,它允许我们把文章对应的 1024 维嵌入向量存进 SQLite,并在这个基础上做向量匹配。也就是说,没有它,很多语义检索能力就无从谈起。这两个底层能力合在一起,才让中文知识库真正兼具“字面匹配”和“语义召回”两种能力。
因为这两个 SQLite 插件都是 C 语言底层库,安装往往涉及额外权限和环境处理,所以如果你只是想尽快把系统搭起来,而不是自己折腾底层编译,我会很建议你直接使用我打好补丁的 Docker 镜像来安装 OpenClaw。否则,clawsqlite-knowledge 会退化为主要依赖 FTS 的关键词搜索,语义模糊匹配能力会明显下降,不过基础搜索仍然是可用的。具体安装方法参考我写的文章:OpenClaw Docker 补丁镜像 2.0:给你的 AI Agent 装上六种“新感官” 。
三分钟入坑:给你的小龙虾换个硬核大脑
如果你看到这里,觉得自己的 OpenClaw 确实需要这么一个“带大脑”的知识库,那么接下来的物理实操会非常简单。我更推荐的路径,是直接使用已经打好关键补丁的 ernestyu/openclaw-patched 镜像来安装 OpenClaw。这样,中文分词和向量检索所依赖的底层环境会先准备好,后面再装 clawsqlite-knowledge 就会顺很多。
在这个基础上,clawsqlite-knowledge 的安装目前可以理解为两步。
第一步,在你的 OpenClaw 环境里执行
openclaw skills install clawsqlite-knowledge这一步是把技能的物理外壳拉下来。
第二步,进入这个 skill 目录,执行:
python bootstrap_deps.py这一步才是真正把它依赖的核心部分装进去。它会创建隔离的运行环境,并通过
pip install clawsqlite>=0.1.7安装核心依赖,包括中文分词、拼音等能力。
这里需要额外说明一下:OpenClaw 本身负责的是 skill 的安装和管理,但如果某个 skill 还依赖额外的第三方包或运行环境,那么这些东西并不一定会由 OpenClaw 自动全部处理完。也正因为如此,我才更建议先把底层环境准备好,再去装这个 skill。这样路径会更稳,也更少踩坑。
装好之后,你只需要在 skill 目录下创建一个简单的 .env 文件,填入数据库存放路径、你喜欢的 LLM 接口,以及 embedding 模型接口。这些配置做好以后,你就可以把事情交给小龙虾了。
这里强调一下,想要完全发挥clawsqlite-knowledge,你需要三个关键配置:
- 一个安装了
libsimple.so与vec0.so这两个SQLite插件的OpenClaw版本。其中,libsimple.so分词插件是可选项,可以通过安装jieba第三方库替代;vec0.so是必选项,否则向量搜索无法实现,会降级为FTS关键词搜索,失去模糊匹配的功能。推荐我维护的Docker 镜像:ernestyu/openclaw-patched,已经打好这两个关键补丁 - 一个小型LLM大语言模型,用于抽取文章关键词列表。没有的话会降级为jieba的TextRank算法,但依然可用。这个选项主要是为了帮你省钱。如你嫌麻烦,让OpenClaw做关键词抽取也没有问题。
- 一个embedding模型,用于实现向量化嵌入。我使用的是BAAI/bge-m3,它对中文和跨语言的支持度很高。如果你使用仅支持英语的embedding模型,在中英文混合的场景可能会有性能损失。
安装之后,你可以随时对它说:“帮我把这篇关于模型优化的文章存一下。” 也可以说:“帮我搜搜我上周存的那个关于 RWA 的观点。”你会发现,原来那种“找资料像大海捞针”的感觉会明显减轻。取而代之的,是一种更踏实的、知识随叫随到的掌控感。
最后一块拼图
虽然我们前面一直强调召回,但是收纳是召回的源头。clawsqlite-knowledge支持两种输入模式。
- 一种是
--text,就是给它一段文本,比如你自己的口头总结,突然灵感,或者干脆是一篇markdwon文本,它都会以文本方式存入。 - 另一种是
--url,也就是给它一个网页链接,它会调用网页抓取代码进行全文抓取。
OpenClaw上好用又小巧的网页抓取代码不多,我一直使用自己开发的clawfetch。具体安装参考我为 OpenClaw 写了一个更适合 Agent 的网页抓取工具clawfetch。最近我更新了几次代码,让它在抓取网页时更灵活。现在对付一般的Cloudflare检测,微信公众号,微博,X等页面不在话下。它同样也是一个skill。让小龙虾执行 openclaw skills install clawfetch,或者参考网页 Claw Web Fetch 都可以。
结语:让“存”与“得”物理对齐
我开发 clawsqlite-knowledge只是想解决一个最朴素的物理矛盾:为什么我们拥有了历史上最便捷的收藏工具,却依然在经历严重的“知识焦虑”?
答案很简单:因为“存”和“得”在物理上是不对齐的。存是一瞬间的快感,得是长期的逻辑编排。如果系统不能帮你完成这种编排,那么你存得越多,你的认知负担就越重。
通过引入分词、TextRank、鲁棒截断和自动打标,我们其实是在试着把知识库从一个冷冰冰的“仓库”,变成一个更接近“神经中枢”的东西。我们希望当你再次打开 OpenClaw 搜索知识时,你得到的不再是一个干巴巴的搜索结果,而是一种逻辑上的豁然开朗。
不要再让你辛辛苦苦存下的笔记在收藏夹里发霉了。给你的小龙虾装上这个大脑,让我们一起终结那个“文章坟墓”的时代。