MastraでQiita記事を要約するAIエージェントを作ってみた

# はじめに

AI エージェントを簡単に開発できると話題の Mastra を試してみたくなり、Qiita 記事を要約するというシンプルな AI エージェントを作ってみました。

この記事では Mastra の主要機能を簡単に紹介した後に、どのように AI エージェントを実装するのかを解説していきます。

# Mastra とは

https://mastra.ai/

`The TypeScript Agent Framework` と銘打っているように、簡単にいうと「TypeScript で AI エージェントを簡易に開発できるフレームワーク」となります。

エージェントやワークフロー、RAG といったコンポーネントが提供されており、AI エージェントの実装が直感的にできるフレームワークです。また、OpenAI, Anthropic, Google Gemini など各 LLM プロバイダーの利用を抽象化してくれるので、プロバイダーやモデルの切り替えも簡単です。

また、Mastra は軽量な Web アプリケーションフレームワークである [Hono](https://hono.dev/) を使って実装されているので HTTP サーバーとして実行できます。そのため、Vercel, Cloudflare Workers など様々なプラットフォームへ簡単にデプロイできるので、別のアプリケーションから AI エージェントを利用できるのも嬉しい点ですね。

以下で簡単に Mastra の主要機能を紹介します。

## agents

> Build intelligent agents that execute tasks, access knowledge bases, and maintain
memory persistently within threads.
> 
> タスクを実行し、知識ベースにアクセスし、スレッド内でメモリを持続的に維持するインテリジェントエージェントを構築する。

エージェントは、LLM を活用して目的のタスクを実行する機能です。過去のやりとりから会話文脈を保持して（メモリ機能）回答を生成したり、外部のAPIを実行（ツール機能）して回答を保管したりできます。

この記事ではエージェントを使った実装を紹介しています。

## workflows

> Durable graph-based state machines with built-in tracing, designed to execute complex
sequences of LLM operations.
>
> 複雑な LLM操作のシーケンスを実行するように設計された、トレース内蔵の耐久性のあるグラフベースのステートマシン。

ワークフローは、個々の処理（ステップ）でエージェントの実行や関数の実行を組み合わせて複雑なフロー処理を定義し、各ステップの処理結果を元に分岐処理や並列処理を実行させることができます。

## rag

> Equip agents with the right context. Sync data from SaaS tools. Scrape the web.
Pipe it into a knowledge base and embed, query, and rerank.
> 
> エージェントに適切なコンテキストを提供 SaaSツールからデータを同期 ウェブをスクレイピング。ナレッジベースにパイプし、埋め込み、クエリ、再ランク。

RAG（ `Retrieval-Augmented Generation` ）は、独自データソース（データベースや、資料など）を活用して AI エージェントの回答をより正確なものにする機能です。
データの前処理やベクトル化、ベクトルデータベースへの保存や検索などが簡易に行えるます。

## ops

> Track inputs and outputs for every step of every workflow run. See each agent tool call and decision. Measure context, output, and accuracy in evals, or write your own.
> 
> ワークフロー実行の各ステップの入力と出力を追跡します。各エージェントツールのコールと意思決定を確認。エバルのコンテキスト、出力、精度を測定するか、独自のエバルを作成します。

Ops 機能では、AI エージェントの実行メトリクスや、入出力の評価、トレース内容の確認を効率的に行えるようになっています。
`OpenTelemetry Protocol (OTLP) ` をサポートしているので、OpenTelemetry に対応した監視サービスなどとの連携ができるようになっています。

# 「Qiita記事を要約するAIエージェント」の実装

ここからは、どのように AI エージェントを実装するかを解説していきます。
今回は Mastra を初めて使うので、ユーザーが指定した Qiita 記事を要約するだけのシンプルなエージェントを作ってみました。

今回作ったものは下記の GitHub リポジトリにて公開しています。
`OpenAI API` の API キーと Qiita API の API キー（こちらは任意）があれば、AI エージェントの動作を試していただけます。

https://github.com/sumihiro3/qiita-post-agent

## 開発環境

- macOS
    - 15.2
- node.js
    - 20.14.0
- Cursor
    - 0.47.8

# 実装内容の解説

## プロジェクトの初期化

公式で提供されている `create-mastra` コマンドを使ってプロジェクトを初期化します。

```sh
npx create-mastra@latest
```

`Choose components to install` では、`Agents` を選択しておきます。

<details><summary>実行結果</summary>

```sh
┌  Mastra Create
│
◇  What do you want to name your project?
│  qiita-post-agent
│
◇  Project created
│
◇  npm dependencies installed
│
◇  mastra installed
│
◇  @mastra/core installed
│
◇  .gitignore added
│
└  Project created successfully


┌  Mastra Init
│
◇  Where should we create the Mastra files? (default: src/)
│  src/
│
◇  Choose components to install:
│  Agents, Workflows
│
◇  Add tools?
│  Yes
│
◇  Select default provider:
│  OpenAI
│
◇  Enter your openai API key?
│  Skip for now
│
◇  Add example
│  Yes
│
◇  Make your AI IDE into a Mastra expert? (installs Mastra docs MCP server)
│  Cursor
│
│  
│  Note: you will need to go into Cursor Settings -> MCP Settings and manually enable the installed Mastra MCP server.
│  
│
◇  
│
◇   ─────────────────────────────────────────────────────────╮
│                                                            │
│                                                            │
│        Mastra initialized successfully!                    │
│                                                            │
│        Add your OPENAI_API_KEY as an environment variable  │
│        in your .env.development file                       │
│                                                            │
│                                                            │
├────────────────────────────────────────────────────────────╯
│
└  
   To start your project:

    cd qiita-post-agent
    npm run dev
```

</details>

## Qiita 記事を取得するツールの実装

まずはエージェントから利用するツールを実装します。
今回は Qiita 記事を取得する処理をツールとして実装します。

Mastra のツールでは下記を定義して実装していきます。

- id
    - ツールを一意に表すID
- description
    - ツールの概要
        - `Mastra Playground` という GUI からツールの参照や実行ができるので、分かりやすく書いておく
- inputSchema
    - ツール実行に必要となる入力定義
        - `zod` で定義する
- outputSchema
    - ツールでの処理結果を表す出力定義
        - 同じく `zod` で定義する
- execute
    - ツール処理の内容

今回の実装では下記のようになりました。
Qiita API から指定 ID の記事を取得し、主要な項目だけ返すシンプルな実装です。

```typescript: src/mastra/tools/qiita-post.ts
/**
 * Qiita API を使用して、指定の記事内容を取得するツール
 */
export const getQiitaPostTool = createTool({
  id: 'get-qiita-post',
  description: 'Qiita API を使用して、指定の記事内容を取得するツール',
  inputSchema: z.object({
    postId: z.string().describe('記事のID'),
  }),
  outputSchema: z.object({
    title: z.string().describe('記事のタイトル'),
    body: z.string().describe('記事の本文'),
    author: z.string().nullable().describe('記事の作者'),
    tags: z.array(z.string()).describe('記事のタグ'),
    createdAt: z.string().describe('記事の作成日時'),
    updatedAt: z.string().describe('記事の更新日時'),
  }),
  execute: async ({ context }) => {
    const postData = await getQiitaPost(context.postId);
    return {
      title: postData.title,
      body: postData.body,
      author: postData.user.name ? postData.user.name : postData.user.id,
      tags: postData.tags.map((tag) => tag.name),
      createdAt: postData.created_at,
      updatedAt: postData.updated_at,
    };
  },
});
```

## Qiita 記事を要約するエージェントの実装

次にエージェントを実装します。
今回は、先に実装した「Qiita 記事取得ツール」を利用して取得した記事の内容を LLM を使って要約します。

Mastra のエージェントでは下記を定義して実装していきます。

- name
    - エージェント名称
- instructions
    - LLM への指示（プロンプト）
        - エージェントの専門性や、出力の目的・制約などを設定します
- model
    - 利用する LLM プロバイダーとモデル
        - 今回は OpenAI API の `gpt-4o-mini` を利用しました
- tools
    - エージェントの処理で利用するツール
- output
    - エージェントからの出力定義（今回の実装では使用していません）
        - こちらも `zod` で定義する

今回の実装では下記のようになりました。

```typescript: src/mastra/agents/qiita-post.ts

/**
 * Qiita 記事の要約を生成するエージェント
 */
export const qiitaPostSummarizeAgent = new Agent({
  name: 'Qiita Post Summarize Agent',
  instructions: `
    あなたはプロの編集者です。ユーザーから与えられたインプットを、要点を逃さない形で要約します。
    要約の読み手は日本のエンジニアです。エンジニアが読んで理解しやすい内容にすると喜ばれます。

    ## 制約
      - 要約は800文字程度で出力します
      - 難しい漢字は読み手が間違えないように、ひらがなで書きます
      - 要約には markdown の記法やコード、改行コード、URL は含めないでください
  `,
  model: openai('gpt-4o-mini'),
  tools: { getQiitaPostTool },
});
```

## エージェントの登録

エージェントの実装ができたら Mastra にエージェントを登録して利用できるようにします。

実装したエージェント（`qiitaPostSummarizeAgent`）を Mastra クラスの `agent` へ登録します。
なお、`weatherAgent` は Mastra 公式実装例のエージェントです。


```typescript
import { Mastra } from '@mastra/core/mastra';
import { createLogger } from '@mastra/core/logger';
import { qiitaPostSummarizeAgent, weatherAgent } from './agents';

export const mastra = new Mastra({
  workflows: { weatherWorkflow },
  agents: { weatherAgent, qiitaPostSummarizeAgent },
  logger: createLogger({
    name: 'Mastra',
    level: 'info',
  }),
});
```

## Mastra サーバーの起動

下記のコマンドで Mastra サーバーを起動できます。

```shell
yarn dev
```

今回の実装では `yarn` を利用していますが、`npm` などお好みのパッケージマネージャーが利用可能です。


```shell
INFO [2025-03-20 18:30:05.016 +0900] (BUNDLER - Dev): Starting watcher...
INFO [2025-03-20 18:30:05.257 +0900] (BUNDLER - Dev): Bundling finished, starting server...
INFO [2025-03-20 18:30:05.262 +0900] (Mastra CLI): [Mastra Dev] - Starting server...
INFO [2025-03-20 18:30:05.988 +0900] (Mastra): 🦄 Mastra API running on port 4111/api
INFO [2025-03-20 18:30:05.991 +0900] (Mastra): 📚 Open API documentation available at http://localhost:4111/openapi.json
INFO [2025-03-20 18:30:05.991 +0900] (Mastra): 🧪 Swagger UI available at http://localhost:4111/swagger-ui
INFO [2025-03-20 18:30:05.991 +0900] (Mastra): 👨‍💻 Playground available at http://localhost:4111/
```

正常に起動すると上記のようなログが出力され `http://localhost:4111/` で Mastra サーバーの画面 (Mastra Playground) にアクセスできます。

![Mastra Playground](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154381/d9cc1675-5a27-4321-9786-d15aec557fff.png)

### エージェントの実行

それでは実装したエージェントを Mastra Playground から実行してみましょう。
トップページから実装したエージェント 「`Qiita Post Summarize Agent`」を選択します。

すると、見慣れたチャット画面が表示されますので、要約してもらいたい Qiita 記事の URL を指定します。

![エージェントのチャット画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154381/cfe4d4ee-75fe-4dd2-928f-8b67f3354927.png)

勢い余って？ 2つの記事 URL を要約するようエージェントに指示しましたが、見事に2つとも要約して返してくれました！

![エージェント実行結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154381/db4e6eb2-c0c5-40fe-8dd2-9f8b286362fb.png)

### Mastra サーバーで利用できる API

先のチャット画面のバックグランドでは、`http://localhost:4111/api/agents/qiitaPostSummarizeAgent/stream` という API が実行されています。

API として外部から利用できるようになっているので、Mastra サーバーを Vercel などにデプロイして、フロントエンドや別のバックエンドアプリケーションから AI エージェントを実行することもできます。
また、OpenAPI (Swagger) 形式で利用できる API 定義を出力する機能が標準で備わっているので、API クライアントを自動生成でき、より型安全に実装できるのもありがたいですね。

#### Swagger UI

なお、`http://localhost:4111/swagger-ui` にアクセスると Swagger UI が表示されるので、どのような API が用意されているかが分かり、ここからも API を実行できるようになっています。

![Swagger UI](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154381/7db1fab3-2954-42a9-910d-2f564e92c149.png)

# まとめ

本記事では、話題の AI エージェント開発フレームワーク `Mastra` の主要機能を簡単に紹介して、どのような事ができるかを解説しました。
また、AI エージェントをどのように実装するのかを、Qiita 記事要約エージェントを例にして解説しました。

初めて Mastra を使ってみましたが、とても直感的にエージェントを実装することができました。今回の実装であれば1時間もあれば実行できるところまで持ってこれました。

RAG やワークフローについても直感的に実装できそうなので、個人開発している AI ラジオ配信サービス [Tech Post Cast](https://techpostcast.com/) にも組み込んでいこうと考えています。

[Tech Post Cast](https://techpostcast.com/) に関する解説記事を公開していますので、ご覧いただければ嬉しいです。

https://qiita.com/sumihiro3/items/105c0b74ef080ba05a5d

## 関連リンク

- [Mastra](https://mastra.ai/)
- [Mastra GitHub repository](https://github.com/mastra-ai/mastra)
- [実装例](https://mastra.ai/examples)
- [Qiita API document](https://qiita.com/api/v2/docs)