news 2026/10/28 7:30:02

Last30Days-skill:用信号评分构建近30天信息雷达

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Last30Days-skill:用信号评分构建近30天信息雷达

如果你做过信息聚合或AI提示词工程,一定遇到过这类尴尬:传统搜索引擎返回结果里,关于“昨天刚发生的事”几乎为零;搜热点新闻,拿到的可能是官方号几天前发的通稿,而真正的当事者已经开始在社交平台吵架了。这里要聊的Last30Days-skill,就是为了填这个时间差设计的开源项目。我最初是在一个信息监控仓库的推荐列表里看到它的,名字很直白——它只关心最近30天内出现在各个源头上的信号,然后用一套“信号评分体系”告诉你哪些信息值得看、哪些只是噪音。今天这篇不打算做泛泛的项目介绍,而是把它的架构、信号评分机制和用法逐层拆开,结合我在本地部署和调参时踩过的坑,给想要自己搭一套“近30天信息雷达”的朋友一份能直接参考的记录。

1. 为什么还需要一个“30天窗口”的搜索增强工具:传统搜索的盲区

1.1 时间盲区不是缓存问题,而是爬虫预算问题

先说清楚传统搜索引擎“搜不到新东西”的本质。很多人以为是搜索结果缓存了几小时,其实更大的瓶颈在索引端。搜索引擎为了覆盖整个互联网,爬虫必须优先抓取高质量、高引用、更新频繁的页面,而一个新上线的个人博客、一个小论坛的讨论串、一条刚发布的GitHub Release,在爬虫优先级队列里的权重极低。加上反爬限制、robots协议、JS动态渲染等因素,一个页面从发布到被搜索引擎收录并进入索引,经常是几小时到几周不等。对“最近30天”这样苛刻的时间窗口,传统搜索引擎天然就不是为它优化的。

1.2 哪些“近30天信息”最容易从传统搜索里漏掉

我自己在维护技术情报列表时,发现四类信息几乎全靠人工盯:

  • 二级市场的产品更新:中小型开源项目发布新版本、功能变更、弃用通知,除非上了Hacker News头条,否则很难第一时间被搜索到。
  • 特定社区的高质量讨论:某个IDE插件出了新版本,Reddit或V2EX上的实测吐槽往往比官网文档更有参考价值。
  • 本地化事件:某个城市的技术沙龙、行业展会、招聘动态,搜索引擎收录慢,而且搜索结果经常被泛化内容覆盖。
  • 突发事实的“第一现场”:事故报告、漏洞通告、法律判决书原件,早期通常只出现在小众源里。

Last30Days-skill的思路很直接:与其依赖搜索引擎那个“全网快照”,不如直接对接那些更新快、时效性强的源(RSS、社交平台API、内容平台的热门接口),把抓取范围固定在一个滚动窗口内,再通过评分把最有信号价值的内容捞出来。

2. 项目架构全景:四条管线如何协同完成“30天窗口”的数据收集

Last30Days-skill的源码体现的是一种典型的“采集-清洗-评分-输出”四段式结构,整体用Python实现,入口在cli.py,运行起来后可以拆成下面这条链:

sources → collector/fetchers → normalizer → scorer → sqlite store → output (cli/api/skill)

2.1 采集层:RSS、公开API与站点定向爬虫的取舍

采集层是项目里最灵活也最容易被低估的部分。它不做什么“通用全网爬虫”,而是做“可配置的订阅源管理器”。默认实现了三类适配器:

  • RSS/Atom适配器:适配主流博客平台、新闻站、GitHub Releases,只做简单的XML解析,通过feedparser库实现。
  • 公开API适配器:内置了Hacker News(Firebase API)、Reddit(JSON接口)、GitHub Trending(无官方API,走页面解析)等等。这些接口不需要token,但都有速率限制,项目里默认对每个源加了请求间隔参数。
  • 自定义抓取适配器:让你用CSS选择器或XPath定义一个站点列表,适配那些没有RSS、但更新频繁的论坛或监控页。

这个设计的好处是:你不必维护一个庞大的爬虫集群,只需要把“真正的时效性源头”接入进来,采集压力小,反被封的风险也低。

2.2 规范化与存储层:为什么选了SQLite而不是更重的数据库

采集到的原始内容五花八门,必须统一成一条标准“信号记录”。我看到的版本里,normalizer会把字段收敛成下面这套结构:

