news 2026/10/20 8:46:26

本地优先的AI资讯浏览器插件:用轻量级模型实现智能筛选与摘要

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
本地优先的AI资讯浏览器插件:用轻量级模型实现智能筛选与摘要

1. 信息过载时代的自救:为什么我要做这个插件

每天早上睁眼第一件事,打开手机,十几个科技媒体的推送已经堆满了通知栏。某某模型发布了新版本,某某公司开源了新的框架,某某研究团队发了篇重磅论文,某某工具又更新了功能。你一条条点开看,看完发现真正跟自己相关的可能只有两三条,剩下的全是噪音。更让人头疼的是,这些信息里大部分是英文的,或者翻译腔浓重的中文,读起来费劲不说,还经常看完才发现是半个月前的旧闻。

我做这个浏览器插件的出发点特别简单:我不想再被信息牵着鼻子走,我要让信息来找我,而且只找我关心的那部分。这个插件叫「中文AI情报站」,名字听着挺大,其实核心逻辑就一句话——在浏览器里安静地待着,自动从你常看的几个信息源里抓取内容,用本地跑的轻量级模型做筛选和摘要,最后把真正值得看的中文AI资讯推到你面前。整个过程数据不出本地,不需要注册账号,不需要联网调用第三方API,装完就能用。

你可能会问,市面上不是已经有很多RSS阅读器、资讯聚合工具了吗?没错,但那些工具的问题在于:第一,它们大多需要你把内容源手动配置进去,配置过程本身就够折腾半小时;第二,它们没有智能筛选能力,你订阅了十个源,它就给你推十个源的全部内容,信息过载的问题一点没解决;第三,很多工具是云端处理的,你的阅读偏好、浏览记录全在别人的服务器上。我这个插件就是冲着这三个痛点去的——自动发现内容源、本地智能筛选、数据完全留在自己电脑里。

适合谁来用呢?如果你是AI领域的产品经理、开发者、研究者,或者只是对AI动态保持关注的普通从业者,每天需要花半小时以上浏览各种资讯但总觉得效率不高,那这个插件就是给你准备的。它不追求大而全,不做什么社交功能,就是一个纯粹的、安静的、本地的信息过滤器。接下来我会从设计思路、核心实现、踩坑记录、优化技巧几个方面,把这个插件从零到一的过程完整拆开讲一遍。

2. 插件架构设计:本地优先到底意味着什么

2.1 为什么坚持本地优先而不是云端处理

做这个插件之前,我试过用现成的云端资讯聚合服务。把几个常看的网站加到收藏夹,每天手动刷一遍,后来用IFTTT之类的工具做自动化,再后来尝试了一些带AI摘要功能的在线服务。用下来的感受是:云端服务确实方便,但代价是隐私和可控性。你的阅读习惯、点击行为、停留时长,这些数据一旦上传,你就不知道它们会被用来做什么。而且很多服务免费额度用完之后,要么收费,要么降级到几乎不可用的状态。

本地优先的设计意味着所有数据处理都在你的浏览器里完成。抓取的内容存在IndexedDB里,筛选和摘要用的模型是量化后的小模型,通过WebAssembly在浏览器里跑。这样做的好处很明显:没有网络请求发往第三方服务器,没有账号体系,没有使用时长限制。代价是模型能力比云端大模型弱一些,但对于“筛选+摘要”这个任务来说,一个几百MB的量化模型已经足够用了。

具体来说,我选的是ONNX Runtime Web作为推理引擎,模型用的是经过蒸馏和量化的中文文本分类模型,参数量控制在100M以内,量化到INT8之后模型文件大概40MB左右。这个体积对于浏览器插件来说是可以接受的,首次加载会花几秒钟,之后缓存在本地,后续使用几乎无感。

2.2 插件的三大核心模块拆解

整个插件我分成了三个相对独立的模块,每个模块各司其职,通过消息传递机制通信。

第一个模块是内容采集器。它负责从用户配置的信息源里抓取内容。这里我没有用传统的爬虫思路,而是利用了浏览器插件的内容脚本能力。当用户打开一个支持的网站时,内容脚本会自动注入,提取页面上的文章标题、链接、发布时间、正文摘要等结构化信息。这样做的好处是不需要维护复杂的爬虫规则,网站改版了也不容易失效,因为提取逻辑是基于DOM结构的通用启发式规则,而不是写死的CSS选择器。

