Skip to main content

WhatsApp 聊天机器人

🌐 WhatsApp Chat Bot

本指南演示了如何使用 Mastra 代理和工作流程创建 WhatsApp 聊天机器人。该机器人通过 webhook 接收传入的 WhatsApp 消息,通过 AI 代理处理这些消息,将回复拆分为自然文本消息,然后通过 WhatsApp 商业 API 发送回去。

🌐 This guide demonstrates how to create a WhatsApp chat bot using Mastra agents and workflows. The bot receives incoming WhatsApp messages via webhook, processes them through an AI agent, breaks responses into natural text messages, and sends them back via the WhatsApp Business API.

先决条件
Direct link to 先决条件

🌐 Prerequisites

此示例需要 WhatsApp Business API 设置,并使用 anthropic 模型。将这些环境变量添加到你的 .env 文件中:

🌐 This example requires a WhatsApp Business API setup and uses the anthropic model. Add these environment variables to your .env file:

.env
ANTHROPIC_API_KEY=<your-anthropic-api-key>
WHATSAPP_VERIFY_TOKEN=<your-verify-token>
WHATSAPP_ACCESS_TOKEN=<your-whatsapp-access-token>
WHATSAPP_BUSINESS_PHONE_NUMBER_ID=<your-phone-number-id>
WHATSAPP_API_VERSION=v22.0

创建 WhatsApp 客户端
Direct link to 创建 WhatsApp 客户端

🌐 Creating the WhatsApp client

该客户端负责通过 WhatsApp 商业 API 向用户发送消息。

🌐 This client handles sending messages to users via the WhatsApp Business API.

src/whatsapp-client.ts
// Simple WhatsApp Business API client for sending messages

interface SendMessageParams {
to: string;
message: string;
}

export async function sendWhatsAppMessage({ to, message }: SendMessageParams) {
// Get environment variables for WhatsApp API
const apiVersion = process.env.WHATSAPP_API_VERSION || "v22.0";
const phoneNumberId = process.env.WHATSAPP_BUSINESS_PHONE_NUMBER_ID;
const accessToken = process.env.WHATSAPP_ACCESS_TOKEN;

// Check if required environment variables are set
if (!phoneNumberId || !accessToken) {
return false;
}

// WhatsApp Business API endpoint
const url = `https://graph.facebook.com/${apiVersion}/${phoneNumberId}/messages`;

// Message payload following WhatsApp API format
const payload = {
messaging_product: "whatsapp",
recipient_type: "individual",
to: to,
type: "text",
text: {
body: message,
},
};

try {
// Send message via WhatsApp Business API
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify(payload),
});

const result = await response.json();

if (response.ok) {
console.log(`✅ WhatsApp message sent to ${to}: "${message}"`);
return true;
} else {
console.error("❌ Failed to send WhatsApp message:", result);
return false;
}
} catch (error) {
console.error("❌ Error sending WhatsApp message:", error);
return false;
}
}

创建聊天代理
Direct link to 创建聊天代理

🌐 Creating the chat agent

该代理负责主要的对话逻辑,具有友好、会话式的个性。

🌐 This agent handles the main conversation logic with a friendly, conversational personality.

src/mastra/agents/chat-agent.ts
import { Agent } from "@mastra/core/agent";
import { Memory } from "@mastra/memory";
import { LibSQLStore } from "@mastra/libsql";

export const chatAgent = new Agent({
id: "chat-agent",
name: "Chat Agent",
instructions: `
You are a helpful, friendly, and knowledgeable AI assistant that loves to chat with users via WhatsApp.

Your personality:
- Warm, approachable, and conversational
- Enthusiastic about helping with any topic
- Use a casual, friendly tone like you're chatting with a friend
- Be concise but informative
- Show genuine interest in the user's questions

Your capabilities:
- Answer questions on a wide variety of topics
- Provide helpful advice and suggestions
- Engage in casual conversation
- Help with problem-solving and creative tasks
- Explain complex topics in simple terms

Guidelines:
- Keep responses informative but not overwhelming
- Ask follow-up questions when appropriate
- Be encouraging and positive
- If you don't know something, admit it honestly
- Adapt your communication style to match the user's tone
- Remember this is WhatsApp, so keep it conversational and natural

Always aim to be helpful while maintaining a friendly, approachable conversation style.
`,
model: "anthropic/claude-4-sonnet-20250514",
memory: new Memory({
storage: new LibSQLStore({
id: 'agent-storage',
url: "file:../mastra.db",
}),
}),
});