字段含义示例
source来源标识github_releases
source_url原始链接https://github.com/xxx/releases/tag/v1.2
title标题或主题Release v1.2: 支持多线程下载
content清洗后的纯文本包含变更列表、作者说明……
published_at发布的时间戳(UTC)2025-05-14T09:30:00Z
fetched_at抓取时间(UTC)2025-06-01T00:00:00Z
content_hash去重用的哈希sha256:0a3f...

存储层用的是SQLite,原因也很实际:单机运行、几十个源、一天几千条记录,SQLite完全够用。而且Python标准库自带sqlite3,部署时不需要额外启动数据库服务。项目在store/目录里建了一张signals表,索引放在published_at和score两个字段上,查询排序很快。

2.3 信号评分层:从“抓到的内容”到“值得看的信号”

评分层是整个项目的核心,它跑在normalizer之后,对每条记录算出一个score(0到100的浮点数)。评分的输入不只是文本,还包括来源权重、发布时间、互动数据(如果源头提供了)。这里值得注意的一点是:项目刻意把“相关性”和“时效性”分开计算,而不是混成一个公式,因为用户经常需要调“更看重新”还是“更看重准”。

2.4 输出层:既给了API,也给了可嵌入AI的技能描述

输出层有三种形态,对应不同使用场景:

  • 命令行文本输出:运行python cli.py直接打印最近30天的高分信号,适合定时任务重定向到日志。
  • HTTP API:用FastAPI起一个轻服务,开放GET /signals?days=30&min_score=50这样的接口,方便其他程序调用。
  • Skill定义:项目里附带了一个skill_manifest.json,描述了用途、参数、返回格式,这让它可以直接被AI助手(如Claude、自研Agent)识别,当成一个“时间敏感信息检索工具”来调用。

3. 信号评分体系的工作机制:时间衰减、来源权重与置信度融合

3.1 评分因子拆解:新鲜度、命中强度、来源权威度

评分体系不是某个单一公式,而是一组可配置的因子。我把其中关键项整理成了一张表:

因子变量名作用默认权重
新鲜度衰减time_decay越新分越高,按下文半衰期公式衰减0.35
关键词命中强度keyword_boost标题/正文中包含配置关键词越多,加分越高0.25
来源权威度source_authority每个源在配置里单独设0~1的权重0.20
互动密度engagement_factor点赞/回复/分享经对数缩放后的值0.10
唯一性奖励novelty_bonus与近期同主题记录相似度低时加分0.10

当然,权重不是写死的,配置文件里每一项都对应一个可调整的数字。默认值只是我看到的仓库默认值,实际使用时几乎所有人都要调。

3.2 计算公式与归一化:让不同量纲的信号可比

评分计算大体分三步:

第一步:计算新鲜度衰减。项目默认采用“信号半衰期”模型,公式为:

time_decay = exp( -age_days * ln(2) / half_life )

其中age_days = (fetched_at - published_at) / 86400。半衰期half_life默认设为7天,含义是:一条信息发布7天后,它的新鲜度因子降到0.5;30天时降到约0.05。这个设计让“30天窗口”的信息不是一刀切淘汰,而是逐渐淡化,比较贴合人对信息时效的感知。

第二步:计算内容匹配强度。把用户感兴趣的关键词列表(配置文件里interests字段)与标题、正文做分词匹配,计算一个0~1的覆盖率系数。公式接近:

keyword_boost = matched_keyword_count / total_keyword_count

注意,这里用的是“已配置关键词的覆盖率”而不是“命中绝对次数”,避免少数高频词霸榜。

第三步:融合出总分。把所有因子做加权和,再用一个类似于Max-Min的方式挤压到0~100区间:

raw_score = (0.35*time_decay + 0.25*keyword_boost + 0.20*source_authority + 0.10*engagement_factor + 0.10*novelty_bonus) score = raw_score / (0.35 + 0.25 + 0.20 + 0.10 + 0.10) * 100

由于分母恒定,其实等价于加权平均后乘100。公式背后隐含了一个假设:这五个因子之间没有强相关性。实际上source_authority和engagement_factor经常正相关,但这种粗粒度评分在“排序”这件事上已经够用,不需要更复杂的贝叶斯融合。

3.3 一个具体的打分示例:从原始信息到排序结果

举一个能跑通的例子。假设你关注的关键词是“llm、agent、rag”,配置的源包括:

  • GitHub Releases:权威度0.9
  • Reddit r/LocalLLaMA:权威度0.75
  • 某个人博客:权威度0.4

某天抓下来两条信息:

