AI热点追踪系统设计:从多源采集到事件聚类与热度计算 最近我把一个叫 last30days 的小系统跑起来了——它每天自动扫一圈全网公开渠道的热门信号用 AI 把过去 30 天里真正值得关注的事情按热度排出名单再把来龙去脉写成简报推给我。用了一段时间最大的感受是当 AI 学会“追热点”之后它确实比我自己刷手机更早知道发生了什么。这个项目解决的是我一直以来的痛点天天看热搜却总觉得知道得太晚。头条上挂着的事件往往是已经发酵了一两天的“结论”真正有价值的是“正在涨但还没爆”的信号。人眼盯不过来那么多信息源个人偏好又会让我们自动屏蔽掉不感兴趣但重要的话题。AI 没有这个问题它可以按小时粒度扫几百个公开信息源在事件讨论量刚刚爬升的时候就把信号拎出来。这套系统不需要多高深的技术适合做自媒体运营、产品观察、投资研究或者单纯不想被信息茧房困住的人。下面我把完整的设计思路、核心实现和踩过的坑都写出来。1. 为什么用 30 天作为热点窗口1.1 热点生命周期与 30 天窗口的逻辑“last30days”这个名字不是随手起的热点分析窗口选 30 天有明确的业务逻辑。一个事件从萌芽、发酵、爆发到消退完整周期通常在三天到三周之间。太短的窗口比如 7 天只能看到“此刻正在发生什么”看不到事件的来龙去脉太长的窗口比如 90 天又会混入大量已经过时的旧闻信噪比急剧下降。30 天刚好覆盖热点从出现到退场的完整生命周期既能捕捉突发的短期爆点也能观察那些慢慢升温的长线话题。我在设计初期对比过 7 天、30 天和 90 天三个窗口的识别效果。7 天窗口的问题是一个事件如果在第 3 天开始发酵、第 5 天登上热榜到第 7 天它已经是“所有人都知道”的旧闻了提醒的时效性约等于零。90 天窗口正好相反算法会把两个月前的讨论和今天的热点混在一起趋势判断严重失真。30 天窗口下一个事件从萌芽到爆发再到回落所有关键节点都能被完整记录趋势计算也有足够的样本量。1.2 人工追热点 vs AI 追热点这个标题说“它比你还知道发生了什么”听起来有点夸张但实际操作之后你会发现 AI 在三个维度上是真的碾压人工。对比维度人工追热点AI 追热点信息源覆盖通常 5 到 10 个固定平台上百个公开源RSS、榜单、社区全覆盖扫描频率一天看几次凭记忆拼图按小时调度事件萌芽即入系统主观偏好不感兴趣的话题会直接被跳过没有偏好所有类型一视同仁记忆跨度很难记住 20 天前的讨论细节所有历史数据可检索、可关联趋势计算凭感觉判断“这事会不会火”用速度因子、持续度指标量化判断最典型的例子是我跑这个系统第二周遇到的一件小事。有一个我一直关注的开源项目我刷 GitHub 趋势榜时看到它排在前面觉得“哦这个项目好像最近不错”。但 last30days 的系统里这个项目已经被标记为“连续第 5 天讨论量上升速度因子进入异常区间”了——也就是说它已经悄悄涨了一个星期而我直到它进入头部榜单才发现。这就是人工追热点和系统化追热点的本质区别人工看到的是“已经火了的”AI 捕捉到的是“正在火的”。2. 整体架构从多源采集到事件聚类2.1 数据源选型与标准化整个系统的数据层设计原则只有一条只用公开、合法、稳定的数据源坚决不碰需要特殊手段才能获取的数据。我把数据源分成三个层级。第一层是 RSS 订阅源这是整个系统的地基。我订阅了科技媒体、行业博客、官方公告频道等差不多六十个源。RSS 的好处是格式标准、更新稳定、不需要处理复杂的页面结构而且内容质量普遍偏高。采集器每隔一小时拉取一次拿到的就是结构化的标题、链接、发布时间和摘要。第二层是公开榜单和官方 API。各家平台的公开热榜、排行榜页面以及一些开放 API能提供“此刻讨论度最高”的信号。这一层我用来做“量”的标定某事件在榜单上的排名变化直接反映它在普通用户群体中的传播情况。第三层是社区和论坛的讨论帖。这里的数据最原生态能反映真实用户的反应而不是媒体的报道口径。我会抓取帖子的标题、回复数和发布时间用回复增长速度来判断一个话题是不是正在被社区热烈讨论。三层数据汇总后统一进入标准化流程。每一条数据至少清洗出五个字段原始标题、规范化标题、来源类型、发布时间、热度参考值。规范化标题是个容易被忽略的细节——同一件事媒体标题写“某公司发布新一代模型”社区帖子可能写“刚试了下新模型效果有点猛”如果不做归一化后续聚类阶段会把它们当成两个完全无关的事件。2.2 事件聚类让 AI 先“看懂”再“评论”采集到的原始数据是一堆碎片化的标题和摘要直接扔给大模型分析会产生两个问题一是成本高几百条标题逐条分析每次调用都在烧钱二是上下文割裂AI 看单条新闻和看一个事件的完整脉络得出的判断质量完全不同。所以我在中间加了一层事件聚类。聚类用的是一个很朴素的方案先把每条标题用嵌入模型转成向量然后计算向量之间的余弦相似度。相似度超过阈值的标题会被归入同一个事件簇。比如“某公司发布新一代模型”和“刚刚某公司的下一代产品正式亮相”语义相似度通常在 0.8 以上会被自动归为一个簇。每个事件簇会产生几个关键属性最早出现时间、最近出现时间、累计提及次数、来源分布、以及簇内所有原始标题。到这里AI 就不再面对碎片了它看到的是“某事件在 30 天内的完整讨论过程”。有了这个基础后面的热度计算和内容生成才有意义。2.3 任务调度与多 Agent 协作整个系统由四个各司其职的 Agent 协作完成。采集 Agent 负责按计划拉取数据清洗 Agent 负责去重和字段规范化分析 Agent 负责做聚类和热度计算撰写 Agent 负责把分析结果写成可读的简报。四者之间通过消息队列传递任务互相不阻塞。这里我踩过一个很实际的坑如果所有步骤串行执行某一层卡住会导致整条链路堆积。比如采集层某一次抓取超时后面所有任务都得排队。改成多 Agent 异步协作之后每个环节独立调度采集慢了几分钟不影响分析任务处理上一批数据。并发控制方面我给每个环节设置了任务上限和重试次数避免某个数据源异常时产生雪崩效应。这套设计对个人项目来说足够健壮也为我后续扩展新的数据源留了位置。3. 热度计算AI 判断“哪些正在变成热点”3.1 热度指数公式热度计算是整个系统的核心。我设计了一个四项加权公式每一项都对应一个可以解释的维度。hot_score w1 * volume_rate w2 * velocity_rate w3 * persistence_rate w4 * authority_rate其中 volume_rate 是事件在 30 天内的讨论量归一化值代表“这件事被谈论得多不多”velocity_rate 是最近 3 天讨论量在全时段讨论量中的占比与日均占比的比值代表“它是不是正在加速”persistence_rate 是事件持续被讨论的天数占总窗口天数的比例代表“它是不是长线热度”authority_rate 是权威信源媒体、官方公告在该事件所有来源中的覆盖度代表“这个热度是不是有实质内容支撑”。权重方面我经过几轮调整最终使用的是 w10.3、w20.4、w30.15、w40.15。速度因子的权重最高因为“正在加速”的信号价值远大于“已经很多人在讨论”。这也回应了标题里那句话AI 比你先知道发生了什么本质上是因为它把“速度”纳入了判断维度而不是只看绝对值。3.2 速度因子与“爆发前夜”识别举一个具体例子来说明速度因子的威力。假设某个新消费品牌和某知名 IP 出了联名款第一周全网讨论量每天只有三五条系统里这个事件只是一个普通簇。到了第 4 天讨论量突然变成每天三十条第 5 天变成每天一百条。人眼在这个阶段可能只觉得“好像最近看到好几次”但系统算出来的速度因子已经从 0.2 跳升到 0.8热度指数瞬间进入“预警区间”。速度因子的计算方式是取最近 3 天的平均日讨论量除以过去 27 天的平均日讨论量然后做指数压缩。这样设计是为了避免“某一天突然集中爆发但第二天下线”的虚假信号。真正的热点速度因子会保持在高位至少两到三天而一次性事件通常第二天就会回落。系统会专门标记“连续两天速度因子大于 0.7”的事件这些就是真正的“爆发前夜”信号。3.3 热度排序的两个视角有了热度指数之后最开始的版本直接按 hot_score 排序生成每日推荐清单。但实际操作两周后发现一个问题排名靠前的基本都是“所有人都知道的新闻”这些根本不需要 AI 来告诉我。后来我把输出拆成两个视角。第一个视角是“热度总榜”按 hot_score 排序作为基线参考。第二个视角是“异动榜”只按 velocity_rate 排序并且过滤掉已经连续三天进入热度总榜前三的事件。异动榜的价值远大于总榜因为它列出的都是“正在涨但还没成为头条”的事件这才是“比你先知道”的核心输出。排序视角能看到什么隐藏风险按热度指数近期最重要的事件全景头部全是已知新闻价值有限按速度因子正在升温、尚未刷屏的事件噪音多需要配合持续度过滤按权威度有实质支撑的深度话题可能低估娱乐类热点的传播力4. 核心实现代码逻辑与提示词设计4.1 采集器与任务管线的代码骨架技术选型上我用了 Python 做主要开发语言。原因很简单处理 RSS、调用嵌入模型、操作数据库的生态最成熟社区资料也最多遇到问题几乎都能搜到解法。存储用了 SQLite单机跑量完全够用。嵌入模型和摘要模型分开使用嵌入模型负责算相似度摘要和趋势判断统一走大模型 API。采集器的代码骨架长这样from dataclasses import dataclass from typing import List dataclass class RawItem: title: str source: str published_at: str url: str extra: dict None class BaseCollector: def fetch(self) - List[RawItem]: raise NotImplementedError def run(self): items self.fetch() cleaned [self.clean(item) for item in items] return [item for item in cleaned if item is not None] def clean(self, item: RawItem): # 子类可覆写逐字段清洗、去空白、格式统一 return item每个数据源实现一个 BaseCollector 子类RSS 源、榜单源、社区源都统一返回 RawItem 列表。这样新接入一个数据源只需要实现 fetch 和 clean 两个方法不用动任何上层逻辑。实际开发过程中这个抽象帮我省了大量时间后期新增数据源基本是半小时以内的事。标准化之后的数据进入聚类模块def incremental_cluster(new_item, clusters, embed_model, threshold0.82): new_vec embed_model.encode(new_item.title) best_cluster None best_score 0.0 for c in clusters: score cosine_similarity(new_vec, c.centroid) if score best_score: best_score score best_cluster c if best_score threshold: best_cluster.add(new_item, new_vec) return best_cluster else: return create_new_cluster(new_item, new_vec)增量聚类的思路是每来一条新数据都跟现有的事件簇中心点算一次相似度超过阈值就归入该簇否则新建一个簇。阈值 0.82 是我在真实数据上调出来的值低于这个值会把“某公司发布新手机”和“某公司发布新耳机”错误合并成同一件事高于这个值又会让同一事件的不同报道角度散落到多个簇里。4.2 聚类阈值调参经验阈值调参这件事值得单独说一下。我第一次跑数据时随便设了一个 0.7结果把“某模型发布”和“某模型的评测合集”归成了同一件事AI 生成的摘要一团糟。后来调到 0.85又发现同一事件因为标题措辞差异被拆成了四五个小簇每个簇的讨论量都被低估了。最终采用的办法是“双阈值”标题向量相似度超过 0.85 直接合并在 0.75 到 0.85 之间时再看两个簇内关键词的重叠度重叠度超过一定比例也合并。这样既保留了同一事件不同表达方式的聚合能力又避免把不同事件硬凑在一起。这个调参过程没有任何捷径就是拿一周的真实数据反复跑、反复看聚类结果直到肉眼观察的基本合理。4.3 提示词模板摘要、解读、趋势聚类完成后每个事件簇内的原始标题会被打包交给大模型处理。提示词我设计成三个独立的任务而不是一次调用全部完成。分开调用有两个好处单个任务失败时只需要重试那一步不用浪费整次调用后面调整某个环节的提示词时不需要动其他部分。事件摘要模板你是经验丰富的新闻编辑。以下是一个事件在过去30天内出现的全部相关标题和摘要 请用三句话概括这件事的核心事实。要求客观、可验证、不包含推测。 同时给这个事件起一个简短的名字不超过12个字。 事件原始标题列表 {cluster_titles} /事件原始标题列表趋势解读模板基于以下数据判断这个事件当前处于什么阶段萌芽期/爆发期/平缓期/消退期 并说明判断依据。重点回答这件事为什么会在这个时间点被关注未来3到5天 有哪些值得关注的走向 事件信息 名称{event_name} 首次出现时间{first_seen} 最近出现时间{last_seen} 累计提及次数{volume} 最近3天日提及次数{recent_volume} 来源分布{source_distribution} /事件信息每次调用我都会把事件的时间信息、数量信息显式写进提示词。一开始我图省事只丢标题列表AI 的分析结果经常出现“这个事件近期受到关注”——这完全是一句废话。后来把数量和时间信息加进去AI 的输出才真正有了判断依据。这是我在这个项目里学到的很重要的一课模型没有数据库它只能依据你给的信息做推理信息给的颗粒度决定了输出质量。4.4 简报输出最终输出的日报格式每一条包含六个部分事件名、热度指数、速度状态、事件摘要、为什么重要、值得关注的方向。速度状态用文字描述比如“爆发前夜”“持续升温”“热度回落”这是把速度因子数值转成可阅读表达后的结果。我贴一份实际运行中生成的日报条目做参考【事件】某开源跨平台框架 GitHub Star 一周破万 【热度指数】0.83 【速度状态】爆发中连续3天速度因子0.7 【事件摘要】该项目解决了移动端与桌面端统一开发的核心痛点 本周因核心维护者公布路线图获得大量关注。 【为什么重要】已有多个知名项目宣布接入可能影响前端工具链生态。 【值得关注】预计本周内将出现更多企业级应用案例。5. 实际运行中的坑与排查5.1 数据源失效与漂移系统跑了不到一周就遇到第一个问题有几个 RSS 源突然不更新了。排查下来发现有些是源站改版导致 RSS 地址失效有些是反爬逻辑升级直接拒绝了定时请求。我的解决方案有两层一是给每个数据源做了健康检查连续三次拉取失败会在简报里标记“数据源异常”避免系统静默降级二是给关键类型的数据源做冗余——比如主流科技媒体至少保持两到三个不同源单一源失效不会导致信息盲区。5.2 AI 总结的“幻觉”问题大模型生成的摘要偶尔会出现“幻觉”内容也就是编造原文里不存在的事实。有一次系统生成的一周要闻里写“某机型因过热问题被用户集体退货”实际上原始数据里只有两条讨论散热的帖子AI 硬是推演出了“集体退货”这种耸人听闻的表述。这个问题没有一劳永逸的解法我用的是多层校验。第一层提示词里明确规定“只基于给定信息禁止推测无法验证的结论”第二层生成结果里出现“据称”“疑似”“可能”“引发争议”这类词时系统会做一次复核把事件原始标题列表再交给模型检查一遍确认结论是否有原始数据支撑。第三层最笨但最有效热度指数进入顶部的少量事件我在整个流程的最后追加一次人工抽查。这一层花不了太多时间但能及时发现提示词调整引发的大规模质量问题。5.3 “马后炮”偏差这个坑比较隐蔽。我最初判断“AI 预测准确率”时拿历史数据回放测试发现系统表现很好。但上线跑了一周后发现实际提醒的时效性没有回放测试时那么出色。原因是回放测试时我用的已经是“事件已经发生完”的完整数据模型理所当然知道后续走向实盘运行时模型只能看到过去某个时间点之前的数据判断自然有偏差。理解这个问题之后我不再追求“百分百提前预判”而是接受一个现实AI 能稳定做到的是“事件已经加速时第一时间发现”通常比普通用户刷到头条早半天到两天这在大多数场景下已经非常有价值。真正的零点预测很难因为热点爆发往往需要某个外部触发点而那可能来自任何地方。5.4 信息过载与噪音过滤跑了一个月之后事件簇越来越多日报清单从最初的二十条膨胀到六十条基本失去阅读价值。我回过头来重新设计了噪音过滤规则过滤掉单日讨论量少于阈值的簇过滤掉没有权威信源且持续度低于一天的纯粹梗图式话题过滤掉同一事件在不同平台的重复簇合并残留物。这些规则加完之后日报通常稳定在十五条到二十条之间阅读负担刚好合理。5.5 问题排查速查表症状可能原因排查思路事件簇拆得过多相似度阈值设太高降到 0.82同时看关键词重叠度不同事件被合并阈值设太低或标题太像提高阈值到 0.85增加来源约束简报出现虚构结论提示词缺少“禁止推测”约束追加复核环节检查触发词某数据源连续不更新源站改版或地址失效看健康报告补同类冗余源日报越来越长噪音过滤规则不足增加最小讨论量和权威度门槛预测时效性差用了事后数据回测改用增量窗口模拟实盘验证最后再分享一个小技巧。我每周会抽五分钟回看上周系统标出的“爆发前夜”事件把“确实很快刷屏”的标记为命中把“根本没起来”的标记为误报然后把误报的分发回给分析模块作为下一周阈值调整的参考。这个环节看着简单实际对提升准确率帮助非常大因为它相当于给系统做每周一次的人工评测反馈。AI 追热点这件事本质上是把“热点为什么会热”这个模糊问题拆成可计算、可迭代的小问题你喂给它的反馈越多它越清楚你想要的“知道”是哪一种。