创建短信代理
Direct link to 创建短信代理

🌐 Creating the text message agent

该代理将较长的回复转换为适合 WhatsApp 的自然、简短文本消息。

🌐 This agent converts longer responses into natural, bite-sized text messages suitable for WhatsApp.

src/mastra/agents/text-message-agent.ts
import { Agent } from "@mastra/core/agent";
import { Memory } from "@mastra/memory";
import { LibSQLStore } from "@mastra/libsql";

export const textMessageAgent = new Agent({
id: "text-message-agent",
name: "Text Message Agent",
instructions: `
You are a text message converter that takes formal or lengthy text and breaks it down into natural, casual text messages.

Your job is to:
- Convert any input text into 5-8 short, casual text messages
- Each message should be 1-2 sentences maximum
- Use natural, friendly texting language (contractions, casual tone)
- Maintain all the important information from the original text
- Make it feel like you're texting a friend
- Use appropriate emojis sparingly to add personality
- Keep the conversational flow logical and easy to follow

Think of it like you're explaining something exciting to a friend via text - break it into bite-sized, engaging messages that don't overwhelm them with a long paragraph.

Always return exactly 5-8 messages in the messages array.
`,
model: "anthropic/claude-4-sonnet-20250514",
memory: new Memory({
storage: new LibSQLStore({
id: 'agent-storage',
url: "file:../mastra.db",
}),
}),
});

创建聊天工作流程
Direct link to 创建聊天工作流程

🌐 Creating the chat workflow

此工作流程协调整个聊天过程:生成回应,将其分解为消息,并通过 WhatsApp 发送。

🌐 This workflow orchestrates the entire chat process: generating a response, breaking it into messages, and sending them via WhatsApp.

src/mastra/workflows/chat-workflow.ts
import { createStep, createWorkflow } from "@mastra/core/workflows";
import { z } from "zod";
import { sendWhatsAppMessage } from "../../whatsapp-client";

const respondToMessage = createStep({
id: "respond-to-message",
description: "Generate response to user message",
inputSchema: z.object({ userMessage: z.string() }),
outputSchema: z.object({ response: z.string() }),
execute: async ({ inputData, mastra }) => {
const agent = mastra?.getAgent("chatAgent");
if (!agent) {
throw new Error("Chat agent not found");
}

const response = await agent.generate([
{ role: "user", content: inputData.userMessage },
]);

return { response: response.text };
},
});

const breakIntoMessages = createStep({
id: "break-into-messages",
description: "Breaks response into text messages",
inputSchema: z.object({ prompt: z.string() }),
outputSchema: z.object({ messages: z.array(z.string()) }),
execute: async ({ inputData, mastra }) => {
const agent = mastra?.getAgent("textMessageAgent");
if (!agent) {
throw new Error("Text Message agent not found");
}

const response = await agent.generate(
[{ role: "user", content: inputData.prompt }],
{
structuredOutput: {
schema: z.object({
messages: z.array(z.string()),
}),
},
},
);

if (!response.object) throw new Error("Error generating messages");

return response.object;
},
});