第一条:GitHub上某个项目发布新版本,标题“Release v2.0: Agent memory and RAG enhancements”,发布时间距今2天,有23条release评论。关键词覆盖3/3=1.0,互动对数缩放约0.8。

  • time_decay = exp(-2*0.693/7) ≈ 0.82
  • keyword_boost = 1.0
  • source_authority = 0.9
  • engagement_factor ≈ 0.8
  • novelty_bonus 假设中等 = 0.6

raw_score = 0.350.82 + 0.251.0 + 0.200.9 + 0.100.8 + 0.10*0.6 = 0.287+0.25+0.18+0.08+0.06 = 0.857 → 85.7分。

第二条:某博客文章“聊聊LLM应用的架构设计”,发布时间距今25天,有2条评论,关键词覆盖2/3≈0.67。

  • time_decay = exp(-25*0.693/7) ≈ 0.084
  • keyword_boost = 0.67
  • source_authority = 0.4
  • engagement_factor ≈ 0.2
  • novelty_bonus = 0.7

raw_score = 0.350.084 + 0.250.67 + 0.200.4 + 0.100.2 + 0.10*0.7 = 0.0294+0.1675+0.08+0.02+0.07 = 0.367 → 36.7分。

两条信息一目了然:尽管博客内容有深度,但25天的年龄让它的时效价值大打折扣,在“近30天信号”场景下被版本发布消息碾压。如果反过来,你想专门收集“长文分析”,把source_authority调高、把time_decay权重调低,排序结果就会反过来。这就是信号评分体系可配置的价值。

4. 实战使用:从克隆仓库到跑通第一轮“30天窗口”检索

4.1 环境准备与安装依赖(Python + uv)

官方推荐的运行环境是Python 3.11以上。我用的是3.12,没遇到兼容问题。依赖管理用的是uv,这个比pip快不少,安装方式:

git clone https://github.com/your-repo/Last30Days-skill.git cd Last30Days-skill uv sync

如果你机器上还没装uv,先执行:

curl -LsSf https://astral.sh/uv/install.sh | sh

然后uv sync会读取pyproject.toml,把feedparser、requests、fastapi、uvicorn、jieba(用于中文分词)等依赖全部装好。注意,如果在中国大陆网络环境下,PyPI源可能慢,可以在uv.toml里加镜像源配置,否则安装会卡在jieba这种体积较大的包上。

4.2 配置数据源与评分权重:yaml文件说明

项目根目录下有一个config.example.yaml,复制成config.yaml后需要改这几项:

interests: - llm - agent - rag sources: - name: github_releases type: rss url: "https://github.com/search?q=llm&type=repositories&ref=advsearch&order=desc" authority: 0.9 - name: reddit_local_llama type: rss url: "https://www.reddit.com/r/LocalLLaMA/.rss" authority: 0.7 scorer: time_decay_half_life_days: 7 weights: time_decay: 0.35 keyword_boost: 0.25 source_authority: 0.20 engagement: 0.10 novelty: 0.10 output: top_n: 20 min_score: 40

有几个细节容易踩坑:

  • url如果填RSS链接,必须确认该源是否支持Gzip压缩和条件请求(ETag/Last-Modified),否则抓取频率高了容易被封。
  • authority的取值范围是0到1,建议不要在配置里给任何一个源设满1,否则那个源的稿子会长期占据榜首,信号多样性大幅下降。
  • interests支持中文关键词,但需要启用jieba分词。默认配置里中文分词是关的,要打开:
nlp: enable_chinese_segmentation: true

4.3 命令行调用与API调用两种常用姿势

配置改完,先跑一次全量采集加评分:

python cli.py --config config.yaml --fetch --score --show

--fetch表示抓取新内容,--score表示执行评分,--show表示终端输出结果。输出结果里会按照score降序,打出每条信号的时间和摘要。

如果要持续提供服务,用API模式更合适:

python server.py --port 8080

启动后,用curl请求:

curl "http://localhost:8080/signals?days=7&min_score=50&limit=10"

返回的是JSON列表,每个元素包含标题、URL、时间、评分和各因子得分。这个接口设计得比较原始,但足够用,我把它接到过家庭网关的Web页面上,每天早上瞄一眼,当成技术雷达。

4.4 接入AI助手/智能体的技能定义:让大模型能直接调用

项目里最有意思的部分是它把“技能”这个AI概念落地了。根目录下的skill_manifest.json长这这样:

{ "name": "last_30_days_search", "description": "获取最近30天内在多个来源中出现的高分信息信号。适合回答时效性强的问题,如'最近有没有新的RAG框架发布'。", "url": "http://localhost:8080/signals", "method": "GET", "params": { "days": {"type": "int", "default": 30}, "min_score": {"type": "int", "default": 40}, "keywords": {"type": "string", "optional": true} } }

