- 新增常驻调度器 daily/scheduler.py + run-scheduler.ps1(定时生成/推送) - 新增 daily/bridge_manager.py:Windows 兼容的 Cursor SDK 桥接 - 新增 skills/daily-featured-pick 首推 Skill 与叙事轴/去重逻辑 - 新闻抓取窗口、GitHub 搜索、企微 delta 模式等多项改进 - 补充设计文档与 superpowers 计划/规范 - 新增对应测试(scheduler、featured_pick、github_search、news_fetch_window 等) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
10 KiB
Design: 企微早报 Delta 模式
Generated: 2026-07-09
Repo: daily-robots
Status: DRAFT
Mode: Builder
Problem Statement
企微早报每天推送五榜 Top 10 + 18 条新闻,内容与前几日高度重复(find-skills、openclaw、飞书集群等长期霸榜)。读者真实需求是「今天有什么新变化」,而非「再读一遍黄页」。
根因:
daily-agent/SKILL.md要求即使较昨日无新增,仍须完整列出 Top 榜。movement仅用于 opening / signals,列表区块仍全量渲染。- Trending 与 Hot 独立展示,同一 skill 描述写两遍。
- 新闻
DAILY_AI_NEWS_HOURS=72,无已推送 link 去重,旧闻可连续出现。
What Makes This Cool
把早报从「日报复印机」变成「变化通知」:只有新入榜、新新闻、编辑推荐时才占版面;榜全稳且无新新闻时静默不推。读者打开企微即知「今天值得扫一眼的是什么」。
Explicit Non-Goals(已否决方案)
以下方案不在本设计范围内:
| 方案 | 状态 |
|---|---|
| 静态页 / 外链档案库 | ❌ 不做 |
今日一装(每天一个 npx skills add) |
❌ 不做 |
| 按星期轮换版面 | ❌ 不做 |
| 榜首锚点(稳定日仍展示 #1) | ❌ 不做 |
Premises
- 重复感主要来自列表区块全量复印,而非 opening 里引用榜首数字。
output/*.data.json与daily/delta.py已具备新入榜对比能力,应上升为列表渲染主数据源。- 企微消息仍在应用内读完,不依赖外部页面。
- 叙事层(opening、信号、首推、新闻)保持充实;缩短的是榜单列表,不是整报。
Recommended Approach: Delta 模式
环境变量
# full = 现有行为(全量 Top 榜列表)
# delta = 本设计(默认推荐)
DAILY_WECOM_MODE=delta
# 无对比基准时(首日或缺历史 data.json)是否自动 full 一次
DAILY_DELTA_BASELINE_FALLBACK=full # full | empty
# 推送闸门全不满足时是否跳过 webhook(仍写 output 文件)
DAILY_SKIP_PUSH_WHEN_SILENT=1
# 强制推送(忽略静默)
# DAILY_FORCE_PUSH=1
# 新闻:缩短窗口 + 去重天数
DAILY_AI_NEWS_HOURS=24
DAILY_NEWS_DEDUP_DAYS=7
推送闸门(Push Gate)
满足任一条件则生成并推送企微早报:
| 条件 | 数据源 |
|---|---|
| 任榜单有新入条目 | movement.*_moves 非空 |
| 去重后仍有新新闻 | 国际或国内 AI 时讯 |
存在 featured_pick |
Step 0 编辑推荐 |
DAILY_FORCE_PUSH=1 |
环境变量 |
静默日:以上皆不满足 → 不调用 webhook(DAILY_SKIP_PUSH_WHEN_SILENT=1 时)。
仍执行 daily generate,写入 output/{date}.md、output/{date}.wecom.md、output/{date}.data.json 留档。
注意:仅新闻有新、榜单全稳时仍推送,但 Skills/GitHub 列表区块整块省略(不是全天静默)。
列表渲染(Delta 列表)
DAILY_WECOM_MODE=delta 时:
Skills
- 仅展示
movement.skills_trending_moves/movement.skills_hot_moves中的新入榜条目。 - 跨榜去重:按
skill_id(id或source/title)合并;同一 skill 只出现一次,标注来源榜(如Trending #4 · Hot #2)。 - 无新入:该榜区块整块不出现(不写多行「较昨日无新增」)。
GitHub
- 仅展示
movement.github_trending_moves、github_emerging_moves、github_topic_moves。 - 无新入则区块省略。
不包含
- 全量 Top N 列表
- 榜首锚点
(新入 … #n)括号标注(与现agent_workflow._strip_new_entry_notes一致,列表标题用[新入 #n]前缀即可)
固定骨架(不因 Delta 缩短)
Agent 模式(DAILY_REPORT_MODE=agent)下,以下区块保持:
- opening(2–3 句,首句含具体证据)
- headline / 今日主题
- 今日信号(3–5 条)
- 今日首推
- 国际 AI / 国内 AI 精选(条数仍由
DAILY_WECOM_AI_NEWS等控制)
榜单变短;叙事与新闻不主动砍到 0。
Full 模式逃生口
DAILY_WECOM_MODE=full 时行为与当前生产一致(format_wecom.build_wecom_report / replace_wecom_skill_sections 全量 Top N)。用于手动切回或对比测试。
首日 / 无历史基准
find_previous_data(date) 返回 None 时:
DAILY_DELTA_BASELINE_FALLBACK |
行为 |
|---|---|
full(推荐) |
当日按 full 模式渲染列表一次;次日起 delta |
empty |
当日列表区块为空;opening 须说明「首日报,暂无对比基准」 |
实现时在 generate_report 或 build_llm_input 传入 baseline_date 供 Agent 引用。
News Dedup
P0(本阶段)
- 维护
cache/pushed-news-links.json(或写入output/旁 cache):最近DAILY_NEWS_DEDUP_DAYS天已出现在企微早报中的link集合。 prepare_wecom_news_items/prepare_wecom_cn_news_items输出前过滤已见 link。DAILY_AI_NEWS_HOURS默认改为24(.env.example同步)。
P1(可选后续)
- 标题归一化去重(同一事件多源报道)
- 每
source_name每日上限 N 条
Agent Skill 变更
文件:skills/daily-agent/SKILL.md
删除 / 修改
- 删除规则:「即使某榜较昨日无新增,仍须完整列出 Top 榜条目」。
- 删除:「禁止改用 movement 作为列表来源」(在 delta 模式下反转)。
新增
当 DAILY_WECOM_MODE=delta(或 llm_input 含 wecom_mode: delta):
- Agent 不写 Skills Trending / Hot / GitHub 列表(仍由 Python 插入,与现流程一致)。
- opening / signals 可引用榜首与 movement 摘要;禁止在 signals 重复列表已展示的同一事实。
- 榜全稳时,signals 聚焦新闻与首推,不必编造榜单变化。
当 wecom_mode: full 时保持现有 SKILL 规则。
Python 模块变更
| 模块 | 变更 |
|---|---|
daily/config.py |
wecom_mode(), news_dedup_days(), skip_push_when_silent(), delta_baseline_fallback() |
daily/delta.py |
可选:merge_skill_moves_for_wecom(trending_moves, hot_moves) 跨榜去重 |
daily/format_wecom.py |
build_skills_delta_section(), build_github_delta_section();replace_wecom_skill_sections 支持 delta |
daily/news/fetch.py |
filter_pushed_news() + cache 读写 |
daily/generate.py |
推送闸门;baseline fallback;静默 skip push |
daily/report_data.py |
llm_input 增加 wecom_mode, push_gate 摘要 |
daily/agent_workflow.py |
无逻辑变更;依赖 Python 插入 delta 列表 |
.env.example |
新 env 文档 |
企微消息示例
有变化日
📰 **早报 · 2026-07-10**
[opening:今天最大变化,含数字/条目名]
🎯 **{headline}**
💡 **今日信号**
> ...
📦 **今日首推**
[...]
🌍 **国际 AI · 精选 N**
...
📈 **Skills Trending 变化**
1. [新入 #4] [**xxx**](...) · ...
描述一行
🔥 **Skills Hot 变化**
1. [新入 #2] [**yyy**](...) · ...
🐙 **GitHub Trending 变化**
1. [新入 #4] [owner/repo](...) · ...
仅新闻有新(榜稳)
- 无 📈/🔥/🐙 区块
- opening 可一句:「榜单较昨日 Top15 无新入;以下为今日 AI 时讯。」
静默日
- 不推送企微
output/仍落盘;日志:[silent] no push gate matched for 2026-07-10
Approaches Considered
Approach A: 配置瘦身(缩 Top N、24h 新闻)
- Effort: S | Risk: Low
- 只减篇幅,榜头仍天天重复;未解决根因。
Approach B: Delta 列表 + 推送闸门 + 新闻去重(本设计)
- Effort: M | Risk: Med
- 复用
delta.py;改 format + skill + push 逻辑。
Approach C: 仅改 Agent 文案
- Effort: S | Risk: High
- Python 仍插入全量列表,规则冲突,不可持续。
Recommendation: B — 数据层与展示层一致,静默日与跨榜去重可测。
Success Criteria
- 连续 3 天对比
output/*.data.json:企微列表区块重复 skill_id 占比显著下降。 - 榜全稳且无新新闻日:
DAILY_SKIP_PUSH_WHEN_SILENT=1时不发 webhook。 - Trending/Hot 同一 skill 在列表中最多出现 1 次。
DAILY_WECOM_MODE=full与现网行为一致(回归用)。- 首日
DAILY_DELTA_BASELINE_FALLBACK=full不产生空列表投诉。
Open Questions
- 静默日是否需要在企微发一行「今日无更新」?当前设计:不发。
- 新闻去重 cache 是否纳入 git?建议:否,放
cache/(已在.gitignore)。 - Classic 模式(非 agent)是否同步 delta?建议:是,同一
format_wecom路径。
Implementation Tasks
| ID | Priority | Task | Files |
|---|---|---|---|
| T1 | P1 | 新增 config helpers + .env.example |
daily/config.py, .env.example |
| T2 | P1 | 新闻 link 去重 cache | daily/news/fetch.py, daily/config.py |
| T3 | P1 | Delta 列表渲染 + 跨榜去重 | daily/format_wecom.py, daily/delta.py |
| T4 | P1 | 推送闸门 + 静默 skip push | daily/generate.py, daily/webhook.py |
| T5 | P1 | baseline fallback full 一次 | daily/generate.py |
| T6 | P1 | 更新 daily-agent/SKILL.md |
skills/daily-agent/SKILL.md |
| T7 | P2 | llm_input 传 wecom_mode / push 摘要 |
daily/report_data.py |
| T8 | P2 | 单元测试:跨榜去重、推送闸门、新闻去重 | tests/test_wecom_delta.py |
Test Plan
- 有
2026-07-09.data.json时生成2026-07-10:列表仅含新入项 - 人造「全稳 + 无新新闻」:不 push
- 人造「全稳 + 有新新闻」:push,无 Skills/GitHub 块
DAILY_WECOM_MODE=full输出与改前2026-07-09.wecom.md结构一致- 无 baseline +
DAILY_DELTA_BASELINE_FALLBACK=full:首日全量列表 - 同一 skill 在 Trending/Hot moves 均出现:列表只 1 条
What I Noticed
- 重复感是产品形态问题,不是 Agent 文笔问题。
- 明确否决静态页、今日一装、轮换、锚点后,方案边界清晰,实现可分期。
- 推送闸门必须把新闻算进去,否则静默日会被新闻绕过。