🗂

Mastra で作る AIエージェント(7) JSONで結果を返してほしい

に公開

Mastra で作るAI エージェント というシリーズの第7回です。


前回までは、AIエージェントの構成を「三国志」になぞらえて以下のように把握しました。

  • フロントに立つリーダーの劉備=エージェント:何をやるにしても軍師に相談
  • 天才軍師・諸葛孔明=LLM:劉備に何かと助言するが、決して自分が直接前面に出ない
  • 将軍たち=ツール:劉備に呼ばれて定型作業を遂行、RAG/API/MCPなどなど

ひととおり、「チーム劉備」の組成の仕方が分かったところで、前々回からしばらくは、チームの組成以外の話をまとめてご紹介しています。今回は構造化出力です。

JSON形式で結果を返してほしい

AIエージェントの出力をそのままチャット画面のスレッド欄に表示するのであればともかく、アプリケーションの一部として組み込みたい場合は、ダラダラっとした長文ではなくてJSON形式のような構造化データでキリっと返却してほしいことが多いです。

Mastra Agentで構造化データ(JSON形式)を出力するには、generate() メソッドに structuredOutput オプションを渡します。スキーマは Zod (または JSON Schema )で定義できます。

import { z } from 'zod';
import { Agent } from '@mastra/core/agent';
import { openai } from '@ai-sdk/openai';

// スキーマを定義
const weatherOutputSchema = z.object({
  location: z.string().describe('場所'),
  temperature: z.number().describe('気温(℃)'),
  conditions: z.string().describe('天気の状態'),
  humidity: z.number().describe('湿度(%)'),
});

const weatherAgent = new Agent({
  id: 'weather-agent',
  name: 'Weather Agent',
  instructions: '天気情報を構造化データで返してください',
  model: openai('gpt-4o'),
  tools: { weatherTool },
});

// 構造化出力で呼び出し
const result = await weatherAgent.generate('東京の天気を教えて', {
  structuredOutput: {
    schema: weatherOutputSchema,
  },
});

console.log(result.object);
// {
//   location: '東京',
//   temperature: 18,
//   conditions: '曇り',
//   humidity: 65
// }

ストリーミングと構造化出力

ストリーミング中も構造化出力を使用できます。つまり、ダラダラっとした長文をストリーミングで順次取得しつつ、最後に構造化データも取得できます。

  1. テキストストリーム (textStream) : 自然言語の説明が順次流れる
  2. フルストリーム (fullStream) : すべてのチャンクイベント(テキスト、ツール呼び出し、オブジェクト結果など)
  3. 構造化データ (object) : ストリーム完了後に取得できる
const stream = await weatherAgent.stream('東京の天気を教えて', {
  structuredOutput: {
    schema: weatherOutputSchema,
  },
});

// 方法1: テキストストリームで自然言語を取得(ユーザーに見せる用)
for await (const chunk of stream.textStream) {
  process.stdout.write(chunk);
  // 出力例: 「東京の天気を調査しています...」「現在18度で曇りです...」
}

// 方法2: フルストリームですべてのイベントを取得
for await (const chunk of stream.fullStream) {
  if (chunk.type === 'text-delta') {
    console.log('テキスト:', chunk.textDelta);
  }
  if (chunk.type === 'object-result') {
    console.log('構造化データ:', chunk);
  }
}

// ストリーム完了後に構造化データを取得
const weatherData = await stream.object;
console.log(weatherData);
// {
//   location: '東京',
//   temperature: 18,
//   conditions: '曇り',
//   humidity: 65
// }

重要なポイントですが、構造化データそのものがストリーミングで順次構築されるわけではありません。自然言語の説明がストリーミングされ、最後に構造化データが完成します。

ユースケース例としては、UIに「調査中...」「気温は18度です」などとリアルタイムにテキストを表示し、完了後に構造化データをDBに保存するような使い方が考えられます。

AIエージェント単品ではなく、それを組み込んだアプリへ

AIエージェントに質問して回答してもらうチャットベースのシステムも有用ですが、AIの結果をアプリケーションが受け取って活用したり編集したり判断したりすることでAIエージェントの活用の用途が一気に広がります。ユースケースは無数に挙げられますが、例えば・・・

  • 企業マッチングシステム

    • AIが企業の適合度を{companyName: string, matchScore: number, corporateNumber: string, matchReasons: string[], nextActions: string[]}形式で返却し、アプリケーションがスコア順にソート・CRMへの自動登録・営業担当への通知を行う
  • ECサイトの商品情報抽出システム

    • AIが商品ページから{productName: string, price: number, specifications: {}, images: string[], inStock: boolean}を抽出し、アプリケーションがデータベースへの一括登録・在庫管理システムとの連携・価格変動アラートを実施する
  • カスタマーサポートチケット分類システム

    • AIが問い合わせ内容を{category: string, priority: 1-5, sentiment: string, suggestedDepartment: string, estimatedResolutionTime: number}形式で分析し、アプリケーションが自動ルーティング・優先度キューへの振り分け・SLA管理を行う
  • 契約書レビューシステム

    • AIが契約書から{riskItems: [{clause: string, riskLevel: string, suggestion: string}], keyDates: Date[], parties: string[], totalRiskScore: number}を抽出し、アプリケーションがリスク順に表示・法務部への自動エスカレーション・承認ワークフロー開始を実行する
  • 履歴書スクリーニングシステム

    • AIが応募者情報を{candidateName: string, skills: string[], experienceYears: number, matchScore: number, interviewRecommendation: boolean, salaryRange: {min: number, max: number}}形式で返却し、アプリケーションが合格者リストの自動生成・面接スケジュール提案・ATSへのデータ連携を行う

ぜひ、みなさんの業務にも組み込んで、さらなる自動化を進めてみてください。

>> 次回 : (8) ワークフローでエージェントを並べる

Discussion