const sendMessages = createStep({
id: "send-messages",
description: "Sends text messages via WhatsApp",
inputSchema: z.object({
messages: z.array(z.string()),
userPhone: z.string(),
}),
outputSchema: z.object({ sentCount: z.number() }),
execute: async ({ inputData }) => {
const { messages, userPhone } = inputData;

console.log(
`\n🔥 Sending ${messages.length} WhatsApp messages to ${userPhone}...`,
);

let sentCount = 0;

// Send each message with a small delay for natural flow
for (let i = 0; i < messages.length; i++) {
const success = await sendWhatsAppMessage({
to: userPhone,
message: messages[i],
});

if (success) {
sentCount++;
}

// Add delay between messages for natural texting rhythm
if (i < messages.length - 1) {
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}

console.log(
`\n✅ Successfully sent ${sentCount}/${messages.length} WhatsApp messages\n`,
);

return { sentCount };
},
});

export const chatWorkflow = createWorkflow({
id: "chat-workflow",
inputSchema: z.object({ userMessage: z.string() }),
outputSchema: z.object({ sentCount: z.number() }),
})
.then(respondToMessage)
.map(async ({ inputData }) => ({
prompt: `Break this AI response into 3-8 casual, friendly text messages that feel natural for WhatsApp conversation:\n\n${inputData.response}`,
}))
.then(breakIntoMessages)
.map(async ({ inputData, getInitData }) => {
// Parse the original stringified input to get user phone
const initData = getInitData<typeof chatWorkflow>();
const webhookData = JSON.parse(initData.userMessage);
const userPhone =
webhookData.entry?.[0]?.changes?.[0]?.value?.messages?.[0]?.from ||
"unknown";

return {
messages: inputData.messages,
userPhone,
};
})
.then(sendMessages);

chatWorkflow.commit();

设置 Mastra 配置
Direct link to 设置 Mastra 配置

🌐 Setting up Mastra configuration

使用代理、工作流和 WhatsApp 网关端点配置你的 Mastra 实例。

🌐 Configure your Mastra instance with the agents, workflow, and WhatsApp webhook endpoints.

src/mastra/index.ts
import { Mastra } from "@mastra/core";
import { registerApiRoute } from "@mastra/core/server";
import { PinoLogger } from "@mastra/loggers";
import { LibSQLStore } from "@mastra/libsql";

import { chatWorkflow } from "./workflows/chat-workflow";
import { textMessageAgent } from "./agents/text-message-agent";
import { chatAgent } from "./agents/chat-agent";

export const mastra = new Mastra({
workflows: { chatWorkflow },
agents: { textMessageAgent, chatAgent },
storage: new LibSQLStore({
id: 'agent-storage',
url: ":memory:",
}),
logger: new PinoLogger({
name: "Mastra",
level: "info",
}),
server: {
apiRoutes: [
registerApiRoute("/whatsapp", {
method: "GET",
handler: async (c) => {
const verifyToken = process.env.WHATSAPP_VERIFY_TOKEN;
const {
"hub.mode": mode,
"hub.challenge": challenge,
"hub.verify_token": token,
} = c.req.query();

if (mode === "subscribe" && token === verifyToken) {
return c.text(challenge, 200);
} else {
return c.status(403);
}
},
}),
registerApiRoute("/whatsapp", {
method: "POST",
handler: async (c) => {
const mastra = c.get("mastra");
const chatWorkflow = mastra.getWorkflow("chatWorkflow");

const body = await c.req.json();

const workflowRun = await chatWorkflow.createRun();
const runResult = await workflowRun.start({
inputData: { userMessage: JSON.stringify(body) },
});

return c.json(runResult);
},
}),
],
},
});

测试聊天机器人
Direct link to 测试聊天机器人

🌐 Testing the chat bot

你可以通过模拟 WhatsApp webhook 负载在本地测试聊天机器人。

🌐 You can test the chat bot locally by simulating a WhatsApp webhook payload.

src/test-whatsapp-bot.ts
import "dotenv/config";

import { mastra } from "./mastra";

// Simulate a WhatsApp webhook payload
const mockWebhookData = {
entry: [
{
changes: [
{
value: {
messages: [
{
from: "1234567890", // Test phone number
text: {
body: "Hello! How are you today?",
},
},
],
},
},
],
},
],
};

const workflow = mastra.getWorkflow("chatWorkflow");
const workflowRun = await workflow.createRun();

const result = await workflowRun.start({
inputData: { userMessage: JSON.stringify(mockWebhookData) },
});

console.log("Workflow completed:", result);

示例输出
Direct link to 示例输出

🌐 Example output

当用户向你的 WhatsApp 机器人发送“你好!你今天怎么样?”时,它可能会回复多条消息,例如:

🌐 When a user sends "Hello! How are you today?" to your WhatsApp bot, it might respond with multiple messages like:

Hey there! 👋 I'm doing great, thanks for asking!

How's your day going so far?

I'm here and ready to chat about whatever's on your mind

Whether you need help with something or just want to talk, I'm all ears! 😊

What's new with you?

该机器人通过内存保持对话上下文,并提供适合 WhatsApp 消息风格的自然回应。

🌐 The bot maintains conversation context through memory and delivers responses that feel natural for WhatsApp messaging.