第二个模块是本地推理引擎。它接收采集器传来的文本,先做一轮粗筛,把明显不相关的内容过滤掉,比如标题里带“招聘”“广告”“活动报名”这类关键词的直接丢弃。然后对剩下的内容做细粒度的相关性打分,这个打分是基于用户的历史点击行为和显式反馈(点赞/忽略)来动态调整的。最后对高分内容生成一段简短的中文摘要,方便用户快速判断要不要点开看全文。

第三个模块是展示层。我把它做成了浏览器侧边栏的形式,点击插件图标就能滑出来。侧边栏里按时间倒序排列筛选后的资讯,每条显示标题、来源、摘要和相关性评分。用户可以直接在侧边栏里标记“已读”“忽略”或者“稍后读”,这些反馈会实时更新到本地模型里,让筛选越来越准。

2.3 数据流与存储方案的选择

数据流的设计上,我遵循一个原则:能本地算的绝不发网络请求,能增量更新的绝不重新计算。采集器抓到的原始内容先存到IndexedDB的raw_items表里,推理引擎处理后的结果存到processed_items表,用户的反馈记录存到feedback表。三个表通过item_id关联,查询的时候用索引加速。

存储方案上我对比过几种选择。localStorage容量太小,只有5MB左右,存几百条资讯就满了。IndexedDB容量大得多,而且支持索引和事务,适合这种结构化数据的存储。唯一需要注意的是IndexedDB的异步API用起来比较繁琐,我封装了一层Promise化的工具函数,用起来跟localStorage差不多方便。

这里有个细节值得提一下:IndexedDB在不同浏览器里的实现有差异,尤其是Safari的隐私模式下,IndexedDB的写入可能会被限制。我的处理方式是检测到写入失败时自动降级到内存存储,并提示用户当前处于隐私模式,数据不会持久化。

3. 内容采集器的实现细节与避坑

3.1 内容脚本注入时机的选择

内容脚本的注入时机看起来是个小问题,实际做的时候踩了不少坑。最开始我用的是document_idle,也就是页面加载完成后注入。这个时机对于大多数静态页面没问题,但对于那些用前端框架渲染的网站,document_idle触发的时候页面内容可能还没渲染出来,提取到的就是空数据。

后来我改成了document_end,配合MutationObserver监听DOM变化。具体做法是:页面DOM结构稳定后先提取一次,然后启动一个观察器,如果检测到主要内容区域有新增节点,延迟500毫秒再提取一次。这样既能覆盖静态页面,也能覆盖动态渲染的页面。延迟500毫秒是为了避免频繁触发提取,给页面渲染留出缓冲时间。

还有一个特殊情况是无限滚动的页面。用户往下滚,新内容不断加载。我的处理是在侧边栏里加了一个“手动刷新”按钮,用户滚动到一定程度后可以点一下,触发一次全量提取。自动监听滚动事件的话性能开销太大,而且容易误判。

3.2 结构化信息提取的通用策略

提取文章信息的时候,我没有针对每个网站写专门的规则,而是用了一套通用的启发式策略。核心思路是:找到页面上最像“文章列表”的那个容器,然后从里面提取条目。

具体步骤是这样的:先遍历页面上所有的article、section、div元素,计算每个元素的“文章密度”——也就是它包含的链接数量、文本长度、标题类元素(h1-h6)的数量。密度最高的那个元素大概率就是文章列表容器。然后在容器内部,把每个直接子元素当作一个候选条目,从中提取标题(找最长的文本节点或者h标签)、链接(找第一个a标签的href)、时间(找包含日期格式文本的节点)。

这套策略在大多数新闻站和博客上都能工作,准确率大概在八成左右。剩下的两成主要是那些结构特别奇葩的网站,或者把文章列表放在iframe里的网站。对于iframe的情况,我暂时没有处理,因为跨域限制太多,投入产出比不高。

3.3 去重与增量更新的工程实现

