从零搭建AI日报自动化系统:信息聚合、筛选与摘要的工程实践
1. 当“日报”变成一种自动化流水线我为什么要做这件事每天早上八点半我端着咖啡坐到工位第一件事不是看邮件而是打开十几个信息源把过去二十四小时里值得关注的动态过一遍。这个习惯保持了三年多直到某天我意识到光是“筛选”这个动作每天就要吃掉我将近四十分钟。更麻烦的是信息源越多漏掉重要内容的概率反而越高——因为注意力被大量低价值内容稀释了。“AI 日报”这个项目本质上就是把我这套手动流程自动化。它的核心目标很朴素在每天固定时间把分散在各处的信息聚合、去重、排序、摘要最终输出一份可以直接阅读的简报。听起来像是一个简单的爬虫加模板渲染但真正动手之后才发现从“能跑”到“每天稳定跑、内容质量可控”中间隔着一整套工程化的坑。这篇文章适合两类人看。一类是和我一样有信息聚合需求、想自己搭一套日报系统的开发者另一类是正在做内容聚合类产品、需要处理多源异构数据的同行。我会把整个系统的设计思路、关键取舍、踩过的坑以及那些文档里不会写的经验尽量完整地摊开来讲。你不需要有很深的机器学习背景但需要对基本的后端开发和数据处理有概念。先说结论这套系统目前每天处理约两百条原始条目经过筛选后保留十五到二十五条进入日报端到端耗时控制在三分钟以内运行成本主要是模型调用费用一个月下来在可接受范围内。下面我从架构开始一层一层拆。2. 信息源接入为什么我没有用“万能爬虫”2.1 信息源分类与接入策略做聚合系统的第一步永远是搞清楚“数据从哪来”。我最初的想法很天真写一个通用爬虫配置不同的选择器什么源都能抓。实际跑了两周就放弃了原因很简单——不同信息源的更新机制、内容结构、反爬策略差异太大强行统一只会让维护成本指数级上升。我最终把信息源分成了三类每类用不同的接入方式源类型典型特征接入方式更新频率结构化接口类有公开的 API 或 RSS 输出直接消费接口实时或准实时半结构化页面类页面结构稳定但无接口定向解析 缓存每小时轮询非结构化聚合类内容混杂、格式不统一人工配置规则 模型辅助每天一次这个分类的关键在于不要试图用一种技术方案解决所有源。结构化接口类最省心直接按字段映射就行半结构化页面类需要写针对性的解析逻辑但页面结构一旦稳定维护量很小非结构化聚合类最麻烦往往需要结合规则和模型来做内容提取。2.2 轮询频率与增量抓取的取舍轮询频率是个容易被忽视但影响很大的参数。我一开始把所有源的轮询间隔都设成十分钟结果发现两个问题一是部分源更新频率根本没那么高大量请求是浪费二是高频轮询容易触发源站的限流机制导致 IP 被临时封禁。后来我改成按源的实际更新节奏来配置。具体做法是先跑一周的观察期记录每个源的实际更新时间分布然后据此设定轮询间隔。比如某个源固定在每天上午九点和下午三点更新那就没必要全天候高频轮询只需要在这两个时间点前后加密检查即可。增量抓取的核心是去重。我的做法是在入库时对每条内容生成一个指纹指纹由标题的规范化文本加来源标识组成。这里有个细节标题规范化不能简单地转小写去空格还要处理全角半角、标点符号差异、以及常见的标题前缀比如“【重磅】”“快讯”这类。我踩过的坑是早期没做前缀清洗导致同一篇文章因为标题前缀不同被当成两条内容日报里出现了重复条目。提示去重指纹的生成逻辑建议单独抽成一个模块方便后续调整规则时不影响主流程。我现在的指纹模块已经迭代了四版每次都是因为发现了新的重复模式。2.3 源站变更的监控与告警信息源接入最怕的不是一开始接不上而是接上了、跑了一段时间、然后源站悄悄改了结构。这种情况往往不会报错而是静默地返回空数据或者错误数据等你发现的时候可能已经漏了好几天的内容。我的应对方案是给每个源加一个“健康检查”机制。具体来说每次抓取后记录三个指标返回条目数、解析成功数、内容长度中位数。如果某个源的返回条目数突然降到历史均值的百分之二十以下或者解析成功率跌破百分之八十就触发告警。告警方式很简单发一条消息到自己的通知渠道就行。这个机制帮我抓到过好几次源站改版。有一次某个源把文章列表从分页改成了滚动加载我的解析逻辑直接返回空健康检查在第一次抓取后就报了警前后不到半小时就修复了。3. 内容清洗与筛选把噪音挡在日报之外3.1 为什么“全量摘要”是个陷阱系统刚跑通的时候我犯了一个典型错误把所有抓到的内容都丢给模型做摘要然后全部塞进日报。结果日报长达几十条阅读体验极差而且大量内容其实是重复的、低价值的、或者跟我的关注领域无关的。问题的本质在于摘要解决的是“读得快”但筛选解决的是“读什么”。如果源头没有做好筛选摘要只会让你更快地读完一堆不需要读的东西。所以我后来把流程改成了“先筛选、后摘要”。筛选分两层第一层是规则筛选第二层是模型打分。规则筛选负责处理那些确定性高的判断比如来源白名单、关键词黑名单、发布时间窗口模型打分负责处理那些需要语义理解的判断比如内容的相关性、信息密度、是否属于观点输出而非事实陈述。3.2 规则筛选层的设计细节规则筛选层看起来简单但细节很多。我列几个实际用到的规则和背后的考虑时间窗口只保留过去二十四小时内发布的内容。但这里有个坑——有些源的时间戳是“最后更新时间”而非“发布时间”如果一篇文章被编辑过时间戳会变新导致旧内容被误判为新内容。我的处理方式是优先取发布时间字段取不到时才用更新时间并且在指纹里加入首次抓取时间来做二次校验。来源权重不同来源的可信度和信息密度不一样。我给每个源设了一个基础权重权重高的源在后续排序中会获得加成。权重的设定没有绝对标准我的做法是先给所有源相同权重跑两周后根据实际阅读体验手动调整。关键词规则这部分要特别小心。早期我设了一批“必须包含”的关键词结果发现很多有价值的内容因为用词不同被误杀。后来改成“加分制”而非“过滤制”——命中关键词加分但不命中不扣分最终由模型打分来决定是否入选。3.3 模型打分的提示词设计模型打分是整个筛选流程里最需要反复调试的部分。我试过很多种提示词写法最终稳定下来的版本有几个关键设计第一给出明确的评分维度和分值范围。不要让模型自由发挥而是让它按“相关性”“信息密度”“时效性”三个维度分别打分每个维度一到五分最后加权求和。这样输出的结果更稳定也方便后续调整权重。第二提供正例和反例。在提示词里放几条“应该入选”和“不应该入选”的示例模型的判断准确率会明显提升。示例不需要多每个方向两三条就够了。第三要求模型输出理由。虽然理由本身不直接用于筛选但它有两个好处一是方便我排查误判二是模型在“解释为什么”的过程中判断往往更准确。# 打分提示词的核心结构示意 prompt_template 你是一个内容筛选助手。请对以下内容按三个维度打分1-5分 1. 相关性内容是否属于技术/行业动态范畴 2. 信息密度是否包含具体事实、数据或可验证的信息 3. 时效性内容是否具有当下参考价值 评分标准 - 5分完全符合信息量大时效性强 - 3分部分符合有一定信息量 - 1分基本不符合 参考示例 [正例] ...此处省略具体示例内容 [反例] ...此处省略具体示例内容 待评分内容 标题{title} 正文{content} 请以JSON格式输出{relevance: x, density: x, timeliness: x, reason: ...} 实测下来这套打分机制能把两百条原始内容压缩到三十条左右进入候选池再经过人工规则微调最终日报稳定在十五到二十五条。4. 摘要生成从“能读”到“好读”的距离4.1 摘要长度的动态控制摘要不是越短越好也不是越长越好。我最初的设定是固定两百字后来发现不同类型的内容适合不同的摘要长度。比如一条产品更新公告一百字就能说清楚而一篇技术分析文章可能需要三百字才能保留核心论点。现在的做法是根据内容类型动态调整摘要长度。具体来说在打分阶段就让模型判断内容类型公告类、分析类、观点类、数据类然后按类型映射到不同的目标字数区间。公告类控制在八十到一百二十字分析类控制在两百到三百字观点类控制在一百五到两百字。这个调整带来的阅读体验提升很明显。以前固定长度时公告类摘要显得啰嗦分析类摘要又丢了很多关键信息。4.2 保留原始信息 vs 重新组织语言摘要生成有一个根本性的取舍是尽量保留原文的表述还是让模型用自己的话重新组织两种方式各有优劣。保留原文表述的好处是信息保真度高不容易出现事实性错误坏处是可能保留了大量冗余表达读起来不够精炼。重新组织语言的好处是可读性强、逻辑更清晰坏处是模型可能在重组过程中引入偏差或遗漏。我的选择是混合策略对于事实性内容数据、时间、名称要求模型原样保留对于描述性内容允许模型重新组织。在提示词里明确区分这两类信息的处理方式能显著降低摘要出错的概率。4.3 摘要质量的自动检查摘要生成之后我加了一道自动检查。检查项包括长度检查是否落在目标区间内关键实体检查原文中出现的人名、产品名、数字是否在摘要中保留重复检查摘要是否与原文高度重复说明模型没有做有效压缩格式检查是否包含多余的标记符号或未完成的句子任何一项不通过就触发重新生成。重新生成时会在提示词里附加具体的失败原因比如“上次生成的摘要遗漏了以下关键实体xxx请确保本次包含”。这道检查帮我拦住了不少问题。有一次某个源的文章里包含一个关键数字模型连续两次都漏掉了第三次在提示词里明确要求后才正确保留。如果没有这道检查这个错误就会直接进入日报。5. 日报排版与分发最后一公里的体验优化5.1 日报的结构设计日报的排版看起来是小事但直接影响阅读体验。我试过几种结构最终稳定下来的版本包含四个部分第一部分是今日概览用三到五句话概括当天最重要的几条动态。这部分由模型基于入选内容生成帮助读者快速判断今天有没有值得细读的内容。第二部分是分类列表按内容类型分组展示每条包含标题、来源、摘要和原文链接。分类的粒度不能太细我目前用的是“产品与工具”“行业动态”“技术分享”三个大类。第三部分是深度推荐从当天内容中挑出一到两条信息密度最高的附上更详细的摘要和推荐理由。这部分是人工规则加模型打分共同决定的。第四部分是数据统计简单展示当天处理了多少条原始内容、筛选掉了多少、最终入选多少。这个部分对普通读者意义不大但对我自己监控系统运行状态很有用。5.2 分发渠道的选择与适配分发渠道我试过三种邮件、即时通讯工具、静态页面。最终保留的是即时通讯工具加静态页面组合。即时通讯工具的好处是触达及时适合快速浏览坏处是长内容阅读体验差而且历史消息不好检索。静态页面的好处是排版自由、便于归档和检索坏处是需要主动打开触达率低。我的做法是即时通讯工具推送精简版概览加标题列表静态页面承载完整版。推送消息里附上静态页面的链接想看详细内容的人点进去就行。5.3 异常情况的兜底处理系统跑久了总会遇到各种异常某个源挂了、模型接口超时、摘要生成失败。这些异常如果处理不好轻则日报内容缺失重则整个流程中断。我的兜底策略分三层第一层是重试机制。对于接口调用类的操作失败后自动重试两次每次间隔递增。大部分临时性故障都能通过重试解决。第二层是降级处理。如果某个源连续失败就跳过该源继续处理其他源同时在日报末尾标注“今日以下来源未能获取内容”。这样至少保证日报能正常发出不会因为一个源的问题导致整体失败。第三层是人工介入告警。如果核心流程比如模型调用连续失败超过阈值就发告警通知由我手动检查处理。注意降级处理一定要在日报里明确标注否则读者会以为当天没有相关内容而不是系统出了问题。这个细节很容易被忽略但直接影响读者对系统的信任度。6. 运行成本与稳定性那些跑久了才会暴露的问题6.1 模型调用的成本控制模型调用是这套系统的主要成本项。我算过一笔账每天两百条内容每条内容打分加摘要两次调用按当时的模型价格一个月下来是一笔不小的开销。控制成本有几个方向。一是减少不必要的调用比如规则筛选能确定排除的内容就不要送去模型打分。二是合并调用把打分和摘要合并成一次调用让模型同时输出评分和摘要比分开调用省将近一半的费用。三是缓存复用对于重复内容指纹相同直接复用之前的处理结果。我目前用的是合并调用的方案提示词里同时要求输出评分和摘要实测效果和分开调用差别不大但成本明显下降。6.2 长期运行中的数据积累系统跑久了会积累大量数据抓取记录、评分结果、摘要文本、读者反馈。这些数据如果只是存着不利用就浪费了。我目前用这些数据做两件事。一是优化筛选规则通过分析历史入选和落选内容的特征差异调整打分权重和规则参数。二是监控源质量统计每个源的入选率入选率持续偏低的源可以考虑降权或移除。这里有个经验不要频繁调整规则。我早期每天看数据每天调结果系统行为很不稳定今天入选的内容明天可能就被筛掉了。后来改成每周回顾一次只在有明确证据时才调整系统表现反而更稳定。6.3 我踩过的三个典型坑第一个坑是时区问题。系统服务器用的是协调世界时但我的时间窗口判断用的是本地时间导致每天早上的日报会漏掉一部分内容。修复方式是在所有时间比较的地方统一时区并且在配置里明确标注时区设置。第二个坑是编码问题。部分源返回的内容包含特殊字符直接入库会导致后续处理报错。修复方式是在入库前统一做编码清洗把非法字符替换掉。第三个坑是并发控制。早期为了追求速度所有源并行抓取结果触发了某个源的限流导致整个 IP 段被临时封禁。后来改成了按源分组、组内串行、组间并行的策略既保证了速度又避免了触发限流。7. 后续可以继续打磨的方向这套系统目前运行稳定但还有不少可以优化的空间。我列几个自己在考虑的方向给有类似需求的同行参考。第一个方向是个性化排序。现在的排序是全局统一的但不同读者的关注点其实不一样。如果引入读者反馈比如点击、收藏行为就可以做个性化的排序调整。不过这个方向需要先有足够的读者数据目前还在观察阶段。第二个方向是多语言内容处理。现在的系统只处理中文内容如果扩展到多语言需要在清洗和摘要环节增加语言识别和翻译的步骤。技术上是可行的但会增加不少复杂度暂时没有动手。第三个方向是历史内容的关联分析。现在每天的内容是独立处理的如果能把当天内容和历史内容做关联比如识别出“某个话题连续多天出现”就能提供更有深度的洞察。这个方向我觉得很有意思但需要先解决历史数据的索引和检索问题。最后分享一个我在实际运行中体会最深的心得自动化系统的价值不在于完全替代人工而在于把人工从重复劳动中解放出来让人可以专注于判断和决策。我现在的日常操作是每天早上花五分钟浏览日报标记几条值得深读的内容剩下的时间用来做真正需要思考的事情。这个状态比我当初手动刷信息源的时候效率高了不止一个量级。