ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Mastra Slack Agent 模板详解:构建支持流式响应与线程记忆的多 Agent Slack Bot

Mastra Slack Agent 模板详解:构建支持流式响应与线程记忆的多 Agent Slack Bot Mastra Slack Agent 模板详解构建支持流式响应与线程记忆的多 Agent Slack Bot【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra本篇以 template-slack-agent 模板为主体讲解如何在 Mastra 框架中把 AI Agent 接入 Slack包括多 Agent 各自绑定独立 Slack App 与 Webhook 路由的架构、HMAC 签名安全校验、基于消息线程thread的会话记忆以及把 Agent 流式输出逐字渲染到 Slack 消息中的完整实现。读完之后你可以按 Quickstart 直接搭起一个可运行的 Slack Bot 项目并能读懂模板每一处关键源码以完成二次定制。模板要解决的问题将 AI Agent 接入 Slack 是最常见的集成场景之一——无论是内部工具、客服还是团队自动化。这个模板展示了如何用 Mastra 把 Agent 接入 Slack并做对了三件最容易踩坑的事流式响应streamingAgent 生成回答的过程中Slack 消息实时显示“思考中/调用工具中”的动画状态最终替换为完整回复线程级会话记忆thread-based conversation memory同一个 Slack 线程内的对话共享上下文不同线程互不干扰多 Agent 支持每个 Agent 绑定自己独立的 Slack App 与独立的 webhook 路由/slack/{agentName}/events互不串扰。模板内置了两个演示 Agentreverse、caps来演示这套模式你可以随时替换成自己的 Agent 快速上手。模板结构与技术栈模板采用src/mastra/下的单入口组织方式核心文件如下文件职责src/mastra/index.ts创建 Mastra 实例注册 agents、workflows、LibSQL 存储与 Slack 路由src/mastra/slack/routes.tsSlack 事件路由工厂每个 Slack App 一个路由src/mastra/slack/verify.tsSlack 请求签名HMAC-SHA256校验src/mastra/slack/streaming.ts把 Agent 流式输出渲染到 Slack 消息src/mastra/slack/status.ts / constants.ts状态文案与动画帧、计时常量src/mastra/agents/reverse-agent.ts / caps-agent.ts两个演示 Agentsrc/mastra/workflows/reverse-workflow.ts4 步演示工作流package.json 声明了 Node.js22.13.0的运行要求核心依赖为mastra/core、mastra/libsql、mastra/memory与slack/web-api^7.14.1工具与工作流的 schema 使用zod^4.3.6。脚本方面提供devmastra dev、build、start三个命令。前置条件OpenAI API key模板默认使用 OpenAI 模型源码中为openai/gpt-5-mini但换成任意模型即可Slack App每个 Agent 各需要一个独立的 Slack App包含 bot tokenBot User OAuth Tokenxoxb-开头和 signing secretngrok 或类似隧道本地开发时需要一个公网 URL 供 Slack 回调。Quickstart第 1 步克隆模板执行脚手架命令在本地生成项目npx create-mastralatest --template slack-agent第 2 步配置环境变量把.env.example复制为.env并填写密钥。模板提供的 示例文件 结构如下每 Agent 一对 Slack 凭证变量名与 Agent 对应OPENAI_API_KEYyour-api-key # Slack App Configuration (per Agent, replace names with your Agents) # Reverse Agent App SLACK_REVERSE_BOT_TOKENxoxb-... SLACK_REVERSE_SIGNING_SECRET... # Caps Agent App SLACK_CAPS_BOT_TOKENxoxb-... SLACK_CAPS_SIGNING_SECRET...从源码看routes.ts中读取的是SLACK_{NAME}_BOT_TOKEN/SLACK_{NAME}_SIGNING_SECRET形式的变量见 routes.ts#L114-L127。示例文件里还多出一组SLACK_NUMBERS_*变量而当前slackApps配置数组并未引用它们可以视为预留的占位示例新增 Agent 时按同样的命名规则补一对变量即可。第 3 步创建 Slack App每个 Agent 都要在 api.slack.com/apps 上独立创建一套 AppCreate New App → From scratchOAuth Permissions→ 添加 scopesapp_mentions:read、channels:history、chat:write、im:history并把 Bot User OAuth Token 复制进.envEvent Subscriptions→ 开启订阅Request URL 设置为https://your-server.com/slack/{agentName}/events{agentName}对应routes.ts中配置的name字段如reverse、caps订阅 bot eventsapp_mention、message.imAgents AI Apps→ 开启开关Basic Information→ 复制 Signing Secret 到.env。四个 scopes 与源码行为一一对应chat:write用于chat.postMessage/chat.update发送与更新回复channels:history与im:history用于读取频道和私聊消息app_mentions:read用于接收 提及事件。第 4 步启动开发服务器ngrok http 4111拿到公网 URL 后启动 Mastra 开发服务器并访问 http://localhost:4111 试聊npm run dev把 ngrok 得到的公网域名填入第 3 步的 Request URL例如https://xxxx.ngrok-free.app/slack/reverse/eventsSlack 会先发送url_verification挑战请求模板已内置应答逻辑验证通过后事件订阅即生效。工作原理从 Slack 事件到 Agent 响应这一节深入模板源码说明一次 Slack 消息从进入到回复的完整链路。多 App 路由工厂Mastra 实例入口 把 agents、workflows、存储与路由一次性装配好export const mastra new Mastra({ agents: { reverseAgent, capsAgent }, workflows: { reverseWorkflow }, storage: new LibSQLStore({ id: mastra, url: file:./mastra.db, }), server: { apiRoutes: slackRoutes, }, bundler: { externals: [supports-color], }, });slackRoutes来自routes.ts的工厂函数。其核心是一个SlackAppConfig配置数组每个元素声明一个 Slack App 的路由名、凭证与绑定的 Agentinterface SlackAppConfig { name: string; // Route path: /slack/{name}/events botToken: string; signingSecret: string; agentName: string; // Mastra 实例中的 agent 名称 } const slackApps: SlackAppConfig[] [ { name: reverse, botToken: process.env.SLACK_REVERSE_BOT_TOKEN!, signingSecret: process.env.SLACK_REVERSE_SIGNING_SECRET!, agentName: reverseAgent, }, { name: caps, botToken: process.env.SLACK_CAPS_BOT_TOKEN!, signingSecret: process.env.SLACK_CAPS_SIGNING_SECRET!, agentName: capsAgent, }, ]; export const slackRoutes slackApps.map(createSlackEventsRoute);createSlackEventsRoute(config)为每个 App 注册一个POST /slack/{name}/events路由handler 内部的处理顺序是见 routes.ts#L22-L109URL 验证挑战若payload.type url_verification直接回{ challenge: payload.challenge }这是 Slack 开启事件订阅时的握手签名校验取出x-slack-signature与x-slack-request-timestamp两个请求头缺失则 401用verifySlackRequest()校验失败同样 401事件过滤忽略bot_id或带subtype的事件即机器人自己的消息和消息编辑避免自激循环文本预处理只处理app_mention与message事件并用正则/[A-Z0-9]/g剥掉 机器人的提及片段得到用户真正输入的文本异步处理Slack 对事件回调有 3 秒超时而 LLM 生成往往更久因此路由立即返回{ ok: true }真正的 Agent 调用放进一个 fire-and-forget 的异步 IIFE 中执行调用streamToSlack传入 channel、线程时间戳、Agent 名以及两个关键的记忆标识resourceId: slack-${teamId}-${userId}—— 同一工作区同一用户共享资源threadId: slack-${channelId}-${threadTs}—— 记忆按“频道 线程”隔离这正是“线程级会话记忆”的来源。签名校验HMAC-SHA256 时间窗口verify.ts 实现了 Slack 官方的请求签名协议// Reject old requests (more than 5 minutes old) const fiveMinutesAgo Math.floor(Date.now() / 1000) - 60 * 5; if (parseInt(timestamp) fiveMinutesAgo) return false; const sigBasestring v0:${timestamp}:${body}; const mySignature v0 crypto.createHmac(sha256, signingSecret) .update(sigBasestring, utf8).digest(hex); // 长度不一致或类型异常时先短路再走 timingSafeEqual 恒定时间比较 return crypto.timingSafeEqual(Buffer.from(mySignature), Buffer.from(requestSignature));三个要点5 分钟时间戳容差用于防重放签名基串为v0:{timestamp}:{body}比较前先用长度一致性检查短路再使用timingSafeEqual防止时序侧信道。流式渲染动画状态机 fullStream模板最有特色的部分是 streaming.ts 中的streamToSlack()它把 Agent 的流式输出“翻译”成 Slack 里一段不断刷新的状态消息先发一条“思考中”占位消息chat.postMessage到该线程记下返回的ts作为后续更新句柄启动动画定时器每ANIMATION_INTERVAL 300ms帧号 1 并调用chat.update刷新文案文案由 status.ts 的getStatusText()根据当前 chunk 类型生成——工具调用显示“⚙️ Tool Call: Reverse Text...”、工作流步骤显示“ Workflow Step Start: Analyze Text...”之类消费 Agent 流agent.stream(message, { memory: { thread: threadId, resource: resourceId } })拿到fullStream逐 chunk 更新内部状态StreamStatechunk 类型处理逻辑text-delta累加state.texttool-call记录工具名立刻刷新状态消息并停留TOOL_DISPLAY_DELAY300mstool-output工作流事件会被包在 tool-output 里拆出内层workflow-step-start时更新步骤名并停留STEP_DISPLAY_DELAYworkflow-execution-start记录工作流名步骤显示为 “Starting”状态文案的图标与 spinner 帧来自 constants.tsSPINNER是 10 帧 braille 字符⠋ ⠙ ⠹ ...另有TOOL_ICONS、WORKFLOW_ICONS两组图标三个计时常量均为 300ms——想调整“动画手感”只需改这几个常量 4.收尾停止动画定时器把完整state.text通过retrySlackUpdate()写回占位消息。该函数最多重试 3 次、间隔 500ms以应对 Slack 的限流动画期间的chat.update失败则被静默忽略限流属正常现象 5.错误路径任何异常都会把❌ Error: ...写进占位消息若占位消息尚未创建则补发一条然后向上抛出由路由侧记录日志——注释明确说明错误已投递到 Slack路由只需打日志。StreamState与StreamingOptions的接口定义见 types.ts名字美化kebab-case/camelCase → Title Case的formatName与sleep工具在 utils.ts。线程级记忆的落盘会话记忆由三部分拼起来Agent 声明memory: new Memory({ options: { lastMessages: 20 } })即上下文最多保留最近 20 条消息调用agent.stream()时传入thread/resource作为记忆键实例级LibSQLStore({ url: file:./mastra.db })负责把消息、线程元数据持久化到本地 SQLite 文件。从源码结构看resourceId取teamId userId、threadId取channelId threadTs意味着同一个人在同一个 Slack 线程里连续对话会共享上下文换线程或换频道则开启新的记忆线程——这是模板“thread-based conversation memory”承诺的具体实现方式。两个演示 Agent 的实现caps-agent最简单的形态caps-agent.ts 演示了“单工具 记忆”的最小 Agentconst allCapsTool createTool({ id: all-caps, description: Converts text to ALL CAPS, inputSchema: z.object({ text: z.string() }), execute: async ({ text }) text.toUpperCase(), }); export const capsAgent new Agent({ id: caps-agent, name: caps-agent, description: Converts text to ALL CAPS, instructions: You are an enthusiastic caps agent! ..., model: openai/gpt-5-mini, tools: { allCapsTool }, memory: new Memory({ options: { lastMessages: 20 } }), });reverse-agent工具 工作流双能力reverse-agent.ts 同时挂载了一个简单工具reverse-text逐字符反转和一条多步工作流并在instructions中教会模型按用户意图选择简单反转走工具要求“fancy”格式时走工作流。配套的 reverse-workflow.ts 是一个 4 步串行工作流每步都用 zod 声明输入输出 schemaanalyze-text统计字符数/单词数reverse-text执行反转uppercase-text转大写format-output用╔═╗边框排版成带统计信息的装饰块。export const reverseWorkflow createWorkflow({ id: reverse-workflow, inputSchema: z.object({ text: z.string() }), outputSchema: z.object({ result: z.string() }), }) .then(analyzeStep) .then(reverseStep) .then(uppercaseStep) .then(formatStep) .commit();两个 Agent 的instructions里都有一条值得注意的提示工程细节“只把用户当前消息里的文本传给工具/工作流不要带上历史对话”。因为线程记忆会让模型拿到完整上下文若不显式约束它可能把历史消息里的文本也一并反转。把它变成你自己的模板的 README 给出了四个延伸方向对应到源码就是换掉演示 Agent新建自己的 Agent 并注册进 index.ts 的agents对象然后在 routes.ts 的slackApps数组里加一条配置name、环境变量、agentName同时在.env补上对应的SLACK_{NAME}_BOT_TOKEN/SLACK_{NAME}_SIGNING_SECRET最后在 Slack 后台再建一个 App 指向新的/slack/{name}/events路由加工具与工作流像 reverse-agent 那样给 Agent 挂tools/workflows让 Agent 在 Slack 里触发 API 调用、数据库操作或多步流程——工作流执行时状态消息会自动显示当前步骤名见 streaming.ts 对workflow-step-start的处理定制流式行为动画帧、图标、300ms 计时常量集中在 constants.ts状态文案模板在 status.ts重试策略在 streaming.ts 的retrySlackUpdate上生产去掉 ngrok部署到带 TLS 的公网 URL并在 Slack 后台把 Request URL 换掉即可。关于 Mastra 模板Mastra 模板是仓库内置的“即取即用”参考工程展示一个可跑的集成模式克隆下来拆开看、改成自己的即可。它们统一放在本仓库的templates/目录下本模板位于 templates/template-slack-agent与 monorepo 内其他包共享依赖版本。想理解更多实现细节可直接从 templates/template-slack-agent/src/mastra/index.ts 入口顺着 import 一路读下去模板的协作约定见 CONTRIBUTING.md。【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表