Files
my-daily/系统优化方案指南.md

360 lines
17 KiB
Markdown
Raw Permalink 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.
# 军事科技每日摘报系统优化方案指南
## 🎯 优化目标
适配100+RSS订阅源、每日200+文章的处理需求,降低运行成本,提升稳定性,缩短整体处理时间到5分钟以内。
---
## 📋 优化优先级划分
### 🔴 P0级(高优先级,投入极小,收益极大,已完成)
| 优化项 | 预期效果 | 实施难度 | 状态 |
| --- | --- | --- | --- |
| 抓取模块线程池改造+失败重试 | 抓取速度提升60%,成功率提升15% | ⭐ | ✅ 已完成 |
| AI全链路并发化改造 | AI相关环节耗时降低70%,整体流程缩短一半 | ⭐ | ✅ 已完成 |
| 处理顺序前置优化 | 翻译token成本降低40%,翻译时间缩短40% | ⭐ | ✅ 已完成 |
### 🟠 P1级(中优先级,投入小,收益大,优先开展)
| 优化项 | 预期效果 | 实施难度 | 状态 |
| --- | --- | --- | --- |
| 增量处理+SQLite本地缓存 | ~~避免重复处理已抓取/分析的文章,再次运行时间缩短80%,支持断点续跑~~ 已实现文章缓存+网摘缓存+分类介绍缓存+自动过期清理,再次运行几乎零token消耗 | ⭐⭐ | ✅ 已完成 |
| 失败降级机制 | ~~某环节失败自动降级,不会中断整体流程,提升稳定性~~ 全链路10个模块均已覆盖:抓取重试/翻译fallback/AI默认评分/字体多级fallback/缓存连接降级 | ⭐ | ✅ 已完成 |
| 基础监控统计 | ~~各环节耗时统计、API消耗统计、成功率统计,便于排查问题和成本管控~~ 已实现:阶段耗时/API调用量+token/源成功率+缓存命中率一手掌控,运行结束自动打印 | ⭐⭐ | ✅ 已完成 |
### 🟡 P2级(中低优先级,投入中等,长期收益明显)
| 优化项 | 预期效果 | 实施难度 | 状态 |
| --- | --- | --- | --- |
| main()函数拆分重构 | ~~主函数从200+行缩减至~50行,每个子函数15-30行职责单一;可单独测试去重/分类/网摘等步骤~~ 已实现:7个子函数提取完毕,main()从310→115行(-63%),每步可独立测试 | ⭐⭐ | ✅ 已完成 |
| 推送模块完善 | ~~实现完整的微信/飞书webhook推送,支持自定义推送内容~~ 已实现:modules/pusher.py 封装企业微信文本/图片/Markdown + 飞书文本推送,主流程末自动触发,失败优雅降级 | ⭐⭐ | ✅ 已完成 |
| **图片生成模块去重重构** 🔥 | create_webzine_image与create_combined_webzine_image存在~100行重复(文本解析、字体配置、渲染绘制三层重复),提取4个公共函数消除重复,代码量减少~40% | ⭐ | ⏳ 待开展 |
| 差异化抓取调度 | 高频新闻源缩短抓取间隔,低频源延长间隔,降低无效抓取请求 | ⭐⭐ | ⏳ 待开展 |
| 异步流式处理队列 | 抓取和后续处理并行执行,整体耗时再缩短30% | ⭐⭐⭐ | ⏳ 待开展 |
### 🟢 P3级(低优先级,投入大,规模扩大后再考虑)
| 优化项 | 适用场景 | 实施难度 | 状态 |
| --- | --- | --- | --- |
| SimHash相似内容去重 | 源>500、大量转载内容场景,减少重复文章 | ⭐⭐⭐⭐ | 💤 待规划 |
| 微服务拆分+分布式消息队列 | 源>1000、单机器性能不足时,支持水平扩展 | ⭐⭐⭐⭐ | 💤 待规划 |
| 管理后台界面 | 可视化配置源、查看历史报告、统计分析 | ⭐⭐⭐⭐ | 💤 待规划 |
| 本地大模型部署 | 降低API调用成本,实现私有化部署 | ⭐⭐⭐⭐ | 💤 待规划 |
---
## 📊 已完成进度总览
| 阶段 | 完成度 | 核心成果 |
| --- | --- | --- |
| 架构重构 | 100% | 单文件拆分为模块化结构,可维护性大幅提升 |
| P0级优化 | 100% | 抓取+AI环节速度提升2-3倍,成本降低40% |
| P1级优化 | 100% | SQLite缓存+全链路降级+基础监控统计,再次运行几乎零token消耗 |
| 功能完善 | 100% | 推送模块完成,企业微信文本+图片推送+飞书文本推送 |
| 稳定性优化 | 100% | 抓取重试+全链路降级+监控统计 |
---
## 🚀 下一阶段优化实施计划
### 第一阶段 ~~(当前优先开展,预计1-2天完成)~~ ✅ 已完成
> 核心目标:完善可观测性,补齐P1最后一块拼图
1. ~~**统计监控功能**(P1收尾)~~ ✅ 已完成:
- 阶段耗时自动统计,运行结束输出结构化报表
- API调用量/token消耗按用途和模型分组统计
- 源抓取成功/失败率一目了然
2. ~~**SQLite增量缓存系统实现**~~ ✅ 已完成
3. ~~**全链路失败降级机制**~~ ✅ 已完成
### 第二阶段(当前开展,预计2-3天完成)
> 核心目标:提升代码质量,完善功能
**推荐顺序**(按投入产出比排列):
1. ~~**main()函数拆分重构**(建议最先做)~~ ✅ 已完成
2. ~~**推送模块完善**~~ ✅ 已完成:
- `modules/pusher.py` 封装企业微信(文本/图片/Markdown)+ 飞书(文本)webhook 推送
- `config.py` 新增 `load_push_config()` 统一加载推送配置(环境变量 > .env > config.json
- 主流程末自动调用,推送失败优雅降级(warning 日志,不影响 exit 0
- 支持关闭推送(`enable_wechat_push: false` / `enable_feishu_push: false`
3. **异步流式处理改造**
- 需变更架构(引入队列),建议在函数拆分完成、代码结构清晰后再做
4. **差异化抓取调度**
- 为 rss_feeds.txt 增加频率字段,需配合定时调度器改造
### 第三阶段(按需扩展,规模扩大后开展)
> 核心目标:支持更大规模源和更高性能要求
根据实际业务需求,优先开展最急需的优化点。
---
## 📌 实施建议
1. ~~优先完成第一阶段优化~~ ✅ P0+P1 共 6 项全部到位
2. ~~第二阶段 main()拆分 + 推送模块~~ ✅ 已完成
3. 当前优先级:图片生成模块去重重构 → 差异化抓取调度 → 异步流式处理(源扩展后再做)
4. P3 级优化建议在单机器无法满足性能要求,或者有明确功能需求时再实施
---
## 🧪 验证阶段
### 4.1 main() 函数拆分验证
2026-05-14 完成拆分重构,按 `主函数过长问题.md` 方案落地:
| # | 提取函数 | 职责 | 行数 | 可测试性 |
|:---:|---|------|:---:|:---:|
| ① | `merge_from_cache` | 合并缓存+新文章,按评分排序 | 9 | ⭐⭐⭐ |
| ② | `process_new_articles` | 完整管线:排序→标题翻译→筛选→正文翻译→AI分析→写缓存 | 32 | ⭐⭐ |
| ③ | `deduplicate_articles` | 同源标题去重 | 12 | ⭐⭐⭐ |
| ④ | `categorize_articles` | 三类文章分组 | 11 | ⭐⭐⭐ |
| ⑤ | `write_markdown_report` | Markdown报告拼接+写入(含`_append_category`消除三分类重复) | 40 | ⭐⭐ |
| ⑥ | `build_webzine_content` | 网摘文本生成(优先缓存+写回) | 33 | ⭐⭐ |
| ⑦ | `get_or_generate_overview` | 分类介绍查缓存/生成(消除原有4处×8行重复) | 9 | ⭐⭐ |
**拆分效果:** main() 从 ~310 行缩减至 ~115 行(-63%),消除代码重复 60+ 行。拆分后 7 次独立运行全部 exit 0。
**附带修复的 Bug** 发现 `keyword_filter.py` 在正文翻译前硬读 `a['translated_content']` 导致 `KeyError`,已修复为安全 fallback`a.get('translated_content') or a.get('content') or ''`)。
---
### 4.2 SQLite 缓存数据完整性验证
2026-05-14 冷启动全链路运行后,直接查询 `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 | ✅ 合理 |
**缓存命中验证(连续运行2次):**
| 指标 | 第一次(冷启动) | 第二次(含缓存) |
|------|:---:|:---:|
| 文章缓存命中 | 0 / 15 | **15 / 15** ✅ |
| API 调用次数 | 37 次 | **0 次** ✅ |
| 总耗时 | 153s | **~5s** ✅ |
| 退出码 | 0 | 0 |
> 第二次运行时文章缓存、网摘缓存、分类介绍缓存全部命中,跳过所有 AI 调用,仅做 RSS 抓取 + 文件排版,几乎零 token 消耗。
---
### 4.3 全链路冷启动验证
2026-05-14 清除所有缓存和输出文件后运行,完整链路通过:
| 阶段 | 耗时 | 状态 |
|------|:---:|:---:|
| 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 ✅ 数据完整无异常
```
---
### 4.4 当前优化完成总览
| 优先级 | 完成度 | 已实现项目 |
|:---:|:---:|---|
| P0 | 100% | 线程池抓取、AI全链路并发、处理顺序前置 |
| P1 | 100% | SQLite缓存、全链路降级、基础监控统计 |
| P2 | 60% | main()函数拆分 ✅ / 推送模块 ✅ / 图片去重 ⏳ / 差异化调度 ⏳ / 异步流式 ⏳ |
| P3 | 0% | 待规划 |
| **安全** | **100%** | `.gitignore` + 配置分离 + 全项目扫描无硬编码凭据 |
| **配置** | **100%** | `RSS_PROXY_BASE` 提取 + `.env.example` 结构对齐 |
---
### 4.5 推送模块验证
2026-05-21 完成推送模块开发并实际调用验证:
**架构:**
| 文件 | 职责 |
|------|------|
| `modules/pusher.py` | 企业微信文本/图片/Markdown + 飞书文本推送,含失败兜底(5级异常分层捕获) |
| `modules/config.py:load_push_config()` | 三层配置加载(环境变量 > .env > config.json |
| `military_daily_report_v3.py:L334-338` | 主流程末自动触发 |
**配置职责分离:**
| 配置来源 | 内容 | 说明 |
|------|------|------|
| `config.json` | `enable_wechat_push`, `enable_feishu_push` | 仅开关标志,可 git 追踪 |
| `config/.env` | `WECHAT_ACCOUNT`, `WECHAT_TARGET`, `FEISHU_WEBHOOK` | 敏感凭据,.gitignore 排除 |
**错误处理矩阵(5级分层):**
| 异常类型 | 处理方式 | 主流程影响 |
|------|------|:---:|
| `ConnectionError` | warning 日志 + 返回 False | 无 |
| `Timeout` (连接5s/读取15s) | warning 日志 + 返回 False | 无 |
| `HTTPError` (4xx/5xx) | warning 日志 + 返回 False | 无 |
| `JSONDecodeError` | warning 日志 + 返回 False | 无 |
| 其他 `Exception` | warning 日志 + 返回 False | 无 |
**实际运行验证(2026-05-21):**
| 场景 | 配置 | 结果 | 主流程 |
|------|------|------|:---:|
| 双推送关闭 | `enable_wechat_push: false, enable_feishu_push: false` | "未启用任何推送渠道,跳过" | exit 0 ✅ |
| 企业微信(无效key | `enable_wechat_push: true` | 服务器返回 `errcode=93000`warning 降级 | exit 0 ✅ |
| **飞书(真实webhook** | `enable_feishu_push: true` | **飞书推送成功** 🎉 | exit 0 ✅ |
**关键验证点:**
- ✅ 飞书 webhook 真实连接成功,消息送达飞书群
- ✅ 企业微信请求正确送达服务器(无效 key 返回标准 errcode,非网络异常)
- ✅ 所有异常均优雅降级为 warning 日志,不抛异常,不影响主流程
- ✅ 推送代码可通过 config.json 开关一键启用/关闭,webhook 凭据统一在 .env 管理
---
### 4.6 配置安全加固
2026-05-21 完成全项目敏感信息扫描和加固:
**发现的问题:**
| 问题 | 严重程度 | 修复 |
|------|:---:|------|
| 项目缺少 `.gitignore``config/.env` 可能泄露到 Git | 🔴 严重 | 新建 `.gitignore`,首行即排除 `config/.env` |
| `config.json``wechat_target`/`wechat_account` 敏感字段 | 🟡 中等 | 删除,统一迁移到 `.env``WECHAT_ACCOUNT`/`WECHAT_TARGET` |
| `docker-compose.yml` 缺少推送环境变量 | 🟡 中等 | 两个服务均补充 `WECHAT_ACCOUNT`/`WECHAT_TARGET`/`FEISHU_WEBHOOK` |
| `.env` 字段名与代码不一致 | 🟡 中等 | `WECHAT_WEBHOOK_KEY``WECHAT_ACCOUNT``FEISHU_WEBHOOK_URL``FEISHU_WEBHOOK` |
**加固后架构:**
```
config.json ← 仅开关标志,可 git 追踪
config/.env ← 所有敏感凭据,.gitignore 排除
环境变量 ← Docker/CI 场景的最终覆盖
```
**扫描结论:** 所有 `.py` 代码、`Makefile``Dockerfile``config.json` 中均无硬编码凭据残留。`.env.example``.env` 结构完全一致(11 个字段全部对齐)。
---
### 4.7 RSS_PROXY_BASE 配置提取
2026-05-21 将 `default_feeds` 中 8 个硬编码的 `werss.yynnice.top` URL 统一提取为可配置项:
**配置架构:**
| 层级 | 来源 | 效果 |
|:---:|------|------|
| 默认值 | 代码内置 | `https://werss.yynnice.top` |
| 覆盖 | `config/.env``RSS_PROXY_BASE` | 更换代理服务只需改一行 |
| 最终覆盖 | 环境变量 | Docker/CI 注入 |
**涉及文件:**
| 文件 | 改动 |
|------|------|
| `config.py` | `_load_rss_proxy_base()` 三层加载 + 8 个 `default_feeds` 改用 f-string |
| `.env` / `.env.example` | 新增 `RSS_PROXY_BASE` 配置项 |
| `docker-compose.yml` | 两个服务均传递 `RSS_PROXY_BASE` |
> 第三方 RSS 代理服务更换时只需改 `.env` 一行,无需修改 Python 代码或 `rss_feeds.txt`。
---
### 4.8 图片生成模块去重重构
`01.md` 方案提取 4 个公共函数:
| # | 提取函数 | 职责 | 消除重复行 |
|:---:|---|------|:---:|
| ① | `_parse_webzine_line` | 统一文本前缀解析(标题:/正文:/价值点:等) | ~30行 × 2 |
| ② | `_load_webzine_fonts` | 集中字体加载和配置(banner/article_title/bold/content | ~4行 × 2 |
| ③ | `_build_render_commands` | 将网摘文本转为渲染命令列表 | ~40行 × 2 |
| ④ | `_execute_render_commands` | 执行渲染命令,在画布上绘制内容 | ~30行 × 2 |
**重构效果预期:**
| 指标 | 重构前 | 重构后 |
|------|:---:|:---:|
| `create_webzine_image` | 115行 | ~50行 |
| `create_combined_webzine_image` | 106行 | ~45行 |
| 新增公共函数 | 0 | 4个(合计~110行) |
| **净减少代码** | — | **~100行(-45%** |
| 可单独测试的单元 | 0 | 4个公共函数 |
**回归验证方式:** 运行一次完整冷启动,对比重构前后输出的 3 个文件(md/txt/png)的字节级一致性。
---
## 🎯 下一步推荐
P2 剩余 3 项待开展,建议按以下顺序推进:
### 🥇 图片生成模块去重重构(投入 ⭐,收益大,建议最先做)
**当前问题:** `image_generator.py``create_webzine_image`131行)与 `create_combined_webzine_image`106行)存在三层重复:
- **文本解析层**:前缀识别(标题:/正文:/价值点:等)逻辑完全一致
- **字体配置层**:4种字体的加载代码完全相同(banner/article_title/bold/content
- **渲染绘制层**prefix_sameline / article_title / normal 等命令的绘制逻辑高度相似
**方案:** 提取 4 个公共函数(`_parse_webzine_line` / `_load_webzine_fonts` / `_build_render_commands` / `_execute_render_commands`),建立清晰的抽象层次。详见 `01.md`
**涉及改动:**`modules/image_generator.py` 一个文件,纯内部重构,无外部依赖变化。
**推荐理由:**
- 投入最低(⭐),仅涉及同一文件内的函数提取
- 风险极低,两个函数的现有行为完全不变
- 延续 main() 拆分的重构方法论,代码风格一致
- 可作为热身任务,在差异化调度和异步流式之前快速完成
### 🥈 差异化抓取调度(投入 ⭐⭐,收益大)
**当前问题:** 所有源统一 24h 抓一次,高频源(无人机类、战区类)可能错过半天内的重要新闻。
**方案:**`rss_feeds.txt` 增加频率字段,格式从 `名称|URL` 扩展为 `名称|URL|频率(小时)`。兼容现有格式(无频率默认 24h)。
**涉及改动:** `config.py` 解析逻辑 + `rss_fetcher.py` 读取上次抓取时间 + 外部 crontab 调高频率。
### 🥉 异步流式处理队列(投入 ⭐⭐⭐,规模化时收益大)
**当前架构:** 阶段间串行(全部抓取完 → 全部过滤完 → ...)。5 源 153s 完全够用。
**何时做:** 源扩展到 50+、冷启动耗时明显增加时再考虑。当前 5 源 RSS 抓取仅占 7-15s,瓶颈在 AI 调用而非抓取。