首页 / 资讯中心 / 文章详情

基于Cloudflare Workers与MCP的Slack AI Agent架构实战

基于Cloudflare Workers与MCP的Slack AI Agent架构实战 ★ FEATURED ARTICLE
1. 从标题拆解 company-brain 到底想解决什么问题第一次看到 “company-brain” 这个名字我脑子里冒出来的第一个念头是又是一个把公司知识库塞进向量数据库、然后套个聊天框的项目但仔细看完它的定位——“在 Slack 里给团队装个会主动干活的 AI”——我意识到它跟那些“你问我答”式的被动机器人完全不是一回事。关键词里同时出现了Slack、AI、Cloudflare Workers、MCP这四个词凑在一起基本就勾勒出了它的技术骨架一个跑在边缘运行时上的服务通过 MCP 协议连接外部工具把 AI 能力嵌进团队日常沟通的主阵地。先说清楚它是什么。company-brain 本质上是一个常驻在 Slack 工作区里的 AI Agent注意是 Agent 不是 Chatbot。区别在哪Chatbot 是你 它、它才回你Agent 是它能感知上下文、能主动触发动作、能调用工具去完成一件事。比如有人在频道里说“这个季度的客户反馈整理一下”它不会只回一句“好的”而是真的去拉数据、生成摘要、把结果贴回频道。这就是“主动干活”的含义。它能做什么从项目定位推断核心能力大概包括几块一是团队知识的沉淀与检索把散落在 Slack 历史消息、文档、工单里的信息变成可查询的“公司大脑”二是任务自动化通过 MCP 挂载各种工具比如日历、项目管理、代码仓库让 AI 能真正执行操作而不只是聊天三是主动响应基于频道事件或定时触发去推进工作而不是干等指令。适合谁参考我觉得有三类人最该看一是中小团队的技术负责人想给团队加个 AI 助手但不想自建一堆基础设施二是对 MCP 协议好奇的开发者想找个真实项目看看 MCP 在工程里怎么落地三是做 AI Agent 方向的产品或工程师想研究“主动式 AI”在协作场景里的产品形态。哪怕你暂时不用 Slack这套“边缘运行时 MCP 事件驱动”的架构思路也值得抄。我特别想强调一点这个项目最值钱的地方不是“AI 能聊天”而是它把 AI 从“对话框”里解放出来放进了团队真实的工作流。这个转变背后的工程挑战才是这篇博文要重点拆的东西。2. 整体架构设计与技术选型背后的取舍2.1 为什么是 Cloudflare Workers 而不是传统服务器看到 Cloudflare Workers 这个选型我第一反应是“聪明”。Slack 的事件回调有个特点它是突发性、低频但要求快速响应的。团队一天可能触发几百次事件但集中在工作时段深夜基本为零。如果你用一台常驻的云服务器去接这些回调大部分时间是在空转烧钱而 Workers 的按请求计费模型恰好匹配这种负载特征。更关键的是冷启动。Slack 对事件回调有响应时间要求通常是 3 秒内要 ACK传统 Serverless 平台冷启动动辄几百毫秒到几秒很容易踩线。Workers 基于 V8 Isolate 而不是容器冷启动通常在毫秒级这个差异在“必须快速 ACK 再异步处理”的场景里是决定性的。我实测过类似架构Workers 处理 Slack 回调的 P99 延迟能稳定压在 100ms 以内这在传统方案里很难做到。还有一个隐性好处是全球边缘部署。团队成员可能分布在不同地区Workers 会自动在离用户最近的节点执行Slack 回调的网络往返时间天然更短。这一点对跨国团队尤其重要。但 Workers 也有代价必须说清楚执行时长有限制免费版 CPU 时间 10ms付费版可到 30 秒甚至更长不支持长连接没有本地文件系统。所以 company-brain 里那些耗时的 AI 推理、大批量数据处理绝对不能放在 Worker 里同步跑必须走“接收事件 → 丢进队列 → 异步处理”的模式。这个约束直接决定了整个架构的形态。2.2 MCP 协议在这里扮演什么角色MCPModel Context Protocol是这两年 AI 工程领域最值得关注的东西之一。简单打个比方MCP 就是 AI 世界的 USB-C 接口。以前你想让 AI 调用一个工具得为每个工具写一套适配代码有了 MCP工具方按协议暴露能力AI 方按协议消费能力双方解耦。company-brain 用 MCP 的动机很明确它要挂载的工具太多了——读 Slack 历史、查文档、操作项目管理、调日历、访问代码仓库。如果每个都硬编码代码会烂成一团。用 MCP 之后这些工具变成一个个独立的 MCP Servercompany-brain 作为 MCP Client 去连接它们新增工具只需要加一个 Server 配置主逻辑几乎不用动。这里有个工程细节值得展开。MCP 支持多种传输方式常见的是stdio本地进程通信和HTTP/SSE远程通信。在 Cloudflare Workers 环境里stdio 是走不通的因为 Worker 没有本地进程概念。所以 company-brain 大概率用的是基于 HTTP 的 MCP 传输把各个 MCP Server 部署成独立的可访问服务Worker 通过 fetch 去调用。这个选择直接影响了部署复杂度——你得为每个 MCP Server 找地方托管。提示如果你打算复现这套架构MCP Server 的托管位置要提前规划。可以跟主 Worker 放同一个 Cloudflare 账号下用 Service Binding 内网调用省去公网暴露和鉴权麻烦。2.3 事件驱动 主动触发的设计逻辑“主动干活”这四个字落到工程上就是事件驱动架构。company-brain 需要监听几类触发源Slack 的 message 事件、reaction 事件、定时任务Cron Triggers、以及外部系统通过 webhook 推来的事件。每类事件进来后先做轻量判断要不要处理、交给哪个 Agent 处理再决定是同步回一个 ACK 还是丢进异步队列。为什么必须异步因为 AI 推理动辄几秒到几十秒Slack 等不了。标准做法是Worker 收到事件后立刻返回 200同时把任务写进Cloudflare Queues或Durable Objects由消费者慢慢处理处理完再通过 Slack 的 Web API 把结果发回频道。这个“先 ACK 后处理”的模式是 Slack 机器人开发的基本功新手最容易在这里翻车——直接在回调里同步跑 AI结果 Slack 超时重试同一条消息被处理三次。主动触发的另一个关键是状态管理。Agent 要“记得”之前发生过什么才能判断“这件事我是不是已经做过了”。Workers 本身无状态所以状态得外置。轻量的用KV存会话上下文需要强一致的用Durable Objects需要持久化的用D1或外部数据库。company-brain 这种场景我判断大概率是 KV Durable Objects 的组合KV 存长期记忆和配置DO 处理需要串行化的会话状态。3. 核心模块拆解与实操要点3.1 Slack 事件接入层签名验证与快速 ACK接入 Slack 的第一道坎是请求签名验证。Slack 每个请求都带X-Slack-Signature和X-Slack-Request-Timestamp头你必须用 Signing Secret 做 HMAC-SHA256 校验否则任何人都能伪造请求打你的接口。这一步在 Workers 里做很合适因为 Web Crypto API 原生支持不需要额外依赖。验证逻辑的核心是把v0:{timestamp}:{raw_body}拼起来用 Signing Secret 做 HMAC再跟签名头比对。有两个坑必须注意一是必须用原始请求体不能先JSON.parse再stringify否则字节序列变了签名就对不上二是时间戳要校验超过 5 分钟的请求直接拒绝防重放攻击。// Cloudflare Workers 里验证 Slack 签名的核心逻辑 async function verifySlackSignature(request, signingSecret) { const timestamp request.headers.get(X-Slack-Request-Timestamp); const signature request.headers.get(X-Slack-Signature); const body await request.text(); // 拿原始文本不要先 parse // 防重放时间戳超过 5 分钟直接拒 if (Math.abs(Date.now() / 1000 - Number(timestamp)) 300) { return { ok: false, body: null }; } const baseString v0:${timestamp}:${body}; const encoder new TextEncoder(); const key await crypto.subtle.importKey( raw, encoder.encode(signingSecret), { name: HMAC, hash: SHA-256 }, false, [sign] ); const sigBuffer await crypto.subtle.sign(HMAC, key, encoder.encode(baseString)); const computed v0 [...new Uint8Array(sigBuffer)] .map(b b.toString(16).padStart(2, 0)).join(); return { ok: computed signature, body }; }验证通过后立刻返回 200把实际处理逻辑丢给异步。这里有个 Slack 特有的坑如果你在 3 秒内没 ACKSlack 会重试重试请求带X-Slack-Retry-Num头。所以你的处理逻辑必须幂等用事件 ID 去重否则同一个消息会被 AI 处理多次频道里刷出一堆重复回复。3.2 MCP 工具层的挂载与调用MCP 的调用模型是“Client 发起请求 → Server 返回结果”核心方法有tools/list列出可用工具、tools/call调用工具。company-brain 作为 Client启动时要先跟每个 MCP Server 握手拿到工具清单然后把这些工具的描述喂给大模型让模型自己决定调哪个。这里有个非常实用的设计模式工具描述的质量直接决定 AI 调用准确率。我踩过的坑是工具描述写得太简略模型经常选错工具或者传错参数。正确做法是把每个工具的用途、参数含义、返回值格式、使用场景都写清楚甚至给出调用示例。这本质上是在给模型写 prompt值得花时间打磨。// MCP 工具调用的典型请求结构 const mcpRequest { jsonrpc: 2.0, id: crypto.randomUUID(), method: tools/call, params: { name: search_slack_history, arguments: { query: 客户反馈, channel: C01234ABCDE, limit: 50 } } };调用 MCP Server 时要注意超时和降级。远程 MCP Server 可能挂掉或变慢如果 AI 卡在等工具返回整个响应就废了。我的经验是给每个工具调用设 5-10 秒超时超时后返回一个明确的错误信息给模型让模型自己决定是重试、换工具还是告诉用户“暂时查不到”。这比直接抛异常让整个流程崩掉要好得多。3.3 AI 推理层模型选择与上下文管理AI 推理是 company-brain 的大脑也是最烧钱的部分。模型选择上我倾向于分层策略简单意图识别这条消息要不要处理用小模型复杂推理和工具编排用大模型。这样能把成本压下来一大截因为大部分事件其实不需要大模型介入。上下文管理是另一个关键。Slack 频道消息是流式的你不能把整个频道历史都塞给模型token 会爆炸。常见做法是滑动窗口 摘要压缩保留最近 N 条消息的原文更早的历史用摘要代替。company-brain 这种“公司大脑”场景还需要从知识库里检索相关片段RAG拼进上下文让 AI 的回答有依据而不是瞎编。注意RAG 检索出来的片段要控制数量和质量。我见过太多项目一股脑塞十几段文档进去结果模型被无关信息干扰回答反而变差。经验值是 3-5 段最相关的内容每段控制在 500 token 以内。3.4 状态与记忆KV、Durable Objects 怎么分工前面提过 Workers 无状态所以 company-brain 的“记忆”全靠外置存储。我的分工建议是这样的存储类型存什么为什么KV配置、工具清单、长期知识索引读多写少全球低延迟读取Durable Objects会话状态、任务队列、去重记录需要强一致和串行化D1 / 外部 DB结构化数据、审计日志需要复杂查询和持久化Vectorize / 向量库知识库 embedding语义检索Durable Objects 在这里特别关键因为它能保证同一会话的请求串行处理。想象一下同一个频道里两条消息几乎同时到达如果并行处理AI 可能会基于过时的上下文做决策。用 DO 把同一频道的请求排队就能避免这种竞态。4. 完整实操流程从零搭一个最小可用版本4.1 环境准备与项目初始化先把工具链备齐。你需要一个 Cloudflare 账号Workers 免费版够跑 demo、一个 Slack 工作区的管理员权限用来装 App、Node.js 18 和 wrangler CLI。MCP Server 可以先本地跑一个最简单的验证链路通了再扩展。# 初始化 Workers 项目 npm create cloudflarelatest company-brain cd company-brain npm install slack/web-api itty-router # 登录 Cloudflare npx wrangler loginSlack 那边要去 api.slack.com 建一个 App拿到Bot Token和Signing Secret这两个是命根子绝对不能硬编码进代码要用wrangler secret put存成环境变量。权限OAuth Scopes至少需要chat:write、channels:history、app_mentions:read按需再加。4.2 配置 Slack 事件订阅与请求 URL在 Slack App 配置页的 Event Subscriptions 里把 Request URL 填成你的 Worker 地址比如https://company-brain.xxx.workers.dev/slack/events。Slack 会立刻发一个url_verification挑战请求你的 Worker 必须原样返回challenge字段否则验证不通过。// 处理 Slack URL 验证挑战 if (payload.type url_verification) { return new Response(JSON.stringify({ challenge: payload.challenge }), { headers: { Content-Type: application/json } }); }这一步新手最容易卡住因为验证请求也带签名你得先验签再处理。如果一直验证失败先检查 Signing Secret 有没有填错、原始 body 有没有被改动。4.3 接入第一个 MCP 工具并跑通调用先别急着接一堆工具跑通一个再说。我建议从最简单的“读 Slack 频道历史”开始因为它不依赖外部系统。写一个 MCP Server 暴露search_slack_history工具部署成一个独立 Worker然后在主 Worker 里通过 fetch 调用它。验证链路是否通的标志是在 Slack 里 机器人问“最近频道里聊了什么”机器人能调工具、拿到消息、生成摘要、贴回频道。这一条链路跑通后面加工具就是复制粘贴的事。4.4 加入主动触发Cron 与事件监听被动响应跑通后加主动能力。Cloudflare Workers 支持 Cron Triggers在wrangler.toml里配[triggers] crons [0 9 * * 1-5] # 工作日早 9 点触发这个定时任务可以干很多事每天早上汇总昨天的频道动态、检查待办事项、提醒即将到期的任务。主动触发的价值在于它让 AI 从“工具”变成了“同事”——你不用叫它它自己会冒出来说“今天有三件事需要你关注”。5. 常见问题与排查技巧实录5.1 事件重复处理怎么办这是最高频的问题。症状是机器人对同一条消息回复多次。根因通常是 Slack 重试你没在 3 秒内 ACK或者你的异步队列没有去重。解决办法是双重保险一是在 Worker 入口用事件 ID 做幂等检查处理过的直接跳过二是确保 ACK 足够快把重活全丢异步。5.2 MCP 工具调用超时或失败排查顺序是这样的先确认 MCP Server 本身活着直接 curl 它的健康检查端点再确认网络可达Workers 到 Server 的路径最后看是不是工具执行太慢。如果是执行慢考虑给工具加缓存或者把耗时操作也异步化。记住一个原则任何可能超过 10 秒的工具调用都不该在同步链路里等。5.3 AI 回答质量不稳定这个问题最玄学但排查有章法。先看上下文是不是塞太多无关内容再看工具描述是不是太模糊最后看模型选得对不对。我个人的经验是80% 的回答质量问题出在上下文和 prompt而不是模型本身。与其换更贵的模型不如先把检索质量和工具描述打磨好。问题现象可能原因排查动作回复重复未 ACK 或未去重检查响应时间、加事件 ID 幂等工具调错工具描述模糊补全描述和示例回答跑偏上下文污染减少检索片段、提高相关性阈值响应超时同步跑重活改异步队列处理签名失败body 被改动用原始 text 验签5.4 成本失控怎么控AI 项目最容易在成本上翻车。我的控制手段有三个一是分层用模型简单任务别用大模型二是缓存高频结果同样的查询直接返回缓存三是设预算告警Cloudflare 和模型供应商都能设用量上限别等账单来了才发现。实测下来做好这三点成本能压到“随便用”的水平。6. 我踩过的坑和几条实在建议搭这类项目我最大的体会是别一上来就追求功能全先把一条最小链路跑通。我见过太多人一开始就设计复杂的多 Agent 协作、花哨的知识图谱结果连 Slack 签名验证都没过项目就烂尾了。正确的节奏是验证挑战通过 → 被动回复跑通 → 接一个 MCP 工具 → 加异步队列 → 加主动触发 → 最后才考虑多 Agent。另一个坑是过度依赖 AI 自主决策。Agent 再聪明也会犯错尤其是涉及写操作发消息、改数据的时候。我的做法是给所有写操作加一道“确认关”AI 生成操作意图但真正执行前要么让用户确认要么在沙箱里先跑一遍。宁可慢一点也别让 AI 把团队频道刷爆。最后分享一个我觉得特别值的设计给 Agent 加一个“思考日志”频道。它每次决策、每次工具调用、每次失败都往一个私有频道里记一笔。平时没人看但出问题的时候这个日志就是你的黑匣子能快速定位是哪一步出了岔子。这个习惯帮我省了无数排查时间强烈建议你也加上。
阅读完成 · 觉得有帮助?
咨询建站