はじめに
AIエバンジェリストの浅田です。
AIエージェント、話題ですよね。様々な企業がAIエージェントの発表をするとともに、AIエージェントを作成するためのツールも色々出てきています。
そんなツールの一つにMastraというTypeScript製のオープンソースフレームワークがあります。現時点で、同時期に出たOpenAIのAgentsSDKや、先発のLangChainのAgent構築フレームワークであるLangGraphよりもGitHubのスター数が多く、その注目されぶりが伺えます。
そこで、今回はMastraのコードを見ながらAIエージェントを実装する際の構成要素について書いてみたいと思います。
準備
まず、インストールします。公式の手順に従いインストールしますが、npmが使える環境であれば、以下のコマンドでインストールできます。
npm create mastra@latest
そうするといくつか質問されます。
- What do you want to name your project?
- 任意の名前をつけます
- Where should we create the Mastra files? (default: src/)
- デフォルトのままにします
- Choose components to install:
- Agents, Workflowsの選択肢が出るので、両方にチェック(スペースキーでチェックできます)を入れてEnterを押すと、
Add tools?
と質問されるので「Yes」を選択します
- Agents, Workflowsの選択肢が出るので、両方にチェック(スペースキーでチェックできます)を入れてEnterを押すと、
- Select default provider:
- AIのプロバイダーの選択肢はデフォルトのままOpenAIを選択し、
Enter your openai API key?
と聞かれるので、Skip for Now(default)を選択します。
- AIのプロバイダーの選択肢はデフォルトのままOpenAIを選択し、
- Add example
- 「Yes」を選択します
- Make your AI IDE into a Mastra expert? (installs Mastra docs MCP server)
- Skip for now (default)を選択します
上記が完了すると、最初に決めたproject名のディレクトリが作成され、その中に.env.development
というファイルがあります。このファイルを開くと
OPENAI_API_KEY=your-api-key
となっているので、your-api-keyを自分のOpenAIのAPIキーに修正します。
これで準備完了です。
起動
インストール時に出力されるメッセージにも書かれていますが、以下のコマンドでMastraプロジェクトを起動できます。
npm run dev
Mastraは、デフォルトで二つのインターフェースを持っています。
- API(別のツールから呼び出すためのエンドポイント)
- Playground(定義したエージェントの挙動を確認できるブラウザ上のGUI)
http://localhost:4111/ にアクセスすることで、Playgroundにアクセスできます。以下のような画面が表示されれば起動成功です。


