OpenClaw 只能命令行触发?自研企业微信实现“发消息即执行“
系列: SmartClaw × OpenClaw:企业级浏览器自动化实战(第⑤篇)日期: 2026-05-04标签: OpenClaw, 企业微信, Webhook, Spring Boot, AES 解密, 消息触发适合谁看: Spring Boot 开发、企业微信集成、后端工程师

前言
OpenClaw 需要通过命令行或 API 触发任务,非技术人员无法使用。
场景: 门店员工需要通过微信发起设备报修,但她们不会用命令行,只会用微信。
SmartClaw 的做法: 接入企业微信 Webhook,员工发送”报修 空调不制冷 3楼302 张三”,系统自动提取信息并创建工单,完成后回复”✅ 工单已创建”。
本文是系列第⑤篇,完整讲解 Spring Boot 如何接入企业微信 Webhook,实现”发消息即执行”的自动化流程。
一、OpenClaw 的交互局限
1.1 需要 CLI/API 触发
OpenClaw 的典型使用方式:
# 命令行触发openclaw run --prompt "登录系统,填写表单"# 或者调用 APIcurl -X POST http://localhost:3000/api/run \-d '{"prompt": "登录系统,填写表单"}'
问题:
-
非技术人员无法使用 -
无法与现有工作流集成 -
移动端操作不便
1.2 对比表格
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
二、业务场景:门店报修自动派单
2.1 背景
某连锁零售集团有 50 个门店,每个门店每天需要:
-
将设备报修信息自动创建到工单系统 -
人工操作耗时 3 分钟/条 -
每天约 100 条,总耗时 5 小时
2.2 消息格式约定
前台通过企业微信发送:
报修 空调不制冷 3楼302 张三
2.3 执行流程

