
每天早上打开电脑的第一件事我以前都是刷信息流。先是Hacker News然后切到GitHub Trending再翻翻产品发布相关的社区最后还要被手机里那几个资讯App轮番轰炸一轮。闹钟定的七点半真正开始写代码的时候往往已经九点出头。最气人的是刷完一个多小时我基本什么都记不住只记得“好像有个项目挺火的”以及顺手给十几条“信息流广告”点了一遍“不感兴趣”。后来我把本地部署的一个开源AI助手——我习惯叫它Jev——接到了这套流程里让它每天晚上替我把三个信息源完整刷一遍第二天早上直接给我一份三源新闻日报。这套东西我用下来快三个月了每天能稳定省下一个半小时而且关键信息一条都没漏。这篇文章就把实现过程完整拆给你选型逻辑、四道工序的管线设计、具体代码以及我踩过的坑和最终的优化方案。适合那种每天必须跟大量技术信息打交道、又不想在刷信息流里耗掉半天的人。1. 每天刷两小时信息流记住的不超过五条我决定做三源日报1.1 信息流的时间账算完我自己都不信我之前给自己做过一次统计很粗略地记了三天早上刷信息流大概55分钟中午午休再刷30分钟晚上睡前还会惯性刷20分钟。三天平均下来每天花在“刷”这件事上的时间接近1小时40分钟。但真正有效的产出呢我统计了一下自己“刷完之后能立即说出并复述”的信息三天里加起来不到15条。换句话说我用接近5个小时的时间只换来了15条值得上头的信息剩余全是被算法塞进来的标题党、热点复读机以及伪装成内容的广告。这个转化率低到离谱。那时候我就意识到问题并不在于“获取信息的渠道”而在于“过滤信息的系统”。算法给我的是一条一条的流我需要的是每天一页纸的答案。1.2 为什么是这三个源技术讨论、开源动态、产品发布三源新闻日报里的“三源”我最终定的是Hacker News、GitHub Trending和Product Hunt。这三者分别代表信息流的三个不同环节大家在讨论什么、代码世界正在长出什么、商业化层面有什么新产品冒出来。信息源核心属性它回答的问题时效窗口Hacker News全球技术社区热度榜今天开发者群体在争论什么、关注什么小时级GitHub Trending开源项目趋势最近哪些项目正在获得大量关注和star天级Product Hunt新产品发布平台今天有哪些新产品、新玩法值得了解天级这三个源恰好把“讨论—代码—产品”三段拼成了一个完整切片。刷Hacker News能看到技术社区的情绪和风向GitHub Trending能告诉你某个方向正在起量Product Hunt能帮你发现下一个可能用到的工具或商业模式。三者合在一起就是我需要的“当日科技信息流快照”。1.3 为什么是日报而不是推送可能有人会说实时推送不更爽吗真不是。实时推送会把“主动获取信息”变成“被动接受打断”一上午弹十次通知每次看两眼都是碎片反而什么都没深读。日报的核心优势在于它有确定的节奏每天早上固定时间到固定格式固定长度。大脑会把阅读它当成一个批处理任务而不是被不停地打断。我选的时间是工作日早上7点30分生成7点45分之前发到邮箱。到了办公室坐下来花十分钟看完今天该知道的全知道了。这个节奏比任何推送都舒服也更容易坚持。2. 为什么核心部件是本地部署的 Jev选型逻辑与分工边界2.1 Jev 在我这套方案里的角色定位先说明一点Jev 不是某个大厂的黑盒服务是我给本地部署的开源AI助手起的工作代号。它跑在我内网一台小服务器上通过一个与主流大模型API兼容的HTTP接口对外提供对话和文本生成能力。我用Docker方式部署数据完全不出内网。在三条信息流的管道里Jev 干的活有三件把经过初步清洗的30条左右原始信息流条目理解之后重新组织成一篇有结构的日报。对每条有效信息提炼“为什么值得关注”的一句话推荐语。按重要性对条目排序避免整篇文章变成顺手一拉的水账。这三件事恰恰是纯规则脚本做不好的。你可以用爬虫抓取几百条数据也可以用正则过滤掉垃圾词但让程序理解“这条新闻对今天的AI从业者意味着什么”还是得靠语言模型完成。2.2 爬虫负责量Jev 负责理解谁也别越权这个分工是踩过几次坑之后才想明白的。一开始我试图让Jev把抓取、过滤、去重全包了结果每次让它“处理”上百条原始条目它的响应时间就会拖到五分钟以上偶尔还会把重复内容合并得乱七八糟。后来我把管线拆成两层所有能用确定性规则解决的问题都用脚本在前端处理掉只有“语义理解”和“文本生成”这两件事才交给Jev。比如一个标题里同时出现“广告”两个字的条目直接由正则丢掉根本不用让模型判断。再比如同一个GitHub仓库在同一批数据中出现了三次清洗层就根据仓库URL做了去重也不必依赖模型去“猜”。这样设计之后Jev每次只需要消化20到30条精筛过的数据单次调用一分钟左右就能完成输出质量也稳定了很多。2.3 本地部署的三个实际好处隐私、可控、省钱本地部署这个选择我一开始也犹豫过毕竟云端API直接调多省事。但真正跑起来之后我确信本地部署是更合适的选择理由有三点。隐私性。所有抓来的数据、我自己的兴趣配置、日报输出的中间稿全部保存在内网不经过任何第三方的服务器。这对一个希望保留个人偏好的信息聚合器来说挺重要的。可控性。Prompt改了随时重跑模型不合适了可以直接换一个后端模型不用等API版本更新。接口完全自控这也让我后续可以很轻松地把它接进Codex的数据处理流程里做结果摘要。成本。本地部署的日常开销基本只有服务器电费。之前我按月订阅云端API那阵单是让它每天总结三次信息流一个月的额度半个月就见底了超出的费用足够我吃好几顿好的。本地部署之后这个成本问题彻底消失了。2.4 这套方案到底适合什么样的人说实话这套东西并不适合所有人。如果你想要的只是一个“装好就什么都不用管”的现成信息App那你大可去用各种现成的资讯订阅和RSS客户端。但如果你愿意花一个下午折腾脚本想要一个完全属于自己、能不断调整口味的信息入口并且对每天只读一份高质量摘要这件事有执念那这个方案会很值得做。对我来说它还有一个更微妙的回报自从信息流变成了日报我不再时刻担心“我是不是错过了一个大事件”。我清楚知道就算今天什么都不刷明天早上也会有一份系统性的总结替我把关。3. 三源日报的完整管线抓取、清洗、生成、推送四道工序3.1 先看整体流程图式的分工整个系统跑在一台 Linux 服务器上调度依靠 Cron核心脚本是一个 Python 文件pipeline.py。每道工序都有明确的输入和输出也算是一种最简单的管道式设计。工序职责输入输出第一道抓取从三个源拿原始数据无raw/hn.json、raw/gh.json、raw/ph.json第二道清洗过滤广告与重复项按规则打分三个原始JSONclean/items.json第三道生成调用Jev生成日报正文精筛后的条目output/daily_report.md第四道推送整理并送达用户Markdown日报邮件、Git 仓库记录Cron 配置很简单注意最后加上环境变量指定时区TZAsia/Shanghai 30 7 * * 1-5 cd /path/to/news-daily python pipeline.py logs/run.log 21工作日早上7点30分准时跑周末我不发日报改为让它在周六生成一份本周汇总。3.2 第一道工序三个源的抓取细节Hacker News 的官方API是最好抓的不需要任何认证直接请求顶帖列表再逐条取详情即可。核心代码大致是import requests def fetch_hackernews(): top_ids requests.get( https://hacker-news.firebaseio.com/v0/topstories.json, timeout15 ).json()[:80] items [] for item_id in top_ids: url fhttps://hacker-news.firebaseio.com/v0/item/{item_id}.json item requests.get(url, timeout15).json() if not item: continue items.append({ source: hn, title: item.get(title, ), url: item.get(url, ), score: item.get(score, 0), desc: item.get(text, ), }) return itemsGitHub Trending 我建议直接用官方Search API按“创建时间介于昨天和今天”来搜索仓库再按star数排序。这样能避开直接解析HTML页面导致的脆弱性。搜索API需要带一个Token否则每小时只能请求60次很容易被打爆。def fetch_github(date_str): headers {Authorization: token os.environ[GITHUB_TOKEN]} q fcreated:{date_str} r requests.get( https://api.github.com/search/repositories, params{q: q, sort: stars, order: desc}, headersheaders, timeout20, ) data r.json() return [ {source: gh, title: item[full_name], url: item[html_url], stars: item[stargazers_count], desc: item.get(description, )} for item in data.get(items, [])[:30] ]Product Hunt 走的是 GraphQL 接口需要先在其开发者后台创建一个应用拿到Token。查询当天的“今日产品”列表即可。如果你不想用GraphQL也可以退而求其次直接抓它的每日榜单页面但我实测过页面结构改过三次还是用API省心。3.3 第二道工序清洗层是真正决定日报质量的地方很多人做类似项目时会把精力全放在抓取和生成忽略了清洗层。其实日报好不好看清洗层至少占一半功劳。我做了几件事。第一是去重。同一个开源项目可能会同时出现在Hacker News的帖子和GitHub Trending里如果按标题去重会漏掉这种跨源重复。我的做法是对URL做归一化处理截取仓库完整路径作为唯一键只要仓库指纹相同就保留一条。第二是过滤。标题或描述里出现“sponsored”“广告”“推广”“限时免费”等词的直接丢掉这类内容基本可以肯定是营销向。判断逻辑我写成了一个简单的黑名单列表。第三是打分。我给每条数据算一个基础分Hacker News按点赞数、GitHub按star数、Product Hunt按当天排名。然后叠加一个关键词加权如果你正在关注“llm”“self-hosted”“python”这些方向相关条目会整体前移。经过这步原始抓取的上百条数据被我压缩成20到30条精筛条目存进clean/items.json。这一步的输出才是Jev真正要处理的原料。3.4 第三道工序把精筛后的条目交给 Jev生成日报这一层我写得非常克制Prompt也不复杂重点在“明确要求、限定结构、保留出处”。import requests, json, os def generate_daily_report(items): system_prompt 你是一名资深科技编辑。请阅读下面提供的信息流条目 完成三件事 1. 过滤掉明显无价值、重复或营销向的内容。 2. 将剩余条目按重要性排序归类输出。 3. 对每条精选条目给出不超过20字的推荐理由。 输出格式为JSON结构如下 { summary: 今日一句话概览, sections: [ { title: 分类名, items: [ {title: 原标题, source: 来源, url: 链接, reason: 推荐理由} ] } ] } 注意只输出JSON不要有额外解释。语气客观不要夸大成瘾。 user_content json.dumps(items, ensure_asciiFalse) resp requests.post( http://127.0.0.1:8000/v1/chat/completions, json{ model: jev-local, messages: [ {role: system, content: system_prompt}, {role: user, content: user_content}, ], temperature: 0.3, }, timeout120, ) content resp.json()[choices][0][message][content] return json.loads(content)为什么要用JSON结构而不是直接生成Markdown因为脚本拿到结构化的JSON之后可以做二次排版、分类合并将来想改成周报也容易。更重要的是结构化输出让我可以在外层加校验一旦Jev给出的JSON解析失败脚本能及时发现并自动重试而不是生成一篇格式错乱的日报。3.5 第四道工序把日报送到该去的地方日报生成之后我会做三件事。先把原始Markdown写入output/daily_report.md然后转成邮件发出最后把文件提交到Git仓库日积月累下来等于有了一个可搜索的信息历史库。30 7 * * 1-5 cd /path/to/news-daily python pipeline.py logs/run.log 21邮件发送我用的就是标准库smtplib正文以纯文本和简单HTML各发一份方便在不同客户端里阅读。SMTP账号密码配置通过环境变量读取避免写死在脚本里。import smtplib, os from email.mime.text import MIMEText def send_email(md_content, subject): msg MIMEText(md_content, _subtypeplain, _charsetutf-8) msg[Subject] subject msg[From] os.environ[SMTP_USER] msg[To] os.environ[REPORT_TO] with smtplib.SMTP_SSL(os.environ[SMTP_HOST], 465) as server: server.login(os.environ[SMTP_USER], os.environ[SMTP_PASS]) server.send_message(msg)Git提交那步也简单git add指定日报文件commit信息显示日期push到私有仓库。之后无论在电脑还是手机上都能随时回溯某一天的日报。4. 第一版日报跑通之前我踩过的四个坑和修复记录4.1 GitHub速率限制跑了不到五十次直接403第一次稳定运行不到两天GitHub接口就给我返回了403。我当时的直觉是网络问题后来看了响应头才发现X-RateLimit-Remaining显示的剩余次数是0这才意识到GitHub匿名搜索API每小时只有60次的额度。因为我要搜索“最近24小时创建的仓库”一次搜索请求统计次数每天跑一次其实用不了太多。但问题出在脚本偶尔一次运行会失败重试重试次数一多很快就把额度烧完了。定位到根因后解决方式很直接申请一个普通Token放进环境变量请求时带上Authorization头额度立刻升到每小时5000次彻底不再为这个发愁。这个排查过程也让我养成一个习惯遇到第三方API报错先看响应头里的速率限制字段比瞎猜哪里写错了要高效得多。4.2 Jev 输出格式漂移今天能解析的JSON明天就解析不了用模型生成日报最难受的一点是它不会像普通程序那样严格守规矩。我要求输出纯JSON它大多数时候给的是标准JSON但偶尔会在开头加一句“好的这是生成的日报”或者多出个多余的逗号。第一次遇到时我的脚本直接抛了json.JSONDecodeError日报当天就断了。我做了两层防护。第一层是Prompt里再次强调“只输出JSON不要任何解释和前缀”。第二层是解析时的容错拿到输出后先用正则抓住从{到最后一个}的片段再交给json.loads解析如果还失败自动重试一次并带上“上一轮输出格式错误请严格按照JSON格式重新生成”的提示。这套组合下来连续跑了一个多月都没再因为格式问题中断过日报。4.3 Cron时区错乱日报永远在报道“昨天”有段时间我发现每天早上收到日报里面的Hacker News条目永远是前一天凌晨的高分帖感觉总慢半拍。排查后发现不是抓取逻辑的问题是Cron运行环境的默认时区是UTC而我在脚本里生成“今天”用的是datetime.now()于是“今天”比本地时间少了8小时。修复分两步一是在Crontab第一行加上TZAsia/Shanghai环境变量让定时任务整体运行在本地时区二是脚本内部所有涉及日期的操作都显式用zoneinfo.ZoneInfo(Asia/Shanghai)初始化不依赖运行环境的默认值。修复后日报的日期和内容才真正对上了。4.4 跨源重复同一个项目出现了三次清洗层却没拦住清洗层设计的时候我做了标题去重但这个去重对跨源重复基本没用。一个开源项目在Hacker News上被人发帖讨论GitHub Trending上也登了榜两条数据的标题完全不同怎么可能被标题去重拦住。这个坑是在一次手动复检日报时发现的当天出现了两个条目指向同一个GitHub仓库一个来自HN的帖子一个来自GitHub Trending。我加了“仓库指纹”去重逻辑只要能从URL里提取出owner/repo这样的结构就把它当作唯一键。HN帖子里如果链接指向GitHub仓库同样提取仓库指纹参与去重。清洗之后再去重跨源重复基本绝迹了。5. 从“能跑”到“天天想读”让日报更合你口味的优化5.1 让 Jev 记住你的个人兴趣兴趣文件动态注入日报能收到、能推送、格式稳定这只是“能用”。真正让日报变成“每天想读”的是让Jev了解你的偏好。我加了一个简单的interest.md配置文件内容大概是interests: - llm - local-ai - python - self-hosted ignore: - nft - crypto - game-fi在调用Jev之前把这个文件的文本拼接到System Prompt末尾明确告诉它“以上是我的兴趣方向和明确不关心的话题排序时据此调整权重”。这个改动非常简单却让日报的命中率肉眼可见地提升了。以前是一堆“热门但和我无关”的东西现在则有一半以上是我真正在关注的方向。5.2 缓存与增量单次运行从五分钟压到四十秒早期每次跑全量管线抓取加生成要五分钟左右。后来我发现三个源每天真正变化的内容量并没有那么大于是做了两个优化。第一个是抓取层缓存。每次都把原始结果和当天的日期一起存下来第二次抓取时如果发现Hacker News的顶帖ID集合和前一天完全一致就直接复用上一次的缓存文件跳过网络请求。第二个是生成层的增量判断。把清洗后的items.json和昨天的做对比如果完全没变化说明今天没有值得写的新内容直接沿用昨天的日报并在文件头部标注“今日无重大更新”。这两个优化做完无变化时整个流程40秒左右跑完有变化时也不会超过一分半Cron任务压力小了很多。5.3 后续可以继续扩展的方向这套三源日报的框架跑顺之后扩展空间其实很大。我把周六的日报改成了“本周趋势总结”让Jev读取周一到周五五份日报的JSON数据输出一份包含“本周值得持续关注的方向”的周报用于周末复盘。我还打算再加一个下午茶版本下午1点只推送一条一句话速览和一两个值得深读的链接适合午休后进入状态时快速过一眼。如果你也想搭一套我的建议是先跑通最简单的邮件日报不要一上来就堆功能。管线稳定之后再根据你真实的使用习惯慢慢加进周报、兴趣配置或额外信息源。那才是这套系统真正好玩起来的时候。我个人体会最深的一点是让Jev替我去刷信息流不是“偷懒”而是把注意力还给真正重要的事情。每天固定一个时间用十分钟读一页由机器帮我整理好的摘要剩下的时间安心写代码。它没有让我彻底告别信息流但它让我重新成了信息的主人而不是算法屏幕前被喂食的那个拖延者。