☰
不租服务器不用 Notion:我把 1.6 万个文件和 147 段 AI 对话炼成本地图书馆「琥珀」
2026/10/2 23:51:43 网站建设 项目流程

不租服务器不用 Notion:我把 1.6 万个文件和 147 段 AI 对话炼成本地图书馆「琥珀」

前言:为什么我要自己造这个轮子

起因很简单:我的资料散落在三个地方,而我的脑子只记得"我好像写过/见过这个东西"。

具体来说有三个痛点。第一,我现在日常被一堆 AI 工具包围(WorkBuddy、Codex……),每个工具都产生大量对话——“这个坑当时是怎么解的”"那个选型为什么否决了"这些决策过程只存在于对话里,文件里只有结果。过两周想回头查,对话早翻不到了。第二,写的代码、笔记、报告散在 C、D、F 三个盘上,Windows 自带的搜索基本是个摆设,搜中文内容更是没眼看的。第三,我试过把资料往云笔记里搬,但说句实话,把几年的私货传到别人家的服务器上,还要按月交钱,图什么?

所以我给自己定了个死指标:纯本地、零网络依赖、零订阅费,中文全文可搜,文件和对话一个入口全查。最后做出来的东西我给它起了个名字叫「琥珀」(AmberKB)——把散落的记忆封进琥珀,需要的时候打开看,过去的每一个决定都完整地冻在里面。

这篇文章是它的完整复盘:架构怎么定的、踩了哪些真坑、花了多少钱(0 元)、以及哪些事它做不到。

一、选型:为什么是 SQLite FTS5 + trigram

先说结论:整个系统没有一个第三方依赖(除了 Python 标准库),全文检索靠 SQLite 自带的 FTS5,中文分词靠 trigram。

很多人一听"中文全文检索"就上 Elasticsearch、上 jieba 分词,那个阵仗是给百万级文档准备的。我的库是 1.6 万个文件、420 MB,trigram 方案完全够用而且有个致命的优点:不需要分词。

trigram 的原理是把文本切成所有连续的 3 字符片段建倒排索引。比如「运放读书报告」会被切成「运放读 / 放读书 / 读书报 / 告报告……」这样存。查询时任意 ≥3 字的子串都能直接命中,不需要理解词边界——这对中文是天大的好事,因为分词器搞不定的问题(新词、错词、半角全角混排)在 trigram 面前统统不存在。实测本机 SQLite 3.50.4 支持良好(要求 3.34+)。

方案中文支持依赖资源占用对我来说
Elasticsearch要装 IK 分词JVM 一大坨内存起步 1GB杀鸡用牛刀
jieba + SQLite要维护词典纯 Python中分词错就搜不到
FTS5 + trigram免分词,子串命中零(SQLite 内置)索引约为原文 1.5~3 倍真香

唯一的代价是索引体积:kb.db 现在 1.65 GB,比 420 MB 的原文大不少。但这是本地磁盘,1.65 GB 换零依赖,这买卖性价比极高。

二、架构:两个库、四个导入器、一个入口

架构我刻意做成了"多个导入器 + 统一出口"的扇形:每种资产有自己的导入器,互不知道对方存在,但所有检索走同一个命令。这样加一个新数据源(比如后来加的 Codex 会话)只需要写一个新导入器,检索层一行代码都不用改。

目前四条数据线:

  1. 磁盘文件线(kb.py scan / index):实时遍历 C 盘用户目录、D 盘、F 盘,文本类文件(.md/.py/.c/.h/.json/.txt……)元数据进docs表,正文进fts全文表。PDF/Word/Excel/PPT 是二进制,由kb_office.py单独抽取文本进office_fts。
  2. WorkBuddy 会话线(kb_conv.py):解析本地~/.workbuddy/projects/下的会话 jsonl,收109 条对话链。注意是"全账号"的——我日常用 WorkDaddy 切换多个 WorkBuddy 账号,但本地存储根本不区分账号,所有账号的对话都落在同一棵目录树里,一并收录。
  3. Codex 会话线(kb_codex.py):解析~/.codex/sessions/的 rollout 文件,38 条。写这个导入器花了不到一小时,因为表结构直接复用会话库,CLI 改改解析格式就行。
  4. 老格式线(kb_office.py convert-legacy):.doc/.xls/.ppt这种上个时代的二进制格式,纯 Python 无解,走 Office COM 自动化硬啃,实测 0.8 秒/个。

出口只有一个命令行入口kb.py:find给 AI 调用(输出 JSON),search给人看(排版 + 分层标签)。我自己的使用方式是直接对 AI 说"搜一下我之前怎么配置 XX 的",AI 调 find,带路径带日期地回给我。

三、几个值得说的设计细节

1. 增量索引靠 mtime+size 双标记。docs 表里给每个文件记idx_size/idx_mtime,scan 时没变的文件直接沿用索引标记,只有新增和改动过的才重新抽正文。全量重索引要 30 分钟,增量后日常维护几秒钟。

2. 会话用文件名当主键,不用 sessionId。这是个血泪教训(见坑三)。另外同一话题的会话链会有多个快照文件,按"工作区 + 标题链"聚合后只显示最新那份,标注"另有 N 份副本"。

3. 查询改写让我可以用口语搜。系统内置停用词剥离 + 同义词表 + 多词合并排序。实测输入「我那个邮箱的自动转发是怎么做的」,会自动展开成 邮箱/mail/转发规则/收信规则 等词各查一次,按命中词种类数 + bm25 排序。口语进,术语出,这层是日常使用体验的分水岭。