去重是个看似简单实则麻烦的问题。最简单的去重是用URL做唯一标识,但实际中同一个内容可能有多个URL(带不同的追踪参数),或者URL变了但内容没变。我的方案是URL规范化+内容指纹双重去重。

URL规范化就是把查询参数里的追踪参数(utm_*、ref、source之类的)去掉,只保留路径和必要的参数。内容指纹是对标题+正文前200字做SimHash,得到一个64位的指纹。存储的时候两个都存,查询的时候先按规范化URL查,查不到再按SimHash的汉明距离查(距离小于3认为是重复)。

增量更新方面,每次提取的时候只处理发布时间在最近72小时内的条目,更早的默认忽略。这个时间窗口可以在设置里调整,但我不建议设得太长,因为本地模型的推理速度有限,一次处理太多内容会卡顿。

去重策略优点缺点适用场景
URL精确匹配实现简单,速度快无法处理URL变化内容源稳定的场景
URL规范化匹配能过滤追踪参数规则需要维护大多数新闻网站
SimHash指纹能识别内容重复计算开销稍大多来源聚合场景
混合策略准确率高实现复杂度高本插件的选择

4. 本地推理引擎:小模型也能干好筛选的活

4.1 模型选型:为什么不用大模型

一开始我想过用云端的大模型API来做摘要和筛选,效果肯定好,但问题也很明显:一是要花钱,二是要联网,三是隐私没保障。后来转向本地模型,又面临选择:是用规则引擎还是用机器学习模型?

纯规则引擎我试过,写了几十条规则,比如标题包含“发布”“开源”“突破”就加分,包含“招聘”“活动”就减分。效果怎么说呢,刚开始还行,但规则越加越多,维护成本越来越高,而且规则之间经常打架。比如“某公司发布招聘广告”这条,按“发布”加分,按“招聘”减分,最后得分取决于哪个规则权重高,调起来很痛苦。

后来决定用机器学习模型。选型的时候考虑了几个因素:模型大小要控制在50MB以内,推理速度要在100毫秒以内,中文支持要好。最终选了一个基于BERT架构蒸馏出来的小模型,6层Transformer,隐藏层维度256,参数量大概30M。量化到INT8之后模型文件35MB左右,在浏览器里用ONNX Runtime Web跑,单条推理时间大概50到80毫秒,完全可以接受。

4.2 训练数据的构造与标注策略

模型要能筛选出用户关心的内容,就得有训练数据。我没有现成的标注数据,只能自己造。方法是:用规则引擎先跑一遍,把结果分成“高相关”“中相关”“低相关”三档,然后人工抽查修正。修正后的数据用来训练模型,模型跑出来的结果再人工抽查,再修正,迭代了几轮之后模型效果就上来了。

标注的时候我定义了四个维度:主题相关性(是否跟AI相关)、时效性(是否近期内容)、信息密度(是否有实质内容而非标题党)、来源可信度(来源是否权威)。每个维度打1到5分,加权求和得到最终的相关性分数。权重是主题0.4、时效0.2、信息密度0.3、来源0.1,这个权重是根据我自己的阅读偏好调的,用户可以在设置里改。

训练数据量大概5000条左右,覆盖了新闻、博客、论文摘要、产品发布等不同类型的内容。训练是在本地用PyTorch跑的,跑完之后导出ONNX格式,再用ONNX Runtime的量化工具转成INT8。整个流程跑下来大概半天时间,不算太折腾。

4.3 推理性能优化的几个关键手段

在浏览器里跑模型,性能是绕不开的问题。我做了几件事来优化:

第一是模型量化。FP32转INT8之后,模型体积缩小到四分之一,推理速度提升大概两倍,精度损失在可接受范围内(准确率下降不到2%)。

第二是批处理。单条推理的时候,每次都要做一遍预处理和后处理,开销不小。改成批处理之后,一次处理16条,预处理和后处理的开销被摊薄了,整体吞吐量提升明显。

第三是缓存。同样的文本内容,如果之前已经推理过,直接把结果从缓存里取出来,不用重新跑模型。缓存用LRU策略,最多存1000条,超出之后淘汰最久未使用的。

第四是Web Worker。推理放在Web Worker里跑,不阻塞主线程。这样即使用户在浏览网页,侧边栏的更新也不会导致页面卡顿。

