> Discover all available pages from the documentation index: https://mastra.zisheng.pro/ja/llms.txt # WhatsApp chat bot このガイドでは、Mastra の Agent と Workflow を使用して WhatsApp chat bot を作成する方法を説明します。bot は webhook を介して WhatsApp メッセージを受信し、AI Agent で処理します。応答を自然なテキストメッセージに分割し、WhatsApp Business API を介して送信元に返します。 ## 前提条件 この例では WhatsApp Business API のセットアップが必要で、`anthropic` モデルを使用します。次の環境変数を `.env` ファイルに追加します。 ```bash ANTHROPIC_API_KEY= WHATSAPP_VERIFY_TOKEN= WHATSAPP_ACCESS_TOKEN= WHATSAPP_BUSINESS_PHONE_NUMBER_ID= WHATSAPP_API_VERSION=v22.0 ``` ## WhatsApp クライアントの作成 このクライアントは WhatsApp Business API を介してユーザーにメッセージを送信します。 ```typescript // 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 } } ``` ## Chat Agent の作成 この Agent は、親しみやすく会話的な personality で、会話の主要なロジックを処理します。 ```typescript 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: 'openai/gpt-5.6-sol', memory: new Memory({ storage: new LibSQLStore({ id: 'agent-storage', url: 'file:../mastra.db', }), }), }) ``` ## Text Message Agent の作成 この Agent は長い応答を、WhatsApp に適した自然で短いテキストメッセージに変換します。 ```typescript 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: 'openai/gpt-5.6-sol', memory: new Memory({ storage: new LibSQLStore({ id: 'agent-storage', url: 'file:../mastra.db', }), }), }) ``` ## Chat Workflow の作成 この Workflow は、応答の生成、メッセージへの分割、WhatsApp での送信という chat 処理全体を指揮します。 ```typescript 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() 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 設定のセットアップ Agent、Workflow、WhatsApp webhook エンドポイントを使用して Mastra インスタンスを設定します。 ```typescript 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) }, }), ], }, }) ``` ## Chat bot のテスト WhatsApp webhook payload をシミュレートして、chat bot をローカルでテストできます。 ```typescript 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) ``` ## 出力例 ユーザーが WhatsApp bot に「Hello! How are you today?」と送信すると、次のように複数のメッセージで応答することがあります。 ```text 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? ``` bot は Memory によって会話のコンテキストを維持し、WhatsApp でのやり取りとして自然に感じられる応答を送信します。