# 新闻智能分析系统开发计划 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` **表1:article_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` **表2:category_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](截取即可) └─ 外文文章 → 提交到 ThreadPoolExecutor(max_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("非目标领域") # 约束2:KOL转述上限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 字(含标点),一个字都不能少,一个字都不能多! 如果内容不够,请合理补充相关背景、行业态势、同类项目对比等专业内容 价值点要求 正文结束后空一行,再写价值点 价值点严格 35~45 字(含标点) 句式结构:事件 - 影响 / 后果 - 值得关注 ``` **字数校验重试机制**: ```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 --- ## 📋 全量新闻速览 | # | 实体 | 摘要 | 来源数 | 热度 | |---|------|------|--------|------| | 1 | 歼-35A | 空军确认列装\|隐身性能对标F-35C | 8 | ★★★★★ | ## 🔥 热点深度洞察 ### 1. 歼-35A列装进展 [持续跟踪] > 速览:空军官方确认歼-35A已列装首批作战部队 [8源报道] **事件脉络** - 5月20日:首次公开亮相 - 5月24日:【新进展】确认列装部队 ... ## 📰 参考消息网摘 (网摘文本内容,含标题/原标题/发布日期/正文/价值点) ``` **核心代码**: ```python import re from datetime import datetime, timedelta def extract_section(content: str, section_name: str) -> str: """从日报内容中提取指定section""" pattern = rf'(.*?)' 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元(含翻译),缓存命中时几乎零成本 --- ## 附录A:military-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 六大工程资产*