1. 为什么AI Agent需要任务完成通知?
当我们在开发AI Agent时,经常会遇到一个实际痛点:Agent执行任务的时间长短不一,有些可能需要几秒钟,有些则要运行几个小时。作为开发者或使用者,我们不可能一直盯着终端或日志页面等待结果。这就引出了一个核心需求——如何让AI Agent在完成任务后主动通知我们?
传统做法是定期轮询检查任务状态,但这既低效又浪费资源。想象一下,你正在开发一个自动爬取数据的AI Agent,每次都要手动刷新页面查看是否完成,这种体验有多糟糕。更合理的方案是让Agent在任务结束时主动推送通知,就像外卖小哥送到餐后给你打电话一样自然。
微信作为国内最普及的即时通讯工具,自然成为通知渠道的首选。根据2023年微信生态报告,微信月活用户已突破13亿,覆盖了绝大多数互联网用户。这意味着:
- 几乎人人都有微信,无需额外安装应用
- 通知可以实时送达手机,保证及时性
- 支持文字、图片、文件等多种消息格式
- 具备成熟的API生态和开发文档
2. 微信推送服务的实现方案选型
2.1 企业微信 vs 公众号 vs 个人号
实现微信通知主要有三种技术路线:
企业微信API:
- 优点:官方支持,稳定性高,功能丰富
- 缺点:需要注册企业,个人开发者使用门槛较高
- 适合:企业级应用或团队协作场景
微信公众号模板消息:
- 优点:无需添加好友,一次发送多人可见
- 缺点:需要用户关注公众号,模板消息有严格的内容限制
- 适合:面向公众的信息推送
个人微信号(Web协议):
- 优点:直接发送给指定联系人,体验最自然
- 缺点:存在封号风险,需要维护登录状态
- 适合:个人项目或小范围使用
对于大多数AI Agent开发者来说,企业微信API是最稳妥的选择。虽然初期配置稍复杂,但长期来看稳定性最好。下面我们就以企业微信为例,详细讲解实现步骤。
2.2 企业微信API的核心组件
要使用企业微信API发送消息,需要了解以下几个关键概念:
- CorpID & Secret:相当于账号密码,用于获取访问令牌
- AgentID:每个应用都有唯一的AgentID
- Access Token:时效2小时的API调用凭证
- 消息类型:支持文本、图文、文件等格式
重要提示:Secret相当于密码,一定要妥善保管,不要上传到公开代码库
3. 手把手搭建微信推送服务
3.1 前期准备工作
注册企业微信:
- 访问 企业微信官网 注册
- 个人开发者选择"免费注册",按指引完成企业创建
创建应用:
- 进入"应用管理" → "自建" → "创建应用"
- 填写应用名称(如"AI任务通知")、上传Logo
- 记录下生成的AgentID
获取凭证信息:
- 进入"我的企业" → "企业信息",记录CorpID
- 进入刚创建的应用 → "查看Secret",生成并记录Secret
3.2 获取Access Token的代码实现
Access Token是企业微信API调用的基础,每2小时需要刷新一次。以下是Python实现示例:
import requests import time class WeChatNotifier: def __init__(self, corpid, corpsecret): self.corpid = corpid self.corpsecret = corpsecret self.token = None self.token_expire = 0 def get_token(self): # 如果token未过期,直接返回 if self.token and time.time() < self.token_expire: return self.token # 请求新token url = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={self.corpid}&corpsecret={self.corpsecret}" resp = requests.get(url).json() if resp['errcode'] != 0: raise Exception(f"获取token失败: {resp['errmsg']}") self.token = resp['access_token'] self.token_expire = time.time() + 7000 # 提前200秒过期 return self.token3.3 发送消息的完整实现
下面是一个支持多种消息类型的发送类扩展:
def send_message(self, user_ids, content, msg_type="text"): token = self.get_token() url = f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={token}" # 基础消息结构 payload = { "touser": "|".join(user_ids), "agentid": self.agentid, "msgtype": msg_type, msg_type: {} } # 根据不同类型构建内容 if msg_type == "text": payload[msg_type]["content"] = content elif msg_type == "markdown": payload[msg_type]["content"] = content elif msg_type == "file": # 需要先上传文件获取media_id media_id = self.upload_file(content) payload[msg_type]["media_id"] = media_id resp = requests.post(url, json=payload).json() if resp['errcode'] != 0: raise Exception(f"发送失败: {resp['errmsg']}") return True3.4 文件上传的实现
如果需要发送任务生成的报告或结果文件,需要先上传到企业微信服务器:
def upload_file(self, file_path): token = self.get_token() url = f"https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token={token}&type=file" with open(file_path, 'rb') as f: files = {'media': f} resp = requests.post(url, files=files).json() if resp['errcode'] != 0: raise Exception(f"上传失败: {resp['errmsg']}") return resp['media_id']4. 与AI Agent的集成实践
4.1 任务完成时的通知触发
在AI Agent的主逻辑中,我们需要在任务完成时调用通知服务。以下是典型集成方式:
def run_agent_task(task_params): # 初始化微信通知服务 notifier = WeChatNotifier( corpid="YOUR_CORPID", corpsecret="YOUR_SECRET", agentid=YOUR_AGENTID ) try: # 执行AI任务 result = ai_agent.execute(task_params) # 任务成功通知 notifier.send_message( user_ids=["User1", "User2"], content=f"🎉 任务完成!\n" f"任务ID: {task_params['id']}\n" f"耗时: {time.time() - start_time:.2f}秒\n" f"结果摘要: {result[:100]}...", msg_type="markdown" ) # 如果有结果文件 if result.output_file: notifier.send_message( user_ids=["User1"], content=result.output_file, msg_type="file" ) except Exception as e: # 任务失败通知 notifier.send_message( user_ids=["User1"], content=f"❌ 任务失败!\n" f"任务ID: {task_params['id']}\n" f"错误信息: {str(e)}", msg_type="markdown" ) raise4.2 消息内容的优化建议
好的通知消息应该包含以下要素:
- 明确的状态标识:使用✅/❌等表情符号直观展示成功/失败
- 关键任务信息:任务ID、执行时间等诊断信息
- 结果摘要:如果是数据分析任务,包含关键指标
- 后续指引:如"点击查看详情"或"请及时处理"
示例优化后的Markdown消息:
### 数据分析任务完成通知 🔍 **任务名称**: 用户行为分析_202405 ⏱ **执行时间**: 2分18秒 📊 **关键指标**: - 总用户数: 12,458 - 活跃率: 62.3% - 转化提升: +15.2% [点击查看完整报告](内部链接) | [下载原始数据](文件链接)4.3 处理异步长时任务
对于运行时间较长的AI任务,可以考虑增加进度通知:
def long_running_task(task_params): notifier = WeChatNotifier(...) # 任务开始通知 notifier.send_message( user_ids=["User1"], content=f"⏳ 任务开始执行\n任务ID: {task_params['id']}" ) # 每10%进度发送通知 for progress in range(10, 101, 10): update_progress(task_params['id'], progress) if progress % 30 == 0: # 每30%发详细通知 notifier.send_message( user_ids=["User1"], content=f"📊 任务进度: {progress}%\n" f"当前状态: {get_current_status()}" ) # ...剩余任务逻辑5. 生产环境中的注意事项
5.1 安全性最佳实践
凭证管理:
- 不要将CorpSecret硬编码在代码中
- 使用环境变量或专业的密钥管理服务
- 定期轮换Secret(企业微信支持多个Secret)
频率限制:
- 企业微信API有调用频率限制(约2000次/分钟)
- 对于大量通知,考虑批量发送或使用消息队列
错误处理:
- 实现自动重试机制(特别是token过期时)
- 记录发送失败的日志,方便排查
5.2 性能优化技巧
Token缓存:
- 将token存入Redis等缓存系统,多个服务共享
- 设置合理的过期时间(建议比官方2小时稍短)
异步发送:
- 使用Celery等任务队列异步处理发送逻辑
- 避免阻塞主任务流程
消息合并:
- 对于高频通知,可以累积一段时间后合并发送
- 如将每分钟的状态更新合并为摘要报告
5.3 常见问题排查
收不到消息:
- 检查应用是否已启用
- 确认用户在企业微信通讯录中
- 验证用户是否被添加到了应用的可见范围
媒体文件上传失败:
- 检查文件大小(不超过20MB)
- 确认文件类型在允许范围内
- 尝试重新获取token后重试
API限频错误:
- 实现指数退避重试机制
- 考虑减少发送频率或合并消息
我在实际项目中发现,最容易出问题的环节是token过期后的重新获取。一个可靠的解决方案是使用装饰器自动处理token刷新:
def refresh_token(func): def wrapper(self, *args, **kwargs): try: return func(self, *args, **kwargs) except Exception as e: if "invalid token" in str(e).lower(): self.token = None # 强制刷新token return func(self, *args, **kwargs) raise return wrapper # 使用示例 @refresh_token def send_message(self, user_ids, content): # 原发送逻辑这套微信通知服务我已经在三个AI Agent项目中实际应用,最长的稳定运行超过8个月。一个有趣的发现是:相比纯文字通知,带有适当emoji和格式化的Markdown消息的点击率提高了近3倍。这提醒我们,即使是技术通知,良好的用户体验设计也很重要。