做 AI 日报这个项目,最初是因为我每天要盯着十几个信息源去找值得读的AI动态,结果经常被重复推送、标题党和低质量转载折腾得头大。后来我给自己的工作流加了一个自动采集+大模型摘要的中间层,每天固定时间生成一份面向个人或团队的简报。严格来说,这篇文章不是一篇当天的新闻快讯,而是关于“如何搭建一套AI日报自动化生产线”的踩坑记录;文里涉及 2026 年 10 月 4 日的字段,都是演示流程中写死的示例日期,不代表对当天具体事件的描述。如果你也在做类似的信息聚合产品,或者想给自己组一套“早报流水线”,下面这些环节会非常值得参考。
1. 项目整体设计:为什么不直接“定时抓取+粘贴发送”
很多人一开始会把AI日报理解得很简单:每天跑一次爬虫,把抓到的标题拼起来,发到群里就算完事。但真按这个思路做,第一天就会翻车。抓回来的内容经常重复、过时、夹杂大量噪音;你花在“删掉无关内容”上的时间,可能比手动整理还多。所以整个项目的核心不是“抓取”,而是“筛选和可信度控制”。
1.1 核心需求:不是“让信息变多”,是“让信息变少”
日报的第一职责是帮读者节省时间。这意味着系统必须把一天里几十上百条原始动态,压缩成五到十条真正值得看的重点。压缩策略不能只按时间排序,也不能只按热度排序,而是要做多维度加权:官方公告类动态权重最高,权威媒体转载其次,论坛揣测和二手印象再往后排。
你在实际配置权重时,可以先用一张小表把自己的偏好写清楚,再转化为分数。比如“是否涉及新模型发布”加5分,“是否涉及重大版本升级”加4分,“是否带有可复现链接”加3分,“是否属于某平台内部消息”只加1分但不能作为头条。这样生成的日报才像一个真正懂行的编辑做的,而不是爬虫随手堆出来的转储。
1.2 功能模块拆解:把一条流水线拆成六个环节
我最终把系统拆成了六层:采集层、清洗层、去重层、排序层、摘要层、发布层。每层只做一件事,层与层之间用结构化数据传递,避免互相牵扯。
- 采集层:定时抓取各信息源的最新条目,统一转成内部消息格式。
- 清洗层:去掉HTML标签、过滤广告位、修正编码和时间字段。
- 去重层:根据URL特征和文本相似度识别相同事件的不同转载。
- 排序层:结合时效、来源可信度、热度信号计算当日最终顺序。
- 摘要层:把原文交给大语言模型,生成适合日报的短摘要和关键点。
- 发布层:把结果渲染为Markdown/HTML文本,推送到邮箱、群机器人或静态站点。
这样拆的好处是任何一环出问题都可以单独替换。比如摘要模型不好用,直接换模型接口,不用动采集逻辑;某个站源经常超时,把它在采集列表里标记降级,也不影响其他源继续工作。
1.3 方案选型:为什么选“规则调度+大模型摘要”的组合
有朋友建议我直接用大模型写一份“今日AI综述”,说这样最省事。我试过,效果不稳定。纯靠大模型驱动整个日报,模型很容易把不同来源的信息混在一起,甚至为了逻辑通顺编造细节。更稳的做法是:用规则保证“来源是什么、什么时候发布、链接对不对”,用大模型负责“怎么总结、怎么突出看点”。前者是确定性的,后者是生成性的;两者各管一摊,才不容易互相拖累。
这个思路也决定了项目的整体成本。没有大模型也能跑,只是摘要会变成“截取原文前几句话”,可读性差很多。有了大模型后,单条摘要的耗时约在一到三秒,一天的日报候选量假设是五十条,也就两分钟左右的模型调用量,成本完全可控。
2. 信息源治理:日报的质量上限由源头决定
不管摘要有多强,源头垃圾进来,出来的日报依然是垃圾。信息源治理是这套系统里最朴素也最容易被低估的环节。
2.1 信息源怎么选:官方公告优先,社交热榜二次核实
我选源时有个原则:能用公开接口就拿公开接口,能看官方公告就不看二手讨论。列表里可以分成三个梯队。
| 信息源类型 | 典型内容 | 更新频率建议 | 优先级 |
|---|---|---|---|
| 官方公告与文档 | 模型版本发布、平台功能上线、规则变更 | 每1小时一次 | 最高 |
| 技术社区与媒体 | 深度解读、工具评测、应用案例 | 每2小时一次 | 中 |
| 社交平台热榜/讨论 | 行业风向、爆料、用户反馈 | 每4小时一次 | 低,只作线索 |
这里有个容易被忽略的细节:热度榜上的话题不一定都值得进日报。一个话题冲上热榜,可能只是因为它争议大,不代表它在技术上前进了一步。所以我把热榜类信息源单独放在“候选池”,只有它同时满足“有真实事件来源”和“有可追溯链接”两个条件,才会被提升为日报候选。
2.2 增量采集与字段归一化
采集频率不是越高越好。很多站点并不希望被高频抓取,适当降低频率反而更稳定。我采用最常见做法:每次采集后,记录每个条目的唯一ID和发布时间,下次只取比这个ID更新的内容。这样即使定时任务跑漏了一次,也不会重复推送旧内容。
伪代码大概是这样的:
def fetch_and_delta(source): items = source.fetch() for it in items: item_id = hash_url(it.url) if item_id in seen_ids: continue seen_ids.add(item_id) save_to_queue({ "id": item_id, "source": source.name, "title": clean_html(it.title), "content": clean_html(it.content), "url": it.url, "published_at": normalize_time(it.published) })normalize_time这一步特别重要。不同源返回的时间格式五花八门,有的带时区,有的只有相对时间“3小时前”,有的干脆是字符串但缺小时。我会在清洗层里统一转为带时区的ISO格式,后面排序才不会出现“昨天20点”排到“今天凌晨”前面的尴尬。
2.3 去重:处理同一事件的三种马甲
同一条新闻会有不同马甲:同一家媒体改个标题重发、不同媒体转述同一份官方文档、社区里出现“转帖转帖再转帖”。如果不去重,一份日报里可能出现四条内容其实都在说同一件发布。
最简单的去重是URL去重,解决不了标题改写问题。我建议再做一次相似度判断。技术含量不必太高,算一下标题的公共前缀和正文开头的语义向量余弦相似度就够了。相似度超过0.82的就合并成一条,保留原始来源优先级最高的那个。
需要注意相似度阈值不能设得太高。AI领域里“模型A发布”和“模型B发布”可能长得很像,但它们是两件事。我调参后的经验是:标题相似度要结合关键词做二次判断;如果两篇文章都提到同一组模型代号和同一组性能数字,才认为是重复事件。
3. 摘要生成与人工复核:模型只做草稿,人做终审
日报成败的另一个关键时刻,是“从原料到成文”。这部分的工具箱其实只有一个核心提示词模板,但坑都在细节里。
3.1 我最终在用的摘要提示词模板
给模型的输入尽量结构化。我会把原始标题、原始摘要、发布时间、来源类型组装好,一起丢给模型,并要求只返回固定JSON格式的结果。下面是我调过很多版后的提示词骨架:
你是AI行业日报编辑。我提供候选新闻的原始信息,你负责生成日报条目。 要求: 1. 摘要控制在80字以内,覆盖事件主体、核心变化、影响范围; 2. 使用客观陈述句,禁止出现“小编”“震惊”“重磅”“突破性”等空泛用词; 3. 如果原文信息不足以支撑结论,必须输出unknown,不得自行脑补; 4. 每条输出格式为JSON,字段包括headline、summary、impact、confidence; 5. 只依据给定原文,不依赖你记忆中的背景信息。 原始信息: 标题:{{TITLE}} 正文摘要:{{RAW_TEXT}} 发布时间:{{PUBLISH_TIME}} 来源类型:{{SOURCE_TYPE}}模板里最关键是第四和第五条。第五条能有效降低模型把“训练数据中的旧闻”当成这条新闻铺垫的风险。再加上固定JSON格式,下游解析很容易,即使某个条目失败,也不会整个流程崩溃。
3.2 幻觉与时效性控制:模型最常犯的两个“低级错误”
大模型摘要看起来极其自信,但它在做日报时最常犯两类错误。
第一类是日期混淆。它不理解“现在”是什么时候,很容易把文章正文里的旧日期当成最近事件。解决方法是在提示词里显式注入系统当前日期,并在返回结果里增加一个published_at字段,由程序校验这条摘要对应的时间是否在当天时间窗内;如果模型返回的发布时间和原始发布时间相差超过48小时,直接丢弃。
第二类是数据脑补。比如原始文本只说“推理速度提升”,模型可能顺手写成“推理速度提升30%”。这不是它说谎,是它在做语言连贯性补全。解决办法是要求所有数字必须能在原文中找到对应原文片段,否则置空。我在代码里做了一层正则校验:输出里出现%、倍、秒、毫秒等关键词时,必须能在原文中匹配到同字符串,否则该条目的confidence强制降级。
3.3 人工复核边界:不是每条都要人眼看过
如果日报有五十条候选,每一条都人工核对,自动化就失去意义了。我的做法是分三级:
- L0级:来自官方公告源且字段完整,直接进入日报候选。
- L1级:来自转载源,但能和官方公告匹配,可以保留但降低排序。
- L2级:涉及数字、版本号、企业战略判断的条目,必须人工看一遍再决定是否进日报。
实际运行下来,人工处理的量大概是每天五到八条,集中在“值得放进头条”的候选上。人工复核时我看三件事:标题是否和原文一致、数字是否精确、该条会不会引起误导。尤其最后一点,AI行业内很多说法只是一家之言,需要在摘要里标注“该观点来自某方,尚未被独立验证”。
3.4 输出样例:一天的日报候选长什么样
下面是我跑通流程后得到的一个占位示例。它只是模板的呈现效果,不代表当天真实新闻事件。
{ "published_at": "2026-10-04T08:00:00+08:00", "items": [ { "headline": "某团队发布轻量级端侧多模态模型", "summary": "该模型可在低算力设备上离线运行,重点优化图像理解与语音输入延迟,官方公布了几项基准测试数据。", "impact": "对端侧AI应用开发有直接借鉴意义,但基准数据来源单一。", "confidence": 0.9 } ] }本来摘要阶段我也试过直接输出自然语言长段落,后来发现固定JSON让后续排版、筛选、失效处理都简单太多。日报这种场景,宁可格式死板一点,也不要让模型自由发挥。
4. 定时调度与发布:把日报变成“没人管也自动跑”的服务
前面几步是单次流程,真正让它成为“日报”的关键是定时调度和发布通道。这部分的坑主要不在代码,而在运维习惯。
4.1 用定时任务把流程串起来
我用调度器定时执行整个流程,并强制加上两个保护措施:互斥锁和超时上限。互斥锁保证上一次任务没跑完时,下一次不会并发启动;超时上限避免某个信息源卡住后整条流水线停摆。
以cron为例,一个标准的每日执行可以写成:
30 7 * * * cd /opt/ai-daily && ./run_daily.sh >> logs/$(date +\%Y-\%m-\%d).log 2>&1脚本内部结构其实就四步:先采集,再清洗去重,然后调模型做摘要,最后把结果发布到目标通道。每次执行之后,在日志文件里记录每条候选的去留原因,比如“因相似度重复被合并”“因超过48小时被过滤”“因无来源链接被打回人工池”。这些日志是后面调优最重要的依据。
4.2 发布通道怎么接:从群机器人到静态站点
日报发布并不需要做成一个复杂应用。最简单也最实用的通道有三种。
第一种是文档仓库方式:把日报渲染成Markdown文件,提交到代码仓库,通过持续集成服务自动部署到静态站点。好处是历史日报全部沉淀下来,方便检索,也不需要维护独立的服务器。
第二种是消息机器人方式:通过Webhook把日报推送到团队群或自己的私人群。这种方式反馈最快,适合每天早会同步,但要注意推送内容里别带难以阅读的Markdown复杂表格,尽量用短段落和列表。
第三种是邮件方式:把日报以纯文本或简单HTML发送到订阅邮箱。实现成本也不高。我个人最喜欢的方式是“仓库文件+群机器人双发”,一个留档,一个提醒,两全其美。
4.3 用占位日期跑通全流程:2026年10月4日
为了验证系统的日期处理逻辑,我把当天时间参数固定为 2026 年 10 月 4 日跑了一遍完整流程。占位日期的好处是可以测试“跨日”“跨周”逻辑,确保第二天的增量采集不会把前一天内容重复拾起。
测试结果里有几个关键观察值得记录:时间格式化在不同系统下容易出错,最稳妥的做法是全部在服务端用同一时区统一运算,只在最终展示时转换为读者时区;信息源的时间如果缺失,宁可跳过也不要猜测补一个默认时间,猜测会把排序搞乱。
5. 常见问题与排查实录:稳定运行一个多月后踩到的坑
任何自动化系统跑到第三周就会开始出各种莫名其妙的零碎问题。下面是我整理的一张排查速查表,基本覆盖了日常维护的大部分场景。
| 现象 | 可能原因 | 处理方案 |
|---|---|---|
| 日报某条摘要里出现“昨晚”,但发布时间其实在白天 | 模型把相对时间写进了输出 | 提示词禁止输出相对时间,发布前用正则检查“昨晚”“今天上午”等词 |
| 多个信息源反复推送同一条行业动态 | 去重相似度阈值设太高 | 把阈值从0.95降到0.82,并增加关键词匹配补充判断 |
| 某个源连续三次采集返回空列表 | 对方修改了页面结构或停更 | 调整解析规则,采集失败连续计数,达到阈值后自动摘除该源 |
| 摘要中出现原文没有的数字 | 模型在补全上下文 | 强制校验“原文是否包含该数字”,不包含则置为unknown并降级 |
| 定时任务偶尔漏跑 | 调度器所在设备休眠或重启 | 增加健康检查和“错过补跑”机制,任务启动时先判断今天是否已生成 |
| 推送消息里Markdown渲染错乱 | 模型输出包含不配对标记 | 发布前做格式化清洗,统一为白名单标记 |
| 人工复核池堆积大量低质内容 | 源头质量变差 | 降低该源权重,或提高进入人工池所需的分数门槛 |
5.1 训练数据污染:模型把“旧闻”当成“今日新闻”
这是最隐蔽的问题之一。大模型面对一条语义模糊的标题时,有时会从自己的训练记忆里补一段看似合理的背景,导致日报里出现不准确的历史描述。
我的解决办法是在提示词的“原始信息”区域加一行“已知发布时间”,并在后置校验里增加一个规则:摘要文本中出现的历史年份,不能早于文章发布时间超过一年;如果出现,就把摘要标记为confidence:0.5并转人工。这样做虽然不能彻底杜绝,但能显著减少日报告诉读者“一台旧型号设备发布新功能”这种别扭状况。
5.2 来源不可用时的优雅降级
有一次,我依赖的一个核心官方源连续半天不可用,当天日报的候选量直接少了一半。最初我没有做降级,结果日报变得非常单薄。后来我加了级联策略:优先读取官方源;官方源失败时,自动去读这个官方源关联的媒体转载作为替代;如果替代也没有,就等下一个采集周期,而不是把空档强行填上低质内容。
这里要克制住“宁可错塞也不能空着”的冲动。对于日报产品,空一天比错一天更容易被接受;错了会消耗读者的信任。
5.3 定时任务重复执行的锁机制
cron本身不保证同一时间只有一个进程在跑。如果某次采集耗时特别长,下一次调度又触发了,就可能出现两个流程同时写一个输出文件。我的防止办法是加一个文件锁目录,任务启动时先尝试创建锁文件,创建失败就直接退出,并在日志里标记“skipped because previous run still running”。
用伪代码来表示就是:
if not acquire_lock("/tmp/ai-daily.lock"): log("previous run still running, skip") exit(0) try: run_daily() finally: release_lock("/tmp/ai-daily.lock")这个锁还能帮你做另一件事:如果某次任务中途崩溃,锁没释放,下次任务会被卡住。所以要给锁加有效期,比如超过三十分钟自动释放,并通知维护人员。
5.4 监控与告警:日报系统也需要被“日报”
日报系统如果只是每天早上默默跑,出了问题你可能第二天才发现。最好的状态是给它自己加一条“日报”:每天任务成功后,把采集条数、去重比例、模型调用耗时、发布结果一并汇总,推给维护者自己。
我用过最简单的做法:在发布通道后面追加一条“系统运行摘要”,读者看不到,维护通道里能看到。这样既能确认系统活着,也能提前发现某个源的数据量突然下降,在用户察觉之前做修复。
回头看我整个搭建过程,最花时间的其实不是采集代码,也不是模型提示词,而是不断调整“什么内容值得进日报、什么内容不值得”的判断标准。AI日报最容易犯的错就是什么都想装进去,最后变成一份噪音放大器。做信息聚合产品,筛选和克制才是真正的核心能力。希望这篇记录能帮你在搭建自己的日报系统时少走一些弯路。