☰
从信息过载到个人情报系统:AI日报自动化流水线实战
2026/10/8 21:09:00 网站建设 项目流程

1. 当"日报"变成一种产品形态:我为什么要做这件事

做内容的人都有一个共同的痛点:信息过载。每天醒来,光是各个渠道推送的行业动态、技术更新、产品发布、论文预印本,就能轻松刷掉两个小时。更麻烦的是,这些信息散落在不同的平台、不同的格式里,有的是一段推文,有的是一篇长文,有的干脆就是一个PDF链接。你花了很多时间去"看",但真正沉淀下来的东西少得可怜。

"AI 日报"这个项目,本质上就是在解决这个问题。它不是简单的新闻聚合,而是一条从信息采集、筛选、摘要、结构化到最终呈现的完整流水线。我把它定位成一个"个人情报系统"——每天自动跑一遍,把当天值得关注的AI领域动态整理成一份格式统一、信息密度高、可快速扫读的日报。适合谁用?独立开发者、技术博主、产品经理、投资分析人员,以及任何需要持续跟踪AI行业但不想被信息淹没的人。

这个项目的核心逻辑可以用一句话概括:用工程化的方式,把"刷信息"这件事变成"读报告"。前者是被动的、碎片化的、高消耗的;后者是主动的、结构化的、可积累的。我做了大概三个月,中间踩了不少坑,也积累了一些在常规教程里看不到的经验。下面我把整个系统的设计思路、关键实现、以及那些"只有做过才知道"的细节,完整地拆一遍。

2. 信息源的取舍:不是越多越好,而是越稳越值钱

2.1 我评估信息源的三个维度

刚开始做的时候,我犯了一个很典型的错误:贪多。一口气接了十几个数据源,RSS、API、网页抓取全上,结果每天跑出来的原始数据有上千条,光去重和筛选就耗掉大量时间,而且质量参差不齐。后来我给自己定了一个筛选框架,每个信息源都要过这三关:

  • 信噪比:这个源里真正有价值的内容占比多少?如果一个源每天推50条,其中只有2条值得看,那它的信噪比就是4%,维护成本远高于收益。
  • 稳定性:接口会不会频繁变动?页面结构会不会经常改版?一个三天两头挂掉的源,比没有这个源更糟糕,因为它会污染整个流水线的可靠性。
  • 时效性:这个源的内容是不是第一时间发布的?还是二手转载?二手转载往往滞后半天到一天,对于日报这种追求"当天事当天报"的场景,价值大打折扣。

基于这三个维度,我最终把信息源压缩到了六个类别:官方博客与公告、预印本平台、技术社区热门帖、行业媒体、开源项目动态、以及社交平台上的关键账号。每一类选一到两个最稳定的源,总数控制在十个以内。

2.2 抓取方式的选择:API优先,RSS兜底,网页抓取慎用

在抓取方式上,我的优先级排序很明确:有API就用API,没API就找RSS,两者都没有才考虑网页抓取。这个排序背后的逻辑是维护成本。

API的好处是数据结构稳定、字段明确、有速率限制但可预期。RSS的好处是格式统一、解析简单、大多数内容平台都支持。网页抓取的问题在于,它依赖于页面的DOM结构,而DOM结构是最容易变的——今天用.article-title能抓到标题,明天人家改成.post-heading,你的脚本就废了。

我实际用的抓取策略是这样的:

import feedparser import requests from bs4 import BeautifulSoup def fetch_rss(url): feed = feedparser.parse(url) items = [] for entry in feed.entries: items.append({ "title": entry.get("title", ""), "link": entry.get("link", ""), "published": entry.get("published", ""), "summary": entry.get("summary", "") }) return items def fetch_api(url, headers=None, params=None): resp = requests.get(url, headers=headers, params=params, timeout=15) resp.raise_for_status() return resp.json()

对于确实需要网页抓取的源,我会加一层"结构校验":每次抓取后检查关键字段是否为空,如果连续两次为空,就触发告警,提醒我页面可能改版了。这个机制帮我省了很多事——有一次某个源改版,我在当天就收到了告警,而不是等到几天后才发现日报里少了一大块内容。

提示:抓取频率不要设得太高。我一开始设的是每10分钟跑一次,结果被好几个源限流。后来改成每天固定跑两次(早上和傍晚),完全够用,而且更稳定。

