从零搭建 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-aggregatoraihotai-news-zh)和一个很长的处理指令,总 token 约 7000。DeepSeek 的内容安全策略对这个量级的 prompt 偶尔会返回 400 Content Exists Risk。

排查结果:skill 的全文会被注入到 prompt 里,每个 skill 大几千 token。解决方法是砍掉不必要的 skill,改用内置的 web_searchweb_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 层了。这个投入产出比,我觉得值。