#给 AnythingLLM 实现本地文件夹自动同步

背景

AnythingLLM 是一个本地部署的 RAG(检索增强生成)知识库工具,支持将文档上传后进行向量化,然后通过对话的方式检索知识。但它本身不支持监控本地文件夹------每次新增或修改文档都需要手动上传,用起来很不方便。

我的需求很简单:在本地维护一个 Obsidian 笔记文件夹,文件有任何变化时自动同步到 AnythingLLM 的指定工作区,不需要任何手动操作。

方案

基于 watchdog 的实时文件监控守护进程,彻底解决重复上传问题。

核心架构

scss 复制代码
文件系统事件 → 防抖(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 源码后,确认正确的更新流程是:

bash 复制代码
① 从工作区移除旧嵌入(向量数据库)
   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,崩溃自动重启,开机登录后自动启动,不依赖终端。

xml 复制代码
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>

坑:macOS 文件夹访问权限

macOS Catalina 以后,对"文稿"等目录的 FSEvents 监控需要显式授权。进程没有权限时 watchdog 会静默失败------不报错,但完全收不到任何文件事件。

解决方法:在「系统设置 → 隐私与安全性 → 完全磁盘访问」中添加 /usr/bin/python3 或终端 App。

配置说明

ini 复制代码
[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 查询:

bash 复制代码
curl -s http://localhost:3001/api/v1/workspaces \
  -H "Authorization: Bearer 你的API-Key"

返回结果中的 slug 字段即为所需值:

json 复制代码
{
  "workspaces": [
    {
      "name": "我的知识库",
      "slug": "my-kb-a1b2c3",
      "id": 1
    }
  ]
}

效果

  • 保存文件后约 2 秒内自动同步到 AnythingLLM
  • 不再出现重复文档
  • 更新文档后 LLM 能正确检索到新内容
  • 后台常驻,内存占用约 25MB,平时 CPU 占用 0%

依赖

  • Python 3(系统自带)
  • requests:HTTP 请求
  • watchdog:文件系统事件监听
  • sqlite3:Python 标准库自带,无需安装
bash 复制代码
pip3 install requests watchdog
相关推荐
米花丶2 小时前
同样的 while(true),不同的工程深度:Claude Code 源码中的 Agent 设计启示
人工智能·claude
liliangcsdn2 小时前
对基于Pydantic BaseModel的实例进行JSON序列化
人工智能·json·全文检索
TDengine (老段)3 小时前
TDengine IDMP 工业数据建模 —— 元素与数据查询
大数据·数据库·人工智能·物联网·时序数据库·tdengine·涛思数据
志栋智能3 小时前
轻量级部署:低成本实现混合云环境自动化巡检
运维·网络·人工智能·自动化
点云SLAM3 小时前
Qt+PCL手把手教材(第11讲)——PCL库PCLVisualizer点云可视化以及与 VTK 交互器(Interactor)详解和代码示例
人工智能·交互·3d数据可视化·pcl点云库·qt+pcl·pclvisualizer使用·vkt
码与农3 小时前
硬件控制器是如何实现与ros2_control交互的
人工智能·机器人·自动驾驶
搬砖者(视觉算法工程师)3 小时前
世界动作模型(WAM)的泛化能力是否优于视觉语言动作模型(VLA)?
人工智能
AI营销先锋3 小时前
AI营销SaaS榜单评测:原圈科技如何助力品牌客户破局增长?
大数据·人工智能
AI服务老曹3 小时前
GB28181 与 RTSP 深度解析:企业级 AI 视频中台的全协议接入架构
人工智能·架构·音视频