在上一篇博客中,我们分享了如何通过 OAuth2Graph API 彻底穿透海内外主流邮箱的风控屏障,安全地将账单、通知邮件拉入 AI 代理的本地存储中。

但随着数据滚雪球般增长——不仅有每天抓取的各类账单邮件,还有从 MongoDB 数据库中持续沉淀的 27 万篇 RSS 互联网资讯,一个棘手的问题浮出水面:

“如何在一瞬间找到我上个月的外币信用卡账单,或者检索出某篇被淹没的 AI 技术资讯?”
并且,如何安全、优雅地把指令发送给机器人执行,并实时看到机器人的输出?

为此,我们再次对架构进行了升级,在 lite_agent 中深度集成了开源轻量级搜索引擎 Meilisearch,并手搓了一个极致美学的零构建暗黑玻璃态(Dark Glassmorphism)检索与中枢控制台

本文将向大家盘点本次架构打通的硬核技术细节:数据增量同步、双层安全网关、Nginx 极窄只读注入、以及 SSE 流式任务终端的构建


🏗️ 整体架构设计

在个人数据的检索上,我们坚决反对“粗暴的暴露”。整个中枢控制台的调用与防线可以用如下架构图表示:

 用户 (浏览器) ──( HTTPS + Basic Auth )──> [ Nginx 网关 ]
                                            │
               ┌────────────────────────────┴───────────────────────────┐
               ▼ (只读 Search Key 注入)                                ▼ (API Token 注入)
       /meili/* ──> [ Meilisearch ]                                   /agent/* ──> [ Lite Agent API ]
      (只读全文检索与数据量统计)                                          (流式命令执行 & SSE 日志流)

⚡ 性能调优:增量同步与大包分批(Payload Batching)

我们的数据分散在 SQLite(邮件)和 MongoDB(RSS 资讯)中。要将它们同步给 Meilisearch,我们需要解决性能与稳定性的双重问题。

1. SQLite + MongoDB 增量状态同步

我们开发了独立的同步技能 ops_meili_sync。为了防范反复扫信导致的 CPU 飙升与网络带宽浪费,我们设计了基于 meili_sync_state.json 的增量同步机制:

  • 对于 SQLite,通过主键 uid + fetched_at 时间戳增量拉取新邮件,并进行 category(分类)和 sender(发件人)的多表联合查询(JOIN)同步。
  • 对于 MongoDB,由于采用了按月归档集合的设计(例如 FeedItem_202607),同步程序自动计算当前月和上个月的动态集合,并利用 ObjectId 递增比对过滤,实现无感知的增量抓取。
  • 定时任务集成:我们在 Agent 的 Cron 引擎中注册了定时器,每 10 分钟自动在后台拉取更新,实现数据源的源源不断。

2. 避免“413 Payload Too Large”:数据分批设计

在第一次进行 27 万条 RSS 历史文章全量同步时,最初由于将全部数据打包在一个 HTTP POST 中发送,直接触发了 Meilisearch 的单次负载限制,返回了 413 Payload Too Large
我们迅速将同步策略重构为 200 篇分批并发推送(Batching)

# 核心分批逻辑
batch_size = 200
for i in range(0, len(docs), batch_size):
    batch = docs[i : i + batch_size]
    res = _meili_request("/indexes/rss/documents", "POST", batch)
    if res:
        rss_count += len(batch)
        state["last_rss_sync"] = batch[-1]["fetched_at"]

这样不仅极其省内存,在遇到网络波动时还能实现“断点续传”。


🔒 网关安全:Nginx 极窄权限注入模型

把搜索引擎和 Agent API 暴露给前端静态网页,最大的安全隐患莫过于 Master Key 泄露。一旦主密钥暴露在前端 JavaScript 中,任何恶意访客都能直接删光你的整个索引库。

为了杜绝这一隐患,我们设计了三重网关防线

防线 1:全站 Basic Auth

整个虚拟主机部署在 mail.maifeipin.com 下,由 Nginx 的 auth_basic 在最外层直接拦截,未授权用户甚至无法加载页面的一张图片、一个 JS 字节。

防线 2:只读 API 密钥注入

在配置 Meilisearch 代理时,Nginx 在反向代理层隐式将只读的 Search Key 注入到 Request Header 中。前端 JavaScript 甚至感知不到 Key 的存在,从而彻底阻断了密钥通过前端泄露的可能性:

location /meili/ {
    proxy_pass http://127.0.0.1:7700/;
    # 代理层注入 Meilisearch 只读 Search Key,前端完全无感
    proxy_set_header Authorization "Bearer f404afbf2e397f28...d1da8dd62f011b9d";
}

防线 3:极窄 stats 权限通道 (Master Key 动态提权)

只读 Key 固然安全,但它只能调用 /search 检索接口,无权调用 /stats 统计接口。这会导致页面左侧的数据源数量无法显示真实总量(空查询时只能拿到 /search 的 1000 条默认上限估算)。
为此,我们设计了一条极其精细的极窄 stats 提权通道

# 仅当访问 stats 统计接口时,才在 Nginx 内部用 Master Key 进行提权转发
location ~ ^/meili/indexes/([^/]+)/stats$ {
    proxy_pass http://127.0.0.1:7700/indexes/$1/stats;
    proxy_set_header Authorization "Bearer MeiliUnifiedSearchSecureKey...Awesome";
}

由于 /stats 是只读元数据接口,不涉及任何文档详情,也不支持写入/删除,这样的定向注入实现了“既能显示真实总数,又防范了任何越权操作”的精美平衡。


💻 前端极致体验:零构建 SPA 与 SSE 长连接控制台

在前端呈现上,我们坚持不引入任何构建工具(如 Vite, Next.js),用原生的 HTML, CSS 和 JS 实现了一个零依赖的单页应用(SPA)。

1. Spotlight 式智能命令面板 (Command Palette)

在网页中敲击 /(斜杠)即可呼出 Spotlight 命令弹窗。我们设计了按键 autocomplete 状态填充联动

  • 键盘上下方向键导航时,当前项的命令(如 /ops_backup_data/reprocess)会自动实时填充并同步进输入框,支持就地进行参数编辑(如 /reprocess uid=120)再敲击回车。
  • 鼠标悬停(mouseenter)自动跟随机键盘高亮焦点,体验如丝般顺滑。

2. 拟物化终端与 SSE 实时日志流

当你通过命令面板发送异步任务(如数据云备份)时,网页右下角会自动弹出一个拟物化设计的黑色 Console 控制台:

  • 前端通过监听 Agent 的 /api/v1/tasks/{task_id}/stream,建立起持久的 SSE (Server-Sent Events) 连接
  • 后台执行的日志通过 SSE 实时在终端里逐行打出,仿佛直接在服务器上跑 Shell 脚本一样亲切。
  • 为了确保流式输出零延迟,我们在 Nginx 代理上配置了 proxy_buffering off,防止响应被 Nginx 缓冲区拦截造成卡顿。

🔮 后续规划:更庞大的个人知识网

邮件和 RSS 仅仅是个人信息数字孤岛的第一步。接下来,我们计划继续扩大 Meilisearch 与 AI Agent 的索引版图:

  1. HedgeDoc 与云笔记互通(搭建个人知识库)
    • 我们计划打通 HedgeDoc(Markdown 协作文档)与私有云笔记系统。通过 Webhook 实时捕获文档的创建与修改,自动将其推送到 Meilisearch 建立索引。
    • 挂载 LLM 对半结构化的 MD 笔记进行实体提取语义标签化,让你能够一键搜索所有关于“架构设计”或“会议纪要”的碎片化记忆。
  2. NAS 本地媒体库与智能检索
    • 接入家中 NAS 媒体服务(如 Emby/Jellyfin/Plex)的元数据,甚至是照片库的 EXIF 属性。
    • 届时,你只需在微信端输入“帮我找找去年秋天拍的猫咪照片”或“检索所有 4K 分辨率的科幻电影”,Agent 就能瞬间定位本地文件,完成智能多模态调度。

🚀 结语

通过将 Meilisearch 的全文检索Lite Agent 的指令下发 熔铸于一体,我们不再只是拥有一堆冷冰冰的数据库,而是真正搭建了一个随身携带、绝对安全的数据和命令检索中枢。

如果您也想摆脱杂乱无章的账单与信息孤岛,不妨试试把搜索引擎挂载到你的 AI Agent 上!

Enjoy hacking with Meilisearch, Agent & Nginx!

image-1783855268171