🐽

Mastraの基本機能と何ができるか

2025/03/19に公開
13

はじめに

TypeScriptでAIエージェントの開発ができると噂のMastraを試してみたくなり、主要機能をざっと調べてみました。

この記事では、エージェントやワークフロー、RAGなどMastraの基本機能を一通り紹介し、「どんなことができるのか」をざっくり掴めるようまとめてみました。より高度な機能や環境構築、デプロイ方法など詳しい設定方法を知りたい方は、公式ドキュメントを参照してみてください。

Mastraとは

Mastraは、AIエージェント、ワークフロー、RAGなどの機能を統合的に提供するTypeScriptフレームワークです。VercelのAI SDKをベースにしており、OpenAI、Anthropic、Google Geminiなど様々なAIプロバイダーとシームレスに連携できます。オープンソースであるため、カスタマイズ性が高く、コミュニティによる継続的な改善が期待できます。

Mastraの主要コンポーネントと機能

以下の主要コンポーネントで構成されています。

エージェント

エージェントは、LLMを活用して特定のタスクを実行する、会話型AIの中核となるコンポーネントです。エージェントは以下の特徴を持ちます。

  • メモリ機能: 会話の文脈を保持し、過去のやり取りを踏まえた応答を生成できます。
  • ツール利用: 外部API(天気情報、検索エンジンなど)を呼び出し、LLMの応答を補完できます。
  • LLMプロバイダー連携: OpenAI、Anthropic、Google Geminiなど、様々なLLMプロバイダーに対応しています。

ユースケース例:

  • カスタマーサポートチャットボット
  • パーソナルアシスタント
  • Eコマースの商品レコメンダー

コード例:

import { Agent } from "@mastra/core/agent";
import { openai } from "@ai-sdk/openai";
import { weatherTool } from "../tools/weather-tool"; // 天気情報取得ツール

export const weatherAgent = new Agent({
  name: "Weather Agent",
  instructions: `あなたは天気情報を提供するアシスタントです。
  ユーザーの質問に対して、正確な天気情報を提供してください。
  場所が指定されていない場合は、場所を尋ねてください。`,
  model: openai("gpt-4o"), // OpenAIのGPT-4oモデルを使用
  tools: {
    weatherTool, // 天気情報取得ツールを追加
  },
});

ワークフロー

ワークフローは、LLM呼び出しやその他の処理を組み合わせ、複雑なタスクを自動化するための機能です。

  • ステップ定義: 個別の処理(LLM呼び出し、関数実行など)をステップとして定義します。
  • 制御フロー: ステップ間の依存関係、条件分岐、並列処理などを定義できます。
  • 状態管理: 各ステップの入出力を記録し、ワークフロー全体の実行状態を追跡できます。

ユースケース例:

  • コンテンツ生成(アイデア出し、記事作成、フォーマット)
  • データ分析(データ収集、前処理、分析、レポート作成)
  • ビジネスプロセス自動化(承認フロー、顧客対応)

コード例:

import { Workflow, step } from "@mastra/core/workflow";
import { openai } from "@ai-sdk/openai";

export const contentCreationWorkflow = new Workflow({
  name: "Content Creation",
  steps: {
    generateIdeas: step({ // アイデア生成ステップ
      execute: async ({ input }) => {
        const response = await openai("gpt-4").generate({
          prompt: `以下のトピックに関するコンテンツのアイデアを5つ生成してください: ${input.topic}`,
        });
        return { ideas: response.text.split("\n") };
      },
    }),
    expandIdea: step({ // アイデア詳細化ステップ
      execute: async ({ input, context }) => {
        const selectedIdea = context.ideas[input.selectedIndex];
        const response = await openai("gpt-4").generate({
          prompt: `以下のアイデアを詳細に展開してください: ${selectedIdea}`,
        });
        return { expandedContent: response.text };
      },
    }).after("generateIdeas"), // generateIdeasステップの後に実行
    formatContent: step({ // コンテンツフォーマットステップ
      execute: async ({ context }) => {
        const response = await openai("gpt-4").generate({
          prompt: `以下の内容をブログ記事形式にフォーマットしてください: ${context.expandedContent}`,
        });
        return { formattedContent: response.text };
      },
    }).after("expandIdea"), // expandIdeaステップの後に実行
  },
});

