🗒️

AIエージェントは「ただのプロンプト」ではない——mastraで理解するエッセンスと実装

に公開

AI エージェントという言葉がバズワードになり、多くの企業がこぞって使うようになりました。しかし実態として、単に OpenAI や Anthropic にリクエストを実行し結果を表示するだけのサービスも少なくありません。

「AI エージェントって結局プロンプト投げてるだけでしょ」という意見を、エンジニアの方からも聞くことがあります。実際はかなり違うのですが、なかなか埋まらない理解のギャップを本記事で解消したいと思います。本記事では mastra というライブラリを活用し、AI エージェントとプロンプトだけの違いを解説します。

mastra とは

mastra とは TypeScript ベースで書かれたエージェントフレームワークです。技術的な基盤として Vercel AI SDK を採用しており、Google、OpenAI、Anthropic など豊富な AI プロバイダーをサポートしています。類似のライブラリとしては Genkit や LangChain などが存在します。

https://mastra.ai/ja/docs

AI エージェント

mastra の文脈では AI エージェントを 「言語モデルを活用して意思決定やアクションの実行ができるインテリジェントなアシスタントを構築するための仕組み」 と捉えています。

https://mastra.ai/ja/docs/agents/overview#:~:text=エージェントは、言語モデルを活用して意思決定やアクションの実行ができるインテリジェントなアシスタントを構築するための仕組みです。各エージェントには必須の指示と LLM があり、必要に応じてツールやメモリを追加できます。

具体的には、以下のようなものです。

  1. 言語モデルを自らの頭脳として活用し、
  2. ストレージなどを活用して自身の記憶や過去の情報(コンテキスト)を保存した上で、
  3. ツールを活用することによって用途や文脈に合わせた役務を自律的に提供するための仕組み

AIエージェントの概念図

プロンプトを活用するだけとは何が違うのか

「とはいえ、プロンプトを言語モデルに渡しているだけでは?」 という疑問は自然です。しかし AI エージェントの技術を活用すると、プロンプトをチューニングするよりも遥かに効率的なものが提供できるようになります。

ただ利用するだけでは違いをあまり感じれない

こちらのドキュメントで解説されているエージェントを参考に簡単な例を示します。

import { mastra } from "./mastra";

const agent = mastra.getAgent("weatherAgent");
const response = await agent.generate("今日の東京の天気は?");
console.log(response.text);

ここだけを見ると、「プロンプトを活用しているだけ」と思うかもしれません。実際にそうです。だから認識のギャップが深まってしまうのでしょう。

AI エージェントは自らツールを選んで使い、記憶も頼りに結果を出力する

しかし実際は、単にプロンプトを投げるだけのシステムとは異なる挙動をします。プロンプトに応じて、自らツールを選定して使い、自分で使い方を決定して最終的な結果を出力するのです。

具体的に、エージェントの定義を見てみましょう。ここで重要なのは以下の3点です。

ツールとメモリが宣言されていることで、プロンプトに応じて記憶の活用とツールの選定をエージェント自らが行います。プロンプトがツールと関係なければ利用しません。また、ツールの中に所定のロジックを埋め込んだり、別のエージェントを呼び出して役割分担させることも可能です。

import { Agent } from "@mastra/core/agent";
import { openai } from "@ai-sdk/openai";
import { Memory } from "@mastra/memory";
import { LibSQLStore } from "@mastra/libsql";
import { weatherTool } from "../tools";
 
export const memory = new Memory({
  storage: new LibSQLStore({
    url: `file:./mastra.db`,
  }),
  options: {
    semanticRecall: false,
    workingMemory: { 
      enabled: false,
    },
    lastMessages: 5
  },
});
 
