1. 为什么我决定自己搭:每天被AI信息淹没的体验
过去两年我养成了一个非常不好的习惯:每天早上睁眼第一件事,就是刷各种AI资讯。微信公众号、知乎、arXiv、GitHub Trending、Product Hunt、Reddit的r/MachineLearning……每个平台都有自己的推荐算法和内容风格,但信息高度重叠。今天OpenAI发了个新模型,明天Google出了篇论文,后天某个开源项目冲上GitHub热榜——同一件事,我能从八个渠道看到八遍不同角度的解读。
真正让我崩溃的是某一周的周四:那天至少有四条重要新闻同时爆发,我为了追完所有细节,在六个平台之间来回切换,花了一整个上午。下午看总结的时候发现,真正对我有用的信息不超过三条,其余全是重复报道、营销软文和标题党。那一刻我突然想明白了一个问题:我需要的是一个"AI资讯聚合平台",能用一套自动化流程把散落在各处的AI动态收集起来,过滤掉重复内容,再用大模型帮我提炼核心信息,最后推送给我。与其等别人做的聚合产品把规则改来改去,不如自己动手搭一个只属于我的版本。
这个项目做下来,收获比我想象中大得多。它不光是解决了我个人的信息焦虑,还让我把爬虫、消息队列、大模型API调用、前端展示、定时任务调度这一整条技术链路完整地走了一遍。无论你是做后端的、做前端的,还是刚入门想找个完整项目练手的开发者,这篇文章里的拆解思路、踩坑记录和选型逻辑都能让你少走不少弯路。我会尽量把"为什么这么设计"讲透,而不是只丢给你一段能跑的代码。
2. 整体架构:一条从信息源到手机通知的自动化流水线
先说结论:一个能稳定跑起来的AI资讯聚合平台,核心不是爬虫写得多漂亮,也不是前端做得有多炫,而是整条数据管线的可靠性。我把它拆成了四个模块——采集层、清洗层、AI处理层、展示与推送层。每一层各司其职,层与层之间通过消息队列解耦,这样任何一个环节挂了,都不会把整条链路拖死。
2.1 四个核心模块的职责划分
采集层负责定时抓取各个信息源的内容,包括RSS订阅、网页正文、GitHub热门仓库、arXiv论文摘要。它只做一件事:把原始内容塞进消息队列,不关心后续怎么处理。
清洗层从队列里拿到原始内容后做正文提取、HTML标签去除、编码修复和URL去重。这一层最大的挑战是信息源的格式差异极大——同样是RSS,有的给全量正文,有的只有摘要;同样是GitHub仓库,README里可能混着大量无关的徽章图片和表格。清洗层的目标是把这些异构数据统一成结构化的条目。
AI处理层是整条流水线的中枢。它负责对清洗后的每条资讯做三件事:标题重写、核心摘要生成、标签分类。我用的方案是大模型API加少量Python规则兜底,具体怎么设计提示词、怎么控成本,后面单独开一节细说。
展示与推送层把处理好的结构化数据写入数据库,通过一个轻量的Web前端展示,同时按用户配置的规则把每日精选推送到消息通道。这一层直接决定你每天愿不愿意打开它。
2.2 技术选型:为什么是这些而不是那些
很多教程喜欢直接丢一张技术栈清单,却不解释原因。我把自己实际用下来的选型和对比如下:
| 模块 | 选型 | 备选方案 | 选择理由 |
|---|---|---|---|
| 抓取框架 | Python + Requests + BeautifulSoup | Scrapy、Playwright | AI资讯站大多是服务端渲染或轻量反爬,Requests足够;需要执行JS的少数站点用Playwright单独处理 |
| 消息队列 | Redis Stream | RabbitMQ、Kafka | 单机部署场景下Redis Stream够用且运维成本低,自带消费组,天然适合多消费者场景 |
| 主数据库 | PostgreSQL | SQLite、MySQL | 资讯数据带全文检索需求,PostgreSQL内置的全文检索能力对中文场景够用,配合pgvector还能做向量检索 |
| 缓存与去重 | Redis | 无 | 布隆过滤器、SimHash比对、最新资讯热榜缓存全压在Redis上,性能足够 |
| API服务 | FastAPI | Flask、Django | 异步支持和Pydantic数据校验是刚需,前端界面配合Jinja2模板直接渲染,不额外搭前后端分离 |
| 大模型调用 | OpenAI兼容接口 | 各家国产模型API | 只依赖OpenAI的Chat Completions协议,这样换模型厂商不用改代码,配置一个base_url就行 |
| 定时调度 | APScheduler | Celery Beat、系统crontab | Celery对单机项目太笨重,APScheduler嵌在API进程里足够,支持cron表达式控制抓取节奏 |
这套组合跑在单台2核4G的云服务器上,月成本控制在几十块以内。如果你不想维护数据库,也可以把PostgreSQL换成SQLite,把Redis Stream简化成一张带状态标记的MySQL表——牺牲一点并发能力,换来的是部署复杂度大幅降低。
2.3 数据流设计:为什么中间要夹一个消息队列
最简单的实现方式是采集完直接写数据库,然后AI处理层轮询数据库。我一开始就是这么干的,跑了两天就发现问题:采集层抓取速度不均匀,有时候一个小时内同时抓到两三百条,有时候半小时只有一两条。AI处理层调用大模型API是有并发限制和费用消耗的,如果采集层写完数据库直接触发AI调用,高峰期会把API配额瞬间打爆。
后来我改成采集层只负责往Redis Stream里塞原始消息,AI处理层按固定的速率从队列里取消息处理。这样相当于给整条流水线加了一个缓冲区——哪怕某个信息源突然爆发一千条更新,队列先扛住,AI层还是按自己的节奏匀速消费。实测下来,这种方式显著减少了API调用HTTP 429限流错误的出现频率。
我还给每条消息设计了状态机:pending(等待处理)、summarizing(AI处理中)、done(处理完成)、failed(处理失败)。AI处理失败的消息会在Redis里记下重试次数,超过三次就进入死信队列,等周末人工排查一次。这个设计不复杂,但非常有用——头条新闻的抓取偶尔会遇到正文结构异常,没有死信机制,这些消息会一直卡在队列里占用内存。
3. 信息源抓取与内容去重:最花时间、最容易翻车的一层
很多想做资讯聚合的人上来就问"你用了什么神器爬虫框架",实际上爬虫代码只占整个项目工作量的三成,剩下七成都在处理一个极其烦人的问题:反爬规避和内容去重。如果把精力放错地方,后期维护会让人崩溃。
3.1 信息源清单与适配策略
我最终把信息源分成四类,每类的抓取策略完全不同:
- RSS/Atom源:这是优先级最高的信息源。很多AI媒体和博客都提供RSS输出,解析标准,结构规整,几乎不遇反爬。我用feedparser库统一解析,半小时抓取一次。
- 静态HTML页面:比如某些知名AI资讯站的列表页,内容是服务端渲染的。直接用Requests拿HTML,再用BeautifulSoup按CSS选择器提取标题、链接、正文。这类站点一般只在首页或列表页做基本的User-Agent校验,伪装成正常浏览器的请求头就能通过。
- 动态渲染页面:少数站点用Vue或React做客户端渲染,直接拿HTML拿不到正文。我单独准备了一个Playwright实例,无头浏览器加载页面后等待JS执行完再取内容。这个方案对服务器内存有要求,2G内存的机器跑起来比较吃紧,我做了个限制:只有白名单里的域名才走Playwright,且同时最多开两个页面实例。
- 平台API:GitHub和Hacker News这类的开放API是最高质量的信息源。GitHub Trending有非官方API,Hacker News的Algolia API支持按关键词检索,这些接口返回的是结构化JSON,连清洗都省了。
我建议你最初搭建时,优先接RSS源和平台API,这两类源能让你在半天内把整条链路跑通。等核心流程稳定了,再去逐步增加HTML页面源和动态页面源,这样排查问题时不用面对一堆不确定因素。
3.2 抓取频率与反爬的平衡:宁慢勿快
这里必须强调的是,自用聚合平台的抓取频率设置,核心原则是"够用就行"。我在生产环境里对RSS源设置的间隔是30分钟一次,对HTML页面源是60分钟一次,对GitHub API是严格按照配额来——该平台的未授权请求限制是60次每小时,我设置成每小时只访问30次,留足余量。
很多人一上来就把并发数调到20以上,恨不得一分钟内把全网资讯抓一遍。结果往往是被目标站点封IP,或者导致对目标站点服务器造成压力被投诉。我一直坚持用单线程串行抓取加随机延时的方式,在Requests的Session里设置统一的请求头,包含常见的浏览器User-Agent。跑了大半年,除了少数反爬特别严格的站点,没有被封过。
如果你的目标是多个人同时使用,那建议购买代理池和更谨慎的抓取策略——但自用场景完全不需要现在考虑这个问题。
3.3 SimHash去重:让相似文章不会重复轰炸你
资讯聚合场景中,同一条新闻在多个渠道出现是常态。比如某大模型发布新版本,可能有十几个公众号和媒体博客在报道同一个事件。若不做去重,你的推送列表就会有一堆标题换汤不换药的文章。
我调研过几种去重方案:最简单的MD5做完全一致判断只对完全相同的内容有效;数据库里的最长公共子串比较太慢;最终选用SimHash算法加汉明距离。原理可以这么理解:SimHash把一篇文本计算成一个64位的指纹,两篇文章指纹的汉明距离越小说明相似度越高。我设定的阈值是汉明距离小于等于3就判为重复,保留时间戳更早的那条,丢弃后到的。
SimHash在中文文本上的一个隐藏问题是对分词结果敏感。我踩过的坑是:直接拿原始正文去做SimHash,效果很差,因为HTML标签、广告文案这些噪声被哈希进去了。后来我在计算指纹前先做了一次粗清洗:去掉所有HTML标签、去掉常见的CMS追踪参数、只提取文章正文的前两千字参与计算。经过调优之后,去重的命中率明显提升,误判率也降到了可接受范围。
如果在做这个项目时你不想自己实现SimHash,可以直接用text2vec库里的简化实现,或者更粗暴地使用Redis的SET结构存储标题的归一化版本,效果能覆盖80%的完全重复场景。对于自用,够用就好,不必追求极致。
4. AI处理层:让大模型把资讯变成"为我定制"的简报
这一层是整个平台的灵魂。采集层和清洗层解决的是"把信息拿进来",AI层解决的才是"把信息变成我能消化的形态"。我一开始尝试过用规则做关键词提取和摘要,但效果和大模型相差太远——比如一篇讲大模型训练技巧的文章,关键词列表里全是"模型""训练",完全看不出文章的核心观点。换成大模型之后,摘要质量直接从"可用"变成了"有阅读价值"。
4.1 为什么选择大模型而非正则和NLP工具
面对资讯摘要和分类任务,传统方案需要为每个场景单独训练或调教模型,通用性差、迭代成本高。大模型的主要优势在于零样本泛化能力——我只需要设计好提示词模板,它就能对来自不同领域、不同语气的文章给出结构清晰的结果。
我实际处理的任务分为三类:
- 标题重写:原文标题往往带营销色彩,如"震惊!AI又双叒突破",我会让模型重写成中性、信息量更足的表达。
- 核心摘要:限制在100-150字,提炼背景、关键结论、对从业者的影响。
- 标签分类:从预先定义的标签集合中选出最匹配的,同时给出置信度排序。
这三类任务在一条大模型调用里完成,输出的是严格JSON格式,方便程序直接解析。整体设计思路就是让大模型服务于平台的"结构化"目标,而不是让它自由发挥写一篇小作文。
4.2 提示词模板设计与实测效果
我使用的提示词模板经过了几轮迭代,目前的版本大致是这样的结构:
你是一个AI行业资讯编辑。请对以下文章执行三项操作: 1. 重新生成标题:去除营销夸张语气,保留核心主体和关键信息; 2. 生成摘要:150字以内,包含技术背景、核心突破、对从业者影响三个层面; 3. 分类打标:从["大模型", "Agent应用", "AI编程", "AI绘画", "AI搜索", "AI基础设施", "开源项目", "行业动态"]中选择1-3个标签。 要求:只输出JSON,格式如下: {"title": "...", "summary": "...", "tags": ["..."]} 文章内容如下: {清洗后的正文}这套提示词在实际使用中有几个值得注意的细节:一是给模型限制输出JSON格式,省去了大量正则解析的麻烦;二是标签集合必须严格固定,否则模型会天马行空地造出十几个标签;三是正文长度如果超过模型上下文限制,我用截取前1500个字符的方式做"头重脚轻"式处理,因为开头部分通常包含了文章的核心信息。
实测下来,GPT-4o级别的模型在这套模板上的效果很稳定,摘要几乎没有废话;稍微小一点的模型也够用,只是偶尔会把"摘要"写成"评论"。为了避免劣质结果污染数据库,我在AI层加了一个简单的规则校验:摘要少于30个字,或者包含明显的主观评价词如"值得""太好了",就标记为失败并重新调用一次。
4.3 成本控制:一个资讯平台的API费用能压到多低
算一笔账:假设平均每次任务输入是1800个token,输出是500个token,换算成约2300个token,按市面上中等偏低价位的大模型API来算,单次成本约0.01元,每天抓600条资讯(实际有效去重后通常只有200条左右),一天的全部处理成本也就2块钱上下。一个月下来几十块钱,完全可以接受。
但成本控制依然是必要的,尤其是你的聚合平台信息源较多的时候。我用了三个手段降低消耗:
- 批量处理:把多条资讯拼进同一轮对话,让模型一次性输出多个JSON对象。单次请求固定开销被摊薄,实测贵了约30%的上下文但省了70%的来回开销。
- 短文本策略:如果RSS源已经提供了摘要,那就不需要全文重写,直接用小成本模型跑一遍摘要即可,只有正文质量高的资讯才动用更贵的模型。
- 降级规则:把资讯按当天是否被用户阅读来分等级。低频场景下用便宜的轻量模型先处理,用户手动标记"感兴趣"的资讯,再触发一次更高质量模型的深度摘要。
成本控制的核心逻辑不是一味图便宜,而是把贵的计算资源用在对用户最有价值的内容上。
5. 展示层与主动推送:让好的资讯"找上门"
处理完的资讯如果只是堆在网页上,和看普通新闻网站没有本质区别。聚合平台真正提升体验的地方在两点:一是按用户关注领域把内容组织好,二是主动把今日值得看的内容推到用户面前。我的前端做得不算复杂,但信息架构经过了好几轮调整。
5.1 Web端设计:分类导航与"我的关注流"
Web端我用了FastAPI加Jinja2模板,配合一点轻量JavaScript做交互。首页默认展示的是"综合"栏目——按时间倒序展示当天处理完成的所有资讯卡片,每张卡片包含标题、摘要、标签和原文链接。侧边栏是固定的标签筛选区,点击某个标签后,页面会展示该标签下的资讯列表。
这里有一个设计细节很关键:每个标签页都附带一个"相似主题"的推荐模块。我基于PostgreSQL里存的标签向量做简单关联推荐,逻辑是提取用户当前正在浏览的资讯标签组合,在数据库里搜索共享两个以上标签的最近资讯。由于资讯的标签是AI打出来的,这个关联推荐的准确度意外地高。
我在界面里还保留了一个"原始标题区"的折叠面板,默认隐藏,可以点击展开看到原始标题和原文正文。为什么留这个?因为AI摘要偶尔可能带偏原意,提供原文能避免误判——资讯聚合最重要的还是真实性。
5.2 推送通道:Telegram Bot和邮件双通道
资讯平台最核心的功能就是"主动投喂"。我实现的推送规则很简单:每天定时三个时间点(早上8点、中午12点、晚上7点),把过去8小时内新增且打标为高价值的资讯整理成一条汇总消息推送到指定通道。高价值的判定规则是:标签命中用户关注的标签集合,且AI摘要长度超过80字,且来源权重在平均值以上。
Telegram Bot的实施方案是通过官方Bot API发送消息,配合HTML格式的排版做出一条含链接的摘要列表。邮件通道我用了SMTP库直接发送,内容风格更正式一些。两条通道里的每条摘要都附上了"打开原文"的链接。实测下来,推送收到的点击率远高于网页端随机浏览——这也印证了我最初的想法,大家缺的其实不是资讯数量,而是经过筛选和组织的精品摘要。
5.3 阅读体验优化的几个小心思
这里分享几个提升体验的小细节。第一,每篇文章保存时会做一个/阅读时间估算,推送里会显示"预计3分钟读完",这能帮助用户决定要不要立即点开。第二,我在Web端做了今天/本周/历史三个时间维度的切换,避免时间线像微博一样无限下滑。第三,我允许用户对不喜欢的资讯源做"折叠"操作——折叠一次之后,该来源的内容一周内不会出现在首页,这个功能对过滤某些标题党媒体效果立竿见影。
另外一个很实用的小功能是"重读推荐"。我每周日跑一次SQL查询,找出上周被推送过但用户没有点击的高分资讯,生成一封"周末补读"邮件。在大模型时代,偶尔翻出一篇被淹没的好文章,反而最有惊喜感。
6. 部署上线与踩坑纪实:从本机Demo到稳定运行
这个项目从写完第一版能跑的代码,到放在服务器上稳定运行三个月不出大问题,中间经历了好几个让人崩溃的坑。我把最有价值的教训整理出来,你看了能直接避开。
6.1 部署拓扑与资源规划
我的部署目标是单台云的虚拟主机,2核4G配置,阿里云或腾讯云之类的标准机型都行。系统是Ubuntu 22.04,所有服务用Docker Compose编排,一共四个容器:API服务、PostgreSQL、Redis、定时任务。API服务和定时任务共用同一个镜像,只是通过环境变量区分启动命令。
如果你只用一台轻量服务器,建议在买机器时把带宽选到3M以上。因为采集层和AI处理层都要访问外部网络,带宽太小会导致请求超时。另一个重要的资源规划是磁盘空间:PostgreSQL里如果保存了每篇资讯的原始正文,一年的数据量大概会到2-3GB,建议给数据卷挂一个独立的数据盘,防止主系统盘被撑满。
6.2 三个必须提前处理的问题:时区、重试、数据库连接池
时区问题。这个坑很小但极其隐蔽。PostgreSQL默认时区是UTC,而我的定时推送任务用的是北京时间。头两天调试时发现推送总是晚8小时。解决方案是在所有服务和数据库的连接参数里统一指定Asia/Shanghai,并且所有时间戳字段都以TIMESTAMPTZ类型存储,应用层统一用ISO 8601格式传输时间。
重试机制。AI处理层调用大模型API时,偶尔会遇到连接超时或服务端返回5xx错误。如果不加重试,资讯流程会中断。我给所有外部调用封装了一个带指数退避的重试器:第一次失败等2秒重试,第二次等4秒,第三次等8秒,最多重试三次。这个逻辑大约解决了95%的临时性错误。
数据库连接池。FastAPI默认情况下每个请求新建数据库连接,并发一高就会出现too many connections错误。我用psycopg2基于连接池管理,设置最小5个、最大20个连接。API服务和定时任务进程各自独立维护一个连接池,避免互相争抢。
6.3 运行三个月后的复盘:哪些设计被验证有用
项目跑了一段时间后验证了几个初期的设计判断。
消息队列解耦的方案被证明是完全正确的:某次上游信息源出现异常,一次性涌入超过两千条的重复消息,队列扛住了流量峰值,AI层按既定速率慢慢消费,没有出现接口限流或数据库写入风暴。这个场景如果让我同步处理,服务器大概率直接宕机。
SimHash去重的价值也在一次大事件中体现得很明显:某头部实验室发布重大进展的那天,我订阅的四十多个来源里有将近三十条报道同一事件。如果没有去重,当天的推送列表至少有二十五条重复内容,用户会直接失去阅读欲望。去重后只保留了四条不同角度的代表性报道,阅读体验好了很多。
另外,我原本以为"标签分类"这个功能只是锦上添花,实际上它成了整个平台的骨干。有了标签体系,后续做关键词告警、周报生成、相关推荐都变得非常顺手。如果你的平台计划增加"某方面资讯重点盯梢"功能,请务必在最开始就把标签的准确性做扎实。
7. 这个项目后续还能怎么扩展:我列了几个正在考虑的方向
搭建到现在这个阶段,整个平台已经完全自洽了。但我心里清楚,资讯聚合这件事还能往更智能的方向走。
第一个方向是引入多AI协作机制。目前AI处理层只有"单次调用",但复杂任务比如"判断一条资讯是否值得深度阅读",可能需要两个模型先各出意见再汇总。我在阅读热词里看到多AI协作这个概念频繁出现,也已经在本地做了原型验证,准备把它整合进摘要质量评估模块。
第二个方向是向量检索。PostgreSQL里已经可以跑pgvector扩展,如果我把每篇文章的摘要向量化存储,就能实现"语义相似文章"的检索。这比当前基于标签的关联推荐要强大得多,比如你正在看一篇关于Agent记忆机制的深度文章,系统能推荐出几篇并未共用标签但语义上真正相关的内容。
第三个方向是互动反馈闭环。目前推送出去的内容是否被点开阅读,我只有"点击率"这一个粗略指标。下一步我想在每篇文章下加"有用/没用"按钮,把反馈数据喂给标签权重计算和摘要生成提示词调整,实现真正的个性化学习。
我的体会是:搭建这类平台最大的价值反而不是最终产物,而是过程中对整个AI技术生态有了更系统化的认知。在一个信息过载的时代,拥有一个完全为自己定制的资讯入口,那种"信息主动来找我"的掌控感,值得每个重度知识工作者体会一次。