岳峙亭渊 DIGITAL STUDIO

ESSAY

个人情报系统 v2:从能用到好用的三次迭代

自动化 知识管理 AI应用 Obsidian

“能用的系统只解决’有没有’,好用的系统解决’想不想用’。“

从 500 条 RSS 到 9 条搜索

如果你读过我上一篇《用 n8n + DeepSeek 搭建个人科技情报系统》,应该记得 v1 的核心架构:13 个 RSS 源 → n8n 工作流 → DeepSeek 分析 → Obsidian。它每天处理 500+ 条信息,压缩到 10 条精华,执行耗时 2.5 分钟。

它能工作。但用了三个月后,我发现了几个问题:

  • RSS 源的局限性:我在意的不只是固定几个科技媒体的内容,而是整个领域正在发生什么。RSS 本质上是”订阅已知”,搜索才是”发现未知”。
  • n8n 的运维成本:Docker 容器要维护,工作流要调试,凭证系统有奇怪的限制。一个每天跑 2.5 分钟的系统,不值得我在它身上花超过 2.5 分钟的维护时间。
  • 输出缺乏可读性:每天十条长分析,每篇几百字。我看不看完——实际上经常不看。信息太多和没有信息,结果是相同的。

所以三个月后,我重写了整个系统。这次不是”再搭一套”,而是回答一个问题:什么样的情报系统,才会让我每天早上愿意打开?

答案是三条标准:

  1. 一眼看清价值 —— 不用读内容就知道哪条值得点
  2. 摘要先行 —— 每条 20 字,看完决定是否深入
  3. 零运维 —— 开机自动跑,跑完不用管

以下是实现这三条标准的三次迭代。


迭代一:价值评级系统

问题

v1 的输出是一篇长 Markdown,每条情报都有完整的 DeepSeek 分析:翻译、地缘政治洞察、评分。但问题是——所有条目看起来都很重要。每篇都是十行为单位的分析段落,扫读成本太高。

我真正需要的是:在扫读阶段就知道”这条和我有关吗?有多有关?“

方案

抛弃纯 AI 评分的黑盒思路,换成关键词匹配 + 三层分级的透明体系。

每个领域(AI 技术 / 国际政治 / 国际经济)定义三层关键词:

SCORING = {
    "ai_tech": {
        "high": {  # ★★★ 工作相关
            "keywords": ["claude", "gpt", "coding", "deploy", "mcp",
                         "agent", "docker", "github", ...],
            "label": "工作相关",
            "emoji": "💼",
        },
        "medium": {  # ★★☆ 行业趋势
            "keywords": ["llm", "benchmark", "reasoning",
                         "multimodal", "alignment", ...],
            "label": "行业趋势",
            "emoji": "📈",
        },
        "low": {  # ★☆☆ 背景参考
            "keywords": ["ethic", "regulation", "society", "impact", ...],
            "label": "背景参考",
            "emoji": "📖",
        },
    },
    # politics 和 economics 同理
}

匹配逻辑极其简单:标题 + 描述中出现任意关键词即命中该层级,取最高分。没有权重计算,没有机器学习,就是把判断标准白纸黑字写出来。

为什么这样设计

关键词系统有两个 AI 评分无法替代的价值:

  1. 可预测 —— 我知道为什么一条新闻被标为 ★★★。因为标题里有 “claude” 或 “agent”,这是我的工作领域。我不会看到一条莫名其妙的低分或高分,然后质疑系统是不是坏了。
  2. 可调整 —— 觉得某类新闻权重不对?直接编辑关键词列表,改完立即生效,不需要重新训练任何模型。

这是我在 v1 中学到的教训:v1 用 DeepSeek 输出 0-10 的评分,但从来没解释过为什么给这个分。用户(我自己)不信任黑盒评分。而信任是”愿意看”的前提。

输出效果

每条情报在 Obsidian 中显示为:

1. 「★★★」[Claude Code 推出 MCP 支持](链接)
    💼 工作相关
    📝 Claude Code 新增 MCP 协议支持,提升开发工具集成能力。

三星 + 标签 + 一行摘要,半秒内决定是否值得点开。


迭代二:AI 中文摘要

问题

v1 的每条情报包含完整的 DeepSeek 分析:200-300 字翻译 + 地缘政治洞察。但我在 Obsidian Daily Note 中浏览时,根本不想读 300 字——我只想知道”这条说了什么,值不值得我点进去看全文”。

换句话说,我需要的是诱饵,不是大餐

方案

用 DeepSeek 为所有情报批量生成一句话中文摘要(20-30 字),同时给出 0-100 的信号分。

关键设计:9 条情报一次 API 调用

def _build_prompt(data):
    lines = []
    idx = 0
    for domain, label in [("ai_tech", "AI技术"),
                          ("politics", "国际政治"),
                          ("economics", "国际经济")]:
        items = data.get(domain, [])
        start = idx
        for item in items:
            idx += 1
            lines.append(f"{idx}. [{label}] {item['title']}")
            if item.get("description"):
                lines.append(f"   描述: {item['description'][:300]}")
        domain_map[domain] = (start, idx)

    prompt = """你是一个情报分析师。为以下每条新闻生成一句中文摘要
(20-30字,说清核心信息)。同时给出信号分(0-100),
100 = 对该用户(AI开发者+国际政经学生)极有价值。

## 输出格式
严格返回 JSON 数组,每个元素匹配输入顺序:
[
  {"summary": "中文摘要", "signal": 85},
  ...
]
只返回 JSON,不要其他文字。

## 新闻列表
{news}"""
    return prompt, domain_map