如果你在用支持MCP(Model Context Protocol)的客户端,或者给Agent写了Funciton Calling,可以直接把skill_manifest.json作为工具描述注册进去。大模型在碰到“最近发生了什么”这类问题时,会主动调用这个接口,替代传统搜索引擎API。

我自己接的体验是:大模型拿到score之后做摘要会比直接传网页文本干净得多,因为评分已经把低质量噪音滤掉了。不过要注意,接口一次最多返回几十条,如果让大模型直接处理全文,token会爆掉,建议让它只针对 top 3 的URL回去抓详情。

5. 部署与调参中的几个坑:结合真实使用场景的排错记录

5.1 时间字段的时区问题:为什么偶尔会把3天前的数据判成30天前

这是我遇到的第一个必现bug。很多RSS源里的pubDate格式是RFC 822,带时区,像Wed, 01 Jun 2025 08:00:00 +0800。但部分源只给GMT缩写,没有偏移量。项目里最初用的是datetime.fromisoformat做解析,遇到老格式会直接抛异常,导致那几条数据被判为published_at缺失。缺失后代码会退回到fetched_at,也就是抓取时刻,相当于把一条已发布2天的旧闻当成刚刚发布的新鲜信号,新鲜度满分,直接顶到榜首。

解决办法有两个流派:

  • 严格派:解析失败就把该条丢弃,宁缺毋滥。
  • 宽松派:若解析失败,把这条记录的发布时间设为fetched_at - 14天(默认中间值),避免它抢新鲜度榜首。

我实测下来,宽松派更适合做监控,因为很多小众源的日期格式确实不规范,全扔了信息量损失太大。具体做法是在normalizer/generic.py里加一个try-except,并在回退时打警告日志,方便提前发现哪些源格式需要特殊处理。

5.2 来源权重设置不当导致的标题党回潮

默认配置里source_authority的权重是0.20,看似不多,但如果某个源权威度设了0.9、另一个设了0.2,哪怕后者的内容质量明显更高,前任只要关键词命中率高,就能把后者压下去。我一开始按自己的“偏见”把某个新闻站的权威度调到了0.98,结果三天后首页全是它的标题党“震惊体”,一个重要讨论帖沉在底下看不见。

后来我把权重方式改成了“惩罚制”:所有源默认0.5,只有被人工标记为“高质量长文源”的才加0.2,被标题党污染的直接降0.2,而不是凭印象给一个高分。这样能让评分体系对源质量的区分是相对稳健的,不会因为个别源抢跑而全盘倾斜。

5.3 更新频率与限流:RSS抓太勤被封IP的教训

我曾在一位朋友的建议下,把采集间隔从默认的15分钟改成了1分钟,结果半天后那些源开始对我报403。最难受的不是反爬,而是日志里没有任何告警:HTTP状态是403,RSS解析器拿到的是“Access Denied”的HTML,解析失败后项目静默跳过这条源,表面看采集正常,实际数据源已经断了。

建议做法是:把RSS类源的fetch_interval设成30分钟或更长,同时开启conditional_get(条件请求),用ETag和Last-Modified头避免全量下载。配置文件里加上:

sources: - name: github_releases type: rss url: "..." authority: 0.9 fetch_interval_minutes: 30 use_conditional_get: true

另外,给每个源单独维护一个失败计数,连续失败3次以上时发一个Telegram通知。这个功能不需要重写,项目里notify.py已经预留了钩子,填一个webhook地址就能用。这点小改动,能把“静默断源”的概率降到几乎为零。

6. 延伸玩法:把Last30Days-skill变成你自己的信息雷达

6.1 结合定时任务做每日早报

我目前最稳定的用法是在服务器上跑一个cron任务,每天早上8点执行一次抓取和评分,把score>=60的前10条信号汇总成一份纯文本,通过邮件或钉钉机器人推送到手机。关键配置是把output.min_score调高一些,保证推过来的都是当天的“硬信号”。

0 8 * * * cd /opt/Last30Days-skill && uv run python cli.py --config config.yaml --fetch --score --export /tmp/daily_report.json --notify webhook

这样坚持了快两个月,最大的收获是:以前需要在搜索引擎里翻半天的高价值动态,现在每天早上自动出现在手机里,而且时间集中在最近30天内,没有信息过时的负担。

6.2 把评分结果作为额外特征喂给LLM做摘要

