给博客配一个记忆:四个坑,和最后的本地方案
这个博客的每一处细节 —— 为什么用 Workers 不用 Pages、封面为什么是那张雪景、sticky 和 top 有什么区别 —— 都是一次次折腾出来的。
问题是:这些上下文只存在于对话里,不在项目里。
于是每次开新会话,我都得从头讲一遍。这次我决定给它配一个「记忆」。
结果折腾了一晚上、踩了四个坑才发现:我一开始选的方向,就是重的。
我想要的到底是什么
不是「让 AI 更聪明」,是一件很具体的事:
下次打开这个项目,它就已经知道:技术栈是什么、部署怎么走、
哪些写法是「看起来多余但删了就坏」的、域名卡在哪一步。
这个博客已经有四篇文章和一份很长的 README,但那些是给人看的。我要的是给 AI 看的:能按语义检索,还能在动手之前主动提醒「这里你以前踩过坑」。
第一版方案:云端记忆
我先上的是一个云端记忆插件。它按仓库分库,自动把会话内容抽成「记忆条目」,下次按语义召回。
听起来很顺。然后我在四个坑里各摔了一次。
坑 1:装好了,但没配密钥 —— 读写全部 401
插件装上了,我以为就能用。实际诊断信息是:
1 | api_token_configured: false |
所有调用都返回 401 Authentication failed: API key required。
最要命的是:它连「会话结束时自动留档」也会失败。也就是说,这一整晚的对话一条都存不进去,而界面上没有任何报错 —— 它只是安静地什么都没做。
这正是我这个博客反复出现的那个主题:不报错 ≠ 生效。
坑 2:切到本地守护模式,它又要一个 LLM 密钥
我不想依赖云端账号,就切成了本地守护模式。文档说改个配置就行。
改完之后诊断信息确实变了:
1 | api_url: http://127.0.0.1:9077 ← 切到本地了 |
但调用仍然失败 —— 本地根本没有进程在监听。
去翻插件源码才发现,启动守护进程前要过三道检查:
1 | function preflightDaemon(cfg, harness) { |
「本地」不等于「什么都不用配」。 本地守护进程同样需要一个 LLM 密钥 —— 因为「把对话变成记忆」这个动作本身就要调模型。
装上 uv、配上密钥之后,它接着要别的东西。
坑 3:还要下载两个模型 —— 被代理软件拦了
守护进程起来了,然后卡在读模型上:
1 | ERROR: We couldn't connect to 'https://huggingface.co' to load the files, |
它要下两个模型:BAAI/bge-small-en-v1.5(向量)和 cross-encoder/ms-marco-MiniLM-L-6-v2(重排)。
本机开着 Clash。我做了个对比测试,结论很干净:
| 测试 | 结果 |
|---|---|
系统 Python → hf-mirror.com |
✅ 200 |
系统 Python → huggingface.co |
❌ 502 |
| Node → 云端 API | ✅ 200 |
代理把 huggingface.co 走了代理并替换了证书,Python 的 CA 包不认这张证书。 所以不是网络不通,是证书链对不上 —— 一个很容易误判成「Python 环境坏了」的现象。
坑 4:守护进程不读我注入的环境变量
解决办法本来很简单:让它改用国内镜像(HF_ENDPOINT=https://hf-mirror.com)。我试了两条路:
- 启动时设进程环境变量 —— 无效,它起的是分离进程
- 写进它自己的 profile 配置文件 —— 也无效,实测它不读
所以这个坑我修不了。 要修得去动代理规则(让那个域名走直连,或者把代理的 CA 加进 Python 的信任库),那是另一件事了。
转折:先退回云端
最后我在云端和本地之间选了云端(Node 直连完全可达,一次就通),把攒下来的 8 份知识文档写了进去,然后做了三层验证:
| 验证层 | 方法 | 结果 |
|---|---|---|
| 入库确认 | 拉取文档列表 | 8 份,ID 逐一吻合 |
| 语义检索 | 让它复述这个项目 | 准确说出技术栈、踩过的坑、域名状态 |
| 计数核对 | 数一遍 | 9 个文档 + 1 个会话留档,一个不多不少 |
能用。但我不打算长期用它。
因为它需要:一个云端账号和额度、一个 Python 环境(约 4.7 GB)、两个模型、一个嵌入式 PostgreSQL。
为了存 88 KB 的笔记,这不划算。
换成本地记忆库
后来我换了一个本地记忆插件。它和上面那个的根本区别:
| 云端记忆 | 本地记忆库 | |
|---|---|---|
| 存储位置 | 云端 API | 本机 |
| 需要 LLM | ✅ 需要(抽取事实) | ❌ 不需要 |
| 索引方式 | 服务端异步抽取 | 本地:文档摘要 + 代码符号表 |
| 依赖 | 账号 / Python 环境 / 模型 | 零 |
| 维护成本 | 要管账号和额度 | 零 |
它主要做两件事:
- 索引项目和代码 —— 文档切块存摘要,代码只提符号表(函数/类名 + 行号),全程零 token
- 存「洞察」,并且带触发条件 —— 这条最有意思
最有意思的设计:把注入当成「准入问题」,而不是「检索问题」
大多数记忆系统是检索式的:每一步都找出最相关的那条塞进上下文。
问题是排序是个全函数 —— 永远存在「最相关」,所以噪声是结构性的。用久了你会开始无视它,那这套记忆就白配了。
这个插件反过来:默认沉默,只有「这一步即将跨过我踩过坑的边界」才出声。
我写了 9 条洞察,每条带一个触发条件:
| 洞察 | 什么时候自动提醒 |
|---|---|
| 不报错 ≠ 生效 | 每次提交代码之前 |
| PowerShell 脚本必须纯 ASCII(中文会被按 GBK 解码) | 要写 tools/*.ps1 之前 |
| 改文章前先停 dev server(否则文件被锁) | 提到「改文章」时 |
置顶用 sticky 不是 top |
提到「置顶」时 |
| 部署是 Workers 不是 Pages | 提到「部署」时 |
| 域名委派要查 TLD 注册局(托管商的 DoH 会自己回答自己) | 提到「域名 / DNS」时 |
它不是「我搜到了什么」,而是「你马上要做的事,我拦一下」。
配置时的三个发现
1. 记忆库必须按项目隔离
我的工作目录下并列放着 7 个互不相关的项目 —— 这个博客只是其中之一。
如果直接拿整个工作目录当项目根,7 个项目会混进同一个记忆库,互相污染。
它的根目录解析顺序是:显式指定 → 登记的根 → 最近的 .git / package.json 祖先 → 会话工作目录。
所以正确做法是在项目目录里启动,或者显式指定根。我还在工作区根放了一条「路标」:提到这个博客时,它会告诉模型真正的库在哪。
2. 记忆工具对子代理是硬性禁用的(源码级)
我一开始想省事,让一个子代理去把文档写进记忆。结果 8 份全部失败,报同一句话。
子代理很争气,直接把源码行找出来了:
1 | function workspaceForAgent(agent) { |
它在读取任何内容之前就返回了 —— 所以派子代理去写记忆,必然 0 成功,重试多少次都一样。
3. 构建产物被误索引了
插件有一份内置的忽略名单:node_modules、dist、build、target、coverage……
但它没有 public —— 而 public 正是 Hexo / Hugo / Jekyll 的默认产物目录。
结果 38 个被索引的文件里有 10 个是构建产物的副本(主题 JS 之类)。不影响使用,只是噪音。而且配置里没有「忽略目录」这一项,我自己排不掉。
如果你也在用它,值得给作者提一句:默认忽略名单加上
public。
我又一次验证了那句话
搭这个博客的时候,我总结过 28 个坑,其中大半是同一类:不报错但没生效。
这次折腾记忆,我第一个栽的坑还是它:
插件装好了、界面正常、没有任何报错,我以为它能用了。
实际上它一条都没存进去,连「会话结束时自动留档」都是失败的。
所以这次我坚持了三层验证:入库确认 → 语义检索 → 计数核对。
只跑通第一层(「调用没报错」)是不够的 —— 这个项目里已经栽过太多次了。
现在的效果
给这个博客配好记忆之后:
- 索引了 38 个文件(16 份文档 + 22 个代码符号表)
- 存了 9 条洞察,每条都能在对应场景自动拦一下
- 后台 30 秒轮询,改了文件会静默增量重索引
- 整个库 220 KB,纯本地,零依赖
下次开新会话,它已经知道这个博客的一切。 我不用再从头讲一遍了。
这是建站记录的第 5 篇。前面几篇讲了:不买服务器怎么有博客、Hexo 的 front-matter 和标签插件怎么用、以及这个博客搭起来踩过的 28 个坑。


