0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

マルチエージェント化するときのtoolsとサブエージェントについて整理する

0
Last updated at Posted at 2026-06-26

Mastraを使って実務でエージェントを作成するとき、toolsとサブエージェントの使い分けに改めて疑問を持ったので備忘録です。

  • ToolSub-agent は何が違うか
  • 「オーケストレーター -> サブエージェント -> Toolでデータ取得」だけで十分では?
  • なのに、なぜ Tool の中でさらに Agent を呼ぶ設計があるのか?

などです。

先に結論

まず、次の3行で判断できます。

  1. 「説明文」を返したいなら Sub-agent
    例: 「この市場の売上変化を考察して」
  2. 「固定JSON」を返したいなら Tool
    例: 「この条件でExcel出力したい」
  3. 「自然文を解釈する推論」は必要だが「返却は固定JSON」にしたいなら Tool の中で Agent を呼ぶ。
    例: 自然文の抽出依頼を、{ market, categoryId, fromYm, toYm } に変換して返す

もう少し短く言うと次のようにもいえます。

  • Sub-agent: 考える役(自然文に強い)
  • Tool: 約束を守る役(型保証に強い)

前提

Mastraでは、親が複数の専門エージェントに委譲する設計は Supervisor Agents として説明されています。

この前提を押さえると、次の役割分担が見やすくなります。

  • Supervisor Agent: どこに委譲するかを決める司令塔
  • Sub-agent: 専門タスクを処理する担当
  • Tool: 外部実行 + 入出力整形を担う実行境界

つまり、親エージェント視点では、toolsagentsも「呼び出し先」になります。

責務について

  • agents に登録されたSub-agentへ委譲できる
  • tools に登録されたToolを実行できる

見た目は似ていますが、設計責務は違います。

  • Sub-agent: 推論結果を作る
  • Tool: 呼び出し契約を保証する

つまり、Sub-agentだといつも異なる不定形の自然文が帰ってきますが、
Toolは決JSONなどのまった型で返してくれます。

この分離ができると、プロンプト依存の不安定性を局所化できます。

ToolSub-agent の実務的な使い分け

Tool を選ぶ場面

私はこのような用途で使い分けています。

  • API / DB / 検索基盤 / MCP など、外部システムに問い合わせてデータ取得したい
  • 通知送信、チケット作成、ワークフロー起動など、外部アクションを実行したい
  • LLMに外部機能を安全に呼ばせるため、入力制約(inputSchema)を明示したい
  • 返却値を後段(フロントや別処理)が確実に使えるよう、出力形式(outputSchema)を固定したい

Sub-agent を選ぶ場面

  • 分析・比較・考察など、自然文での説明や解釈が主目的
  • 単発処理ではなく、文脈や履歴を踏まえた判断が必要
  • 「何を先に調べるか」「どの順に進めるか」など、手順の計画が必要
  • 途中で複数Toolを使い分けながら探索的に進める必要がある
  • 返却形式の厳密さより、推論品質や説明品質を優先したい

Tool 内部で Agent を呼ぶユースケース

ここまでで「Toolは実行境界」「Sub-agentは推論担当」という役割を整理しました。
ここからは、本記事の中心テーマである「自然文の依頼を抽出条件へ変換してフロントで使う」ケースに絞って説明します。

なぜ Tool の中で Agent を呼ぶのか

具体的には、ユーザーの自然文リクエストを、フロントがそのまま扱える抽出パラメータに変換したい場面です。

下記のプロダクトは、自然言語で抽出条件を入力しダウンロードできるエージェントサービスです。
Excelダウンロード自体はエージェントではなくAPIで行っていて、AIにリクエストパラメータを作ってもらう必要があります。

しかし、ユーザーに見せる自然文は表示、実際のリクエストパラメータは非表示にする必要があるため、
フロントの動作として、必ず決まった方で返してほしいです。

スクリーンショット 2026-06-27 8.05.29.png

{
  "message": "商品検索ダウンロード条件として処理しますね。少々お待ちください。楽天市場の「化粧水・ローション」カテゴリでの商品Excel抽出条件を作成しました!",
  "params": [
    {
      "market": "market_a",
      "categoryId": "12345",
      "fromYm": "2026-05",
      "toYm": "2026-05",
      "minPrice": "1000"
    }
  ]
}

この場面で Sub-agent だけに任せると出力形式が揺れるリスクが残るため、入口を Tool にして inputSchema で入力を制約し、内部で Parser Agent に自然文理解をさせ、最後に outputSchema で検証して返す構成にします。

これにより、言い換え理解や補完といった推論力は活かしつつ、呼び出し元には安定した契約を返せるため、フロントが自然文パースを持つ必要がなくなります。

Tool が返すレスポンス例(型を固定する)

たとえば、build_export_params のようなToolなら、成功時も失敗時も同じ形で返します。

