背景
AnythingLLM 是一个本地部署的 RAG(检索增强生成)知识库工具,支持将文档上传后进行向量化,然后通过对话的方式检索知识。但它本身不支持监控本地文件夹——每次新增或修改文档都需要手动上传,用起来很不方便。
我的需求很简单:在本地维护一个 Obsidian 笔记文件夹,文件有任何变化时自动同步到 AnythingLLM 的指定工作区,不需要任何手动操作。
方案
基于 watchdog 的实时文件监控守护进程,彻底解决重复上传问题。
核心架构
文件系统事件 → 防抖(2s) → MD5 对比(SQLite) → 清理旧向量 → 上传新文件 → 更新 SQLite
↑
启动时追赶扫描(处理离线期间的变更)
关键设计决策
1. watchdog 替代轮询
watchdog 是一个 Python 库,封装了 macOS 的 FSEvents / Linux 的 inotify API,让操作系统内核在文件变化时主动推送事件,不需要周期性扫描。进程绝大多数时间在睡眠,CPU 和 I/O 开销近乎为零。
2. SQLite 替代 JSON 状态文件
存储结构:(rel_path TEXT PK, hash TEXT, mtime REAL, doc_name TEXT, doc_location TEXT)
SQLite 的原子事务保证了进程崩溃时状态不会损坏。上传成功后记录 AnythingLLM 返回的 doc_location,下次更新时用它精确删除旧版本,不再依赖模糊的文件名匹配。
3. 2 秒防抖
Obsidian 等编辑器保存文件时会触发多次写入事件,防抖机制将其合并,只处理最后一次。
4. 正确的 API 调用链
研究了 AnythingLLM 源码后,确认正确的更新流程是:
① 从工作区移除旧嵌入(向量数据库)
POST /api/v1/workspace/:slug/update-embeddings
{ "deletes": ["custom-documents/xxx.json"] }
② 删除旧文档文件
DELETE /api/v1/system/remove-documents
{ "names": ["custom-documents/xxx.json"] }
③ 上传新文件并自动嵌入到工作区
POST /api/v1/document/upload
multipart: file + addToWorkspaces=slug
步骤 ① 是关键——不清除旧向量的话,LLM 检索到的仍然是旧内容。
5. 启动追赶扫描
守护进程启动时对比本地文件和 SQLite 记录,处理离线期间的所有变更,保证即使进程临时停止,重启后也不会漏掉任何变化。
6. LaunchAgent 守护进程
macOS 用 KeepAlive: true 的 LaunchAgent,崩溃自动重启,开机登录后自动启动,不依赖终端。
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
坑:macOS 文件夹访问权限
macOS Catalina 以后,对"文稿"等目录的 FSEvents 监控需要显式授权。进程没有权限时 watchdog 会静默失败——不报错,但完全收不到任何文件事件。
解决方法:在「系统设置 → 隐私与安全性 → 完全磁盘访问」中添加 /usr/bin/python3 或终端 App。
配置说明
[anythingllm]
base_url = http://localhost:3001 # AnythingLLM 服务地址
api_key = ... # API 密钥
workspace_slug = ... # 目标工作区标识
[sync]
watch_folder = /path/to/folder # 监控的本地文件夹(绝对路径)
delete_removed = false # 本地删除文件后是否同步删除远程文档
api_key 获取方式
在 AnythingLLM 界面:设置 → 工具 → 开发者 API → 生成新的 API 密钥
workspace_slug 获取方式
workspace_slug 不是工作区名称,需要通过 API 查询:
curl -s http://localhost:3001/api/v1/workspaces \
-H "Authorization: Bearer 你的API-Key"
返回结果中的 slug 字段即为所需值:
{
"workspaces": [
{
"name": "我的知识库",
"slug": "my-kb-a1b2c3",
"id": 1
}
]
}
效果
- 保存文件后约 2 秒内自动同步到 AnythingLLM
- 不再出现重复文档
- 更新文档后 LLM 能正确检索到新内容
- 后台常驻,内存占用约 25MB,平时 CPU 占用 0%
依赖
- Python 3(系统自带)
requests:HTTP 请求watchdog:文件系统事件监听sqlite3:Python 标准库自带,无需安装
pip3 install requests watchdog