实测数据:在2020款的中端笔记本上,批处理16条内容的推理时间大概1.2秒,平均每条75毫秒。如果开启缓存,重复内容的处理时间几乎为零。

5. 侧边栏交互设计与用户反馈闭环

5.1 侧边栏的布局与信息层级

侧边栏的宽度我设的是360像素,这个宽度在大多数屏幕上不会遮挡主要内容,同时又能显示足够的信息。布局上分三层:顶部是筛选栏,中间是资讯列表,底部是状态栏。

筛选栏放了几个快捷按钮:“全部”“未读”“稍后读”“已忽略”,点击切换列表的过滤条件。还有一个搜索框,支持按关键词过滤。搜索是在本地做的,对标题和摘要做全文匹配,速度很快。

资讯列表是核心区域。每条资讯显示标题(最多两行,超出省略)、来源域名、发布时间(相对时间,比如“3小时前”)、摘要(最多三行)、相关性评分(用颜色条表示,绿色高分、黄色中等、灰色低分)。点击标题在新标签页打开原文,点击评分条可以手动调整评分,点击右侧的菜单图标可以标记已读、稍后读或忽略。

底部状态栏显示当前列表的统计信息,比如“共128条,未读23条,今日新增15条”。还有一个刷新按钮,手动触发一次内容采集。

5.2 用户反馈如何驱动模型迭代

用户反馈是这个插件能越用越准的关键。我设计了三种反馈方式:

显式反馈:用户点击“有用”或“没用”按钮,直接告诉插件这条内容是否符合预期。这个信号最强,权重最高。

隐式反馈:用户点击标题打开原文,说明对这条内容感兴趣,算正向信号。用户快速划过(在列表里停留时间少于1秒就滚走),算负向信号。

修正反馈:用户手动调整相关性评分,比如把系统判为低分的内容手动调高,或者反过来。这个信号用来纠正模型的偏差。

这些反馈数据存在本地的feedback表里,每次模型推理之前,会先用最近100条反馈数据对模型做一次轻量级的微调(其实就是调整输出层的偏置项),让模型适应用户的最新偏好。这个微调过程很快,大概几十毫秒,用户无感知。

5.3 避免信息茧房的几个设计考量

做推荐系统很容易陷入信息茧房——用户越喜欢看什么,系统就越推什么,最后视野越来越窄。我在设计的时候特意做了几个反茧房的机制:

一是多样性约束。每次展示的列表里,同一个来源的内容不超过3条,同一个主题标签的内容不超过5条。这样即使用户对某个话题特别感兴趣,也不会被单一话题淹没。

二是随机探索。列表里会随机插入1到2条相关性评分中等但主题跟用户历史偏好差异较大的内容,给用户一个“尝鲜”的机会。如果用户点击了,说明对这个新方向有兴趣,后续会逐步增加这类内容的权重。

三是来源轮换。如果用户配置了多个信息源,系统会尽量均匀地从各个来源抽取内容,而不是只推某个高产出的来源。

这些机制在代码里就是几行过滤逻辑,但效果很明显。我自己的使用体验是,用了两周之后,列表里的内容既有我关心的老话题,也会时不时出现一些我没想到但确实有意思的新方向。

6. 开发过程中踩过的坑与解决方案

6.1 跨域请求被拦截的绕行方案

内容脚本注入到目标页面之后,如果要抓取页面上的内容,直接读DOM是没问题的。但如果要发网络请求去获取更多数据(比如调用某个API获取评论数),就会遇到跨域限制。浏览器的同源策略不允许内容脚本向非当前域名的地址发请求。

我的解决方案是把网络请求的逻辑放到background脚本里。Background脚本运行在插件的上下文中,不受页面同源策略的限制,可以自由发起跨域请求。内容脚本通过chrome.runtime.sendMessage把请求参数发给background,background发请求拿到数据后再传回来。这个绕行方案是浏览器插件开发的标准做法,但第一次做的时候确实卡了我半天。

还有一个细节:Manifest V3之后,background脚本从持久化后台页变成了Service Worker,生命周期由浏览器管理,不保证一直存活。所以不能把状态存在background的全局变量里,得存到chrome.storage里。这个变化导致我重构了一部分代码,把状态管理从内存迁移到了storage。