2.3 去重这件事,比你想的要复杂

去重看起来简单,实际上是个坑。最基础的URL去重只能解决"同一篇文章被多次抓到"的问题,但解决不了"同一件事被多个源报道"的问题。比如某公司发布了一个新模型,官方博客发了一遍,三家媒体各发了一遍,社交平台上还有十几条讨论。这五条内容本质上是同一件事,但URL完全不同。

我的做法是两层去重:

第一层是URL规范化去重。把URL里的追踪参数(如?utm_source=xxx)全部剥掉,只保留路径部分,然后做哈希比对。这一步能干掉大约30%的重复。

第二层是标题相似度去重。用编辑距离或者简单的Jaccard相似度,把标题相似度超过0.8的条目归为一组,只保留信息最完整的那一条(通常是官方源)。这一步又能干掉20%到30%的重复。

from difflib import SequenceMatcher def title_similarity(t1, t2): return SequenceMatcher(None, t1, t2).ratio() def dedup_by_title(items, threshold=0.8): unique = [] for item in items: is_dup = False for u in unique: if title_similarity(item["title"], u["title"]) > threshold: is_dup = True break if not is_dup: unique.append(item) return unique

实测下来,两层去重之后,原始数据量能从上千条压缩到一百条左右,后续的处理压力小了很多。

3. 从原始信息到日报条目:摘要与结构化的核心逻辑

3.1 为什么不能直接让模型"写摘要"

很多人做类似项目时,第一反应是把原文丢给大模型,让它生成一段摘要。我一开始也是这么做的,但很快发现两个问题:一是摘要质量不稳定,同样的输入,不同时间跑出来的结果差异很大;二是摘要里经常出现"幻觉",模型会编造一些原文里没有的细节。

后来我调整了策略:不让模型自由发挥,而是给它一个严格的结构化模板。每条日报条目必须包含四个字段:事件概述(一句话)、关键信息(两到三个要点)、影响判断(一句话)、原文链接。模型的任务不是"写文章",而是"填表格"。这个转变让输出质量稳定了很多。

具体的提示词设计是这样的:

你是一个信息整理助手。请根据以下原文内容,提取结构化信息。 要求: 1. 事件概述:用一句话概括核心事件,不超过40字。 2. 关键信息:列出2-3个关键要点,每个要点不超过30字。 3. 影响判断:用一句话说明这件事对AI行业可能的影响,不超过30字。 4. 如果原文信息不足以判断影响,影响判断字段填写"待观察"。 原文内容: {content} 请以JSON格式输出,字段名为:summary, key_points, impact。

这个模板的好处是,它把模型的输出空间限制得很窄,大幅降低了幻觉的概率。而且JSON格式方便后续程序化处理,可以直接渲染成日报的固定版式。

3.2 分类标签体系:让日报可检索、可追溯

一份日报如果只是按时间顺序罗列条目,读起来会很累。我加了一套分类标签体系,每条日报条目都会被自动打上一个或多个标签。标签体系是这样的:

标签类别具体标签说明
模型发布大模型、多模态、开源模型新模型发布或重大更新
产品动态新产品、功能更新、商业化产品层面的变化
技术研究论文、算法、训练技巧学术和技术研究进展
行业事件融资、收购、合作、人事行业层面的商业事件
政策法规标准、合规、监管相关政策动态
开源生态框架、工具、数据集开源项目相关

打标签的方式有两种:一种是基于关键词规则,比如标题里出现"发布""开源""融资"等词就自动归类;另一种是用模型做零样本分类。我实际用的是混合策略——先用规则打一轮,规则覆盖不到的再用模型补。这样既保证了速度,又保证了覆盖率。

3.3 排序逻辑:什么内容应该排在前面

日报的排序直接决定了读者的阅读体验。我试过几种方案:按时间排、按来源权重排、按热度排。最后定下来的方案是一个加权分数:

分数 = 来源权重 × 0.4 + 时效性 × 0.3 + 关键词命中 × 0.3

来源权重是我手动给每个源打的1到5分;时效性是发布时间的衰减函数,越新越高;关键词命中是指标题或摘要里是否包含我预设的关注词(比如"开源""突破""首次"等)。这个加权方案的好处是,它不会让某一个维度主导排序,而是综合考量。

