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

17 KiB
Raw Permalink Blame History

军事科技每日摘报系统优化方案指南

🎯 优化目标

适配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,已修复为安全 fallbacka.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=93000warning 降级 exit 0
飞书(真实webhook enable_feishu_push: true 飞书推送成功 🎉 exit 0

关键验证点:

  • 飞书 webhook 真实连接成功,消息送达飞书群
  • 企业微信请求正确送达服务器(无效 key 返回标准 errcode,非网络异常)
  • 所有异常均优雅降级为 warning 日志,不抛异常,不影响主流程
  • 推送代码可通过 config.json 开关一键启用/关闭,webhook 凭据统一在 .env 管理

4.6 配置安全加固

2026-05-21 完成全项目敏感信息扫描和加固:

发现的问题:

问题 严重程度 修复
项目缺少 .gitignoreconfig/.env 可能泄露到 Git 🔴 严重 新建 .gitignore,首行即排除 config/.env
config.jsonwechat_target/wechat_account 敏感字段 🟡 中等 删除,统一迁移到 .envWECHAT_ACCOUNT/WECHAT_TARGET
docker-compose.yml 缺少推送环境变量 🟡 中等 两个服务均补充 WECHAT_ACCOUNT/WECHAT_TARGET/FEISHU_WEBHOOK
.env 字段名与代码不一致 🟡 中等 WECHAT_WEBHOOK_KEYWECHAT_ACCOUNTFEISHU_WEBHOOK_URLFEISHU_WEBHOOK

加固后架构:

config.json   ← 仅开关标志,可 git 追踪
config/.env   ← 所有敏感凭据,.gitignore 排除
环境变量       ← Docker/CI 场景的最终覆盖

扫描结论: 所有 .py 代码、MakefileDockerfileconfig.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/.envRSS_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.pycreate_webzine_image131行)与 create_combined_webzine_image106行)存在三层重复:

  • 文本解析层:前缀识别(标题:/正文:/价值点:等)逻辑完全一致
  • 字体配置层: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 调用而非抓取。