6.2 模型加载失败的降级处理

本地模型加载失败的情况比我想象中要多。有的是因为浏览器不支持WebAssembly的某些特性,有的是因为模型文件下载不完整,有的是因为内存不足导致加载中断。最开始我没做错误处理,模型加载失败之后整个插件就卡在加载界面,用户完全不知道发生了什么。

后来我加了一套降级机制:模型加载失败时,自动切换到规则引擎模式。规则引擎虽然不如模型准,但至少能用。同时在侧边栏顶部显示一个提示条,告诉用户当前处于“基础模式”,并提供一个“重试加载模型”的按钮。如果用户点击重试,就重新走一遍加载流程。

规则引擎的规则我精简到了20条左右,覆盖最常见的加分项和减分项。虽然粗糙,但作为降级方案够用了。实测下来,模型加载成功率在95%以上,降级模式很少被触发。

6.3 内存占用过高的排查过程

开发到中期的时候,我发现插件用久了之后浏览器会变得很卡。打开任务管理器一看,插件的内存占用飙到了800MB以上。这个肯定不正常,一个资讯聚合插件不应该吃这么多内存。

排查过程是这样的:先用Chrome的开发者工具抓了一份内存快照,发现IndexedDB的缓存对象占了大头。原来是我在查询数据的时候,习惯性地把整个表的数据都加载到内存里再过滤,而不是用IndexedDB的索引做条件查询。数据量小的时候没问题,数据量大了之后内存就爆了。

修复方案是把所有查询都改成基于索引的条件查询,只取需要的数据。另外加了一个定时清理任务,每天凌晨把30天前的旧数据删掉。改完之后内存占用稳定在80MB左右,降了一个数量级。

这个坑给我的教训是:IndexedDB虽然叫“数据库”,但它的查询能力比SQL数据库弱很多,用的时候要像对待API一样谨慎,不能想当然地全量加载。

7. 实际使用效果与几个实用技巧

7.1 我的日常使用流程

用了几个月之后,我的日常流程已经固定下来了。早上到工位,打开浏览器,侧边栏自动刷新,大概有十几条新内容。我先扫一遍标题和摘要,把明显不相关的点“忽略”,把感兴趣的标“稍后读”。整个过程大概两分钟,比之前刷各种网站快了十倍不止。

中午休息的时候,打开“稍后读”列表,挑几篇深度文章仔细看。看完之后回到侧边栏,把已经读过的标记为“已读”,顺便给几篇质量高的点个“有用”。这些反馈数据会在后台默默更新模型,让明天的筛选更准。

晚上下班前再刷一次,看看有没有下午新出的内容。如果有特别重要的,直接点开看;如果没有,就关掉浏览器走人。整个过程很轻松,不再有那种“信息永远看不完”的焦虑感。

7.2 配置信息源的经验分享

信息源的质量直接决定了插件的使用体验。我试过几十个不同的来源,总结下来有几个经验:

优先选更新频率稳定的源。有些网站一个月才更新一两篇,加进去之后列表里全是旧内容,反而干扰视线。我一般只加日更或周更的源。

中英文源搭配。纯中文源覆盖面有限,纯英文源读起来累。我的配置是三分之二中文源加三分之一英文源,英文源的内容让模型生成中文摘要,读起来轻松很多。

定期清理低质源。用了一段时间之后,如果某个源的内容我几乎从来不点开,就把它删掉。信息源不是越多越好,精简到十个左右最舒服。

利用分组功能。我把信息源分成了“必看”“常看”“偶尔看”三组,侧边栏里可以按组过滤。必看组的内容会优先展示,偶尔看组的内容只在没有新内容的时候才出现。

7.3 让筛选更准的几个调参建议

模型的相关性评分阈值是可以调的。默认阈值是0.6,高于这个分数的内容才会出现在列表里。如果你觉得列表里内容太少,可以把阈值降到0.5;如果觉得噪音太多,可以升到0.7。我自己的经验是0.55到0.65之间比较合适,具体看当天的信息量。

