Files
my-daily/20260529_新闻智能分析系统开发计划_v3.md
T

1250 lines
54 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 新闻智能分析系统开发计划 v3.0
> 基于大模型的时政/军事/科技新闻聚类、评价与整合系统
>
> **迭代说明**:参考 AI Daily 项目实践与 military-digest-v3 工程落地经验,融合细粒度聚类、SQLite 增量缓存、翻译管线、网摘生成与工程化部署经验
---
## 一、项目概述
### 1.1 项目目标
构建一个自动化新闻分析系统,实现:
- **细粒度聚类**:保留多角度报道,避免简单去重丢失热点
- **动态热点识别**:基于当日新闻分布统计特征自适应判定热点
- **三层整合**:摘要级速览(全量)+ 洞察级深度分析(Top 10)+ 参考消息风格网摘(Top 3)
- **混合处理**:实时热点感知 + 每日批量汇总生成早报
- **跨日关联**:追踪同一事件的多日发展脉络
- **增量缓存**:SQLite 三级缓存(文章/网摘/分类摘要),支持断点续跑,再次运行几乎零 token 消耗
- **外文翻译**:中英分离 + 并发翻译,中文文章零 API 调用
### 1.2 核心约束
| 维度 | 约束 |
|------|------|
| 数据规模 | 200-500篇/日 |
| 数据源 | RSS Feed(公众号订阅源,含外文源) |
| 输出格式 | Markdown日报 / 网摘PNG长图 / 网摘TXT文本 / 飞书推送 |
| 成本预算 | 混合模型调度,日成本约1.3-1.6元 |
| 处理时效 | 批处理15-20分钟完成(冷启动基准:5源156篇→153s) |
| 缓存命中 | 二次运行 ~5s,API 调用 0 次 |
| 部署方式 | 支持systemd服务化部署 |
### 1.3 双循环架构(参考AI Daily优化)
```
┌─────────────────────────────────────────────────────────────────┐
│ Fetch 循环(实时) │
│ 每30分钟运行一次 │
│ RSS抓取 → 中英分离 → 外文并发翻译 → LLM评分 → 重要性判断 │
│ ↓ ↓ ↓ │
│ 存入SQLite缓存 存入JSON文件(fetch-yyyy-mm-dd.json) 飞书推送│
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Push 循环(定时) │
│ 每日定时运行(如早8点) │
│ 读取碎片化信息 → 细粒度聚类 → 多角度关联 → 综合评分 │
│ → 摘要级整合(全量) → 洞察级整合(Top10) → 参考消息网摘(Top3) │
│ → 生成日报+网摘图片 → 飞书推送 │
└─────────────────────────────────────────────────────────────────┘
```
---
## 二、与现有项目的对比分析
### 2.1 与 AI Daily 的相似性
| 维度 | AI Daily | 本系统 | 相似度 |
|------|----------|--------|--------|
| **数据源** | RSS订阅源 | RSS订阅源(公众号+外文) | ⭐⭐⭐⭐⭐ |
| **核心流程** | RSS→LLM评分→推送/汇总 | RSS→翻译→聚类→评分→整合→推送/汇总 | ⭐⭐⭐⭐ |
| **双循环架构** | Fetch循环+Push循环 | 实时检测+批处理 | ⭐⭐⭐⭐⭐ |
| **即时推送** | 飞书/Discord webhook | 飞书 webhook | ⭐⭐⭐⭐ |
| **定时汇总** | 每日定时推送 | 每日早报生成 | ⭐⭐⭐⭐⭐ |
| **成本预算** | 每天6毛钱 | 每天1.3-1.6元 | ⭐⭐⭐⭐ |
### 2.2 与 military-digest-v3 的对比
| 维度 | military-digest-v3(现有系统) | 本系统(新架构) | 差异 |
|------|------|------|:---:|
| **架构** | 单管线(每日一次全量运行) | 双循环(Fetch 30min + Push 每日) | 🔄 架构升级 |
| **去重** | 同源同标题简单去重 | 细粒度语义聚类 + 多角度保留 | 🔄 策略升级 |
| **评分** | 四维度固定加权 | 双层筛选:硬约束 + 动态阈值融合 | 🔄 质量升级 |
| **翻译** | ✅ 中英分离 + 并发翻译 | ✅ 继承 + 统一为 Fetch 循环环节 | ✅ 复用 |
| **缓存** | ✅ SQLite 三级缓存(文章/网摘/分类摘要) | ✅ 继承 + 扩展为跨日关联数据源 | ✅ 复用 |
| **监控** | ✅ 11阶段耗时 + API统计 + 源成功率 | ✅ 继承 + 增加聚类/热点识别指标 | ✅ 复用 |
| **网摘** | ✅ 参考消息风格 + 字数校验重试 | ✅ 继承 + 作为第三层整合输出 | ✅ 复用 |
| **推送** | 企业微信 + 飞书 | **聚焦飞书 webhook** | 🔄 收束 |
| **跨日关联** | ❌ 无 | ✅ Sentinel标记 + 事件时间线追踪 | 🆕 新增 |
| **防退化** | ❌ 无 | ✅ 禁止套话 + 素材支撑要求 | 🆕 新增 |
### 2.3 本系统的差异化优势
| 特性 | AI Daily | military-digest-v3 | 本系统 | 价值 |
|------|----------|------|------|------|
| **热点识别** | 单篇文章评分 | 四维度固定加权 | **双层筛选:硬约束+动态阈值融合** | 质量控制+热点发现协同 |
| **去重策略** | 简单去重 | 同源标题去重 | 细粒度聚类+多角度保留 | 不丢失多角度报道 |
| **内容整合** | 单篇摘要 | 摘要+网摘 | 三层整合(摘要+洞察+网摘) | 覆盖速览/深度/传播三种需求 |
| **翻译能力** | 无 | ✅ 中英分离并发 | ✅ 继承 | 外文源零额外成本 |
| **增量缓存** | JSON文件 | ✅ SQLite三级缓存 | ✅ 继承+扩展 | 断点续跑,二次运行~5s |
| **网摘生成** | 无 | ✅ 参考消息风格+字数校验 | ✅ 继承 | 适合直接传播的成品内容 |
| **领域聚焦** | AI领域 | 军事/科技 | 时政/军事/科技 | 专业领域实体识别 |
| **角度分类** | 无 | 无 | 6种报道角度分类 | 支持多角度整合 |
| **跨日关联** | 无 | 无 | 事件时间线追踪+Sentinel标记 | 追踪事件发展脉络 |
### 2.4 从 AI Daily 借鉴的核心设计
1. **双循环架构**Fetch循环(实时)+ Push循环(定时)
2. **systemd服务化**:使用systemd timer替代Python内部定时,提升稳定性
3. **文件存储规范**fetch/notify/push三种文件类型,明确保留策略
4. **评分硬约束**:非目标领域上限、KOL转述上限,有效控制信息质量
5. **Prompt防退化**:禁止套话、要求从素材出发,避免LLM输出风格趋同
6. **双视角洞察**:metadata(事实压缩)+ 正文(趋势判断)解耦
7. **Sentinel分段标记**:单文件多板块精确管理,支持跨日关联
### 2.5 从 military-digest-v3 继承的工程资产
1. **SQLite 三级缓存**:文章缓存 + 网摘缓存 + 分类摘要缓存,含自动过期清理和数据库迁移机制
2. **翻译管线**:中英分离(汉字占比 > 20% 判定)+ 外文并发翻译(ThreadPoolExecutor),中文文章零 API 调用
3. **监控统计体系**:11 阶段耗时 + API 调用按用途/模型分组 + 源抓取成功/失败率 + 缓存命中率
4. **网摘生成**:参考消息风格 + 公众号源智能识别前缀 + 字数校验重试(280-320字,最多3次)
5. **异步流式管线**:生产者-消费者模型,RSS 抓取与 AI 处理流水线并行
6. **图片生成**:Pillow 命令模式渲染,支持单篇 + TOP3 合并长图
---
## 三、开发阶段规划
### 阶段一:基础架构搭建(Week 1-2)
**目标**:建立数据流和存储基础,确保稳定采集
| 序号 | 任务 | 描述 | 输出 | 依赖 |
|------|------|------|------|------|
| 1.1 | RSS采集模块 | 解析公众号RSS Feed,提取标题、正文、来源、发布时间 | 原始文章数据库 | - |
| 1.2 | 数据标准化 | 统一文章格式,清洗HTML标签,提取纯文本 | 标准化文章表 | 1.1 |
| 1.3 | 文件存储层 | JSON文件存储(fetch-yyyy-mm-dd.json) | 存储规范 | 1.2 |
| 1.4 | **SQLite缓存系统** | 三级缓存设计(文章/网摘/分类摘要),含过期策略与迁移机制 | 缓存模块 | 1.2 |
| 1.5 | **翻译管线** | 中英分离 + 外文并发翻译 | 翻译模块 | 1.2 |
| 1.6 | **监控统计** | 阶段耗时 + API消耗 + 成功率 + 缓存命中率 | 监控模块 | 1.1 |
| 1.7 | 日志系统 | 有效日志记录,便于问题定位 | 日志模块 | 1.1 |
#### 1.4 SQLite 缓存系统设计(继承 military-digest-v3
**数据库位置**`data/article_cache.db`
**表1article_cache(文章处理结果缓存)**
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | TEXT (PK) | 文章唯一标识(RSS entry id/link |
| `source` | TEXT | 来源名称 |
| `title` | TEXT | 原始标题 |
| `link` | TEXT | 原文链接 |
| `translated_title` | TEXT | 翻译后的中文标题 |
| `content` | TEXT | 原始正文 |
| `translated_content` | TEXT | 翻译后的中文正文(前300字) |
| `ai_score` | REAL | AI 加权总分 |
| `ai_summary` | TEXT | AI 生成的中文摘要 |
| `ai_category` | TEXT | 分类(装备动态/地区冲突/战略政策) |
| `ai_scores_json` | TEXT | 四维度评分 JSON |
| `webzine_text` | TEXT | 网摘文本(迁移新增字段) |
| `published_time` | DATETIME | 文章发布时间 |
| `processed_time` | DATETIME | 处理时间(索引,用于过期判断) |
| `status` | INTEGER | 1=成功 2=失败 |
| `error_msg` | TEXT | 失败时的错误信息 |
**索引**`idx_processed_time``idx_source`
**表2category_summary_cache(分类摘要缓存)**
| 字段 | 类型 | 说明 |
|------|------|------|
| `date` | TEXT (联合PK) | 日期字符串(YYYY-MM-DD |
| `category` | TEXT (联合PK) | 分类名称 |
| `summary_text` | TEXT | 分类介绍文本 |
| `generated_time` | DATETIME | 生成时间 |
**缓存策略**
| 策略项 | 设计 |
|------|------|
| 过期时间 | 24 小时(与时间窗口一致,可配置) |
| 自动清理 | 每次运行时清理 7 天前数据(`clear_expired(keep_days=7)` |
| 写入方式 | `REPLACE INTO`(幂等,支持覆盖更新) |
| 网摘分离更新 | `save_article_webzine()` 单独更新 `webzine_text` 字段,不影响其他缓存 |
| 连接降级 | 数据库连接失败时静默降级,不影响主流程 |
| 全局单例 | `get_cache()` 全局单例模式,避免重复创建连接 |
**数据库迁移机制**
```python
def _migrate_add_webzine_text(self):
"""自动检测并添加 webzine_text 列"""
cursor.execute("PRAGMA table_info(article_cache)")
columns = [col[1] for col in cursor.fetchall()]
if 'webzine_text' not in columns:
cursor.execute("ALTER TABLE article_cache ADD COLUMN webzine_text TEXT")
```
**缓存命中流程**
```
文章被抓取 → 以 article.id 查询缓存(expire_hours=24
├─ 命中 + status=1 → 直接使用缓存数据(from_cache=True),跳过翻译和AI分析
└─ 未命中/过期 → 完整翻译+分析管线,结果 REPLACE INTO 写入缓存
```
**实测效果**military-digest-v3 验证数据):
| 指标 | 第一次(冷启动) | 第二次(含缓存) |
|------|:---:|:---:|
| 文章缓存命中 | 0 / 15 | **15 / 15** |
| API 调用次数 | 37 次 | **0 次** |
| 总耗时 | 153s | **~5s** |
| 退出码 | 0 | 0 |
#### 1.5 翻译管线设计(继承 military-digest-v3
**核心策略**:中英分离,中文文章零 API 调用,外文文章并发翻译。
**中文检测**:汉字占比 > 20% 判定为中文(`is_chinese()` 函数)。
**翻译流程**
```
所有文章
├─ 中文文章 → translated_title = title(零API调用)
│ translated_content = content[:300](截取即可)
└─ 外文文章 → 提交到 ThreadPoolExecutormax_workers=AI_CONCURRENCY
├─ translate_title():标题翻译(temperature=0.2, max_tokens=200
└─ translate_content():正文前500词翻译 → 截取300字(max_tokens=800
```
**并发控制**
| 参数 | 值 | 说明 |
|------|-----|------|
| `AI_CONCURRENCY` | 8 | 默认并发数,可通过配置调整 |
| `temperature` | 0.2 | 翻译低温度,确保准确性 |
| 失败降级 | 原文填充 | 翻译失败时 `translated_title = title`,不中断流程 |
**关键实现**
```python
def batch_translate_titles(articles, api_key, base_url, model, max_concurrent=None):
"""中英分离:中文直接填充,外文并发翻译标题"""
chinese_articles = []
foreign_articles = []
for a in articles:
if is_chinese(a['title']):
a['translated_title'] = a['title']
chinese_articles.append(a)
else:
foreign_articles.append(a)
# 外文并发翻译
with ThreadPoolExecutor(max_workers=max_concurrent) as executor:
futures = {executor.submit(translate_title, a, ...): a for a in foreign_articles}
for future in as_completed(futures):
chinese_articles.append(future.result())
return chinese_articles
```
**设计优势**
- 中文文章零 API 调用,节省 40%+ 翻译 token
- 标题和正文分离翻译,先翻译标题再决定是否需要翻译正文(可配合关键词筛选)
- 外文并发翻译,翻译耗时 = 单篇耗时(而非 N × 单篇耗时)
#### 1.6 监控统计设计(继承 military-digest-v3
**阶段耗时统计(11 阶段)**
| 阶段 key | 中文标签 | 统计内容 |
|------|------|------|
| `rss_fetch` | RSS抓取 | 所有源并行抓取耗时 |
| `time_filter` | 时间过滤 | 按时间窗口过滤耗时 |
| `deduplicate` | 去重 | 去重处理耗时 |
| `translate_titles` | 标题翻译 | 外文标题并发翻译耗时 |
| `keyword_filter` | 关键词筛选 | 关键词命中筛选耗时 |
| `translate_contents` | 正文翻译 | 外文正文并发翻译耗时 |
| `ai_analyze` | AI评分分类 | 批量AI评分分类耗时 |
| `webzine_generate` | 网摘生成 | TOP3网摘并发生成耗时 |
| `category_overview` | 分类介绍 | 4类分类介绍并发生成耗时 |
| `report_generate` | 报告生成 | Markdown报告拼接写入耗时 |
| `image_generate` | 图片生成 | 网摘长图渲染耗时 |
**API 调用统计**:按用途(标题翻译/正文翻译/AI评分分类/网摘生成/分类介绍)和模型分组,记录调用次数、token 估算、重试次数、失败次数。
**源抓取统计**:成功/失败源计数,失败源名称列表。
**文章统计**:总数、缓存命中数、本次处理数、缓存命中率。
**报告示例**(运行结束自动打印):
```
================================================================
📊 运行监控报告
================================================================
── ⏱ 阶段耗时 ──
RSS抓取 7.5s
时间过滤 0.0s
去重 0.0s
标题翻译 17.9s
关键词筛选 0.0s
正文翻译 9.9s
AI评分分类 30.7s
网摘生成 53.3s
分类介绍 33.5s
报告生成 0.0s
图片生成 0.3s
────────────────────
合计 153.1s / 总运行 153s
── 📡 文章统计 ──
总计: 15 缓存命中: 0 本次处理: 15
缓存命中率: 0%
── 🤖 API调用统计 ──
[按用途]
标题翻译: 7次 / tokens≈1400 / 重试0
正文翻译: 6次 / tokens≈4800 / 重试0
AI评分分类: 15次 / tokens≈12000 / 重试0
网摘生成: 5次 / tokens≈4000 / 重试2
分类介绍: 4次 / tokens≈600 / 重试0
[按模型]
deepseek-v3: 37次 / tokens≈22800
── 📰 源抓取统计 ──
源总数: 5 成功: 5 失败: 0
================================================================
```
**数据字段规范**(扩展版):
```json
{
"title": "内容标题",
"link": "原始链接",
"published": "发布时间",
"source": "来源(公众号名称)",
"content": "Markdown格式的正文内容",
"translated_title": "翻译后的中文标题",
"translated_content": "翻译后的中文正文",
"tags": "LLM识别的标签",
"score": "LLM评分(0-100",
"summary": "LLM生成的中文摘要",
"fetched_at": "抓取时间",
"entities": ["提取的实体列表"],
"reporting_angle": "报道角度",
"webzine_text": "参考消息风格网摘文本(Top N 专属)",
"from_cache": "是否来自缓存"
}
```
**验收标准**
- [ ] 稳定采集50+ RSS源
- [ ] 数据入库成功率 > 95%
- [ ] SQLite 缓存三级覆盖(文章/网摘/分类摘要)
- [ ] 缓存命中时 API 调用为 0
- [ ] 中英分离正确,中文文章零翻译 API 调用
- [ ] 监控报告包含阶段耗时、API统计、源成功率、缓存命中率
- [ ] 日志系统可定位问题
---
### 阶段二:Fetch循环与双层评分系统(Week 3-4)
**目标**:实现实时采集、双层评分(硬约束+动态阈值融合)、即时推送
| 序号 | 任务 | 描述 | 输出 | 依赖 |
|------|------|------|------|------|
| 2.1 | Fetch循环引擎 | 每30分钟循环一次,抓取RSS→中英分离→并发翻译→评分 | fetch引擎 | 1.7 |
| 2.2 | **第一层:单篇评分Prompt** | 单篇文章重要性评分(0-100),**含硬约束** | `prompts/article_score.txt` | 2.1 |
| 2.3 | **硬约束过滤器** | 非时政军事上限、KOL转述上限、时效衰减 | 硬约束模块 | 2.2 |
| 2.4 | 即时推送判断 | 单篇≥90分触发即时推送候选 | 推送判断模块 | 2.3 |
| 2.5 | 飞书Webhook推送 | 飞书群机器人推送(Fetch 循环即时推送 + Push 循环日报推送) | 飞书推送适配器 | 2.4 |
| 2.6 | systemd服务化 | 使用systemd timer管理服务 | systemd配置 | 2.1 |
#### 双层评分架构设计
```
第一层:单篇文章评分(硬约束) 第二层:实体簇热度(动态阈值)
├── 输入:单篇RSS文章(已翻译) ├── 输入:同一实体的多篇报道(已硬约束评分)
├── 处理:LLM评分 + 硬约束修正 ├── 处理:统计特征 + 动态阈值计算
└── 输出:0-100分(已约束) └── 输出:热点判定
├── ≤79:非目标领域,过滤 ├── 低于阈值:普通关注
├── 80-89:一般关注,进入聚类 └── 高于阈值:热点,优先整合
└── 90+:高优先级,即时推送候选
```
#### 第一层:评分硬约束设计
**Prompt核心约束**
```markdown
## 评分规则(硬性约束)
1. **非时政/军事/科技主题上限 79 分**
- 如果内容不属于目标领域(如纯娱乐八卦、生活琐事),最高只能给 79 分
2. **KOL 转述上限 89 分**
- 如果只是 KOL/大V 对已有信息的转述/评论,而非原创信息,最高只能给 89 分
3. **时效性衰减**
- 发布超过24小时:分数×0.9
- 发布超过48小时:分数×0.8
4. **90+ 分必须同时满足**
- 重大事件/突破性进展/政策发布
- 一手信息源(官方发布、权威媒体首发)
- 对目标领域有实质性影响
5. **标签禁止空泛**
- 禁止:["军事", "新闻", "热点"]
- 要求:["歼-35A", "舰载战斗机", "隐身性能", "海军航空兵"]
```
**代码实现**
```python
def apply_score_constraints(entry: dict, raw_score: int) -> tuple[int, list[str]]:
"""
应用评分硬约束
返回:修正后的分数,应用的约束标签列表
"""
constraints_applied = []
# 约束1:非目标领域上限79
if not is_target_domain(entry['content']):
raw_score = min(raw_score, 79)
constraints_applied.append("非目标领域")
# 约束2KOL转述上限89
if is_kol_repost(entry):
raw_score = min(raw_score, 89)
constraints_applied.append("KOL转述")
# 约束3:时效性衰减
hours_old = get_hours_since_published(entry)
if hours_old > 24:
decay_factor = 0.9 ** (hours_old // 24)
raw_score = int(raw_score * decay_factor)
constraints_applied.append(f"时效衰减({hours_old}h)")
return raw_score, constraints_applied
```
**第一层输出分级**
| 分数段 | 处理策略 | 说明 |
|--------|---------|------|
| ≤79 | 过滤,不入库 | 非目标领域内容 |
| 80-89 | 入库,进入聚类 | 一般关注,参与动态阈值计算 |
| 90+ | 入库,即时推送候选 | 高优先级,同时触发即时推送判断 |
**验收标准**
- [ ] Fetch循环每30分钟稳定运行
- [ ] 翻译管线集成正确(中英分离+并发翻译)
- [ ] 硬约束生效(非目标领域≤79,KOL转述≤89,时效衰减)
- [ ] 90+文章触发即时推送候选
- [ ] SQLite缓存正常工作(二次运行零API调用)
- [ ] 监控统计准确记录各阶段数据
- [ ] systemd服务可一键启动/停止
---
### 阶段三:实体提取与细粒度聚类(Week 5-6)
**目标**:实现细粒度聚类,区分同一实体的不同报道角度
| 序号 | 任务 | 描述 | 输出 | 依赖 |
|------|------|------|------|------|
| 3.1 | 实体提取Prompt | 设计并优化实体提取提示词 | `prompts/extract_entities.txt` | 2.6 |
| 3.2 | 角度分类Prompt | 设计报道角度分类提示词 | `prompts/classify_angle.txt` | 2.6 |
| 3.3 | 批量实体提取 | 实现50篇/批并发调用,小模型处理 | 实体提取服务 | 3.1 |
| 3.4 | 角度分类服务 | 批量角度分类,与实体提取并行 | 角度分类服务 | 3.2 |
| 3.5 | 实体归一化 | 大模型消歧,合并别名 | 实体归一化服务 | 3.3 |
| 3.6 | 聚类算法 | 基于实体+角度的细粒度聚类 | 聚类引擎 | 3.4, 3.5 |
| 3.7 | 记忆系统 | 避免同一信息反复推送 | 去重模块 | 3.6 |
**验收标准**
- [ ] 实体提取准确率 > 85%
- [ ] 角度分类准确率 > 80%
- [ ] 聚类后实体簇数量合理(200篇→30-50个簇)
- [ ] 同一信息不重复推送
---
### 阶段四:热度评价与动态阈值(Week 7-8)
**目标**:实现第二层筛选——基于硬约束后分数的动态热点识别
| 序号 | 任务 | 描述 | 输出 | 依赖 |
|------|------|------|------|------|
| 4.1 | **实体簇热度计算** | 融合硬约束分数的多维度热度计算 | 热度指标服务 | 3.6 |
| 4.2 | **第二层:动态阈值算法** | 基于硬约束后分数分布的自适应阈值 | 阈值计算模块 | 4.1 |
| 4.3 | 热点识别引擎 | 硬约束过滤 + 动态阈值筛选的双层判定 | 热点识别服务 | 4.2 |
| 4.4 | 热点精评Prompt | 大模型深度评分(Top 30热点簇) | `prompts/precise_heat.txt` | 4.3 |
#### 第二层:动态阈值设计(融合硬约束分数)
**实体簇热度计算**
```python
class Cluster:
def __init__(self, entity_name: str):
self.entity_name = entity_name
self.articles = [] # 已硬约束评分的文章列表
self.hot_score = 0 # 综合热度分
def calculate_hot_score(self) -> int:
"""
计算实体簇热度,融合硬约束后的单篇分数
"""
if not self.articles:
return 0
# 基础分数:最高分文章的分数(已硬约束)
max_score = max(a['score'] for a in self.articles)
# 传播热度:报道数量 × log(来源多样性)
report_count = len(self.articles)
source_diversity = len(set(a['source'] for a in self.articles))
propagation_heat = report_count * math.log(source_diversity + 1)
# 角度覆盖度:不同报道角度数 / 6
angles = set(a.get('reporting_angle', 'unknown') for a in self.articles)
angle_coverage = len(angles) / 6
# 高优先级文章加成(90+文章额外加权)
high_priority_count = sum(1 for a in self.articles if a['score'] >= 90)
priority_bonus = high_priority_count * 5 # 每篇90+加5分
# 综合计算
self.hot_score = min(100, int(
max_score * 0.4 + # 单篇最高分权重40%
min(propagation_heat * 3, 30) + # 传播热度权重30%
angle_coverage * 20 + # 角度覆盖权重20%
priority_bonus # 高优先级加成10%
))
return self.hot_score
```
**动态阈值算法(融合版)**
```python
def calculate_hotspot_threshold(clusters: list[Cluster], date: str) -> float:
"""
基于硬约束后分数分布计算动态阈值
同时考虑统计特征和高优先级文章数量
"""
# 获取当日所有簇的热度分数(已融合硬约束)
scores = [c.hot_score for c in clusters]
if len(scores) < 5:
return 75 # 数据不足时使用保底阈值
# 统计特征
mean_score = mean(scores)
std_score = std(scores)
median_score = median(scores)
# 方法1:统计阈值(均值+1.5倍标准差)
threshold_stat = mean_score + 1.5 * std_score
# 方法2:保底阈值(至少3条或前10%)
min_count = max(3, len(scores) * 0.1)
sorted_scores = sorted(scores, reverse=True)
threshold_adaptive = sorted_scores[min_count - 1]
# 方法3:硬约束保底(考虑90+高优先级文章数量)
high_priority_count = sum(
1 for c in clusters
if any(a['score'] >= 90 for a in c.articles)
)
if high_priority_count >= 3:
threshold_backup = median_score
else:
threshold_backup = mean_score + 0.5 * std_score
# 取三者中较低值,确保热点不被遗漏
final_threshold = min(threshold_stat, threshold_adaptive, threshold_backup)
logger.info(f"动态阈值计算: 统计={threshold_stat:.1f}, "
f"保底={threshold_adaptive:.1f}, 硬约束保底={threshold_backup:.1f}, "
f"最终={final_threshold:.1f}")
return final_threshold
```
**双层热点判定流程**
```python
def identify_hotspots(clusters: list[Cluster], date: str) -> tuple[list[Cluster], list[Cluster]]:
"""
双层热点识别:硬约束过滤 + 动态阈值筛选
"""
# 第一层:硬约束过滤(单篇层面已处理,此处检查)
valid_clusters = []
for c in clusters:
if all(a['score'] <= 79 for a in c.articles):
continue
valid_clusters.append(c)
# 计算各簇热度(融合硬约束分数)
for c in valid_clusters:
c.calculate_hot_score()
# 第二层:计算动态阈值
threshold = calculate_hotspot_threshold(valid_clusters, date)
# 阈值筛选 + 额外条件
hotspots = []
normal = []
for c in valid_clusters:
if c.hot_score >= threshold:
has_high_priority = any(a['score'] >= 90 for a in c.articles)
significantly_above = c.hot_score >= threshold + 10
if has_high_priority or significantly_above:
hotspots.append(c)
else:
normal.append(c)
else:
normal.append(c)
hotspots.sort(key=lambda x: (x.hot_score, x.max_article_score), reverse=True)
return hotspots, normal
```
**融合设计优势**
| 层级 | 作用 | 输入 | 输出 |
|------|------|------|------|
| 第一层(硬约束) | 质量控制 | 单篇文章 | 过滤非目标领域,标记高优先级 |
| 第二层(动态阈值) | 热点发现 | 实体簇(多篇聚合) | 识别突发热点,自适应当日分布 |
**验收标准**
- [ ] 实体簇热度计算正确(融合硬约束分数)
- [ ] 动态阈值自适应当日分布
- [ ] 双层筛选协同工作(硬约束过滤→动态阈值筛选)
- [ ] 热点识别召回率 > 90%,误报率 < 20%
---
### 阶段五:Push循环与三层整合(Week 9-10
**目标**:实现定时汇总、三层整合(摘要+洞察+网摘)、日报生成
| 序号 | 任务 | 描述 | 输出 | 依赖 |
|------|------|------|------|------|
| 5.1 | Push循环引擎 | 每日定时运行,读取碎片化信息→整合→推送 | push引擎 | 4.4 |
| 5.2 | 摘要级整合Prompt | 多源报道合并为50-80字精炼摘要 | `prompts/summary_integrate.txt` | 5.1 |
| 5.3 | 洞察级整合Prompt | Top 10生成结构化深度分析(**双视角设计**) | `prompts/insight_integrate.txt` | 5.1 |
| 5.4 | **Prompt防退化模块** | 禁止套话、要求从素材出发 | 防退化检查器 | 5.2, 5.3 |
| 5.5 | 摘要整合服务 | 小模型批量处理全量簇 | 摘要整合服务 | 5.2, 5.4 |
| 5.6 | 洞察整合服务 | 大模型逐个处理Top 10(**双视角输出**) | 洞察整合服务 | 5.3, 5.4 |
| 5.7 | **网摘生成服务** | Top 3 参考消息风格网摘(继承 military-digest-v3 | 网摘生成服务 | 5.1 |
| 5.8 | 时间线提取 | 从多源报道中提取事件时间线 | 时间线提取模块 | 5.5 |
| 5.9 | 多角度整合 | 同一事件不同角度报道的整合 | 多角度整合模块 | 5.6 |
#### 双视角洞察设计(借鉴AI Daily)
**设计理念**:metadata(新闻编辑视角,事实压缩)+ 正文(情报分析师视角,趋势判断)解耦
**Prompt设计**
```markdown
## Part 1: Metadata(新闻编辑视角)
请生成以下结构化信息:
- title: 10字以内的标题(事实陈述,无修饰)
- lead: 20字以内的导语(核心事实)
- highlights: 3-5个关键要点(bullet points,纯事实)
约束:只陈述事实,不做趋势判断,不用形容词。
## Part 2: 洞察正文(情报分析师视角)
基于多源报道,识别:
1. 事件脉络:关键时间节点和进展
2. 多角度分析:技术维度、战略维度、舆论维度
3. 影响与展望:短期影响、中长期趋势、值得关注信号
约束:
- 禁止空泛评论(如"意义重大""影响深远"
- 每个观点必须有素材支撑
- 使用具体名称(装备型号/政策名称/组织名称),不用"某些""部分"等模糊指代
```
**输出示例**
```markdown
---
title: "歼-35A列装部队"
lead: "空军官方确认歼-35A已列装首批作战部队"
highlights:
- 首次公开确认进入实战化部署阶段
- 隐身性能对标F-35C,可能在舰载领域形成优势
- 多国媒体关注其对西太平洋军事平衡的影响
---
## 事件脉络
- 2024-11:珠海航展首次公开亮相
- 2025-03:完成舰载适配测试
- 2025-05:空军确认列装首批作战部队【新进展】
## 多角度分析
- **技术维度**:隐身涂层、航电系统、舰载适配均有突破
- **战略维度**:提升海军航空兵远海作战能力
- **舆论维度**:外媒关注中美舰载机代差缩小
## 影响与展望
短期:提升海军航母编队作战能力
中期:可能在西太平洋形成局部优势
值得关注:后续舰载版测试进展、出口动向
```
#### 网摘生成设计(继承 military-digest-v3
**定位**:在三层整合中,网摘是面向直接传播的成品内容。不同于摘要(速览用)和洞察(分析用),网摘采用《参考消息》官方新闻报道格式,适合直接推送到飞书群或作为独立内容分发。
**核心特性**
| 特性 | 说明 |
|------|------|
| 风格 | 《参考消息》官方新闻报道格式:标题+原标题+发布日期+正文+价值点 |
| 来源识别 | 自动区分微信公众号源("据公众号 XXX 报道")和普通源("据 XXX 报道" |
| 字数校验 | 正文严格 280-320 字(含标点),价值点 35-45 字 |
| 重试机制 | 不达标自动重试,最多 3 次,每次带具体反馈("正文只有 XX 字,太少!" |
| 生成范围 | Top 3 文章,与摘要(全量)和洞察(Top 10)互补 |
| 输出格式 | 文本文件(.txt+ Pillow 渲染长图(.png |
**网摘 Prompt 核心约束**
```markdown
标题要求
简洁、客观、中性、信息密度高
结构:主体 + 事件 + 核心态势
不抒情、不夸张、不用网络用语
正文格式要求
开头第一句必须加:据[来源]报道
正文风格:客观、平实、严谨、书面化,类似外电编译稿
必须充分展开:补充背景、说明意义、分析影响、展望前景
全文一段到底,不分段
【字数强制要求 - 必须严格执行】
正文字数严格控制在 280~320 字(含标点),一个字都不能少,一个字都不能多!
如果内容不够,请合理补充相关背景、行业态势、同类项目对比等专业内容
价值点要求
正文结束后空一行,再写价值点
价值点严格 3545 字(含标点)
句式结构:事件 - 影响 / 后果 - 值得关注
```
**字数校验重试机制**
```python
def generate_webzine_for_article(article, api_key, base_url, model, max_retries=3):
"""为单篇文章生成参考消息风格网摘,支持字数校验重试"""
for attempt in range(max_retries):
result = call_ai([...], purpose="网摘生成")
# 提取正文部分
body_text = extract_body(result)
body_len = len(body_text)
if 280 <= body_len <= 320:
return result # 达标,直接返回
# 不达标,在 prompt 末尾追加反馈
if body_len < 280:
prompt += f"\n\n【上次反馈:正文只有{body_len}字,太少!请大幅增加内容!】"
else:
prompt += f"\n\n【上次反馈:正文有{body_len}字,太多!请精简内容!】"
return last_result # 重试耗尽,返回最后结果
```
**输出示例**
```
标题:歼-35A隐身舰载战斗机正式列装海军航空兵部队
原标题:China's J-35A stealth fighter enters service with naval aviation
发布日期:2025年05月24日
正文:据解放军报报道,中国海军航空兵部队已于近日正式列装歼-35A隐身舰载战斗机,标志着中国成为继美国之后第二个具备隐身舰载机作战能力的国家。歼-35A采用双发中型设计,配备国产涡扇-19发动机,最大起飞重量约30吨,雷达反射截面积据分析优于F-35C。该机配备有源相控阵雷达、分布式光电系统以及先进的电子战套件,可携带霹雳-15中远程空空导弹和鹰击-12超音速反舰导弹等多型武器。军事专家指出,歼-35A的列装将大幅提升中国海军航母编队的制空作战和远程打击能力,特别是在西太平洋方向形成对F-35C的局部数量优势。美国海军战争学院报告认为,中国正加速缩小与美国在舰载航空领域的技术差距,预计到2030年前后将形成至少3个歼-35A舰载机联队的规模。日本防卫省已表示将密切关注相关动向。
价值点:歼-35A列装标志着中国成为全球第二个拥有隐身舰载机的国家,将显著改变西太平洋海上力量对比,后续量产规模和舰载适配进展值得持续关注。
```
**三层整合对比**
| 层次 | 产品 | 覆盖范围 | 定位 | 输出格式 |
|------|------|:---:|------|------|
| 第一层 | 摘要级速览 | 全量(所有簇) | 快速浏览,50-80字精炼 | Markdown表格 |
| 第二层 | 洞察级分析 | Top 10 热点 | 深度分析,双视角(metadata+正文) | Markdown段落 |
| 第三层 | 参考消息网摘 | Top 3 热点 | 成品内容,直接传播 | TXT文本 + PNG长图 |
#### Prompt防退化设计(借鉴AI Daily
**禁止套话列表**
```python
FORBIDDEN_PHRASES = [
"意义重大", "影响深远", "引发关注", "备受瞩目",
"深水区", "拐点", "白热化", "新纪元", "里程碑",
"不容忽视", "值得注意", "值得关注", # 除非后接具体内容
"某些", "部分", "一些", "相关", # 模糊指代
]
def check_degeneration(content: str) -> list[str]:
"""检查内容是否包含禁止套话"""
violations = []
for phrase in FORBIDDEN_PHRASES:
if phrase in content:
violations.append(phrase)
return violations
```
**Prompt中的防退化指令**
```markdown
## 输出约束(防退化)
1. 禁止使用以下套话:
- "意义重大""影响深远""引发关注""备受瞩目"
- "深水区""拐点""白热化""新纪元""里程碑"
2. 每个观点必须有素材支撑:
- 错误:该装备性能先进
- 正确:该装备隐身系数0.01,优于F-35的0.02
3. 使用具体名称,禁止模糊指代:
- 错误:某些国家表示关注
- 正确:日本防卫省发布关注声明
4. 从素材出发,每次措辞应不同,避免模板化输出
```
**验收标准**
- [ ] 摘要信息完整度 > 90%
- [ ] 洞察分析覆盖双视角(metadata + 正文)
- [ ] 网摘正文字数达标率 > 90%280-320字)
- [ ] 网摘价值点字数达标率 > 90%(35-45字)
- [ ] 无禁止套话出现
- [ ] 整合内容无明显事实错误
---
### 阶段六:日报生成与跨日关联(Week 11-12)
**目标**:生成结构化日报(含Sentinel标记),实现跨日关联
| 序号 | 任务 | 描述 | 输出 | 依赖 |
|------|------|------|------|------|
| 6.1 | 日报模板设计 | Markdown模板,包含热点、速览、数据概览、网摘 | `templates/daily_report.md` | 5.9 |
| 6.2 | **Sentinel分段标记** | 单文件多板块精确管理 | `src/utils/sentinel.py` | 6.1 |
| 6.3 | **跨日关联模块** | 从历史日报提取上下文,追踪事件脉络 | `src/processors/cross_day.py` | 6.2 |
| 6.4 | 排序算法 | 综合热度、时效、重要性的排序逻辑 | 排序模块 | 4.4 |
| 6.5 | 日报渲染服务 | 按模板组装数据,生成Markdown(含Sentinel | 日报渲染服务 | 6.1, 6.2, 6.4 |
| 6.6 | 网摘图片渲染 | Pillow渲染TOP3合并长图,含Banner标题 | 图片渲染服务 | 5.7 |
| 6.7 | Web归档站点 | 部署在线阅览站点 | Web站点 | 6.5 |
| 6.8 | 数据保留策略 | fetch保留2天,notify保留2天,push保留5天 | 清理策略 | 6.7 |
#### 简化版Sentinel分段标记设计
**标记格式**
```markdown
---
title: "每日情报早报"
date: "2026-05-24"
stats:
total_entities: 87
hotspot_count: 10
---
<!-- SECTION:summary BEGIN -->
## 📋 全量新闻速览
| # | 实体 | 摘要 | 来源数 | 热度 |
|---|------|------|--------|------|
| 1 | 歼-35A | 空军确认列装\|隐身性能对标F-35C | 8 | ★★★★★ |
<!-- SECTION:summary END -->
<!-- SECTION:insights BEGIN -->
## 🔥 热点深度洞察
### 1. 歼-35A列装进展 [持续跟踪]
> 速览:空军官方确认歼-35A已列装首批作战部队 [8源报道]
**事件脉络**
- 5月20日:首次公开亮相
- 5月24日:【新进展】确认列装部队
...
<!-- SECTION:insights END -->
<!-- SECTION:webzine BEGIN -->
## 📰 参考消息网摘
(网摘文本内容,含标题/原标题/发布日期/正文/价值点)
<!-- SECTION:webzine END -->
```
**核心代码**
```python
import re
from datetime import datetime, timedelta
def extract_section(content: str, section_name: str) -> str:
"""从日报内容中提取指定section"""
pattern = rf'<!-- SECTION:{re.escape(section_name)} BEGIN -->(.*?)<!-- SECTION:{re.escape(section_name)} END -->'
match = re.search(pattern, content, re.DOTALL | re.IGNORECASE)
return match.group(1).strip() if match else ""
def get_historical_context(entity_name: str, days: int = 7) -> dict:
"""获取某实体近N天的历史报道上下文"""
context = {
"first_seen": None,
"previous_summaries": [],
"previous_insights": [],
"mention_count": 0
}
for i in range(days):
date = (datetime.now() - timedelta(days=i)).strftime("%Y-%m-%d")
file_path = f"data/reports/daily-{date}.md"
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
if entity_name in content:
context["mention_count"] += 1
if context["first_seen"] is None:
context["first_seen"] = date
summary_section = extract_section(content, "summary")
for line in summary_section.split('\n'):
if entity_name in line and line.strip().startswith('|'):
context["previous_summaries"].append({
"date": date,
"content": line.strip()
})
insights_section = extract_section(content, "insights")
if entity_name in insights_section:
insight_blocks = re.split(r'### \d+\.', insights_section)
for block in insight_blocks:
if entity_name in block:
context["previous_insights"].append({
"date": date,
"content": block.strip()[:500]
})
break
except FileNotFoundError:
continue
return context
def generate_cross_day_marker(entity_name: str) -> str:
"""生成跨日标记"""
history = get_historical_context(entity_name, days=7)
if history["mention_count"] == 0:
return "首次报道"
elif history["mention_count"] == 1:
return "持续跟踪"
else:
return f"持续跟踪({history['mention_count']}次)"
```
**验收标准**
- [ ] 日报生成时间 < 20分钟
- [ ] Sentinel标记正确,可精确提取summary/insights/webzine
- [ ] 跨日关联可追踪实体历史报道
- [ ] 网摘长图渲染正常(合并多篇 + Banner标题)
- [ ] Web站点可正常访问
---
### 阶段七:优化与迭代(Week 13-14)
**目标**:持续优化,功能扩展
| 序号 | 任务 | 描述 | 优先级 |
|------|------|------|--------|
| 7.1 | Prompt优化 | 基于实际效果迭代优化提示词 | 高 |
| 7.2 | 反馈闭环 | 收集用户反馈,标注数据,优化模型 | 高 |
| 7.3 | 趋势分析 | 7日热点趋势图,周期性报告 | 中 |
| 7.4 | 个性化推荐 | 基于用户阅读历史的个性化排序 | 低 |
---
## 四、技术栈建议
### 4.1 核心组件
| 组件 | 推荐方案 | 说明 |
|------|----------|------|
| 数据采集 | Python + feedparser | RSS解析 |
| 数据存储 | SQLite + JSON文件 | 数据库+文件双存储 |
| LLM调用 | OpenAI SDK / 国产模型SDK | 统一接口封装 |
| 翻译 | 中英分离 + ThreadPoolExecutor并发 | 中文文章零API调用 |
| 缓存 | SQLite 三级缓存 + 自动迁移 | 断点续跑,二次运行 ~5s |
| 图片渲染 | Pillow + 中文字体fallback | 网摘长图生成 |
| 任务调度 | systemd timer | 系统级服务管理 |
| Web展示 | Hugo / Flask | 静态/动态站点 |
| 推送 | 飞书 Webhook | 群机器人消息推送 |
| 日志 | Python logging + systemd journal | 集中日志管理 |
| 监控 | 11阶段耗时 + API统计 + 源成功率 | 运行结束自动打印报表 |
### 4.2 模型选择
| 任务类型 | 推荐模型 | 预估成本 |
|----------|----------|----------|
| 标题翻译 | DeepSeek-V3 / Qwen-Plus | ~0.001元/次 |
| 正文翻译 | DeepSeek-V3 / Qwen-Plus | ~0.002元/次 |
| 实体提取 | DeepSeek-V3 / Qwen-Plus | ~0.001元/次 |
| 角度分类 | DeepSeek-V3 / Qwen-Plus | ~0.001元/次 |
| 单篇评分 | DeepSeek-V3 / Qwen-Plus | ~0.001元/次 |
| 摘要整合 | DeepSeek-V3 / Qwen-Plus | ~0.002元/次 |
| 网摘生成 | DeepSeek-V3 / Qwen-Plus | ~0.005元/次(含重试) |
| 实体消歧 | GPT-4o / Claude-3.5-Sonnet | ~0.01元/次 |
| 热点精评 | GPT-4o / Claude-3.5-Sonnet | ~0.02元/次 |
| 洞察整合 | GPT-4o / Claude-3.5-Sonnet | ~0.1元/次 |
**日成本估算**
- 200-500篇/日 × 0.001元(小模型)= 0.2-0.5元
- 外文翻译(按30%外文率):60-150篇 × 0.003元 = 0.18-0.45元
- 100个簇 × 0.001元(小模型)= 0.1元
- 3篇网摘 × 0.005元 = 0.015元
- 10个洞察 × 0.1元(大模型)= 1元
- **总计:约1.5-2.1元/日**
---
## 五、项目结构
```
news-intelligence-system/
├── config/
│ ├── rss_sources.json # RSS源配置
│ ├── models.yaml # 模型配置
│ └── systemd/ # systemd服务配置
├── src/
│ ├── collectors/ # 数据采集
│ │ └── rss_collector.py
│ ├── processors/ # 处理管道
│ │ ├── translator.py # 翻译管线(中英分离+并发翻译)
│ │ ├── entity_extractor.py
│ │ ├── angle_classifier.py
│ │ ├── cluster_engine.py
│ │ ├── heat_calculator.py
│ │ └── cross_day.py # 跨日关联
│ ├── integrators/ # 内容整合
│ │ ├── summary_integrator.py
│ │ ├── insight_integrator.py
│ │ └── webzine_generator.py # 网摘生成(参考消息风格+字数校验)
│ ├── generators/ # 报告生成
│ │ ├── daily_report_generator.py
│ │ ├── image_renderer.py # 网摘图片渲染(Pillow)
│ │ └── web_renderer.py
│ ├── push/ # 推送平台
│ │ ├── base.py
│ │ └── feishu.py # 飞书 webhook(即时+日报双模式)
│ ├── storage/ # 存储层
│ │ ├── cache.py # SQLite三级缓存(文章/网摘/分类摘要)
│ │ └── file_storage.py # JSON文件读写
│ ├── monitor/ # 监控统计
│ │ └── monitor.py # 阶段耗时+API消耗+成功率+缓存命中率
│ └── utils/ # 工具函数
│ ├── sentinel.py # Sentinel分段标记
│ ├── prompt_checker.py # Prompt防退化检查
│ └── language.py # 中文检测(is_chinese
├── prompts/ # 提示词文件
│ ├── article_score.txt # 单篇评分(含硬约束)
│ ├── extract_entities.txt
│ ├── classify_angle.txt
│ ├── quick_heat.txt
│ ├── precise_heat.txt
│ ├── summary_integrate.txt
│ ├── insight_integrate.txt # 双视角洞察
│ └── webzine_generate.txt # 参考消息网摘(含字数约束)
├── templates/
│ └── daily_report.md # 含Sentinel标记(summary/insights/webzine
├── data/
│ ├── cache.db # SQLite缓存数据库
│ ├── fetch/ # fetch-yyyy-mm-dd.json
│ ├── notify/ # notify-yyyy-mm-dd.json
│ └── reports/ # daily-yyyy-mm-dd.md
├── output/ # 输出文件
│ ├── report_YYYYMMDD.md # Markdown日报
│ ├── webzine_YYYYMMDD.txt # 网摘文本
│ └── webzine_YYYYMMDD.png # 网摘合并长图
├── web/ # Web归档站点
├── tests/
├── scripts/
│ ├── fetch_loop.py
│ ├── push_loop.py
│ └── setup_systemd.sh
├── requirements.txt
└── README.md
```
---
## 六、关键风险与应对
| 风险 | 影响 | 应对措施 |
|------|------|----------|
| RSS源失效 | 数据缺失 | 多源备份,监控告警 |
| LLM API限流 | 处理延迟 | 批量处理,重试机制,降级策略 |
| 翻译质量不稳定 | 后续分析偏差 | 低温度(0.2)翻译,失败时原文填充 |
| 缓存数据库损坏 | 缓存失效 | 连接降级不影响主流程,自动重建 |
| 网摘字数不达标 | 输出质量下降 | 3次重试校验,每次带具体反馈 |
| 实体识别错误 | 聚类偏差 | 人工标注反馈,Prompt迭代 |
| 热点漏识别 | 信息缺失 | 动态阈值保底机制,人工复核 |
| 成本超支 | 预算超支 | Token监控,模型降级,配额控制 |
| 进程崩溃 | 服务中断 | systemd自动重启 |
| LLM输出退化 | 质量下降 | **Prompt防退化检查** |
---
## 七、里程碑与交付物
| 里程碑 | 时间 | 交付物 |
|--------|------|--------|
| M1 | Week 2 | 稳定运行的数据采集系统(含翻译管线、SQLite缓存、监控统计) |
| M2 | Week 4 | Fetch循环上线,**评分硬约束生效**,飞书即时推送可用 |
| M3 | Week 6 | 细粒度聚类引擎,实体提取准确率>85% |
| M4 | Week 8 | 动态热点识别系统,召回率>90% |
| M5 | Week 10 | Push循环上线,**三层整合(摘要+洞察+网摘)+Prompt防退化** |
| M6 | Week 12 | **Sentinel跨日关联上线**,网摘长图渲染,Web归档站点 |
| M7 | Week 14 | 持续优化迭代 |
---
## 八、借鉴与继承总结
### 8.1 架构层面(借鉴 AI Daily
1. **双循环架构**Fetch循环(实时)+ Push循环(定时)
2. **systemd服务化**:替代Python内部定时,提升稳定性
3. **文件存储规范**fetch/notify/reports三种文件类型,明确保留策略
### 8.2 LLM应用层面(借鉴 AI Daily
1. **评分硬约束**:非目标领域≤79、KOL转述≤89,有效控制信息质量
2. **Prompt防退化**:禁止套话、要求从素材出发,避免LLM输出风格趋同
3. **双视角洞察**:metadata(事实压缩)+ 正文(趋势判断)解耦
### 8.3 数据管理层面(借鉴 AI Daily)
1. **Sentinel分段标记**:单文件多板块精确管理,支持跨日关联
2. **跨日关联**:从历史日报提取上下文,追踪事件发展脉络
3. **数据保留策略**:自动清理过期文件
### 8.4 工程资产层面(继承 military-digest-v3
1. **SQLite三级缓存**:文章+网摘+分类摘要,含自动迁移和过期清理,二次运行 ~5s
2. **翻译管线**:中英分离(汉字占比>20%判定)+ 外文并发翻译,中文零API调用
3. **监控统计**:11阶段耗时 + API按用途/模型分组 + 源抓取成功率 + 缓存命中率
4. **网摘生成**:参考消息风格 + 公众号源智能识别 + 280-320字校验重试(3次)
5. **图片渲染**:Pillow命令模式 + 中文字体多级fallback
6. **飞书推送**:webhook文本推送 + 5级异常分层捕获 + 失败优雅降级
### 8.5 工程层面
1. **日志集中管理**systemd journal便于问题定位
2. **推送聚焦飞书**:webhook消息推送,覆盖即时快讯和日报两种场景
3. **成本可控**:每天约1.5-2.1元(含翻译),缓存命中时几乎零成本
---
## 附录Amilitary-digest-v3 实际运行验证数据
> 以下数据来自 military-digest-v3 系统 2026-05-14 的实际运行验证,为新系统的设计和成本估算提供基准参考。
### A.1 全链路冷启动验证
清除所有缓存和输出文件后运行,完整链路通过:
| 阶段 | 耗时 | 状态 |
|------|:---:|:---:|
| RSS 抓取(5源) | 7.5s | ✅ |
| 时间过滤 (156→22篇) | 0.0s | ✅ |
| 去重 | 0.0s | ✅ |
| 标题翻译(7篇外文) | 17.9s | ✅ |
| 关键词筛选 (22→15篇) | 0.0s | ✅ |
| 正文翻译(6篇外文) | 9.9s | ✅ |
| AI评分分类(15篇) | 30.7s | ✅ |
| 网摘生成(3篇,含2次重试) | 53.3s | ✅ |
| 分类介绍生成(4类) | 33.5s | ✅ |
| 图片生成 | 0.3s | ✅ |
| 报告生成 | 0.0s | ✅ |
| **总耗时** | **153s** | ✅ |
**API 消耗统计:**
| 用途 | 次数 | tokens 估算 |
|------|:---:|:---:|
| 标题翻译 | 7 | 1,400 |
| 正文翻译 | 6 | 4,800 |
| AI评分分类 | 15 | 12,000 |
| 网摘生成 | 5 (含2次重试) | 4,000 |
| 分类介绍 | 4 | 600 |
| **合计** | **37** | **~22,800** |
**输出文件验证:**
```
military_report_20260514.md 10.6 KB ✅ Markdown 格式完整
military_webzine_20260514.txt 4.9 KB ✅ TOP3 网摘文本完整
military_webzine_20260514.png 868.5 KB ✅ 合并长图渲染正常
article_cache.db 60.0 KB ✅ 数据完整无异常
```
### A.2 SQLite 缓存数据完整性验证
冷启动全链路运行后,直接查询 `article_cache.db` 验证:
**基本信息:**
| 表 | 行数 | 说明 |
|------|:---:|------|
| `article_cache` | 15 | 与关键词筛选后文章数完全一致 |
| `category_summary_cache` | 4 | 今日必看/装备动态/地区冲突/战略政策全覆盖 |
**逐项检查:**
| 检查项 | 结果 | 判定 |
|------|:---:|:---:|
| id 重复 | 0 条 | ✅ |
| 失败条目 (status≠1) | 0 条 | ✅ |
| translated_title 缺失 | 0/15 | ✅ |
| translated_content 缺失 | 0/15 | ✅ |
| ai_summary 缺失 | 0/15 | ✅ |
| ai_category 缺失 | 0/15 | ✅ |
| published_time 缺失 | 0/15 | ✅ |
| webzine_text 覆盖率 | 3/15 | ✅ (仅TOP3需要) |
| ai_score 范围 | 3.3 ~ 6.5 (avg 5.3) | ✅ 正态分布 |
| 分类分布 | 装备7 / 战略5 / 冲突3 | ✅ 合理 |
### A.3 缓存命中验证(连续运行2次)
| 指标 | 第一次(冷启动) | 第二次(含缓存) |
|------|:---:|:---:|
| 文章缓存命中 | 0 / 15 | **15 / 15** ✅ |
| API 调用次数 | 37 次 | **0 次** ✅ |
| 总耗时 | 153s | **~5s** ✅ |
| 退出码 | 0 | 0 |
> 第二次运行时文章缓存、网摘缓存、分类介绍缓存全部命中,跳过所有 AI 调用,仅做 RSS 抓取 + 文件排版,几乎零 token 消耗。
### A.4 飞书推送验证
| 场景 | 配置 | 结果 | 主流程 |
|------|------|------|:---:|
| 推送关闭 | `enable_feishu_push: false` | "未启用任何推送渠道,跳过" | exit 0 ✅ |
| **飞书(真实webhook** | `enable_feishu_push: true` | **飞书推送成功** 🎉 | exit 0 ✅ |
**错误处理矩阵(5级分层):**
| 异常类型 | 处理方式 | 主流程影响 |
|------|------|:---:|
| `ConnectionError` | warning 日志 + 返回 False | 无 |
| `Timeout` (连接5s/读取15s) | warning 日志 + 返回 False | 无 |
| `HTTPError` (4xx/5xx) | warning 日志 + 返回 False | 无 |
| `JSONDecodeError` | warning 日志 + 返回 False | 无 |
| 其他 `Exception` | warning 日志 + 返回 False | 无 |
---
*文档版本:v3.0*
*最后更新:2026-05-29*
*状态:融合 AI Daily 四大核心设计 + military-digest-v3 六大工程资产*