4. 结果分层打标。命中分[产出]/[工具书]/[缓存]三层,插件和依赖缓存(node_modules 里的 README 之类)标 C 层默认折叠——不然搜个东西出来全是依赖文件,没法看。

四、踩坑实录

下面三条都是真坑,每一个都让我卡住或者差点出大事。

坑一:scan 的清理逻辑差点把 55% 的库一键蒸发。

我的 F 盘是外接盘,时接时不接,而它占了全库 9066/16478 ≈55%的条目。原版 scan 的逻辑是:遍历时跳过不存在的根,但收尾清理是一句全局的DELETE FROM docs WHERE seen_at < scan_start——意思是"这轮没见到的文件 = 已删除,清掉"。于是一个致命场景出现了:F 盘没插的时候跑一次 scan,F 盘 9066 条记录连同全文索引全部蒸发,而且是无声无息的那种。

修复思路是"根感知清理":只对本轮真正遍历过的在线根执行按根删除,离线根跳过,不在配置里的残留根照常清。改完我拿真实库的副本做了模拟测试,第一次模拟居然 FAIL 了——排查发现是模拟前提错了:我模拟"F 盘离线",但盘当时插着,os.path.isdir返回 True,补丁把它当在线根正常清理了,行为反而完全正确。换成合成库 + 真离线假根重测,三个分支全过。测出 FAIL 不一定是坏事,先看是代码错还是测试前提错。

坑二:FTS5 虚拟表上对 UNINDEXED 列做 LIKE,静默返回 0。

这是最近踩的最新鲜的坑。给 Codex 会话写导入器,导完验证"数据进没进",我写了句SELECT count(*) FROM conv_fts WHERE conv_id LIKE 'rollout-%'——返回 0。我以为导入失败,清了重灌,还是 0。折腾三轮之后才意识到:FTS5 虚拟表对 UNINDEXED 列做 LIKE不报错、直接返回空,这是 SQLite 的已知行为。换成等值查询WHERE conv_id = ?,数据全在,第一遍就导成功了。教训写进了我的操作手册:验证 FTS5 数据用 MATCH 或等值,永远别用 LIKE。

坑三:多个 jsonl 共用一个 sessionId,按 sessionId 当主键会互相覆盖。

WorkBuddy 的一条对话链会被切成多个快照文件,我实测 222 个 jsonl 里有 26 个 sessionId 是被多个文件共享的。最初版本拿 sessionId 当主键,结果同一链的快照互相覆盖,数据看着"莫名其妙变少"。改成文件名当主键(一文件一记录)后才稳定,链内去重交给展示层的聚合逻辑。

其余次级坑一句话带过:正文 <20 字的短消息不进全文索引("在吗"这种搜不到,但标题还在);INSERT INTO docs不带列名会在表加列后第一次跑通、第二次崩;老格式 COM 转换会在坏文件上弹框死等,需要"写前标记 + 分片 + 超时清进程"三件套保命。

五、效果与成本

现在日常长这样——搜"当时为什么否决了某个方案",一条命令:

$ python kb.pyfind"收信规则 转发"--kindconv# 返回:命中对话链 + 时间 + 工作区 + 当时的结论片段 + 文件产出清单# 文档和对话混排,带路径带日期,AI 可以直接引用

成本核算:0 元。没有服务器(纯本地磁盘)、没有订阅(SQLite 和 Python 都是现成的)、没有 API 费。代价是 1.65 GB 磁盘占用和每次 scan 几秒钟的时间。对比一下云笔记方案:数据出境 + 月费 + 搜索按条数收费,这个性价比没得比。

AI 对话这条线是我觉得最值的部分:109 + 38 =147 条对话链、10,591 个正文片段,相当于把我和 AI 协作两个多月的所有决策过程变成了可检索资产。"我为什么当时不这么干"这种问题,现在 3 秒出答案。

六、能力边界(哪些事它做不到)

按惯例诚实标注:

  • 不做语义检索:纯关键词/子串匹配,没有 embedding。搜"认证"搜不到只写了"登录鉴权"的文档(靠同义词表缓解,但治标不治本)。向量库我评估过,当前规模收益不抵复杂度,先不上。
  • 不做 OCR:2,486 个 PDF/Office 里有 250 个是扫描版(无文字层),抽不出文本,标 empty 跳过。OCR 方案调研过,成本高收益低,明确放弃。
  • 不做云同步/多机:设计前提就是单机。换机器要整库搬迁(kb.db + kb-conv.db 两个文件拷走即用)。
  • 外接盘的硬约束:两块外接盘时接时不接,虽然清理逻辑已经做了保护,但盘不在手上的时段,检索结果天然缺那部分内容——这是物理现实,软件解决不了。

七、下一步

  • 把发布流程也自动化掉:现在这篇文章的排版、多平台草稿已经用 CLI 工具链(md2wechat)跑通,下一步接 CSDN 草稿箱,实现"写完 → 排版 → 存草稿 → 人工过目 → 发布"。
  • 给会话线加增量定时任务,让 147 这个数字自己涨。

回过头看,这个项目最值钱的不是代码(总共就几百行 Python),而是**"决策过程也是资产"这个认知**——文件告诉你结果,对话告诉你为什么。琥珀的意义就在这。

相关仓库

  • github.com/RainmeoX/auto-publisher (发布工具链与本文配套脚本,私有)
  • 琥珀本体(kb.py / kb_conv.py / kb_codex.py)暂未开源,整理后会放到私有仓,感兴趣的可以评论区留言

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询