RAG

RAG(Retrieval-Augmented Generation)機能は、独自のデータソース(ドキュメント、データベースなど)を活用して、LLMの応答をより正確で信頼性の高いものにします。

  • データ処理: ドキュメントをチャンクに分割し、埋め込みベクトルを生成します。
  • ベクトルデータベース: 埋め込みベクトルを保存し、高速な検索を可能にします。
  • LLM連携: 検索結果をLLMの入力として与え、応答を生成します。

ユースケース例:

  • 社内ドキュメント検索
  • 製品FAQシステム
  • 研究論文の要約

コード例:

import { chunk } from "@mastra/core/rag";
import { embed } from "@mastra/core/embeddings";
import { pgvector } from "@mastra/core/vector-stores"; // PostgreSQL + pgvectorを使用

// 文書をチャンクに分割
const chunks = await chunk({
  text: documentText, // ドキュメントのテキスト
  chunkSize: 1000, // チャンクサイズ
  chunkOverlap: 200, // チャンクオーバーラップ
});

// チャンクを埋め込みベクトルに変換
const embeddings = await embed({
  chunks,
  provider: "openai", // OpenAIの埋め込みモデルを使用
});

// ベクトルデータベースに保存
await pgvector.insert({
  embeddings,
  collection: "company_docs", // コレクション名
  metadata: {
    source: "product_manual", // メタデータ
    date: new Date().toISOString(),
  },
});

Voice(音声機能)

ElevenLabs、OpenAI、Google Cloud Text-to-Speechなど、様々な音声プロバイダーをサポートしており、AIエージェントに音声対話機能を追加できます。

ユースケース例:

  • 音声アシスタント
  • 音声対応チャットボット
  • オーディオブック生成

コード例:

import { Agent } from "@mastra/core/agent";
import { openai } from "@ai-sdk/openai";
import { MastraVoice } from "@mastra/core/voice";
import { elevenlabs } from "@mastra/core/voice/providers"; // ElevenLabsを使用

export const voiceAssistant = new Agent({
  name: "Voice Assistant",
  instructions: `あなたは音声アシスタントです。簡潔に回答してください。`,
  model: openai("gpt-4"),
  voice: new MastraVoice({
    provider: elevenlabs({
      apiKey: process.env.ELEVENLABS_API_KEY, // APIキー
    }),
    voiceId: "voice-id-here", // 音声ID
    settings: {
      stability: 0.5,
      similarity_boost: 0.8,
    },
  }),
});

Evals(評価機能)

Mastraの評価機能は、AIモデルの出力(応答)の品質を自動的に評価するためのツールです。毒性、バイアス、関連性、事実の正確性など、様々な観点から評価できます。

ユースケース例:

  • AIモデルの品質管理
  • A/Bテスト
  • 継続的な改善

組み込みの評価指標:

  • 毒性 (Toxicity)
  • バイアス (Bias)
  • 関連性 (Relevance)
  • 事実の正確性 (Factual Accuracy)

コード例:

import { answerRelevancy, toxicity, bias } from "@mastra/core/evals";

// AI応答の品質を評価
const evalResults = await Promise.all([
  // 回答の関連性を評価
  answerRelevancy.evaluate({
    question: "気候変動の主な原因は何ですか?",
    answer: aiResponse,
    context: referenceText,
  }),

  // 毒性を評価
  toxicity.evaluate({
    text: aiResponse,
  }),

  // バイアスを評価
  bias.evaluate({
    text: aiResponse,
  }),
]);

console.log("評価結果:", evalResults);

ストレージ

PostgreSQL、LibSQL、Upstashなど、様々なストレージオプションをサポートしており、エージェントのメモリやワークフローの状態を永続化できます。

ユースケース例:

  • 会話履歴の保存
  • ワークフローの状態保持
  • ユーザー設定の保存

コード例:

import { libsql } from "@mastra/core/storage";

// LibSQLストレージプロバイダーの設定
export const storage = libsql({
  url: process.env.DATABASE_URL,
  authToken: process.env.DATABASE_AUTH_TOKEN,
});

