Files
daily-robots/docs/design-wecom-delta-mode.md
yumao 6ea2a4e4c6 feat: 早报系统重构与功能增强
- 新增常驻调度器 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>
2026-07-17 18:12:00 +08:00

10 KiB
Raw Blame History

Design: 企微早报 Delta 模式

Generated: 2026-07-09
Repo: daily-robots
Status: DRAFT
Mode: Builder

Problem Statement

企微早报每天推送五榜 Top 10 + 18 条新闻,内容与前几日高度重复(find-skillsopenclaw、飞书集群等长期霸榜)。读者真实需求是「今天有什么新变化」,而非「再读一遍黄页」。

根因:

  1. daily-agent/SKILL.md 要求即使较昨日无新增,仍须完整列出 Top 榜。
  2. movement 仅用于 opening / signals列表区块仍全量渲染。
  3. Trending 与 Hot 独立展示,同一 skill 描述写两遍。
  4. 新闻 DAILY_AI_NEWS_HOURS=72,无已推送 link 去重,旧闻可连续出现。

What Makes This Cool

把早报从「日报复印机」变成「变化通知」:只有新入榜、新新闻、编辑推荐时才占版面;榜全稳且无新新闻时静默不推。读者打开企微即知「今天值得扫一眼的是什么」。

Explicit Non-Goals已否决方案

以下方案不在本设计范围内

方案 状态
静态页 / 外链档案库 不做
今日一装(每天一个 npx skills add 不做
按星期轮换版面 不做
榜首锚点(稳定日仍展示 #1 不做

Premises

  1. 重复感主要来自列表区块全量复印,而非 opening 里引用榜首数字。
  2. output/*.data.jsondaily/delta.py 已具备新入榜对比能力,应上升为列表渲染主数据源
  3. 企微消息仍在应用内读完,不依赖外部页面。
  4. 叙事层opening、信号、首推、新闻保持充实缩短的是榜单列表,不是整报。

环境变量

# 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 环境变量

静默日:以上皆不满足 → 不调用 webhookDAILY_SKIP_PUSH_WHEN_SILENT=1 时)。
仍执行 daily generate,写入 output/{date}.mdoutput/{date}.wecom.mdoutput/{date}.data.json 留档。

注意:仅新闻有新、榜单全稳时仍推送,但 Skills/GitHub 列表区块整块省略(不是全天静默)。

列表渲染Delta 列表)

DAILY_WECOM_MODE=delta 时:

Skills

  • 仅展示 movement.skills_trending_moves / movement.skills_hot_moves 中的新入榜条目。
  • 跨榜去重:按 skill_ididsource/title)合并;同一 skill 只出现一次,标注来源榜(如 Trending #4 · Hot #2)。
  • 无新入:该榜区块整块不出现(不写多行「较昨日无新增」)。

GitHub

  • 仅展示 movement.github_trending_movesgithub_emerging_movesgithub_topic_moves
  • 无新入则区块省略。

不包含

  • 全量 Top N 列表
  • 榜首锚点
  • (新入 … #n 括号标注(与现 agent_workflow._strip_new_entry_notes 一致,列表标题用 [新入 #n] 前缀即可)

固定骨架(不因 Delta 缩短)

Agent 模式(DAILY_REPORT_MODE=agent)下,以下区块保持

  • opening23 句,首句含具体证据)
  • headline / 今日主题
  • 今日信号35 条)
  • 今日首推
  • 国际 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_reportbuild_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

  1. Agent 不写 Skills Trending / Hot / GitHub 列表(仍由 Python 插入,与现流程一致)。
  2. opening / signals 可引用榜首与 movement 摘要;禁止在 signals 重复列表已展示的同一事实。
  3. 榜全稳时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

  1. 连续 3 天对比 output/*.data.json:企微列表区块重复 skill_id 占比显著下降。
  2. 榜全稳且无新新闻日:DAILY_SKIP_PUSH_WHEN_SILENT=1 时不发 webhook。
  3. Trending/Hot 同一 skill 在列表中最多出现 1 次
  4. DAILY_WECOM_MODE=full 与现网行为一致(回归用)。
  5. 首日 DAILY_DELTA_BASELINE_FALLBACK=full 不产生空列表投诉。

Open Questions

  1. 静默日是否需要在企微发一行「今日无更新」?当前设计:不发
  2. 新闻去重 cache 是否纳入 git建议,放 cache/(已在 .gitignore)。
  3. 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_inputwecom_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 文笔问题。
  • 明确否决静态页、今日一装、轮换、锚点后,方案边界清晰,实现可分期。
  • 推送闸门必须把新闻算进去,否则静默日会被新闻绕过。