三、核心技术实现
3.1 企业微信配置
步骤 1:创建应用
-
登录 企业微信管理后台 -
进入「应用管理」→「创建应用」 -
获取以下参数: corp_id
:企业 ID agent_id
:应用 ID agent_secret
:应用密钥
步骤 2:配置回调 URL
-
进入「应用管理」→ 选择应用 →「接收消息」 -
设置回调 URL: https://your-domain.com/api/wechat/work/callback -
设置 Token(自定义,如 SmartClaw2026) -
设置 EncodingAESKey(随机生成 43 位字符)
步骤 3:配置 IP 白名单
将 SmartClaw Server 的公网 IP 加入白名单。
3.2 Spring Boot 配置
# application.ymlsmartclaw:wechat:work:enabled: truecorp-id: wwxxxxxxxxxxxxxagent-id: 1000001agent-secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxtoken: SmartClaw2026encoding-aes-key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3.3 回调接收控制器
@RestController@RequestMapping("/api/wechat/work")@Slf4jpublic class WechatWorkCallbackController {@Autowiredprivate WxMsgDecryptService decryptService;@Autowiredprivate WechatMessageDispatcher dispatcher;/*** 企业微信验证 URL 有效性(GET 请求)*/@GetMapping("/callback")public String verify(@RequestParam String msg_signature,@RequestParam String timestamp,@RequestParam String nonce,@RequestParam String echostr) {log.info("Verifying URL: timestamp={}, nonce={}", timestamp, nonce);try {// 验签 + 解密 echostrString decryptedEchostr = decryptService.verifyUrl(msg_signature, timestamp, nonce, echostr);log.info("URL verification successful");return decryptedEchostr; // 必须原样返回} catch (Exception e) {log.error("URL verification failed", e);return "fail";}}/*** 接收企业微信推送消息(POST 请求)*/@PostMapping("/callback")public String callback(@RequestBody String rawXml,@RequestParam String msg_signature,@RequestParam String timestamp,@RequestParam String nonce) {log.info("Received message: timestamp={}", timestamp);try {// 1. 验签 + 解密WxWorkMessage message = decryptService.decryptMessage(rawXml, msg_signature, timestamp, nonce);log.info("Decrypted message: from={}, content={}",message.getFromUserName(), message.getContent());// 2. 只处理文本消息if ("text".equalsIgnoreCase(message.getMsgType())) {// 3. 异步 dispatch,避免阻塞企业微信回调dispatcher.dispatchAsync(message);}// 4. 必须返回 success,否则企业微信会重试return "success";} catch (Exception e) {log.error("Callback processing failed", e);// 即使失败也要返回 success,避免企业微信无限重试return "success";}}}
3.4 AES 解密服务
企业微信使用 AES-256-CBC 加密消息体,需要官方提供的加解密库。
引入依赖
<!-- pom.xml --><dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-cp</artifactId><version>4.5.0</version></dependency>
实现解密逻辑
@Service@Slf4jpublic classWxMsgDecryptService{@Value("{smartclaw.wechat.work.encoding-aes-key}")private String encodingAesKey;@Value("','store-repair-ticket-v1','["issue","location","reporter"]',100);
规则匹配服务
@Service@Slf4jpublic class MessageRuleService {@Autowiredprivate MessageRuleRepository ruleRepository;@Autowiredprivate TaskDispatchService dispatchService;/*** 匹配消息并触发任务*/public Optional<DispatchResult> matchAndDispatch(WxWorkMessage message) {String content = message.getContent().trim();String sender = message.getFromUserName();log.info("Matching message: content={}, sender={}", content, sender);// 1. 从数据库加载启用的规则(按优先级排序)List<MessageRule> rules = ruleRepository.findEnabledRulesOrderByPriorityDesc();for (MessageRule rule : rules) {// 2. 正则匹配Matcher matcher = Pattern.compile(rule.getPattern()).matcher(content);if (matcher.matches()) {log.info("Rule matched: ruleName={}", rule.getName());// 3. 提取命名捕获组作为变量Map<String, String> variables = extractNamedGroups(matcher, rule);// 4. 注入发送者信息variables.put("_senderUserId", sender);variables.put("_msgId", message.getMsgId());// 5. 构建 dispatch 请求DispatchRequest request = DispatchRequest.builder().templateId(rule.getTemplateId()).variables(variables).idempotencyKey("wechat_work:" + message.getMsgId()).source("WECHAT_WORK").requesterOpenId(sender).build();// 6. 下发任务DispatchResult result = dispatchService.dispatch(request);log.info("Task dispatched: runId={}", result.getRunId());return Optional.of(result);}}log.warn("No rule matched for message: {}", content);// 无匹配规则:发送默认回复sendDefaultReply(sender, content);return Optional.empty();}/*** 提取正则命名捕获组*/private Map<String, String> extractNamedGroups(Matcher matcher, MessageRule rule) {Map<String, String> vars = new HashMap<>();// 解析 variable_names JSON 数组List<String> varNames = parseJsonArray(rule.getVariableNames());for (String groupName : varNames) {try {String value = matcher.group(groupName);vars.put(groupName, value);log.debug("Extracted variable: {}={}", groupName, value);} catch (IllegalArgumentException e) {log.warn("Group not found: {}", groupName);}}return vars;}private List<String> parseJsonArray(String jsonArray) {// 使用 Jackson 或 Gson 解析 JSONtry {return objectMapper.readValue(jsonArray,new TypeReference<List<String>>() {});} catch (Exception e) {log.error("Failed to parse JSON array", e);return Collections.emptyList();}}}
3.6 消息调度器
@Service@Slf4jpublic class WechatMessageDispatcher {@Autowiredprivate MessageRuleService ruleService;@Autowiredprivate WechatWorkApiClient wechatApiClient;/*** 异步 dispatch(避免阻塞企业微信回调)*/@Async("wechatExecutor")public void dispatchAsync(WxWorkMessage message) {try {Optional<DispatchResult> result = ruleService.matchAndDispatch(message);if (result.isPresent()) {log.info("Message processed successfully: msgId={}", message.getMsgId());} else {log.warn("Message not matched: msgId={}", message.getMsgId());}} catch (Exception e) {log.error("Message dispatch failed: msgId={}", message.getMsgId(), e);// 发送错误回复wechatApiClient.sendText(message.getFromUserName(),"❌ 处理失败:" + e.getMessage());}}}
3.7 回复消息 API 客户端
@Service@Slf4jpublic class WechatWorkApiClient {private static final String TOKEN_URL ="https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={}&corpsecret={}";private static final String SEND_URL ="https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={}";@Value("{smartclaw.wechat.work.agent-secret}")private String agentSecret;@Value("// 提取变量issue = "空调不制冷"location = "3楼302"reporter = "张三"
4.4 下发任务
DispatchRequest request = DispatchRequest.builder().templateId("store-repair-ticket-v1").variables(Map.of("issue", "空调不制冷","location", "3楼302","reporter", "张三")).idempotencyKey("wechat_work:1234567890").source("WECHAT_WORK").requesterOpenId("ZhangSan").build();dispatchService.dispatch(request);
4.5 Agent 执行 DSL
steps:- stepId: s1action: navigateparams:url: "https://support.example.com/ticket/new"- stepId: s2action: fillparams:selector: "input[name='name']"value: "{issue}" # 空调不制冷- stepId: s4action: fillparams:selector: "input[name='room']"value: "${location}" # 3楼302- stepId: s5action: clickRoleparams:role: "button"name: "提交工单"- stepId: s6action: waitTextparams:text: "工单已创建"timeoutMs: 8000
4.6 回复前台
✅ **自动化任务完成**> 任务:门店报修派单> 流水号:c6efed0a> 耗时:4823ms> 时间:04-27 14:32:11
五、性能优化建议
5.1 AccessToken 缓存
企业微信 AccessToken 有效期 7200 秒,不要每次请求都重新获取:
LoadingCache<String, String> tokenCache = CacheBuilder.newBuilder().expireAfterWrite(7000, TimeUnit.SECONDS) // 7000 秒过期.build(CacheLoader.from(this::fetchAccessToken));
5.2 异步处理消息
企业微信要求 5 秒内响应,因此消息处理必须异步:
@Async("wechatExecutor")public void dispatchAsync(WxWorkMessage message) {// 异步处理,立即返回 success}
线程池配置:
@Configurationpublic class WechatExecutorConfig {@Bean("wechatExecutor")public Executor wechatExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(100);executor.setThreadNamePrefix("wechat-");executor.initialize();return executor;}}
5.3 幂等保护
通过消息 ID 保证同一条消息不会重复触发任务:
.idempotencyKey("wechat_work:" + message.getMsgId())
六、OpenClaw 做不到的事
6.1 自然语言交互
OpenClaw 需要手写 Prompt,而 SmartClaw 可以通过微信消息触发,用户门槛更低。
6.2 工作流集成
SmartClaw 可以与企业微信深度集成,实现:
-
消息触发任务 -
任务完成回复 -
群聊 @机器人触发 -
审批流程集成
6.3 移动端支持
企业微信支持 iOS/Android,用户可以随时随地触发自动化任务。
七、总结
OpenClaw 展示了 AI 操作浏览器的可能性,但在企业落地场景下,还需要解决交互入口的问题。
SmartClaw 通过接入企业微信 Webhook,实现了”发消息即执行”的自动化流程,将用户门槛降到最低。
相关资源
-
系列文章:
-
第④篇:Agent 调度与幂等设计
-
企业微信官方文档:接收消息与事件
💬 互动交流
如果你在学习和使用过程中遇到问题,欢迎:1. 在评论区留言讨论2.如果觉得有帮助,点赞👍收藏📌关注➕,后续会持续分享SpringAI和AI工程的实战经验!
你的支持是我持续创作的最大动力!

夜雨聆风