// メモリの保存
export async function saveConversation(threadId: string, messages: any[]) {
  await storage.set(`conversation:${threadId}`, {
    messages,
    updatedAt: new Date().toISOString(),
  });
}

// メモリの取得
export async function getConversation(threadId: string) {
  return await storage.get(`conversation:${threadId}`);
}

// メモリの削除
export async function deleteConversation(threadId: string) {
  await storage.delete(`conversation:${threadId}`);
}

エージェントネットワーク(Experimental)

エージェントネットワーク機能は、複数のエージェントを連携させ、より複雑なタスクを解決できます。エージェント間のメッセージルーティング、階層構造、協調作業などが可能です。
ただし、実験的機能なので今後変更していく可能性も高いです。

ユースケース例:

  • マルチステップの顧客サポート(一般→専門)
  • 異なる専門知識を持つAIの連携
  • 複雑なタスクの分担と統合

コード例:

import { AgentNetwork } from "@mastra/core/networks";
import { customerAgent } from "../agents/customer";
import { techSupportAgent } from "../agents/tech-support";
import { salesAgent } from "../agents/sales";

export const customerServiceNetwork = new AgentNetwork({
  name: "Customer Service Network",
  agents: {
    customer: customerAgent,
    techSupport: techSupportAgent,
    sales: salesAgent,
  },
  routing: {
    // エージェント間のルーティング設定
    default: "customer", // デフォルトはカスタマーエージェントが対応
    rules: [
      {
        // 技術的な質問は技術サポートエージェントに転送
        condition: (message) => message.text.includes("technical") ||
                               message.text.includes("error") ||
                               message.text.includes("problem"),
        target: "techSupport"
      },
      {
        // 購入や価格に関する質問は営業エージェントに転送
        condition: (message) => message.text.includes("purchase") ||
                               message.text.includes("price") ||
                               message.text.includes("subscription"),
        target: "sales"
      }
    ]
  }
});

// ネットワークの使用例
const response = await customerServiceNetwork.generate({
  messages: [
    { role: "user", content: "製品の価格を教えてください" }
  ]
});
// → 自動的に営業エージェントに転送され、回答が生成される

ロギングとトレーシング

MastraはOpenTelemetryと統合されており、AIアプリケーションの実行状況を詳細に追跡できます。これにより、問題の特定、パフォーマンスの改善、デバッグが容易になります。

ユースケース例:

  • エラーの特定と修正
  • パフォーマンスボトルネックの特定
  • ユーザー行動の分析

サポートされている観測性プロバイダー:

  • Signoz
  • Braintrust
  • Langsmith
  • Langfuse
  • Langwatch

コード例:

import { createLogger } from "@mastra/core/observability";
import { braintrust } from "@mastra/core/observability/providers";

// ロガーの作成
export const logger = createLogger({
  providers: [
    braintrust({
      apiKey: process.env.BRAINTRUST_API_KEY,
      projectId: "my-ai-project",
    }),
  ],
});

// AIエージェントでのロギング
export const myAgent = new Agent({
  // エージェント設定
  logger, // ロガーを設定
});

// 手動でのログ記録
logger.info("ユーザーリクエスト受信", { userId: "123", query: "天気について教えて" });
logger.debug("コンテキスト情報", { retrievedDocs: [...] });

フレームワーク統合

Next.js、React、Node.jsなどの既存のプロジェクトに簡単に組み込むことができます。特にNext.jsとの統合が強力で、APIルートとクライアントコンポーネントを使用したAIアプリケーションの構築が容易です。

ユースケース例:

  • Webアプリケーションにチャットボットを追加
  • 既存のCMSにコンテンツ生成機能を追加
  • バックエンドAPIにAI機能を追加

Next.jsとの統合例:

import { weatherAgent } from "@/mastra/agents/weather";
import { NextRequest } from "next/server";

export async function POST(req: NextRequest) {
  const { messages } = await req.json();

  // エージェントを使用して応答を生成
  const response = await weatherAgent.generate({
    messages,
  });

  return Response.json(response);
}
"use client";

import { useState } from "react";
import { Message } from "@mastra/client-js";

