18mu-blog
一个以 Markdown 为唯一内容源的个人知识站:Astro 静态构建,一个 Cloudflare Worker 同时承载页面与语义地图快照。
文章目录[4]
项目是什么
18mu-blog 是这个站点本身的代码库:一个以 Markdown 为唯一人工内容源的个人知识站。
它要解决的问题只有一个——让「写一篇东西」成为唯一需要人来做的事。内容写成 Markdown,页面、索引、标签、RSS、站点地图和部署全部由构建流程产出,没有一份需要手工维护的列表。
站点同时承载四条内容线:完成写作的中文博客、公开的中英双语项目说明、脱敏可复用的 For Agent 记录,以及一份由结构化事实驱动的简历。
具体结构
站点分三层,每一层只依赖它下面那一层。
内容层。 Markdown 是唯一由人维护的公开来源。博客、项目和 For Agent 记录是三个内容集合,字段契约写在 content.config.ts 里,构建前由校验脚本检查。简历经历走另一条路:事实存放在 fact-base/,只在构建时被读取,不作为内容集合发布。
交付层。 Astro 把内容集合构建成静态站点,输出到 .deploy/;一个 Cloudflare Worker 同时承担两件事——把静态资源递给读者,以及对外提供公开 API。静态资源通过 ASSETS binding 挂在这个 Worker 上,所以整站只有一个部署单元。
语义层。 只有已发布的博客文章会进入语义处理。Worker 调用外部 embedding 服务拿到向量,算出两两余弦相似度,按阈值聚类,再把每篇文章至多六个最近邻居写进 Cloudflare KV。认知地图和随机漫步这两个 React 岛屿从公开快照接口读取结果。
优秀设计
内容契约先于内容。 每个集合的字段由 schema 定义,构建前先跑关系校验:关联字段必须指向存在且已发布的记录。写错一个 slug 会让构建失败,而不是在页面上留下一个死链。
派生数据可以随时重建。 语义快照完全由已发布的博客 Markdown 推导,不存任何手工维护的关系。清掉 KV 里的数据,跑一次同步就能复原。
密钥不进内容。 embedding 的模型端点和密钥只存在于 Worker 配置与 Cloudflare Secret 中;浏览器只读取不含密钥的公开快照,同步令牌只在 GitHub Actions 里使用。
发布路径是 Git。 生产环境只接受已经提交并验证过的 main,工作区里的未提交改动不会被发布。
解决了什么问题
- 写内容不需要维护索引、标签页或站点地图——这些都由构建产出。
- 项目、经历和 For Agent 记录之间用 slug 建立关系,写错会在构建阶段被拦下。
- 文章之间不靠手工打标签建立关联,而由语义相似度自动形成主题聚类。
- 站点没有登录、评论、支付或浏览器端凭据,一次内容更新只改动 Markdown。