我一直觉得,博客的文章列表有一个小问题:它很擅长告诉你“最近写了什么”,却不太擅长告诉你“这些东西之间有什么关系”。
一篇强化学习笔记、一篇 C++ 内存管理文章、一个 FastAPI 项目和一首诗,放在列表里就是四个时间点。可它们明明都来自同一个人的生活,彼此之间也可能有一些不那么容易用分类栏写出来的联系。
所以我做了 Latent Garden↗,中文暂时叫它“语义花园”。它的第一块真实花圃,就是寒柳别苑的语义地图↗。
先看看它长什么样
这里的每一个点,代表一篇文章、一个项目或一条内容记录。点与点之间的远近,来自它们的文本表示;颜色和区域,则是对主题的进一步整理。点击一个点,可以回到原来的页面。
你可以直接打开完整花园↗,也可以从别苑杂务里的语义花园进入。
我不想把它做成一张“看起来很智能”的装饰图。它更像一张可以随时翻阅的索引:先让你发现一条意外的邻近关系,再决定要不要走过去看看。
为什么不直接写在博客里
最开始的想法很简单:抓取 zylatent.com 的文章,用 embedding 表示每篇内容,再降到二维,最后画出一张图。
但如果把所有代码都塞进博客主题里,事情会很快变得别扭。博客负责文章、路由和主题;语义花园负责内容读取、向量化、降维和交互展示。这两件事有关,但并不是同一个问题。
于是我把它做成了一个独立项目。博客只是它的一个数据来源和一个入口,未来也可以换成别的网站、文档库、课程笔记,甚至一个团队的知识库。
这个决定还有一个实际好处:地图最终只需要一份静态的 garden.json。网站可以把它部署到静态托管服务上,访问者打开时不需要等待后端临时计算,也不需要把我的博客内部结构暴露给前端。
它大致怎样工作
完整流程可以压缩成下面几步:
内容来源 ↓统一成 ContentItem ↓文本向量化与缓存 ↓UMAP 降到二维 ↓主题分组与人工整理 ↓生成 garden.json ↓独立前端渲染地图先把内容变成同一种东西
来源可以是 Markdown、MDX、JSON、RSS,也可以是公开网页。不同来源的字段不一样,所以项目先把它们统一成标题、描述、正文、链接和元数据组成的内容对象。
这样做看起来有点像为内容设计一个小型数据结构,但它很重要:后面的 embedding、缓存和地图前端不需要知道内容最初来自哪里。
再把文字变成向量
向量并不是“文章的正确答案”,只是对文本的一种机器表示。语义相近的内容,通常会在向量空间里更接近;但这件事会受到模型、文本长度、语言和预处理方式影响。
为了让地图可以重复生成,我加了 provider 抽象和缓存。没有配置外部模型时,也可以用确定性的 hash provider 跑通完整流程;配置真实 embedding 服务后,再替换 provider 即可。对一个个人项目来说,这比每次改几个标题都重新付费调用接口更实际。
UMAP 负责把高维空间摊开
向量可能有几百甚至上千维,无法直接画在屏幕上。UMAP 把它压到二维,让我们可以在一张图里观察局部邻近关系。
这里有一个需要提前说清楚的限制:地图上的横轴和纵轴没有固定含义。它不是“技术程度”或“文学程度”的坐标系,也不能从左到右读出一条客观尺度。每次数据集或参数变化,布局都可能略有不同。
所以我更愿意把它理解成一次投影,而不是一份测量报告。
模型给出线索,主题由我来收拾
如果完全让聚类算法决定颜色,结果可能会很有趣,但不一定适合一个个人网站。算法也许会把某几篇文章因为词汇相似放在一起,却无法知道我希望访客先看到什么主线。
现在的地图采用“计算相似度 + 人工整理主题”的方式。完整花园保留了“智能与计算”“工具与开源”“互动实验”“诗歌与文学”“影像与见闻”等较宽的区域;另外还准备了一个偏工程的视图,把智能系统、开发者工具和交互实验收拢起来。
这不是为了假装客观,恰恰相反,是把边界说清楚:
- 点的位置,是计算结果;
- 颜色和主题名,有编辑判断;
- 点击后跳转的页面,仍然是原始内容。
语义花园并没有替我理解自己。它只是先把一些可能的关系摆到桌面上,让我重新读一遍自己的东西。
我从第一张地图里看到了什么
最有意思的地方不在于某一篇文章被分到了哪个颜色,而在于列表关系变得不那么线性了。
比如,关于智能系统的文章不一定只和另一篇“AI 文章”靠近,它可能也和一个工具项目、一次交互实验或一段学习记录相邻。过去我会把这些内容分别放进不同栏目;现在地图会提醒我:分类是为了导航,创作过程本身往往没有这么整齐。
当然,这种观察也要克制。地图很容易让人产生“发现了深层规律”的错觉,但一个点靠近另一个点,首先只说明它们在当前数据、当前模型和当前参数下相近。它可以成为继续阅读的理由,不能直接当成结论。
做成独立工具之后,它还能去哪儿
Latent Garden 现在首先服务于我的博客,但它的输入并不绑定寒柳别苑。只要能把内容整理成统一格式,就可以用来做:
- 个人博客或数字花园的内容导航;
- 一组课程笔记的知识地图;
- 项目文档和 issue 的主题浏览;
- 团队内部公开知识库的探索入口;
- 研究资料、读书摘录或长期日志的回看工具。
我暂时没有把它包装成一个“万能知识管理系统”。它目前更像一个小而完整的管线:读取内容,生成地图,部署前端,点击后回到原文。
这种克制反而让它比较容易继续生长。以后可以加入时间轴、筛选快照、更多数据适配器,也可以让使用者选择不同的主题视图。但这些都应该建立在一个前提上:地图要帮助人回到内容,而不是让内容变成一张漂亮的截图。
写在最后
我喜欢“花园”这个比喻,是因为花园不要求所有植物整齐地排列成表格。它允许有主路,也允许有小径;允许一片区域暂时空着,也允许某个角落过一阵子才长出新东西。
博客也是这样。
如果你愿意,可以去完整花园里走走↗。不必先理解 embedding、UMAP 或聚类,随便点一个看起来有点孤单的点就好。也许它旁边,正好藏着一篇你原本不会主动找到的文章。
项目源码在 ZhouYinLong-lab/Latent-Garden↗。