export default function ChatPage() {
  const [messages, setMessages] = useState<Message[]>([]);
  const [input, setInput] = useState("");

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    // ユーザーメッセージを追加
    const userMessage = { role: "user", content: input };
    setMessages([...messages, userMessage]);
    setInput("");

    // AIからの応答を取得
    const response = await fetch("/api/chat", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ messages: [...messages, userMessage] }),
    });

    const data = await response.json();

    // AIの応答を追加
    setMessages((prev) => [...prev, data]);
  };

  return (
    <div className="container mx-auto max-w-2xl p-4">
      <div className="bg-gray-100 rounded p-4 h-96 overflow-auto mb-4">
        {messages.map((msg, i) => (
          <div key={i} className={`mb-2 ${msg.role === "user" ? "text-blue-600" : "text-green-600"}`}>
            <strong>{msg.role === "user" ? "You:" : "AI:"}</strong> {msg.content}
          </div>
        ))}
      </div>

      <form onSubmit={handleSubmit} className="flex">
        <input
          type="text"
          value={input}
          onChange={(e) => setInput(e.target.value)}
          className="flex-1 border border-gray-300 rounded-l p-2"
          placeholder="Message..."
        />
        <button
          type="submit"
          className="bg-blue-500 text-white p-2 rounded-r"
        >
          Send
        </button>
      </form>
    </div>
  );
}

Mastraサーバー

Mastraサーバーは、AIエージェント、ワークフロー、RAG機能などをホストするためのバックエンドサービスで、Mastraアプリケーションの中核となる部分です。Honoフレームワークをベースにしており、APIエンドポイントを提供します。

Mastraサーバーの主な特徴:

  • API提供: エージェント、ワークフロー、メモリなどのAPIエンドポイントを提供
  • バックエンド処理: LLM呼び出し、ベクター検索、メモリ管理などの重い処理を担当
  • スケーラビリティ: 水平スケーリングが可能な設計
  • 安全性: APIキー管理、認証、認可機能の提供
  • オブザーバビリティ: ロギング、トレーシング、メトリクス収集の統合

サーバーのセットアップと実行

import { createServer } from "@mastra/server";
import { weatherAgent } from "../agents/weather";
import { contentCreationWorkflow } from "../workflows/content-creation";
import { postgresql } from "@mastra/core/storage";

// サーバーの設定と作成
const server = createServer({
  // 公開するエージェント
  agents: {
    weather: weatherAgent,
  },
  // 公開するワークフロー
  workflows: {
    contentCreation: contentCreationWorkflow,
  },
  // ストレージ設定
  storage: postgresql({
    connectionString: process.env.DATABASE_URL,
  }),
  // CORS設定
  cors: {
    origin: ["https://example.com", "http://localhost:3000"],
    methods: ["GET", "POST"],
  },
  // 認証設定
  auth: {
    apiKey: {
      header: "X-API-Key",
      keys: [process.env.API_KEY],
    },
  },
  // ロギング設定
  logging: {
    level: "info",
    format: "json",
    level: "info",
    format: "json",
  },
});

// サーバーの起動
server.listen({
  port: process.env.PORT || 3000,
}, (err) => {
  if (err) {
    console.error("Failed to start server:", err);
    process.exit(1);
  }
  console.log(`Server is running on port ${process.env.PORT || 3000}`);
});

サーバーのルート構成

Mastraサーバーは自動的に以下のようなAPIエンドポイントを提供します:

/agents/:agentId/generate       # テキスト生成(非ストリーミング)
/agents/:agentId/stream         # テキスト生成(ストリーミング)
/workflows/:workflowId/start    # ワークフロー開始
/workflows/:workflowId/status   # ワークフロー状態確認
/memory/threads                 # スレッド作成・取得
/memory/threads/:threadId       # 特定スレッド操作
/rag/search                     # ベクターストア検索
/health                         # ヘルスチェック

MCP (Mastra Control Plane) ドキュメントサーバー

Mastraには専用のドキュメント管理サーバー(MCP)も含まれており、APIドキュメントの生成、エージェントとの対話テスト、ワークフローのモニタリングなどの機能を提供します。

import { createMCPServer } from "@mastra/mcp";
import { agents } from "./agents";
import { workflows } from "./workflows";