反馈的权重也是可以调的。默认显式反馈权重是1.0,隐式反馈是0.3。如果你希望模型更快地适应你的偏好,可以把显式反馈权重调到1.5甚至2.0。但调太高也有风险,模型可能会过度拟合你最近几次的点击行为,导致推荐结果波动太大。

还有一个隐藏参数是“探索率”,控制随机探索内容的比例。默认是0.1,也就是每十条内容里有一条是随机探索的。如果你觉得列表太“跳”,可以降到0.05;如果你希望看到更多新方向,可以升到0.2。

这些参数都在设置页面里,用滑块调整,调完立即生效,不需要重启插件。我建议刚开始用的时候保持默认值,用了一周之后根据自己的感受再微调。

8. 后续可以继续折腾的方向

这个插件目前的功能已经能满足我的日常需求了,但还有几个方向我觉得值得继续做。一个是多设备同步,现在数据存在本地,换电脑就得重新配置。如果做一个端到端的加密同步方案,把配置和反馈数据加密后同步到用户自己的云存储里,就能解决这个问题。另一个是移动端适配,现在只能在桌面浏览器上用,如果做成PWA,手机上也能用就方便多了。还有一个方向是社区共享规则,用户可以把调好的筛选规则导出分享给别人,新人不用从零开始调参。

不过这些都是后话了,眼下这个版本已经足够好用。如果你也在被信息过载困扰,不妨试试这个思路——把筛选的活交给本地模型,把选择权留给自己。工具不需要多复杂,能解决实际问题就行。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 8:45:44

多模态主动学习:模态平衡与难度感知如何优化标注预算

Label What Matters:把多模态主动学习的标注预算花在刀刃上做多模态任务的同学,十有八九会被“标注预算”这个问题卡住。图像、文本、深度图,每一种模态都要单独组织人力去标,标完还要做一致性检查;单条样本的综合成本…

作者头像 李华
网站建设 2026/10/20 8:45:12

基于C#的RFID卡识别与读写:从ISO14443A协议到M1卡数据块操作实战

简介:基于C#的RFID卡识别与读写是一份面向.NET开发者的射频识别入门实战资源,涵盖串口通信、事件驱动编程、数据解析及读写器交互等核心环节,适用于门禁系统、物流跟踪等场景。资源共29个文件,压缩包约66KB,以cs源码为…

作者头像 李华
网站建设 2026/10/20 8:44:35

OpenSim与AnyBody人体肌骨建模全流程:从缩放、逆动力学到肌肉重建

先别急着把标题里的词挨个念一遍。这条标题概括的其实是一套完整的科研工作流,从数据采集到仿真计算再到论文输出,我拆开讲清楚,顺便把中间那些文档里不会写的坑也一起填了。处理运动生物力学数据这件事,近几年越来越多人绕不开Op…

作者头像 李华
网站建设 2026/10/20 8:44:32

EmbeddingGemma 2本地部署指南:多模态嵌入实现图文联合检索

做检索增强应用做久了,你会慢慢发现一个尴尬的阶段:文本检索做得再顺,遇到文档里的截图、产品图、带表格的报告页,基本就束手无策了。EmbeddingGemma 2 这个 740M 参数的多模态嵌入模型,是我最近在本地跑得比较顺手的一…

作者头像 李华
网站建设 2026/10/20 8:43:45

SpringBoot+Vue敬老院管理系统:从数据库设计到部署排错全解析

我最初接触敬老院管理系统这个项目,是帮一个熟人机构的信息科搭内部系统。需求一听并不复杂:老人档案、床位、护理记录、费用结算,再加点统计报表。但真正把“基于SpringBootVueMyBatisMySQL”这套组合从零跑到稳定上线,中间还是踩…

作者头像 李华
网站建设 2026/10/20 8:43:11

Matlab手写RNN与LSTM:从零实现时间序列预测与BPTT训练

简介:一套基于Matlab的RNN-LSTM卷积神经网络实现资料,面向深度学习初学者或需要在Matlab中快速搭建序列预测模型的开发者。资料围绕LSTM输入门、遗忘门、细胞状态与输出门等核心机制展开,配套数据预处理、训练主流程和权重更新三个MATLAB脚本…

作者头像 李华