画面上の「Weather Agent」をクリックし、「Write a message…」と書かれているところに「渋谷の天気を知りたい」と入れて送信すると、現時点(2025/3/31の午後6時)だと以下のような結果が返ってきます。後で説明しますが、これはopen-meteo.comという緯度経度から現在の天気を教えてくれるAPIの結果をもとに出力されています。
Shibuya's current weather is overcast with a temperature of 7.6°C, but it feels like 4.5°C due to the wind. The humidity is at 76%, and there is a wind speed of 11.3 km/h with gusts up to 29.9 km/h.
Agent
AIエージェントのフレームワークであるMastraの中心となる構成要素はAgentです。MastraのExampleにおけるAgentはsrc/mastra/agents/index.ts
に記載されています。
export const weatherAgent = new Agent({
name: 'Weather Agent',
instructions: `
You are a helpful weather assistant that provides accurate weather information.
Your primary function is to help users get weather details for specific locations. When responding:
- Always ask for a location if none is provided
- If the location name isn’t in English, please translate it
- If giving a location with multiple parts (e.g. "New York, NY"), use the most relevant part (e.g. "New York")
- Include relevant details like humidity, wind conditions, and precipitation
- Keep responses concise but informative
Use the weatherTool to fetch current weather data.
`,
model: openai('gpt-4o'),
tools: { weatherTool },
});
ここからWeather Agentについて以下のことがわかります。
- instructionsで天気情報を提供することを命じられている
- modelでopenaiの”gpt-4o”のAIモデル(LLM)を使用するように設定されている
- toolsでweatherToolが指定されている
instructionsはそのAgentの基本動作を規定します。これをもとにAIモデル(openAIのgpt-4o)は何をユーザから聞き出し、何を実行し、何をユーザに提供するかをの指針を得ることができます。今回の例であれば天気を調べるにあたり必要な情報(location)を理解します。そして、天気の情報を得るために、weatherToolというツールを使えること、およびユーザに提供する情報に含めるべきこと(wind conditionsなども含める)や、形式(concise but informative)について理解します。
さて、もし同じことをLLMを使わずにやろうとするとどうなるでしょうか。
- ユーザの発話が天気に関することかどうかを判定する
- 発話に天気関連のキーワード、例えば「天気」が入っているかどうかを判定する
- 発話が天気に関するものではない場合には、最初の処理に戻る
- ユーザの発話の中にlocationに関する情報があるかを判定する
- locationの情報がなければユーザに質問し、判定の処理に戻る
- locationが与えられた場合に、情報が英語かどうかを判定する
- 英語でなければ、locationを英語に翻訳する
- 天気情報(weatherTool)の出力をパースし、目的の出力形式に整形して、ユーザに提示する
上記のようにユーザに天気の情報を提供する状態にたどり着くまでに多くの処理が発生することがわかります。上記の例であればユーザの発話を判定する際に「天気」というキーワードが入っていたとしても「脳天気な性格だね」や「天気以外のことを話そう」などといったパターンを処理しようと考えると気が滅入ってきます。
一方、LLMを利用することで、先述のinstructionsを定義するだけで、それらのことが処理できるようになります。これだけでもLLMが利用できることによるメリットが感じられます。
- ユーザが求めるタスクを判定する
- ユーザからタスクに必要な情報を引き出す
- ユーザにタスク実行の結果をわかりやすく提示する
といったことをAIを用いて処理するのがAIエージェントにおけるLLMの果たす第一の役割になるかとおもいます。
Tool
AIエージェントの定義はまだ定まりきっていないかと思いますが、少なくとも以下のような特徴があるかとおもいます。
- ユーザの代わりにタスクを自律的に実行する
「ユーザの代わりに」ということは、ユーザがやろうとしていたことをAI側で代行する必要があります。ですが、AIモデル(LLM)ができることは、基本的には与えられたテキストデータや画像データを入力して、テキストデータを生成することです。外部のデータを入力として取りにいくこともできなければ、結果をファイルとして保存することもできません。
そこでTool
という概念が登場します。
Toolは簡単にいえば、LLMと連携させることを前提にした関数です。簡単に動作を説明すると、プログラムが関数の情報をLLMに渡して、タスクを実行する際に必要であればLLMに「タスク実行のためにこの関数をこの引数で呼び出して、その結果ください!」と出力させます。そして、その出力情報に応じてプログラム側で関数を実行し、その結果をLLMに戻すことで、LLMは情報を得たり、外部へのアクションを起こします。
先ほどのweatherToolは、src/mastra/tools/index.ts
に定義されています。getWeatherは与えられたlocationの情報をもとに、open-meteoのAPIを使って、緯度経度を算出し、その緯度経度の天気情報を取得する関数となっています。
export const weatherTool = createTool({
id: 'get-weather',
description: 'Get current weather for a location',
inputSchema: z.object({
location: z.string().describe('City name'),
}),
outputSchema: z.object({
temperature: z.number(),
feelsLike: z.number(),
humidity: z.number(),
windSpeed: z.number(),
windGust: z.number(),
conditions: z.string(),
location: z.string(),
}),
execute: async ({ context }) => {
return await getWeather(context.location);
},
});
このToolが求める入力情報と、出力情報のスキーマ(構造)、および実行する関数が定義されています。
これによって、LLMは「天気を調べる」というユーザのタスクにおける「特定のlocationの天気情報を調べる」というタスクを代行することができるようになります。
さらに、Toolは複数指定することができます。つまり、今回のケースであれば天気情報を取得するというweatherTool一個ですが、別にメールを送信するためのToolを定義し、与えることができます。
export const sendMailTool = createTool({
id: 'send-email',
description: 'Send result mail.',
inputSchema: z.object({
mailAddress: z.string().describe('MailAddress'),
}),
outputSchema: z.object({
status: z.string(),
}),
execute: async ({ context }) => {
return await sendMail(context.mailAddress);
},
});
上記のようなToolを追加し、weatherAgentのtoolsに与えることで、weatherAgentにメール送信の能力を与えることができるようになります。
それによって、「ロンドンの天気を調べて、 example@example.com に送信しておいて」といったユーザの発話によって天気調査とメール送信といったタスクを実行できるようになります。
また、「ロンドンの天気を調べて」とだけ言われた時にはメールを送らず、上記のようにメール送信の依頼があった時にメールを送るようになります。
このように、if文などの制御文を挟まずに複数のToolと目的を与えることでAgentが自律的
にタスクに必要な処理を判断し、実行してくれるようにフローをシンプルに組めるのがAgent機能の強力な点だと言えます。
Workflow
一方で、ユースケースによっては、必ず実行したいタスクの組み合わせもあるでしょう。ユーザの特定の発話に限らずセットで実行したい処理などです。先ほどの例であれば、AIの判断によらずメール送信を必ずセットで行いたい場合などです。
もちろん、weatherToolの処理の最後にメールを送信することも考えられますが、そのような場合に、Mastraで利用できる仕組みにWorkflowがあります。これは名前のごとしですが、規定の順番で決められた処理を実行するワークフローをつくるための機能です。
例えば、MastraのExampleコードでは、src/mastra/workflows/index.ts
に、以下のようなWorkflowが定義されています。
const weatherWorkflow = new Workflow({
name: 'weather-workflow',
triggerSchema: z.object({
city: z.string().describe('The city to get the weather for'),
}),
})
.step(fetchWeather)
.then(planActivities);
weatherWorkflow.commit();
fetchWeather
はweatherToolと同じように、open-meteoのAPIで天気情報を取得する処理、planActivities
は、fetchWeatherによって取得された天気情報から、LLMに活動予定計画を生成させる処理になります。
このように、Workflowを利用することで、より構造的にタスクの流れを定義できます。失敗時のエラーハンドリングや回数実行の制御など一般的なワークフローを制御するための仕組みもあるので、Mastra単体でタスク実行のワークフローを組めるのはメリットだと言えるでしょう。ただし、このようなことは、普通のワークフローツールでもできるので、Mastraじゃなくても(というよりAIエージェントじゃなくても)可能です。
では、MastraのWorkflowを使うと嬉しい点はなんなのか。それは、ワークフローの各ステップにおける処理でAgentを指定できるので、Agentの処理結果による分岐をシームレスに定義できることだと思います。
たとえば、「直近の業界ニュースを取得」し、「特定の業界に深刻な影響を与えるか判定」した上で、「影響ありの場合に通知する」といったワークフローを組みたい場合に、ネックとなるのは「深刻な影響を与えるかどうかの判定」をどう実現するかになります。その一つの解は、(どのような指標を基準とするか、instructionsの工夫は必要ですが)Agent(のLLM)に判定させるという方法です。
そのようなケースにおいて、Agentをワークフローにシームレスに結合し、Agentの判定結果によって処理フローを構築できるWorkflowは便利かとおもいます。
Agent Network(Experimental)
Workflowを使うことによっても、複数のAgentを組み合わせてタスク実行を行うことができますが、Mastraには複数のエージェントを共同させるための仕組みがもう一つ用意されています。
それがAgentNetworkという仕組みです。これは複数のAgentの集まりに対して、「RoutingAgentと呼ばれる制御用のAgentが、求められたタスクに応じて仕事を動的に割り振っていく」という仕組みです。
import { AgentNetwork } from '@mastra/core';
import { openai } from '@mastra/openai';
// Create specialized agents
const webSearchAgent = new Agent({
name: 'Web Search Agent',
instructions: 'You search the web for information.',
model: openai('gpt-4o'),
tools: { /* web search tools */ },
});
const dataAnalysisAgent = new Agent({
name: 'Data Analysis Agent',
instructions: 'You analyze data and provide insights.',
model: openai('gpt-4o'),
tools: { /* data analysis tools */ },
});
// Create the network
const researchNetwork = new AgentNetwork({
name: 'Research Network',
instructions: 'Coordinate specialized agents to research topics thoroughly.',
model: openai('gpt-4o'),
agents: [webSearchAgent, dataAnalysisAgent],
});
// Use the network
const result = await researchNetwork.generate('Research the impact of climate change on agriculture');
console.log(result.text);
上記はMastraの公式のサンプルですがこのように、複数のAgentをAgentNetworkに集めて、’Research the impact of climate change on agriculture’というプロンプトから適切なAgentを自律的に選択しながら、気候変動の農業の影響を調査するタスクを実行します。
このような仕組みはマルチエージェントシステムと呼ばれます。それぞれのAgentを専門化させて、それを適宜使い分けてタスク達成を目指すという流れです。ここで次のように思われた方もいるかと思います。Agentに色々なツール、例えば上記の例で言えば、webから情報を取得するToolとデータを分析するToolを搭載するのではだめなのでしょうか。
上記の例でいえば問題になることはないと思います。マルチエージェントシステムが必要になってくるのは、より大規模で複雑なタスクをAIエージェントシステムで実行する状態になった時だと思います。
Agentにおける利用に限らず、LLMに渡すテキストが巨大になればなるほど、その解釈の精度が悪くなっていきます。また、外部APIを利用している際には、LLMに与えるテキスト情報が長ければ長いほどコストがかかってくることにもなります。ローカルでLLMをホストしている場合でもCPU、メモリ、ネットワークといったリソースをより多く消費することになります。
つまりAgentにおけるinstructionsやToolの役割などの定義情報が巨大になっていけばいくほど、Agentとしてのタスク処理の精度やコストの面で不利になっていきます。そこで各Agentをより専門化し、それらを連携させることでなるべく効率的に実行させる仕組みがマルチエージェントシステムとなります。
終わりに
Mastraを構成する代表的な要素について紹介してきました。
- Agent
- Tool
- Workflow
- AgentNetwork
これらの要素は他のAIエージェントフレームワーク、例えばLangGraphや、AgentsSDKでも似たような要素が存在します。それはAIエージェントの本質がそこに凝縮されているからだと思います。
- Agentに何をサポートさせるかを定義し、適切なinstructionsを与えること
- Agentがタスクを実行するのに必要なTool(外部処理)を適切に用意し使い分けさせること
- Workflowを組んで目的の処理を構成する要素を適切に定義すること
- 適切に専門化させたAgentを用意し、それらをうまく協調させること
「適切」という言葉を連発していますが、AIエージェントシステムの肝は上記の要素を如何に適切に調整していけるかだと思います。
以上、参考になれば幸いです。
浅田大輔
クラウドサービスソリューション学部・AIエバンジェリスト。
認定ホワイトハッカー。映画・歴史好き。
座右の銘は「酒は人類の友だぞ。友人を見捨てられるか」。