注意:排序权重需要定期调整。我大概每两周会看一遍日报,如果发现某些不重要的内容总是排在前面,就调低对应源的权重。这个调优过程是持续性的,没有一劳永逸的方案。

4. 自动化流水线的搭建:从定时任务到异常处理

4.1 整体架构:四个阶段的流水线

整个系统我拆成了四个阶段,每个阶段独立运行,通过中间文件传递数据:

  1. 采集阶段:从各个源抓取原始数据,统一存成JSON格式。
  2. 清洗阶段:去重、过滤、字段规范化。
  3. 摘要阶段:调用模型生成结构化摘要和标签。
  4. 渲染阶段:把处理好的数据渲染成Markdown格式的日报。

每个阶段的输出都落盘保存,这样如果某个阶段出了问题,不需要从头重跑。比如摘要阶段如果模型调用失败了,我可以只重跑摘要阶段,前面的采集和清洗结果直接复用。

# 流水线执行脚本示例 python collect.py --date 2026-10-03 python clean.py --date 2026-10-03 python summarize.py --date 2026-10-03 python render.py --date 2026-10-03

4.2 定时任务的坑:时区、依赖和重试

定时任务我用的是cron。这里踩过两个坑,值得说一下。

第一个坑是时区。我的服务器默认是UTC时间,但我希望日报在北京时间早上8点生成。一开始我直接写0 8 * * *,结果日报在下午4点才出来。后来改成0 0 * * *(UTC 0点等于北京时间8点),问题解决。如果你也用cron,一定要确认服务器的时区设置。

第二个坑是依赖顺序。四个阶段是有先后依赖的,如果采集阶段还没跑完,清洗阶段就启动了,会读到不完整的数据。我的解决方案是在每个阶段结束时写一个.done标记文件,下一个阶段启动前先检查标记文件是否存在。

import os import time def wait_for_marker(marker_path, timeout=600): start = time.time() while not os.path.exists(marker_path): if time.time() - start > timeout: raise TimeoutError(f"等待标记文件超时: {marker_path}") time.sleep(10)

4.3 异常处理:让系统在出错时"优雅降级"

任何一个环节出错,都不应该导致整个日报生成失败。我的原则是:能降级就降级,不能降级就跳过,绝不整体崩溃。

具体来说,如果某个源抓取失败了,就跳过这个源,用其他源的数据继续生成日报,同时在日报末尾加一行备注说明哪个源出了问题。如果模型调用失败了,就退回到用原文的第一段作为摘要,虽然质量差一些,但至少日报能出来。

def safe_fetch(source_func, source_name): try: return source_func() except Exception as e: print(f"[警告] 源 {source_name} 抓取失败: {e}") return []

这个降级策略看起来简单,但实际运行中非常有用。我有一次在出差路上,某个源的API挂了,但因为降级机制,日报照常生成,只是少了一个源的内容。如果没有这个机制,那天就开天窗了。

5. 日报的呈现设计:让信息密度和可读性兼得

5.1 版式设计:固定结构降低阅读成本

日报的版式我改了大概五版,最终定下来的结构是这样的:

  • 头部:日期、条目总数、各分类数量概览。
  • 要闻区:当天最重要的3到5条,每条包含概述、关键信息、影响判断。
  • 分类区:按标签分组的其余条目,每条只保留概述和链接。
  • 尾部:数据源状态说明和生成时间。

这个结构的核心思路是分层呈现:最重要的信息放在最前面,用最详细的格式;次要信息放在后面,用最精简的格式。读者花两分钟就能扫完要闻区,如果有兴趣再往下看分类区。

5.2 摘要的"可扫读性":短句、要点、加粗

摘要的可读性直接决定了日报的使用体验。我总结了几条规则:

  • 每句话不超过40个字,超过就拆成两句。
  • 关键信息用无序列表呈现,每条不超过30个字。
  • 核心术语和数字加粗,方便快速定位。
  • 避免被动语态和长定语,用"某公司发布了某产品"而不是"某产品被某公司发布"。

这些规则看起来琐碎,但实际效果很明显。我让几个朋友对比过,遵循这些规则的摘要,阅读速度能快30%以上。

5.3 从Markdown到多端分发