上面提到的--export参数会生成一个JSON文件,格式是每条信号的标题、URL、score、因子明细。把这个文件作为上下文文本交给大模型,让它“把今天的信号整理成300字早报”,效果要比直接把网页正文喂进去好得多。因为评分之后留下的每条都具备时效性和相关性,LLM不需要再额外权衡哪条重要,摘要的结构和重点自然就清晰了。

我试过将top_n从20提到50,信息量提升很大,但摘要里“凑数感”明显变强,LLM会开始用“此外还有一些其他更新”这种话带过。把top_n控制在15~20条反而是“可读性/覆盖度”的最佳平衡点。

6.3 开源项目的二期方向:多语言与个性化权重的设计空间

从项目当前版本来讲,它的核心机制还很“原始”——信号评分体系是静态权重的,没有自适应学习逻辑。如果你有心,完全可以为它加两个模块:

  • 个性化反馈环路:记录你点击了哪些信号、忽略了哪些信号,用简单加权方法更新每个源的authority。
  • 多语言时间语义解析:中文RSS里的时间格式五花八门,比如“昨天”“5天前”,目前项目不支持,只能靠抓取时刻推断,这是最值得贡献代码的地方。

我甚至在考虑把它和本地向量数据库结合:抓取后给每条信号embedding,然后维持一个“你已读信号”的向量相似度集合,在看到重复话题时自动增大novelty_bonus。这个改造难度不大,但对信息雷达的体验提升是跨层级的。

回到最初的话题:传统搜索引擎,本质上是“全量索引检索”,更适合“找已知的东西”;Last30Days-skill这类项目填补的是“近30天里发生了什么”的扫描式需求。信号评分体系的价值不在于做出终极排序,而在于让时间窗口内的大量信息变成一个可调节的优先级列表——调得顺手之后,你会发现很多重要的变化不再需要等到搜索指数上升才后知后觉。至少我自己,已经从“每天刷各种网站”变成了“每天早上看一份评分报告”。如果这文章里的架构拆解和调参记录给了你一些帮助,那就不妨也搭一套试试,摸一遍那些配置参数,你会更懂信息保鲜这件事的细节。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 7:29:25

收发一体超声波测距固件开发:时序控制、盲区处理与温度补偿

简介:这是一套面向嵌入式初学者与电子爱好者的超声波测距完整方案,采用51单片机搭配收发一体超声波探头实现距离检测,电路原理与倒车雷达基本一致,适合用来理解测距模块的收发时序、回波捕获与距离换算逻辑。压缩包共21个文件&…

作者头像 李华
网站建设 2026/10/28 7:28:52

时间序列建模中的复杂性税:隐性成本与稳健性精算

1. 什么是“复杂性税”?——时间序列分析里那个没人明说、但人人都在交的隐性成本“复杂性税”这个词,最近在几个量化团队内部复盘会上被反复提起,不是学术论文里的术语,而是工程师和研究员们私下吐槽时自然长出来的词——就像当年…

作者头像 李华
网站建设 2026/10/28 7:28:49

自监督学习在图像领域的应用与实践

1. 自监督学习在图像领域的核心价值第一次接触自监督学习(Self-Supervised Learning,SSL)是在处理一批未标注的医疗影像数据时。传统监督学习需要大量人工标注,而自监督学习只需要原始图像本身就能构建有效的表示学习任务。这种&q…

作者头像 李华
网站建设 2026/10/28 7:28:47

AI大模型全链路技术规范与工程实践指南

1. 为什么需要AI大模型全链路技术规范?三年前我第一次调用GPT-3接口时,踩过所有你能想象的坑:从API密钥泄露到计费爆炸,从超时重试机制缺失到数据格式混乱。这些惨痛教训让我意识到,大模型应用开发需要建立完整的工程规…

作者头像 李华
网站建设 2026/10/28 7:27:32

Kimi Coding Plan API集成实战:问题解析与优化策略

1. Kimi Coding Plan API 集成问题深度剖析最近在对接Kimi Coding Plan的API时,遇到了几个典型的技术难题。这个API作为新兴的编程辅助工具接口,虽然功能强大,但在实际集成过程中存在不少需要特别注意的技术细节。我花了三周时间完整走通了整…

作者头像 李华
网站建设 2026/10/28 7:27:13

AI入门指南:术语解析与认知误区避坑

1. AI入门者的术语迷宫与认知陷阱刚接触AI领域的新手常会陷入术语的迷雾森林——机器学习、深度学习、神经网络、大模型、AI Agent这些词汇在各类文章中高频出现,却鲜有人解释它们之间的关联与区别。我至今记得自己第一次看到"基于transformer架构的预训练大模…

作者头像 李华