Hister 开源解读:把浏览历史变成可检索的私有搜索引擎

浏览器历史里藏着一个人真正的知识轨迹:上个月读过的 PostgreSQL 迁移锁问题分析、半年前某个 GitHub issue 里的 workaround、上周翻过的某篇部署排障文章。这些页面散落在历史记录和本地文件里,浏览器的搜索框只能按标题和 URL 匹配,正文内容一律搜不到。Hister 是 asciimoo 开源的 Go 项目,把"访问过的页面 + 本地文件"变成一个全文搜索索引,数据留在自己机器上。项目在 2026 年 1 月创建,8 月 18 日登上 Hacker News 首页(267 赞、72 评论),GitHub star 数超过 2100,目前最新版本为 v0.17.0。

asciimoo 这个 ID 背后是 Searx 的原作者。Searx 是隐私友好的元搜索引擎,聚合多个搜索源的结果但不自建索引,这个架构决定了它无法控制结果的相关性排序。Hister 换了一条路线:索引范围收缩到个人视野内的内容,换来对存储、排序和查询语言的完全控制。项目以 AGPLv3 发布,作者在 HN 讨论中明确表示近期不做托管服务,长期方向是联邦化搜索。

它解决什么问题

多数"网页存档"工具的定位是收藏:LinkDing、Karakeep、Linkwarden 这类自托管书签服务要求你手动保存页面,忘了存就丢了。Hister 的浏览器扩展在后台自动工作,访问页面时读取浏览器已加载的 DOM(只看浏览器本身加载的内容,不会向被访问站点发请求,对站点完全透明),把完整正文文本、标题、URL、favicon 和访问时间戳打包发给本地 Hister 服务器。扩展还会定期回访已索引页面,发现内容更新就自动送交新版本,所以搜出来的是内容的最新状态,而非首次访问时的快照。

和书签工具的另一个差异:Hister 已经内置了从 Karakeep、Linkding、Linkwarden、Readeck、Shaarli、wallabag 导入数据的通道,浏览器书签和历史数据库(Chrome 的 History、Firefox 的 places.sqlite)也能直接导入。书签服务负责"主动收藏",Hister 负责"全量捕获 + 正文检索",两者可以叠着用。

四个组件的架构

Hister 由四部分组成:

  • 浏览器扩展(Chrome / Firefox,Firefox Mobile 也支持):采集端,自动索引新访问的页面;
  • 索引器:接收页面数据,做去重、相关度排序准备、别名展开;
  • Web 应用:搜索界面,支持实时搜索、自动补全、快捷键(/ 聚焦搜索框,Alt+j/k 移动结果,Alt+o 把当前查询转发给 DuckDuckGo 等外部搜索引擎);
  • 命令行工具:导入历史、爬取文档站、手动索引 URL、管理配置。

部署只需要下载对应平台的二进制文件,执行 hister listen,服务默认监听 127.0.0.1:4433,只接受本机连接,无需任何配置。自托管到服务器时支持 token、密码和 OIDC/Keycloak 认证,多用户模式下每个用户的索引数据相互隔离。

查询语言:按字段精确检索

Hister 的查询语法在全文检索之上叠了一层字段过滤器,支持的字段包括 title:text:url:domain:label:language:type:(web / file / local)、visits:(访问次数,支持 visits:10.. 区间)、added:updated:(相对时长 updated:>90d 或绝对日期 updated:>=2026-04-01)。几种用法组合起来:

text
title:encryption "end-to-end" domain:(signal.org|whatsapp.com) -deprecated

这条查询匹配标题含 encryption、正文含精确短语 "end-to-end"、来自 signal.org 或 whatsapp.com、且不含 deprecated 的页面。括号加竖线构成 OR 条件,减号做排除,星号做通配(secur* 匹配 security、secure、securing)。sort:datesort:visitssort:domain 指令控制排序,加负号反向。文档类型上,type:file 覆盖本地文件,url:/home/user/report.pdf 这样的裸路径会自动解析为 file:// URL。

检索之外还有两个提升召回率的设计。关键词别名把 "go" 自动扩展为 "go + golang",一次查询覆盖两种写法。优先结果机制会学习"某类查询你总是点开哪个页面",下次同样搜索时置顶展示,也可以手动把任意结果固定到指定查询词的首位——常翻的官方文档适合这样处理。

MCP:给 AI 助手接上私有记忆

Hister 在 /mcp 端点暴露 Model Context Protocol 接口(Streamable HTTP 传输),AI 助手连接后可以调用三个工具:

  • search:按查询语言检索,支持 limit(上限 50)、date_from/date_to 日期范围、semantic 布尔参数(服务端配置了 embeddings 端点时启用语义检索,未配置则自动回退关键词匹配);
  • get_preview:按精确 URL 取回存储的完整正文和渲染 HTML,适合"页面后来改了 / 删了 / 要登录 / 反爬"的场景,助手直接读你索引时的版本;
  • get_history:查看最近索引的页面或最近打开的结果。