日报生成后是Markdown格式,但不同平台对格式的支持不一样。我的做法是写一个简单的转换脚本,把Markdown转成适合不同平台的格式:

def to_plain_text(md_content): """去掉Markdown标记,生成纯文本版本""" import re text = re.sub(r'#+\s*', '', md_content) text = re.sub(r'\*\*(.+?)\*\*', r'\1', text) text = re.sub(r'\[(.+?)\]\(.+?\)', r'\1', text) return text

纯文本版本适合发到即时通讯工具或者邮件里,Markdown版本适合发到支持富文本的平台。两个版本同时生成,按需使用。

6. 运行三个月后,我总结出的几条实战经验

6.1 信息源要定期"体检"

信息源不是接上就完事了。我每个月会做一次"源体检",检查每个源的抓取成功率、内容质量和时效性。有一次我发现某个源连续一周抓取成功率为零,排查后发现是对方改了RSS地址,旧地址返回301跳转,而我的脚本没有跟随跳转。加上allow_redirects=True之后问题解决。

体检的另一个目的是发现"僵尸源"——那些还在抓取但内容质量已经严重下降的源。比如某个媒体号以前质量很高,后来变成了标题党,这种源就应该果断砍掉。

6.2 模型调用要控制成本

如果每条内容都调用一次模型,一天一百条就是一百次调用,成本不低。我的优化策略是:先用规则做初筛,只把真正需要摘要的内容送给模型。比如有些源的RSS本身就带摘要字段,质量还不错,那就直接用,不需要再调模型。实测下来,模型调用量能减少40%左右。

另外,摘要用的模型不需要是最强的。我试过用大模型和小模型做对比,在结构化摘要这个任务上,小模型的效果差距很小,但成本差了好几倍。所以我现在用的是中等规模的模型,性价比最高。

6.3 日报的"人味"不能丢

全自动生成的日报有一个通病:读起来像机器写的,冷冰冰的。我的做法是在日报里保留一些"人味"元素。比如在要闻区加一句我自己的短评,或者在尾部写一句当天的观察。这些内容不多,但能让读者感觉到背后有一个人在筛选和判断,而不是纯粹的机器输出。

提示:如果你也做类似的项目,建议保留一个"手动干预"的入口。比如某天你觉得某条内容特别重要,可以手动把它提到要闻区第一位。完全自动化的系统,有时候会漏掉一些"机器觉得不重要但人觉得很重要"的内容。

6.4 数据积累的长期价值

日报本身是"快消品",今天的日报明天就没人看了。但日报背后的数据是有长期价值的。我把每天的结构化数据都存进了数据库,积累三个月之后,就能做一些有意思的分析:比如某个技术方向的热度变化趋势、某个公司的曝光频率变化、某个关键词的出现频率曲线。

这些分析反过来又能优化日报的筛选和排序逻辑。比如我发现某个标签的内容连续两周热度上升,就会临时调高这个标签的权重,让相关条目更容易进入要闻区。这个"数据反哺"的循环,是这套系统最有价值的部分。

7. 如果你也想搭一套,我的建议是从最小可用版本开始

很多人做这类项目,容易陷入"过度设计"的陷阱:一开始就想把架构做得很完美,结果还没跑起来就放弃了。我的建议是,先用最小的成本跑通一个闭环。

具体来说,第一版只需要做三件事:接一个源、生成一条摘要、输出一个Markdown文件。跑通之后,再逐步加源、加分类、加排序、加自动化。每加一个功能,都要确保它真的解决了某个具体问题,而不是"看起来更完整"。

我在实际搭建过程中最大的体会是:这套系统的价值不在于技术有多复杂,而在于它能不能稳定地、持续地跑下去。一个每天都能出日报的简单系统,远比一个功能强大但三天两头挂掉的复杂系统有用。所以,稳定性优先,功能其次。先把流水线跑稳,再考虑优化和扩展。

最后分享一个小技巧:如果你不想自己维护服务器,可以用本地的定时任务(比如macOS的launchd或者Windows的任务计划程序)来跑这套流水线。每天固定时间跑一次,生成的文件直接同步到你的笔记软件或者云盘里。这样零服务器成本,而且完全可控。我自己有一段时间就是这么跑的,效果很好。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询