注意到 prompt 里明确定义了读者画像:AI 开发者 + 国际政经学生。这样 DeepSeek 的摘要会主动突出这两个视角下的关键信息,而不是泛泛概括。

实测效果

原始标题: "Anthropic Announces Claude Code with MCP Support"
原文描述: "Claude Code adds Model Context Protocol support..."
AI 摘要: "Anthropic 推出 Claude Code,支持 MCP 协议,提升 AI 编程效率。"
信号分: 92

原始标题: "US-China Trade Talks Resume"
原文描述: "High-level negotiations continue..."
AI 摘要: "中美高层贸易谈判重启,关注全球经济走向。"
信号分: 78

摘要控制在 20-30 字,刚好是一眼扫完的长度。感兴趣就点链接看全文,不感兴趣就跳过。整个扫读过程不超过 30 秒。

为什么是摘要而不是翻译

v1 做的是”翻译 + 深度分析”——把英文变成中文,再补充背景洞察。这在处理 10 条精选时可行,但每天读 10 篇 300 字分析,认知负担很重。

v2 的假设是:如果我能快速扫完所有条目,自然会点开真正重要的那两三篇看原文。 摘要的任务不是替代阅读,而是帮助决定”读哪篇”。

这个假设成立的前提是摘要质量够高,而 DeepSeek 在这方面表现足够好。


迭代三:从定时触发到开机触发

问题

v1 运行在 n8n 上,v2 最初部署在 Windmill(一个开源任务调度平台)上,设置每天早上 8:00 定时执行。但很快就发现一个尴尬的事实——

如果 8 点电脑还没开机,系统就不会执行。Windmill 跑在 localhost 上,电脑关机它就停了。

定时的逻辑是”每天 8 点你大概率已经开机了”,但这隐含了依赖——我必须每天都在 8 点前开机。

方案

放弃云调度,回到本地触发。用 Windows Task Scheduler 设置开机启动,加上去重机制防止一天内多次重启导致重复追加。

# main.py 中的去重逻辑
def _should_run():
    today = datetime.now().strftime("%Y-%m-%d")
    try:
        with open("state.json") as f:
            state = json.load(f)
        if state.get("last_run_date") == today:
            return False  # 今天已跑过,跳过
    except FileNotFoundError:
        pass
    return True

def _mark_run():
    with open("state.json", "w") as f:
        json.dump({"last_run_date": datetime.now().strftime("%Y-%m-%d")}, f)

开机触发脚本也非常简单——就是一个 PowerShell 脚本,Task Scheduler 调用它:

$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
Set-Location $scriptDir
python main.py 2>&1 | Out-File -Append -FilePath "../boot_run.log"

为什么这是正确的选择

这个决策背后有一个更本质的思考转变:不要把自动化系统设计成”服务器思维”

我之前一直默认——自动化 = 定时触发 = 需要一台 7x24 运行的服务器。但这是我的个人电脑,它不是服务器。强行让个人电脑模拟服务器的行为模式,只会带来运维负担。

开机触发的逻辑是:你开机了 = 你要开始工作了 = 这时候给你情报刚好。它不要求电脑 24 小时在线,不要求设置复杂的时间调度,甚至不需要 Docker。而且实际上,我每天早上进系统的第一件事就是看 Obsidian Daily Note——情报已经在那里等我了。

去重机制保证了一天内多次重启不会重复,日志文件让排查问题变得简单。


技术债务清理

v1 → v2 不只是加功能,也砍了很多东西:

  • 砍掉 Docker:之前 n8n 和 Windmill 都跑在 Docker 里,每个都要维护。现在纯 Python 脚本,一个 pip install requests 就够了
  • 砍掉 n8n:n8n 是优秀的低代码工具,但对我这个场景来说太重了。Python 脚本 + 命令行直接调用,简单到没有任何可坏的环节
  • 砍掉复杂分析:v1 每条情报配多段分析,v2 只保留一行摘要。分析是作者视角(“我分析给你看”),摘要是编辑视角(“我帮你决定看什么”)

保留的只有 Obsidian Local REST API——这是整个系统的”最后一公里”,也是最稳定的一环。

结语:从能用走向好用的路标

回顾这三次迭代,我看到了一个清晰的模式:每次改进都在回答一个问题

问题答案实现
我怎么知道哪条值得看?价值评级★★★/★★☆/★☆☆ + 关键词匹配
我怎么快速决定点不点?AI 摘要DeepSeek 批量生成 20 字摘要
我为什么要记得手动跑?开机触发Task Scheduler + 去重

“能用”和”好用”的区别不在于功能多少,而在于使用阻力的大小

v1 每次看情报需要 3-5 分钟扫读、思考”这条和我有关吗”、决定是否点开——这是阻力。v2 把时间压缩到 30 秒以内,因为评分和摘要已经替我做了预筛选。

同样地,v1 需要我维护 Docker 容器、检查 n8n 工作流是否正常、关注 Windmill 是否还在跑——这也是阻力。v2 的代码量更少,依赖更少,出问题的可能自然也更少。

好的自动化系统最终应该让你忘记它的存在。它默默地出现在你每天打开的第一个页面上,然后你不需要去想它。


项目信息

  • 架构:Python 脚本 + AnySearch API + DeepSeek API + Obsidian Local REST API
  • 触发方式:Windows Task Scheduler 开机启动
  • 数据源:AnySearch(聚合搜索引擎)
  • 情报量:每天 9 条(AI 技术 3 + 国际政治 3 + 国际经济 3)
  • 代码行数:~350 行 Python
  • 外部依赖:仅 requests

从 2.5 分钟的 n8n 工作流到 5 秒完成的 Python 脚本——有时候”少即是多”。