每天早上十点半,手机屏幕亮起,微信弹出一条消息——一份排版整齐的 AI 日报已经躺在对话框里了。这不是某个付费订阅服务,而是我自己搭的一套自动化流程:让 WorkBuddy 在固定时间自动跑一遍信息采集、摘要生成、格式化排版,最后通过微信推送到我手上。整套东西从想法到跑通,前后折腾了大概两个周末,中间踩的坑不算少,但跑稳之后确实省心。
这篇内容适合两类人看:一类是手上有 WorkBuddy 或者类似 AI 工作台工具、想把它用得更"自动化"一点的人;另一类是对"定时任务 + AI 摘要 + 微信推送"这条链路感兴趣、想自己搭一套类似流程的人。我会把整个链路的每个环节拆开讲,包括为什么这么选、参数怎么定、哪些地方容易翻车,以及我实际跑下来觉得最值得注意的几个细节。核心关键词就三个:WorkBuddy、AI 日报、微信推送,围绕它们把自动化这件事讲透。
1. 为什么是"闹钟 + AI 日报"这个组合
1.1 手动整理信息的真实成本
先说清楚我为什么要做这个东西。我每天需要关注的信息源比较杂:行业动态、几个技术社区的热帖、自己项目相关的更新日志、还有一些零散的订阅内容。手动刷一遍,快的话二十分钟,慢的话一个小时就没了,而且刷完之后脑子里留下的东西其实很有限——大部分信息是"看过就忘"。
真正的问题不在于"看",而在于"整理"。人脑在被动浏览时很难做结构化归纳,你刷了三十条内容,最后能记住的可能就两三条。而 AI 摘要的价值恰恰在这里:它不负责帮你"发现"信息,它负责帮你把已经采集到的信息压缩成可快速扫读的结构。这两件事分开之后,整个流程就清晰了——采集归采集,摘要归摘要,推送归推送。
1.2 WorkBuddy 在这条链路里扮演什么角色
WorkBuddy 本质上是一个 AI 工作台,你可以把它理解成一个"能调用模型、能跑脚本、能编排任务"的中枢。它跟单纯的聊天式 AI 工具最大的区别在于:它支持把多个步骤串成一个可重复执行的任务流。这一点对"日报"场景是决定性的——日报的核心诉求就是"每天重复、结果稳定、格式一致",而不是"每次都要我重新描述一遍需求"。
我在 WorkBuddy 里做的事情,说白了就是定义了一个任务:输入是若干信息源的原始内容,处理是调用模型做摘要和分类,输出是一段结构化文本。然后给这个任务挂一个定时触发器,每天上午十点半执行一次。执行完之后,结果通过一个推送环节送到微信。
这里有个很多人会忽略的点:WorkBuddy 负责的是"生成",微信负责的是"送达",这两件事必须解耦。如果你把推送逻辑写死在生成任务里,一旦推送通道出问题,整个任务就失败了,你连日报内容都拿不到。我的做法是让 WorkBuddy 先把日报落成一份文件或者一段可读取的结果,推送环节单独去读这个结果。这样即使推送挂了,我还能手动去取内容。
1.3 "十点半"这个时间点是怎么定的
时间点的选择看着随意,其实有讲究。太早,信息源还没更新完,摘要出来的内容是昨天的残羹;太晚,等你看到的时候上午已经过了一半,失去了"晨间速览"的意义。我试过几个时间点:
| 触发时间 | 实测问题 |
|---|---|
| 7:00 | 多数信息源未更新,内容重复率高 |
| 8:30 | 部分源刚更新,摘要质量不稳定 |
| 10:30 | 主流源基本更新完毕,摘要完整度高 |
| 12:00 | 内容全但偏晚,失去晨间速览价值 |
| 14:00 | 上午信息已过时,实用性下降 |
十点半这个点,是我实测下来"信息完整度"和"时效性"平衡得最好的。当然这个跟你的信息源更新节奏强相关,如果你的源是凌晨更新的,那完全可以提前。建议你先花三天记录一下自己主要信息源的更新时间分布,再定触发点,别照抄别人的时间。
2. 把 WorkBuddy 的任务拆成可复用的三段
2.1 采集段:别让模型去干爬取的活
很多人第一反应是"让 AI 自己去网上找信息",这个思路在日报场景里是错的。原因很简单:模型的联网检索能力不稳定,每次返回的内容范围、质量、去重情况都不一样,你没法保证日报的稳定性。日报要的是"每天结构一致",而不是"每天都有惊喜"。
我的做法是把采集和摘要彻底分开。采集段用固定的脚本或者固定的数据源接口,把原始内容抓下来,存成一个中间文件。这个中间文件可以是 JSON,也可以是纯文本,关键是格式固定。WorkBuddy 的任务从"读取这个中间文件"开始,而不是从"去网上找"开始。
这样做的好处有三个:第一,采集失败和摘要失败可以分开排查;第二,同一批原始内容可以反复跑摘要做对比调优;第三,采集源可以随时增删,不影响摘要逻辑。中间文件的格式我建议至少包含这几个字段:
{ "source": "来源标识", "title": "条目标题", "content": "正文或摘要原文", "timestamp": "采集时间", "url": "原始链接" }字段不用多,但这五个基本够用。source用于后续分类,timestamp用于去重和排序,url用于你看到感兴趣的内容时能点回去。
2.2 摘要段:提示词的结构比文采重要
摘要段是 WorkBuddy 真正发挥价值的地方。这里我踩过的最大坑是:一开始我把提示词写得很"文学",希望日报读起来流畅自然,结果模型开始自由发挥,该保留的数字被改写了,该分类的内容被合并了。后来我把提示词改成"结构化指令",效果立刻稳定下来。
我现在用的提示词骨架大致是这样的逻辑:先给角色和任务边界,再给输出格式的硬性约束,最后给几条负面清单。具体来说,我会明确告诉它"不要改写原文中的数字和专有名词""每条摘要不超过两句话""按来源分组输出""如果某条内容无法判断价值就标注为待定而不是丢弃"。
这里有个经验:负面清单比正面要求更管用。你告诉模型"要简洁",它可能理解成各种样子;但你告诉它"不要超过两句话、不要用形容词堆砌、不要加自己的评论",它的输出就会收敛很多。我大概迭代了五六版提示词才稳定下来,前几版的问题基本都是"模型太想表现"。
另外,摘要段一定要做去重。不同信息源经常报道同一件事,如果不做去重,日报里会出现三条内容讲同一件事的情况,非常影响阅读体验。去重可以在采集段做(按标题相似度),也可以在摘要段做(让模型识别重复并合并)。我倾向于在采集段做粗去重,摘要段做精合并,两层配合效果最好。
2.3 排版段:日报的可读性决定你会不会坚持看
排版这件事,做之前觉得不重要,做之后发现它是决定"你会不会真的每天看"的关键。一份密密麻麻、没有分层的日报,你看两天就烦了。我的排版原则是:分层清晰、重点前置、长度可控。
具体做法是:日报开头放一个"今日三条"的精选区,把当天最重要的三条内容拎出来;然后是分来源的详细区;最后是"待定区",放那些模型判断不了价值的内容。这样你扫一眼开头就知道今天有没有值得深读的东西,没有的话直接跳过,有时间再往下看。
长度控制也很重要。我一开始没限制,结果日报越跑越长,后来加了硬约束:整份日报控制在 800 字以内,单条摘要不超过 60 字。超过的部分要么合并要么砍掉。日报不是越全越好,是越"能快速扫完"越好。这个认知转变花了我不少时间。
3. 微信推送这条链路,坑比想象中多
3.1 为什么不用"直接发到文件传输助手"
最朴素的想法是让脚本模拟微信操作,把内容发到文件传输助手。这条路我试过,结论是:不稳定,不建议。模拟操作依赖界面元素,微信一更新界面就可能失效,而且频繁操作有账号风险。更重要的是,这种方式没法做格式化——你发过去的就是一坨纯文本,跟在记事本里看没区别。
我最后选的是微信小程序 + 服务端推送的方案。思路是:WorkBuddy 生成日报后,把内容写到一个服务端的存储里(可以是数据库,也可以是一个简单的文件服务),然后通过微信的订阅消息或者小程序内的消息通道推送给用户。用户点开小程序就能看到排版好的日报。
这个方案的好处是:推送通道是官方支持的,稳定;展示层是小程序,排版可控;内容存在服务端,历史日报可以回溯。代价是需要一点开发工作,但如果你本来就会写小程序,这部分不算难。
3.2 小程序端的几个实操细节
小程序端我踩过的坑主要集中在两个地方:顶部导航栏高度和缓存策略。
顶部导航栏高度这个事,看起来是个小问题,实际上不同机型、不同微信版本下导航栏高度是有差异的。如果你用固定像素值去布局,在某些机型上内容会被导航栏遮住。正确做法是用微信提供的系统信息接口动态获取状态栏高度和导航栏高度,然后做适配。我一开始图省事写死了 44px,结果在几台安卓机上全翻车了。
缓存策略是另一个坑。日报内容我一开始是每次打开小程序都重新请求,结果网络不好的时候白屏,体验很差。后来改成"本地缓存 + 后台更新":打开时先展示上次缓存的内容,同时后台请求最新数据,拿到后更新界面并刷新缓存。这样即使网络慢,用户也能立刻看到内容。缓存时间我设的是 6 小时,因为日报一天就更新一次,没必要频繁请求。
还有一个细节是请求封装。小程序的网络请求如果散落在各个页面里,后期维护会很痛苦。我建议一开始就做一个统一的请求封装,把 baseURL、超时、错误处理、loading 状态都收进去。这个封装大概五十行代码,但能省掉后面大量的重复劳动。
3.3 推送失败的兜底方案
任何推送通道都有失败的可能,所以兜底方案是必须的。我的兜底逻辑是这样的:WorkBuddy 生成日报后,先落一份到本地文件,再尝试推送。如果推送环节报错,任务不会整体失败,而是记录一条错误日志,同时把日报文件保留下来。第二天我如果发现没收到推送,就去本地文件里找。
更进一步,我加了一个"补推"机制:如果当天推送失败,第二天任务执行时会先检查前一天是否有未推送成功的日报,有的话先补推再执行当天任务。这个机制救过我好几次,尤其是服务端偶尔抽风的时候。
提示:兜底方案的核心思想是"生成"和"送达"分离。只要生成成功了,内容就不会丢,送达只是时间问题。千万不要把两者耦合在一起。
4. 定时触发与任务编排的稳定性设计
4.1 定时器选在哪里
定时触发这件事,可以放在 WorkBuddy 内部,也可以放在外部(比如系统的定时任务)。我的建议是:如果 WorkBuddy 自带定时能力,优先用它;如果没有,用外部定时器去调用 WorkBuddy 的任务接口。
放在 WorkBuddy 内部的好处是链路短、依赖少;放在外部的好处是灵活、可控。我实际用的是外部定时器,因为我想在触发前加一些前置检查(比如检查信息源是否可用、检查昨天的任务是否完成),这些逻辑放在外部更自然。
外部定时器我用的就是最朴素的系统级定时任务,配置简单、稳定、不依赖任何第三方服务。配置的时候注意两点:一是要设置好工作目录,否则脚本里的相对路径会出错;二是要把输出重定向到日志文件,方便排查问题。
# 每天上午 10:30 执行 30 10 * * * cd /path/to/task && /usr/bin/python3 run_daily.py >> /var/log/daily.log 2>&1这行配置里,cd是为了固定工作目录,>>是追加日志,2>&1是把错误输出也重定向到同一个日志文件。别小看这几个符号,我见过太多人因为没写cd导致脚本找不到文件,或者因为没重定向导致出错时完全不知道发生了什么。
4.2 任务幂等性:重复执行不能出乱子
定时任务有个经典问题:如果某次执行卡住了,下一次触发时上一次还没结束,就可能出现两个任务同时跑的情况。日报场景下,这会导致重复推送或者内容错乱。
解决办法是加幂等控制。最简单的做法是用一个锁文件:任务开始时检查锁文件是否存在,存在就退出,不存在就创建锁文件并开始执行,执行完删除锁文件。这样即使定时器重复触发,也只有一个任务会真正执行。
import os import sys LOCK_FILE = "/tmp/daily_task.lock" if os.path.exists(LOCK_FILE): print("任务已在执行中,退出") sys.exit(0) try: with open(LOCK_FILE, "w") as f: f.write(str(os.getpid())) # 执行主逻辑 run_task() finally: if os.path.exists(LOCK_FILE): os.remove(LOCK_FILE)这个锁文件方案简单有效,但要注意:如果任务异常崩溃,锁文件可能残留,导致后续任务永远无法执行。所以要么在锁文件里写进程 ID 并在启动时检查进程是否还活着,要么加一个超时机制(比如锁文件超过两小时就强制删除)。我用的是后者,简单粗暴但够用。
4.3 日志要记到什么粒度
日志这件事,平时觉得烦,出问题时觉得救命。我的日志策略是:关键节点必记,异常必记,正常流程记摘要。
具体来说,任务开始、采集完成、摘要完成、推送完成这几个节点各记一条;任何异常记完整堆栈;正常流程只记条数和耗时,不记具体内容。这样日志文件不会爆炸,出问题时又能快速定位到是哪一段出的问题。
我还会在日志里记录每次任务的耗时。这个数据看起来没用,但当你发现某天任务突然变慢时,它能帮你快速判断是采集慢了还是摘要慢了。我有一次发现摘要段耗时从 30 秒涨到了 5 分钟,查下来是某个信息源返回的内容量突然变大,导致模型处理时间暴涨。没有耗时日志的话,这个问题很难发现。
5. 提示词调优:让日报"像人写的"而不是"像机器生成的"
5.1 摘要质量的三个层次
我把摘要质量分成三个层次:能看、好读、有用。能看是指内容完整、没有明显错误;好读是指结构清晰、语言通顺;有用是指读完能快速抓住重点、知道哪些值得深挖。大部分人做到"能看"就停了,但日报的价值恰恰在"有用"这一层。
从"能看"到"好读",靠的是格式约束;从"好读"到"有用",靠的是价值判断。也就是说,模型不仅要会摘要,还要会判断哪条内容更重要。这个判断能力需要通过提示词来引导。
我的做法是在提示词里给模型一个简单的价值判断框架:时效性(是不是新发生的)、相关性(跟我关注的方向是否匹配)、信息量(有没有具体的数据或结论)。让模型按这三个维度给每条内容打个标签,然后按标签排序。这样出来的日报,重要的内容自然排在前面。
5.2 避免"正确的废话"
AI 摘要最容易犯的毛病是"正确的废话"——每句话都对,但每句话都没信息量。比如"某公司发布了新产品,该产品具有多项新功能"这种,说了等于没说。
要避免这个问题,提示词里必须明确要求保留具体信息:数字、名称、结论、影响范围。我甚至会在提示词里举例说明什么是"废话"、什么是"有效信息",让模型有个参照。这个举例很重要,模型对抽象要求的理解远不如对具体例子的理解。
另外,我会要求模型在摘要里标注"信息密度"——如果某条内容实在没什么可提炼的,就标注为"低信息量"而不是硬凑一句话。这样我扫的时候可以直接跳过这些条目,节省时间。
5.3 提示词版本管理
提示词是要迭代的,所以版本管理很重要。我的做法是把提示词存在一个单独的文件里,每次修改都保留历史版本,并在日志里记录本次任务用的是哪个版本。这样当摘要质量出现波动时,我能快速定位是不是提示词改动导致的。
prompts/ daily_summary_v1.txt daily_summary_v2.txt daily_summary_v3.txt current -> daily_summary_v3.txt用软链接指向当前版本,切换版本时只改软链接,不用改代码。这个做法是从代码版本管理里借鉴过来的,用在提示词上同样有效。我大概迭代了七八版提示词,每一版都有明确的改进目标,没有一次是"随便改改"。
6. 跑稳之后,我总结的几条经验
6.1 先跑通最小链路,再优化细节
我一开始想一步到位,把采集、摘要、排版、推送全做好,结果卡了两周没跑通。后来改变策略,先做一个最小版本:手动准备一份原始内容,让 WorkBuddy 生成摘要,手动复制到微信。这个版本半小时就跑通了。然后逐步把采集自动化、把推送自动化、把排版精细化。
这个顺序很重要。最小链路跑通之后,你才有反馈,才知道哪里是真正的瓶颈。在没跑通之前做的所有优化,很可能都是优化了不重要的地方。
6.2 日报的价值在于"稳定",不在于"惊艳"
我见过很多人做日报,追求每天都有新花样,结果做了两周就放弃了。日报这种东西,价值在于"每天都有一份、格式一致、能快速扫完"。惊艳是锦上添花,稳定才是根本。所以我在设计的时候,宁可内容保守一点,也要保证每天都能准时出来。
具体来说,我会给每个环节设置超时和降级策略。采集超时就跳过该源,摘要超时就输出原始内容,推送失败就落本地文件。任何一个环节出问题,都不会导致整个日报缺失。这种"降级思维"是保证稳定性的关键。
6.3 定期回顾,砍掉不看的板块
日报跑了一段时间之后,你会发现有些板块你从来不看。这些板块要么砍掉,要么合并。我每个月会回顾一次日报的使用情况,把连续两周没看过的板块删掉。日报不是越全越好,是越"贴合你实际需求"越好。
这个回顾习惯还帮我发现了一个问题:我原本以为自己对某个方向很关注,所以放了很多相关源,结果回顾时发现那些内容我基本都跳过。后来我把这些源砍掉,日报长度减了三分之一,阅读体验反而更好了。
6.4 关于 WorkBuddy 的一些使用心得
WorkBuddy 这类工具,用得好不好的关键不在于工具本身,而在于你有没有把任务拆清楚。我的经验是:一个任务只做一件事。采集是一个任务,摘要是一个任务,推送是一个任务。任务拆得越细,越容易调试,越容易复用。
另外,WorkBuddy 的任务配置建议用版本管理,跟代码一样。每次修改都记录改了什么、为什么改。这样当任务行为出现变化时,你能快速定位到是哪次修改导致的。我吃过这个亏——有一次任务突然开始输出乱码,查了半天才发现是某次修改配置时手滑改错了一个参数,因为没有版本记录,排查花了很久。
还有一点是不要过度依赖模型的"智能"。模型很擅长处理模糊的、需要理解的任务,但不擅长处理精确的、需要一致性的任务。所以像时间格式、字段名、分类标签这些东西,能用固定规则就用固定规则,别交给模型去判断。模型负责"理解内容",规则负责"保证一致",两者分工明确,整个系统才稳。
6.5 一个容易被忽略的细节:时区
定时任务和日志时间戳一定要统一时区。我有一次发现日报的时间戳总是差几个小时,查下来是服务器时区和本地时区不一致。这个问题不影响功能,但影响排查问题时的判断。建议在任务开始时就把时区固定下来,所有时间相关的地方都用同一个时区。
import os os.environ['TZ'] = 'Asia/Shanghai'这行代码放在任务脚本的最开头,能避免很多时间相关的困惑。别觉得这是小事,排查时间相关问题时,时区不一致能让你怀疑人生。
整套流程跑到现在大概三个月了,中间大改过两次,小修过无数次。现在每天早上十点半,微信准时弹出日报,我扫一眼,三分钟看完,该深挖的记下来,该跳过的跳过。省下来的时间,够我多写两段代码或者多喝一杯咖啡。如果你也在做类似的事情,我的建议是:先把最小链路跑通,然后慢慢磨,别急着一口吃成胖子。