{
  "message": "商品検索ダウンロード条件として処理しますね。少々お待ちください。楽天市場の「化粧水・ローション」カテゴリでの商品Excel抽出条件を作成しました!",
  "params": [
    {
      "market": "market_a",
      "categoryId": "12345",
      "fromYm": "2026-05",
      "toYm": "2026-05",
      "minPrice": "1000"
    }
  ]
}
{
  "message": "条件を特定できませんでした。市場・カテゴリ・期間を具体化してください。",
  "params": []
}

このように返却型を固定すると、フロント側は params.length の判定だけで次の処理へ進めるため、実装とテストがシンプルになります。

この設計はMastraの思想と仕組みに沿っている

Mastraの設計は、役割分離して組み合わせる考え方と相性が良いです。

Supervisor Agents は「どこに委譲するか」の判断を担い、Tool は外部実行や入出力契約の境界を担います。

そのうえで、公式の Calling Agents 例が示すように、Toolの execute からランタイム経由で別Agentを呼ぶ構成も可能で、今回はこれを利用しています。
つまり「推論はAgent、契約保証はTool」という分担を1つの処理チェーンに落とし込めるのがポイントです。

実装面でも、structuredOutput を使ってAgentの返却をスキーマに寄せ、最終的にToolで検証して返す流れにすると、Supervisor配下の複数経路でもインターフェースを揃えやすくなります。

匿名化した最小構成サンプル

以下は「司令塔 + 分析Sub-agent + 条件抽出Tool(内部でParser Agentを呼ぶ)」の最小例です。

条件抽出Tool(内部でAgent呼び出し)

import { createTool } from '@mastra/core/tools';
import { z } from 'zod';

const exportConditionSchema = z.object({
  market: z.enum(['market_a', 'market_b', 'market_c']),
  categoryId: z.string().min(1),
  fromYm: z.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/),
  toYm: z.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/),
  minPrice: z.string().optional(),
  maxPrice: z.string().optional(),
});

const buildExportParamsOutputSchema = z.object({
  message: z.string().min(1),
  params: z.array(exportConditionSchema),
});

export const buildExportParamsTool = createTool({
  id: 'build_export_params',
  description:
    '自然文の抽出依頼を、フロントが利用できるエクスポート条件へ変換する。',
  inputSchema: z.object({
    prompt: z.string().trim().min(1),
  }),
  outputSchema: buildExportParamsOutputSchema,
  execute: async ({ context, mastra }) => {
    const parserAgent = mastra.getAgent('condition-parser-agent');
    if (!parserAgent) {
      return {
        message: '条件変換エージェントが見つかりませんでした。',
        params: [],
      };
    }

    const result = await parserAgent.generate(context.prompt, {
      structuredOutput: {
        schema: buildExportParamsOutputSchema,
        // 必要なら jsonPromptInjection などを追加
      },
    });

    const parsed = buildExportParamsOutputSchema.safeParse(result.object);
    if (!parsed.success) {
      return {
        message: '条件を特定できませんでした。市場・カテゴリ・期間を具体化してください。',
        params: [],
      };
    }

    return parsed.data;
  },
});

司令塔(Supervisor)から使い分け

import { Agent } from '@mastra/core/agent';

export const coordinatorAgent = new Agent({
  name: 'coordinator-agent',
  instructions: `
あなたは司令塔です。
- 分析や考察が目的なら analysis-agent に委譲
- 条件作成やエクスポート準備が目的なら build_export_params を実行
`,
  tools: {
    buildExportParams: buildExportParamsTool,
  },
  agents: {
    analysisAgent,
  },
  model: yourModel,
});

analysisAgent 側には、委譲条件がわかる description を設定しておく前提です。

この構成にすると、

  • 「説明して」系は analysisAgent
  • 「抽出条件を作って」系は buildExportParamsTool

と役割が衝突しにくくなります。

今回のExcel出力ユースケースに改めて当てはめる

ユーザー要件「自然文から条件抽出し、フロントでExcel出力」に対しては、次の分業が実用的です。

  1. 司令塔が意図を判定
    分析条件作成 かを判断
  2. 条件作成なら Tool を呼ぶ
    Tool が内部 Parser Agent を使って推論
  3. Tool が構造化結果を返す
    失敗時も同一スキーマで返す
  4. フロントは params をそのままエクスポート処理へ渡す

ここで大事なのは、フロントが自然文に依存しないように、AIが返す形式を固定化させることです。
これにより、UIの実装が単純になり、バグも減らせます。

まとめ

Sub-agentTool はどちらが上位という関係ではなく、責務が違います。

  • Sub-agent: 推論と説明
  • Tool: 契約と実行境界

そして、両方の長所を使うのが Tool 内部で Agent を呼ぶ設計です。
特に「自然文を構造化してフロントで再利用する」要件で効果が出ます。

参考リンク(Mastra公式)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?