这个设计的价值在于收敛授权面:不用给助手逐个配置 GitHub、内部 wiki、文档站、论坛的 API 凭据,凡是进过你索引的页面,助手统一走 Hister 一个搜索接口。官方博客给出的典型工作流包括"从我读过的文章里找 PostgreSQL 迁移锁的那篇并总结"、"把最近一个月关于供应链攻击的阅读整理成带引用的简报"、"按今天的浏览记录生成工作日志草稿"。

安全边界处理得比较认真。索引页面属于不可信输入,恶意页面可以埋针对助手的提示注入指令。Hister 的 MCP 响应把源数据放在 structuredContent.untrusted_content 下,每条记录标注 trust: "untrusted",剥离不可见控制字符,HTML 只在显式请求时返回且始终留在不可信结构内。文档同时明确:如果连接的是外部 AI 提供商驱动的助手,搜索结果和预览会作为对话上下文送出,注重隐私就换本地模型,或者用 skip 规则让敏感页面根本不进索引。

索引层:Bleve 的工程实践

Hister 的全文检索建立在 Go 库 Bleve 之上——文件式索引,官方称可处理百万级记录,支持并发读写、索引热交换和匹配高亮。项目博客专门写过一篇 Bleve 实践总结,几个细节值得参考:

  • 字段加权:查询构造时 URL 通配匹配 boost 10,标题匹配 boost 50,正文常规匹配。命中标题是强相关信号,权重远高于正文出现;
  • 游标分页:弃用 From 偏移分页。偏移量分页要求每次对 From + Size 范围内的全部匹配文档评分排序,深翻页时 CPU 和内存开销线性上涨,而且两次请求之间有新文档写入时结果会错位。改用 SearchAfter 游标(按 _score, _id 稳定排序),从上一页最后一条的排序键续读,既快又稳;
  • 多语言索引别名:每种语言一个独立索引(各自的语言分析器、停用词、词干化),IndexAlias 把多个索引挂在一个虚拟入口下,查询扇出到所有索引后合并排序。重建索引时在后台建新索引,用 alias.Swap() 原子切换,进行中的查询跑完旧索引,新查询立即走新索引,零停机;
  • Scorch 调优:持久化 worker 数、每 worker 内存上限、段合并阈值这些参数通过 OpenUsing 的 config map 传入,应对高并发写入。

整个项目约 170 万行 Go 代码(另有 53 万行 Svelte 构成 Web 前端),单二进制交付,没有外部服务依赖。

存储与隐私

默认配置零遥测、零云同步。浏览器扩展除了下载 favicon 外不访问任何网络,页面内容只发给你自己配置的 Hister 服务器。存储上,每个已索引文档平均约 100KB,主要成本来自为离线预览保留的完整原始 HTML;对存储敏感可以关掉离线预览,平均体积会显著下降。按重度浏览五年估算索引规模是可行的,备份则只需复制 ~/.config/hister/ 一个目录。

不进索引的部分同样明确:不存密码、表单数据、Cookie、会话令牌、视频和大文件下载,页面图片只留 favicon。规则页支持按域名和 URL 模式排除(银行、后台、账号设置页),已误索引的内容用 hister delete URL 立即清除。索引器自动跳过 PDF、视频和下载类内容,专注可检索的文本。

适用边界

HN 讨论里有人问"30GB 邮件归档能不能用它建索引",作者的回答没有回避:Bleve 处理百万记录没问题,但这个场景他更推荐 Meilisearch,且 Hister 目前不支持 mbox。它解决的问题限定在"你看过、你拥有、需要按正文找回"的内容范围内。Safari 扩展尚在 PR 阶段(作者没有 macOS 开发环境,正在征集协作者),iOS 上没有自动捕获方案;Android 的自动捕获依赖 Firefox 移动版(Chromium 内核的移动 Chrome 不支持扩展)。移动端多设备同步的官方答案是家庭服务器部署 + 各设备访问同一实例。

动手部署

macOS / Linux 下载 release 二进制后三步跑起来:

bash
chmod +x hister
./hister listen
# 浏览器打开 http://127.0.0.1:4433,安装扩展

导入既有浏览器历史:

bash
hister import browser chrome ~/.config/google-chrome/Default/History
hister import browser firefox ~/.mozilla/firefox/<profile>/places.sqlite

爬一个文档站进索引,供 AI 助手检索:

bash
hister index --recursive \
  --allowed-domain=docs.example.com \
  --max-depth=4 \
  https://docs.example.com/

给 Claude Desktop 或 Cursor 接上 MCP 端点,配置文件里加一项:

json
{
  "mcpServers": {
    "hister": {
      "url": "http://127.0.0.1:4433/mcp",
      "headers": { "Authorization": "Bearer <your-access-token>" }
    }
  }
}

Go 1.26 + npm + C 编译器齐备时也可以从源码构建(./manage.sh build),前端开发用 npm run serve:app 起 Vite 热更新。项目 IRC 频道 #hister(IRCNet)和 Discord 社区活跃,issue 跟踪器接受功能建议。

Hister 网页界面:搜索结果与文档详情

一句判断:如果你曾被"我记得读过但找不回来"折磨过,或者想让 AI 助手基于你真实读过的内容回答问题而不想交出每个站点的凭据,Hister 值得花十分钟部署试试。