我的工作日常大概是这个样子:早上到工位,打开Outlook,30+封未读邮件等你筛选;上午写两小时代码,被"请查收""麻烦确认"打断四次;下午盯着GitHub看有没有新的量化项目值得关注;下班前花20分钟回忆今天到底干了啥,写日报。
一天下来,真正写代码的时间不到4小时。
我受够了。于是我用 Hermes Agent(一个开源本地AI Agent框架)+ WSL2 + 微信,搭了一套7×24小时自动化系统。现在我的工作流是这样的:邮件有人帮我筛、日报有人帮我写、服务挂了有人帮我盯、技术动态有人帮我追。
今天把整个搭建过程和踩坑经验完整分享出来,代码都是真实在跑的。
整体架构:一句话说明白
scss
┌──────────────────────────────────────────────────┐
│ WSL2 (Ubuntu) │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ Hermes Agent v0.10.0 │ │
│ │ ┌─────────┐ ┌──────────────────────────┐ │ │
│ │ │ Cron │ │ Python Scripts │ │ │
│ │ │ 调度器 │──│ ├─ 邮件监控 (每15min) │ │ │
│ │ │ │ │ ├─ 工作日报 (18:00) │ │ │
│ │ │ │ │ ├─ 服务健康监控 (每5min) │ │ │
│ │ │ │ │ └─ 技术动态追踪 (每天) │ │ │
│ │ └─────────┘ └──────────┬───────────────┘ │ │
│ └──────────────────────────┼──────────────────┘ │
│ │ │
└──────────────────────────────┼──────────────────────┘
│
┌──────────┴──────────┐
│ 消息通道 │
│ 微信 / 飞书 │
└──────────┬──────────┘
│
📱 你的手机
核心就三层:WSL2跑Agent → Agent调度Python脚本 → 脚本把结果推送到微信/飞书。
你的手机就是整个系统的控制台和通知中心。
环境准备:10分钟搞定
我选择WSL2而不是直接装Linux,是因为公司电脑是Windows,WSL2可以无缝共享网络和文件系统,同时提供完整的Linux开发环境。
bash
# 安装Hermes Agent(假设已安装Python 3.11+)
pip install hermes-agent
# 初始化工作目录
mkdir -p ~/.hermes/scripts
cd ~/.hermes
# 安装核心依赖
pip install msal requests playwright
playwright install chromium
# 如果需要中文截图(我踩过这个坑,后面细说)
sudo apt install fonts-wqy-zenhei
Hermes的配置文件 ~/.hermes/config.yaml 长这样:
yaml
# ~/.hermes/config.yaml - 核心配置
version: "0.10.0"
agent:
name: "my-workflow-agent"
model: "glm-5-turbo" # 智谱GLM,国内访问无障碍
provider: "zai"
channels:
weixin: # 微信消息通道
enabled: true
feishu: # 飞书消息通道(备用)
enabled: true
cron: # 定时任务配置
enabled: true
timezone: "Asia/Shanghai"
四个自动化任务,从刚需到惊喜
任务1:企业邮件实时监控(每15分钟)
为什么做:我的Outlook每天收50+封邮件,其中70%是系统通知、Jira更新、CI/CD构建结果。真正需要我处理的人类邮件每天大概15封,混在里面很难找。
怎么做 :公司用的是企业Azure AD,限制普通用户注册应用。官方文档推荐的Client Credentials Flow根本走不通------我没有权限创建App Registration。最后用 Device Code Flow + Office公共客户端ID 绕过:
python
# ~/.hermes/scripts/ms365_email_auth.py
import msal
import requests
import json
from datetime import datetime, timedelta
OFFICE_CLIENT_ID = "d3590ed6-52b3-4102-aeff-aad2292ab01c"
SCOPES = ["Mail.Read"]
TOKEN_FILE = "~/.hermes/.ms365_token.json"
def get_access_token():
"""Device Code Flow认证 - 不需要App Registration"""
app = msal.PublicClientApplication(
OFFICE_CLIENT_ID,
authority="https://login.microsoftonline.com/common"
)
# 先尝试从缓存读取
accounts = app.get_accounts()
if accounts:
result = app.acquire_token_silent(SCOPES, account=accounts[0])
if result and "access_token" in result:
return result["access_token"]
# 缓存失效,走Device Code Flow
flow = app.initiate_device_flow(scopes=SCOPES)
print(f"在浏览器打开: {flow['verification_uri']}")
print(f"输入代码: {flow['user_code']}")
# 这里会阻塞,直到用户在浏览器完成认证
result = app.acquire_token_by_device_flow(flow)
return result["access_token"]
def fetch_human_emails():
"""只获取人类发送的邮件,过滤系统通知"""
token = get_access_token()
headers = {"Authorization": f"Bearer {token}"}
# 查询最近15分钟的邮件
since = (datetime.utcnow() - timedelta(minutes=15)).strftime("%Y-%m-%dT%H:%M:%SZ")
url = (f"https://graph.microsoft.com/v1.0/me/messages?"
f"$filter=receivedDateTime ge {since}&$select=subject,from,receivedDateTime")
resp = requests.get(url, headers=headers)
emails = resp.json().get("value", [])
# 过滤规则:排除常见系统发件人
system_keywords = ["noreply", "notification", "jira", "jenkins", "github"]
human_emails = [
e for e in emails
if not any(kw in e["from"]["emailAddress"]["address"].lower()
for kw in system_keywords)
]
return human_emails
第一次运行时,终端会打印一个链接和验证码。你在浏览器打开、登录企业账号、授权,就完事了。Token会缓存到本地,过期后自动刷新。
效果:每15分钟检查一次,只有人类邮件才推送到微信。从每天被打断20次,降到真正需要处理时才收到通知。
任务2:每日工作总结(18:00准时推送)
为什么做:写日报是我最讨厌的事。每天18:00要花15-20分钟回忆今天干了啥,然后组织语言。既然邮件记录了我的大部分工作,为什么不AI自动生成?
怎么做:Hermes的cron调度器 + 时间守卫 + 邮件分析 + 微信推送。
python
# ~/.hermes/scripts/time_guard_18.py
"""时间守卫:确保任务只在18:00-18:10之间执行
防止cron重试或时钟漂移导致任务在错误时间运行"""
from datetime import datetime
def check_time_window():
now = datetime.now()
if not (18 <= now.hour <= 18 and 0 <= now.minute <= 10):
print(f"当前时间 {now:%H:%M} 不在执行窗口内,跳过")
return False
return True
python
# ~/.hermes/scripts/daily_summary.py
"""分析当天邮件,生成工作日报,推送到微信"""
from ms365_email_auth import fetch_human_emails
import json
def generate_daily_report():
if not check_time_window():
return
# 获取当天所有人类邮件
emails = fetch_today_emails()
if not emails:
msg = "📝 今日工作日报\n\n今天没有收到人类邮件,应该是专注写代码的一天 💻"
else:
# 用AI总结邮件内容,提取工作要点
email_summary = "\n".join(
f"- {e['subject']} (来自 {e['from']['emailAddress']['name']})"
for e in emails
)
prompt = f"根据以下邮件主题列表,用简洁的中文生成今日工作日报(3-5条要点):\n{email_summary}"
# 调用Hermes的AI能力生成摘要
report = hermes_ai_call(prompt)
msg = f"📝 今日工作日报\n\n{report}"
# 推送到微信
hermes_send_weixin(msg)
效果:每天18:00准时收到微信推送的工作日报。准确率大约85%,有时候会漏掉口头沟通的工作(毕竟它只能看到邮件),但对于一个自动生成的日报来说,已经很能打了。
任务3:服务健康监控(每5分钟)
为什么做:我搭了好几个定时任务和Web服务,但有一次某个服务挂了整整两天我才发现------因为它不会主动告诉你它挂了,只有用到的时候才报错。我需要一个"监控的监控"。
怎么做:一个轻量级健康检查脚本,定时探测目标服务,连续异常时才告警(避免单次网络波动误报)。
python
# ~/.hermes/scripts/health_monitor.py
"""服务健康监控 - 连续3次失败才告警,避免误报"""
import requests
import json
from pathlib import Path
STATE_FILE = Path.home() / ".hermes" / "data" / "health_state.json"
# 需要监控的服务列表
SERVICES = {
"Hermes网关": "http://localhost:8080/health",
"公司内部系统": "https://internal.company.com/api/ping",
"个人博客": "https://myblog.com",
}
def check_service(name, url):
"""检测单个服务是否可达"""
try:
resp = requests.get(url, timeout=10)
return resp.status_code == 200
except Exception:
return False
def run_health_check():
state = json.loads(STATE_FILE.read_text()) if STATE_FILE.exists() else {}
alerts = []
for name, url in SERVICES.items():
ok = check_service(name, url)
fail_count = state.get(name, 0)
state[name] = 0 if ok else fail_count + 1
# 连续3次失败才告警
if state[name] == 3:
alerts.append(f"🔴 {name} 连续3次不可达: {url}")
elif state[name] == 0 and fail_count >= 3:
# 恢复了也通知一声
alerts.append(f"✅ {name} 已恢复正常")
STATE_FILE.write_text(json.dumps(state, indent=2))
if alerts:
msg = "🏥 服务健康报告\n\n" + "\n".join(alerts)
hermes_send_weixin(msg)
效果:这个脚本跑了一个月,帮我提前发现了两次WSL内存不足导致的服务假死。有了它我才放心地把其他自动化任务全权交给系统跑。
任务4:技术动态追踪(每天早上)
为什么做:技术圈信息爆炸,我关注了20多个技术博客和GitHub项目,但经常错过重要更新。尤其是GitHub上关注的仓库发新版本了,或者常看的博客出了深度文章,靠手动刷根本刷不过来。我需要一个"AI版技术秘书",每天帮我过滤噪音、提炼重点。
怎么做:维护一个关注列表(GitHub仓库 + RSS源),cron每天早上抓取更新、用AI总结、推送精华摘要。
python
# ~/.hermes/scripts/tech_tracker.py
"""技术动态追踪 - 抓更新、AI总结、推微信"""
import json
import requests
from pathlib import Path
from datetime import datetime, timedelta
WATCH_FILE = Path.home() / ".hermes" / "data" / "watchlist.json"
# 关注列表:GitHub仓库 + 博客RSS
WATCHLIST = {
"github": [
{"owner": "vercel", "repo": "next.js", "note": "Next.js主框架"},
{"owner": "anthropics", "repo": "claude-code", "note": "Claude Code CLI"},
],
"blogs": [
{"name": "阮一峰的网络日志", "url": "https://www.ruanyifeng.com/blog/atom.xml"},
{"name": "Dan Abramov", "url": "https://overreacted.io/rss.xml"},
]
}
def check_github_updates():
"""检查GitHub仓库是否有新Release"""
updates = []
for item in WATCHLIST["github"]:
url = f"https://api.github.com/repos/{item['owner']}/{item['repo']}/releases/latest"
try:
resp = requests.get(url, timeout=10)
data = resp.json()
published = data.get("published_at", "")
# 只关注最近24小时的更新
if published and (datetime.now() - datetime.fromisoformat(published.replace("Z","+00:00"))) < timedelta(hours=24):
updates.append(f"📦 {item['note']} 新版本: {data.get('tag_name', '')}\n {data.get('body', '')[:100]}...")
except Exception as e:
updates.append(f"⚠️ {item['note']} 检查失败: {e}")
return updates
def summarize_updates(updates):
"""用AI总结技术动态"""
if not updates:
return None
prompt = f"""以下是今天的技术动态更新,请用中文生成简洁摘要(每条1-2句话,突出重要性):
{chr(10).join(updates)}
格式:
🔥 重点更新(1-3条)
📋 其他动态"""
return hermes_ai_call(prompt)
def run_tech_tracker():
updates = []
updates.extend(check_github_updates())
# RSS博客抓取类似,此处省略
summary = summarize_updates(updates)
if summary:
hermes_send_weixin(f"📡 今日技术动态\n\n{summary}")
效果:每天早上9点,微信收到一份精炼的技术动态摘要。再也不会错过Next.js大版本更新或者关注博主的新文章了。AI帮我把20+信息源压缩成3-5条要点,阅读时间从30分钟降到了2分钟。
踩坑实录:生产环境不骗人
上面讲的都是跑通后的样子。实际上,这套系统我前前后后折腾了两周,踩了5个大坑。每个坑都让我浪费了半天到两天不等。
坑1:微信消息投递超时(最坑的)
现象:cron任务日志显示一切正常执行,但微信始终没收到任何消息。任务跑了好几天,我完全没收到报告,还以为系统在工作。直到某天手动检查日志才发现报错。
原因 :错误信息是 Timeout context manager should be used inside a task。这是因为cron任务的执行上下文和异步消息投递的event loop冲突了。cron在同步线程里执行,而微信通道投递需要async上下文。
解决方案:
python
# 错误写法 - cron线程里直接调用
def cron_job():
hermes_send_weixin(message) # 💥 TimeoutError
# 正确写法 - 用asyncio包装
import asyncio
def cron_job():
asyncio.run(hermes_send_weixin(message))
这个坑教会我一件事:定时任务"执行成功"和"消息送达"是两回事。一定要加监控确认。
坑2:/tmp文件丢失
现象:WSL重启后,定时生成文章的任务突然停止工作。
原因 :我把系列文章的计划文件存在了 /tmp/article-series-plan.md。WSL重启后 /tmp 被清空,计划文件没了,依赖这个文件的后续任务全部失败。
解决方案 :所有持久化数据迁移到 ~/.hermes/data/ 目录。
bash
# 错误 ❌
PLAN_FILE = "/tmp/article-series-plan.md"
# 正确 ✅
DATA_DIR = Path.home() / ".hermes" / "data"
DATA_DIR.mkdir(parents=True, exist_ok=True)
PLAN_FILE = DATA_DIR / "article-series-plan.md"
这条规则现在刻在我的DNA里:持久化数据绝对不进 /tmp。
坑3:企业Azure AD限制
现象 :Microsoft Graph API认证一直失败,报 AADSTS650053: The app is not pre-authorized。
原因:公司Azure AD管理员限制了普通用户注册应用,只允许管理员创建的App Registration。微软文档示例里用的Graph API Explorer的Client ID在我们环境不可用。
解决方案:使用Office的公共客户端ID(这是微软预置的,任何Azure AD租户都能用),配合Device Code Flow:
python
# 关键:用Office公共客户端ID,不用Graph Explorer的
OFFICE_CLIENT_ID = "d3590ed6-52b3-4102-aeff-aad2292ab01c"
app = msal.PublicClientApplication(
OFFICE_CLIENT_ID,
authority="https://login.microsoftonline.com/common"
)
# Device Code Flow - 用户在浏览器手动授权,不需要管理员审批
flow = app.initiate_device_flow(scopes=["Mail.Read"])
坑4:Zscaler代理拦截
现象:在公司的Windows上能正常访问的网站,在WSL里全部超时。GitHub raw内容、Google、DuckDuckGo全部403或连接超时。
原因:公司网络走Zscaler安全代理,WSL的网络栈和Windows的代理配置不互通。
解决方案:
bash
# ~/.bashrc 添加代理配置
export http_proxy="http://your-company-proxy:port"
export https_proxy="http://your-company-proxy:port"
export no_proxy="localhost,127.0.0.1,.internal.company.com"
如果不想全局走代理(会拖慢本地服务),可以只对特定域名配置:
bash
# 只对被拦截的域名走代理
export no_proxy="*"
# 在Python脚本里按需使用代理
proxies = {"https": "http://company-proxy:port"}
requests.get("https://raw.githubusercontent.com/...", proxies=proxies)
坑5:WSL中文字体缺失
现象:用Playwright截图时,所有中文都是方块 □□□□。
原因:WSL默认没有安装中文字体。
解决方案:一行命令搞定:
bash
sudo apt update && sudo apt install -y fonts-wqy-zenhei
# 安装后清除Playwright字体缓存
rm -rf ~/.cache/ms-playwright/
总结和思考
这套系统跑了一个月,最大的感受是:自动化不是省时间,是省注意力。省下的时间你可能又去刷手机了,但省下的注意力是实打实的------我现在能连续写2小时代码不被打扰,这在以前是不可能的。
但也有明显的局限性:
-
单点故障风险高。整个系统跑在一台WSL上,Windows更新重启WSL就全挂了。生产级方案应该跑在独立服务器上,配合systemd做进程守护。
-
邮件监控覆盖率有限。目前只能看到邮件,微信、飞书、Slack里的沟通记录是盲区。如果能接入飞书消息API做统一的"工作流感知层",会强很多。
-
GitHub API有速率限制。未认证请求每小时60次,如果关注列表太大会被限流。解决方案是用Personal Access Token认证,额度提升到5000次/小时。
-
安全边界需要明确。企业邮件数据走本地,不上传第三方(除了必要时的AI推理),这个底线不能破。
下一步计划:给这套系统加一个异常告警机制------如果某个定时任务连续3次执行失败,通过飞书机器人告警。毕竟,"跑了好几天发现消息根本没发出去"这种事,我再也不想经历了。
📌 关注我,「AI工具提效实战指南」系列持续更新。下一篇聊聊:AI编程的真实效率到底提升了多少?我用数据说话。