export const weatherAgent = new Agent({
  name: "Weather Agent",
  instructions: `
    あなたは正確な気象情報を提供する、頼れる天気アシスタントです。
 
    主な役割は、特定の場所の天気情報をユーザーが取得できるように支援することです。回答する際は次を守ってください:
    - 場所が指定されていない場合は、必ず場所を尋ねる
    - 湿度、風の状況、降水量などの関連情報を含める
    - 簡潔でありながら要点を押さえた回答にする
 
    現在の天気データを取得するには weatherTool を使用してください。
  `,
  model: openai("gpt-4o-mini"),
  tools: {
    weatherTool,
  },
  memory,
});

次に、エージェントに渡しているツールの定義を見ていきましょう。ここで重要なのは以下の2点です。

今回は「都市名」という比較的わかりやすい検索条件ですが、「都市名から緯度経度を推定させる」「周囲Xキロまでを検索範囲にする」など自由度高く設定できます。その検索条件はエージェントが自律的に判断して都度生成し、検索を実行します。RAG(検索拡張生成)を活用する際も同様です。

import { createTool } from '@mastra/core/tools';
import { z } from 'zod';
 
export const weatherTool = createTool({
  id: 'get-weather',
  description: '指定した場所の現在の天気を取得します',
  inputSchema: z.object({
    location: z.string().describe('都市名'),
  }),
  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);
  },
});
 
const getWeather = async (location: string) => {
  const geocodingUrl = `[https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(location)}&count=1`](https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(location)}&count=1`);
  const geocodingResponse = await fetch(geocodingUrl);
  const geocodingData = await geocodingResponse.json();
 
  if (!geocodingData.results?.[0]) {
    throw new Error(`Location '${location}' not found`);
  }
 
  const { latitude, longitude, name } = geocodingData.results[0];
 
  const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,wind_gusts_10m,weather_code`;
  const response = await fetch(weatherUrl);
  const data = await response.json();
 
  return {
    temperature: data.current.temperature_2m,
    feelsLike: data.current.apparent_temperature,
    humidity: data.current.relative_humidity_2m,
    windSpeed: data.current.wind_speed_10m,
    windGust: data.current.wind_gusts_10m,
    conditions: getWeatherCondition([data.current.weather](http://data.current.weather)_code),
    location: name,
  };
};

プロンプトだけでは対応できないケース

「記憶もウェブ検索も、Gemini や OpenAI がサポートしてる機能を使えば同じでは?」 という意見もあるでしょう。簡単な機能の場合はそれも一理あります。要件次第では私も Gemini などで代替する場面もあります。

しかし、以下のような場合はどうでしょうか?

  1. 長期的な記憶管理が必要な場合: 半年や1年前のやり取りを参照しつつ、文脈を保持して作業を進める。記憶をどう保存・検索するか(タグ付け、要約生成、時系列整理など)を制御する必要があります。
  2. トークン数の制約がある場合: 長期の会話や大量の画像を扱う場合、プロンプトに全情報を渡す方式では遅かれ早かれエラーが発生します。記憶の取り扱いを最適化する必要があります。
  3. 権限管理やクローズドな情報へのアクセス: ユーザーの属性に応じて使い分けが必要な場合、AI がいつどのツールを使うのかを定義し、エージェントとして実装するのが効率的です(MCP などの活用も含む)。

まとめ

AI エージェントを活用することで、言語モデルの強みを活かした多機能な AI 機能を提供できるようになります。プロンプトだけを活用している場合とは違い、その場・そのやり取り内の情報だけでなく、ユーザーとの文脈を共有し、与えられた権限に基づいてユーザーの代理人としてサービスを提供してくれるのです。

AI エージェントというバズワードに忌避感を感じる気持ちもわかりますが、これだけ AI 機能が増えている現在、解像度が足りないのは致命的です。各社の事業や経営戦略にも影響しかねません。

まずは AI エージェントによってもたらされる恩恵を理解し、何ができるのかを把握することが重要です。本記事がその一助となることを願っています。

Unreliable では、巷であふれる AI ニュースを実務家がピックアップし、調査を行って情報発信を行っております。記事を投稿したい方、こういうネタを取り上げてほしいなどあれば、コメントをお寄せいただけましたら非常にありがたいです!

Unreliable

Discussion