从零搭建 AI 日报系统:一个每天 08:00 推到你手机上的自动机器人
我一直挺烦刷 AI 新闻的。不是不想看,是好内容散在几十个网站和一二十个社交媒体账号里,每天早上要打开七八个标签页慢慢扫,扫到一半就被别的事打断。我对自己说,能不能有一件东西:每天早上准点推到我微信上,就干一件事——告诉我昨天 AI 圈发生了什么值得看的事。
日报搭建系列四篇:① AI 日报(本文) → ② 华尔街日报 → ③ Crypto 日报 → ④ A 股收盘分析 | 这四篇共享同一副骨架:多源采集 + LLM 提炼 + JSON 归档 + cron 调度 + Flask 渲染。第一篇讲骨架本身,后面三篇换数据源。
这篇文章就是这件东西的搭建过程。和我之前的踩坑复盘不同,这篇是一份能照着做、能复现的指南。从选择第一个 skill、到整合三条信息源、到把它塞进 cron、到上线后踩的几个坑和修法。不需要服务器、不写一行爬虫代码,所有东西都在 Hermes Agent 里跑。
一、先想清楚:这个系统的数据流
做之前花几分钟把数据流想清楚。搭过自动化的人都知道,架构先画对,后面只是往里面填 skill。
我画下来是这样的:
三条信息源(并行采集)
├── 1. RSS 聚合(100+ 英文科技/AI 源)→ 按 7 个分类取 10 条
├── 2. AI HOT 公开 API(中文精选,人工标注)→ 按 selected 模式查
└── 3. 英文→中文翻译(The Verge / Wired / TechCrunch)→ 抓取+翻译
↓ 三路并行(三个 delegate_task 子代理)
一条 LLM(deepseek-v4-pro)→ 提炼 / 分类 / 去重 / 压缩
↓ 写入 JSON
前端渲染(Flask + Jinja2)→ 用户打开网页就能看
核心设计点就一个:采集和提炼分开。三路采集可以乱、可以有的路没数据(比如周末某源不更新),但提炼那步只用对采集回来的内容做一次处理。这样万一哪天某个采集链路挂了,剩下的两队数据照样能出一份可用的日报。
二、第一条信息源:RSS 聚合
我翻了一下 Hermes skill 列表。Hermes 有个好处是 skill 目录是公开的,不用猜"有没有这个功能",直接 skillhub search 就能查。
搜 news,第一个命中的就是 ai-news-aggregator——这是一个 RSS 聚合器,背后有 100+ 个英文 AI/科技信息源。它的核心用法只有一条命令:
python3 ~/.hermes/skills/ai-news-aggregator/scripts/rss_aggregator.py \
--category all --days 1 --limit 10 --json
输出是按分类组织的标题和链接列表。我跑到它脚本目录下看了一眼,分类分得挺细:
| 分类 | 覆盖内容 | 日常稳定性 |
|---|---|---|
all |
全部源(默认,10 条/分类) | 稳定,每天上百条 |
company |
OpenAI / Google / Anthropic / 等大厂动态 | 稳定 |
ai-agent |
AI agent 技术进展 | 中等,周末偏稀疏 |
cn_media |
中文科技媒体报道 | 稳定 |
所以第一步很简单:把这个 skill 装上(skillhub install ai-news-aggregator),每天用默认参数跑一遍拿前一天的 RSS 聚合结果,作为日报的"主干"。
三、第二条信息源:AI HOT 公开 REST API
RSS 聚合能抓体量,但有个短板——它只是标题和链接。你拿到的是一堆"Google 发布 Gemini 2.0"这种级别的标题,但没有正文摘要,"这条新闻到底什么意思"还得点进原文。
这时候找到了第二个源:aihot skill。AI HOT 是一个中文 AI 资讯聚合站(aihot.virxact.com),核心价值是人工标注+机器辅助筛选。它每天有个"精选条目",由编辑挑出当天最重要的几条,带中文摘要。而且它是完全公开的 REST API,不需要注册、不需要 token。
核心 API 只有一条:
# 获取过去 24 小时的精选条目(带中文摘要)
curl -s "https://aihot.virxact.com/api/public/items?mode=selected&since=1d"
有几种查询模式:
| 查询意图 | API 调用 | 返回 |
|---|---|---|
| 今天有什么大事 | GET /api/public/items?mode=selected&since=24h |
精选 ~15–25 条 |
| 想看完整的日报 | GET /api/public/daily |
完整日报 JSON |
| 搜某个公司/话题 | GET /api/public/items?q=OpenAI |
关键词搜索结果 |
| 全量(不分好坏) | GET /api/public/items?mode=all |
全部收录 |
注意一个小细节:AI HOT 的 /api/public/* 路径做了反黑产爬虫拦截,默认 curl/X.Y 的 User-Agent 会被 403。调用的时候必须跟一个浏览器的 UA:
curl -sH "User-Agent: Mozilla/5.0" "https://aihot.virxact.com/api/public/items?mode=selected&since=24h"
这个源填补了 RSS 聚合的缺口:RSS 给体量和广度,AI HOT 给精选和中文摘要。
四、第三条信息源:英文→中文翻译管线
前两条信息源都是英文为主。但微信上推给用户的日报必须是中文。RSS 的标题可以靠大模型翻译,但比较长的文章摘要、或者比较关键的产品发布细节,靠标题翻译容易丢信息。
所以加了第三条信息源:ai-news-zh。这个 skill 直接从 The Verge、Wired、TechCrunch 等英文网站的 AI 板块抓取最新文章,用大模型翻译成中文摘要。
核心操作方法是一次传入 5 个 URL 做并行抓取(web_extract 支持一次传一个数组):
web_extract(urls=[
"https://www.theverge.com/ai-artificial-intelligence",
"https://www.wired.com/tag/artificial-intelligence/",
"https://techcrunch.com/category/artificial-intelligence/"
], char_limit=20000)
三条信息源的定位:
| 源 | 给什么 | 语言 | 短板 |
|---|---|---|---|
| RSS 聚合 | 标题 + 链接,体量大、覆盖面广 | 英文 | 无摘要,不知深浅 |
| AI HOT API | 精选 + 中文摘要,人工标注 | 中文 | 条目少(~20条),选稿偏主观 |
| 英文→中文翻译 | 原文直接翻译,保细节和准确性 | 中文 | 依赖原文质量,周末偏稀疏 |
三条叠加互不替代、也互不冲突,合在一起差不多就够了。
五、把三条集成:并行 agent + 提炼
接下来是实现层的决策。Hermes 的 delegate_task 可以把三个任务同时派给三个子代理,各跑各的,互不影响。用完把结果收回来再交给主模型做提炼。
cronjob(action='create',
name='全球AI新闻聚合',
schedule='0 8 * * *',
model={'provider':'custom:api.deepseek.com', 'model':'deepseek-v4-pro'},
skills=['ai-news-aggregator', 'aihot', 'ai-news-zh'],
prompt='''...三路并行采集→合并去重→分类→生成JSON...''')
子代理并行的核心理由: - 超时隔离:每条路可能因为目标源挂了或周末没更新而超时,一个子代理超时不影响另外两个正常返回 - 源独立:三路来源完全不同(RSS / REST API / 翻译),不存在"一个源坏了影响另一个"的耦合 - 结果合并简单:每个子代理返回的结构是独立的,合并那步只要把三组 JSON 数组拼起来去重即可
提炼那步放在所有子代理都返回之后。用 deepseek-v4-pro 做一次统一处理:去重(同一条新闻被多个源同时覆盖)、分类(大模型 / 产品 / 融资 / 政策 / 研究…)、生成一句话摘要、写进一个标准 JSON。
输出 JSON 的结构:
{
"date": "2026-07-07",
"headlines": [
{"category": "大模型", "title": "...", "body": "...", "source": "..."},
...
],
"summary": ["一句话核心洞察1", "一句话核心洞察2", "..."]
}
Flask 那端只管读这个 JSON 渲染成网页。不需要连 AI 接口,也不需要再查数据库。日报一旦生成就是静态数据,打开页面直接展示。
六、部署:cron + 前端渲染 + 失败恢复
调度。 Hermes 的 cronjob 工具一个调用搞定:schedule='0 8 * * *'(北京时间每天早上 08:00),deliver 指向微信,到了 08:00 自动触发三条子代理采集、提炼、写 JSON、推消息。
前端。 日报的 JSON 存在服务器的指定目录。Flask 站点加了两条路由:
@app.route('/ainews/')
@app.route('/ainews/<date_str>')
def ainews(date_str=None):
# 读 date_str 对应的 _ainews.json,不存在就取最新的
return render_template('ainews.html', data=json_data)
日期导航、分类标题、摘要卡片这些都是纯前端渲染,不依赖后端 AI 接口。用户打开网页即展示。
失败恢复。 上线后遇到过几次失败,主要是暑假和周末子代理采集回来的数据偏少,提炼那步觉得"内容不够"就返回了空。设计的恢复流程是:
1. cronjob(action='list') → 看到 FAILED 的输出 .md (由 cron 自动写的)
2. web_search 手动采集当天新闻
3. web_extract 选 2~3 篇最相关的做全文深度阅读(→深度深读门槛)
4. Python 手动生成 JSON 写入 daily-analysis.json
5. 页面刷新即生效
这里有一个关键设计决策:手动恢复时写数据文件,不重跑 prompt。数据文件是 Flask 直接读的 JSON 文件,不受 cron 状态影响。意思是即使 cron 管线彻底瘫了,网页还能显示手动填的数据。
七、三个踩过的坑
不翻这部分就不是我写的了。
坑 1:prompt 被审核拦截(HTTP 400 Content Exists Risk)
刚上线时 prompt 里塞了三个 skill(ai-news-aggregator、aihot、ai-news-zh)和一个很长的处理指令,总 token 约 7000。DeepSeek 的内容安全策略对这个量级的 prompt 偶尔会返回 400 Content Exists Risk。
排查结果:skill 的全文会被注入到 prompt 里,每个 skill 大几千 token。解决方法是砍掉不必要的 skill,改用内置的 web_search 和 web_extract 工具。prompt 从 7000 降到约 1500 token,审核拦截概率大幅降低。
# 修复前
skills=['ai-news-aggregator', 'aihot', 'ai-news-zh'] # 注入大量 token
# 修复后,换成内置 web_search + web_extract
prompt='使用内置 web_search 和 web_extract 工具...'
skills=[]
原则:cron 的 prompt 应该自包含,只加载必不可少的 skill。
坑 2:JSON 里 \n 字面量炸了渲染
大模型在生成摘要和内文时,写到 JSON 的字符串里出现了字面量 \\n 而不是真正的换行符。Python json.dumps() 虽然能处理,但 Flask 的 Jinja2 在渲染多行文本时用 \\n 字面量分隔——结果页面里显示了一堆 \n 字符而不是正常段落。
修复分两层:
- prompt 层:给大模型一个"用真实换行符、禁止 \\n"的指令
- 工具层:在 utils.py 里加一行 summary.replace('\\n','\n') 做防御兜底
坑 3:周末数据稀疏子代理超时不返回
周六/周日的新闻量显著少于工作日。三条子代理在周末常常因为"搜不到结果"而超时,整个日报管线卡在"等子代理返还结果"的阶段。
原因是 ai-news-aggregator 按天数查 RSS,如果某个分类最近 24 小时没有新内容,它就等超时。
解决方法是 fallback:cron 的 prompt 里加一条指令——任一子代理失败时,不要等它,切换到手动顺序执行。同时,超时门的兜底是用 web_search 直接搜标题,把子代理采不到的东西从搜索结果里补进来。
八、效果:数字说话
从 2026-04-27 上线到写这篇时,系统跑了 68 天,累计处理约 56.7 亿 token(含缓存读取),API 调用超过 22,000 次。
每天早晨起床看微信已经成了固定节目:一条 08:00 准时的消息,里面是昨天 AI 圈的重要动态。不用刷网页、不用翻社交媒体。
对个人来说,这套系统的价值不限于 AI 新闻。选什么源、装什么 skill、数据流怎么串,这套框架换了信息源就是另一个日报——财经、学术论文、行业报告、产品发布,结构是一样的。
花几个周末把早上的例行信息摄入自动化,省下的时间连配文带图够给一台服务器做 16 项优化或者补一个 HexaMind 层了。这个投入产出比,我觉得值。