// MCPサーバーの作成
const mcpServer = createMCPServer({
  agents,
  workflows,
  apiDocs: {
    title: "My AI API Documentation",
    description: "APIドキュメントとテストコンソール",
    version: "1.0.0",
  },
  playground: {
    enabled: true, // プレイグラウンドの有効化
  },
  monitoring: {
    enabled: true, // モニタリングの有効化
  },
});

// MCPサーバーの起動
mcpServer.listen({
  port: process.env.MCP_PORT || 3001,
});

MCPサーバーは開発環境でのテストやデバッグに役立つだけでなく、内部開発者ポータルとしても利用でき、チーム内でのAPI利用を促進します。
このようにMastraサーバーコンポーネントは、AIアプリケーションのバックエンドインフラを提供し、フロントエンドとの連携を容易にします。

クライアントSDK(JavaScript/TypeScript)

Mastraはサーバーサイド機能だけでなく、ブラウザやクライアントアプリケーションで使用できるクライアントSDKも提供しています。これにより、フロントエンドから直接Mastraのエージェント、メモリ、ワークフローなどにアクセスできます。

クライアントSDKの主な機能:

  • エージェント操作: クライアント側からエージェントとの対話を管理
  • メモリアクセス: 会話履歴や状態の取得・保存
  • ツール連携: クライアント側で使用可能なツールの提供
  • ワークフロー実行: フロントエンドからワークフローを開始・監視
  • ベクターストア操作: クライアント側からベクターデータへのアクセス
  • ロギング: クライアント側のイベント記録
  • テレメトリ: ユーザー操作の追跡
  • エラーハンドリング: クライアント側でのエラー処理

コード例(React/Next.jsでの使用):

"use client";

import { useState } from "react";
import { MastraClient } from "@mastra/client-js";
import { StreamingText } from "@mastra/client-js/react";

// クライアントの初期化
const mastraClient = new MastraClient({
  baseUrl: "/api/mastra", // APIエンドポイント
});

export function ChatInterface() {
  const [messages, setMessages] = useState([]);
  const [input, setInput] = useState("");
  const [isStreaming, setIsStreaming] = useState(false);

  // エージェントとの対話を処理
  const handleSubmit = async (e) => {
    e.preventDefault();
    if (!input.trim()) return;

    // ユーザーメッセージを追加
    const newUserMessage = { role: "user", content: input };
    const updatedMessages = [...messages, newUserMessage];
    setMessages(updatedMessages);
    setInput("");
    setIsStreaming(true);

    try {
      // エージェントからのストリーミングレスポンスを取得
      const { stream } = await mastraClient.agents.stream({
        agentId: "customer-support",
        messages: updatedMessages,
      });

      // 最終的な応答が完了したら状態を更新
      stream.onComplete((completeResponse) => {
        setMessages([...updatedMessages, completeResponse]);
        setIsStreaming(false);
      });
    } catch (error) {
      console.error("Chat error:", error);
      setIsStreaming(false);
    }
  };

  return (
    <div className="chat-container">
      <div className="messages-container">
        {messages.map((msg, i) => (
          <div key={i} className={`message ${msg.role}`}>
            {msg.content}
          </div>
        ))}

        {isStreaming && (
          <div className="message assistant">
            <StreamingText
              stream={stream}
              loadingText="思考中..."
            />
          </div>
        )}
      </div>

      <form onSubmit={handleSubmit} className="input-form">
        <input
          type="text"
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="メッセージを入力..."
          disabled={isStreaming}
        />
        <button type="submit" disabled={isStreaming}>
          送信
        </button>
      </form>
    </div>
  );
}

クライアントSDKを使用することで、バックエンドとフロントエンドの間でシームレスなAI機能の統合が可能になります。また、ストリーミングレスポンスのサポートにより、LLMの応答をリアルタイムでユーザーに表示できます。

まとめ

本記事では、話題のMastraがどのような機能を持ち、どんなことができるのかをざっくりと紹介しました。
実際に触ってみると、エージェントの作成やワークフローの定義、RAGのセットアップなどが思いのほか直感的に書けるので、すぐにプロトタイプを動かせるのがMastraの強みだと感じました。

次回は実際に何か簡単なものを開発してみようかと思います。

参考リンク

13

Discussion