次の方法で共有


App Service アプリを Azure AI Foundry Agent Service のツールとして追加する (Node.js)

このチュートリアルでは、OpenAPI を使用して Express.js アプリの機能を公開し、それをツールとして Azure AI Foundry Agent Service に追加し、エージェントプレイグラウンドで自然言語を使用してアプリと対話する方法について説明します。

Web アプリケーションにショッピング、ホテル予約、データ管理などの便利な機能が既にある場合は、Azure AI Foundry Agent Service の AI エージェントでそれらの機能を簡単に使用できます。 OpenAPI スキーマをアプリに追加するだけで、エージェントがユーザーのプロンプトに応答したときにアプリの機能を理解して使用できるようになります。 つまり、アプリでできることは何でも、AI エージェントでも実行でき、アプリの OpenAPI エンドポイントを作成する以外の労力は最小限です。 このチュートリアルでは、簡単な to-do リスト アプリから始めます。 最終的には、会話型 AI を使用して、エージェントでタスクを作成、更新、管理できるようになります。

OpenAPI ツールを使用してアクションを実行する会話の途中にあるエージェントのプレイグラウンドを示すスクリーンショット。

  • Web アプリに OpenAPI 機能を追加します。
  • OpenAPI スキーマが Azure AI Foundry Agent Service と互換性があることを確認します。
  • Azure AI Foundry Agent Service で OpenAPI ツールとしてアプリを登録します。
  • エージェントのプレイグラウンドでエージェントをテストします。

Prerequisites

このチュートリアルでは、「 チュートリアル: Node.js + MongoDB Web アプリを Azure にデプロイする」で使用するサンプルを使用していることを前提としています。

少なくとも、GitHub Codespaces で サンプル アプリケーション を開き、 azd upを実行してアプリをデプロイします。

GitHub codespaces で開く で開く

Web アプリに OpenAPI 機能を追加する

  1. codespace ターミナルで、NuGet swagger-jsdoc NPM パッケージをプロジェクトに追加します。

    npm install swagger-jsdoc
    
  2. ファイルの下部に、上記 module.exports = router; 次の API 関数を追加します。 Azure AI Foundry Agent Service と互換性を持たさせるには、operationId注釈で @swagger プロパティを指定する必要があります (OpenAPI 指定ツールで Azure AI Foundry Agent Service を使用する方法: 前提条件を参照)。 To make them compatible with the Azure AI Foundry Agent Service, you must specify the operationId property in the @swagger annotation (see How to use Azure AI Foundry Agent Service with OpenAPI Specified Tools: Prerequisites).

    router.get('/schema', function(req, res, next) {
      try {
        const swaggerJsdoc = require('swagger-jsdoc');
    
        res.json(
          swaggerJsdoc(
            {
              definition: {
                openapi: '3.0.0',
                servers: [
                  {
                    url: `${req.protocol}://${req.get('host')}`,
                    description: 'Task API',
                  },
                ],
              },
              apis: ['./routes/*.js'],
            }
          )
        );
      } catch (error) {
        res.status(500).json({ error: error.message });
      }
    });
    
    /**
     * @swagger
     * /api/tasks:
     *   get:
     *     summary: Get all tasks
     *     operationId: getAllTasks
     *     responses:
     *       200:
     *         description: List of tasks
     */
    router.get('/api/tasks', async function(req, res, next) {
      try {
        const tasks = await Task.find();
        res.json(tasks);
      } catch (error) {
        res.status(500).json({ error: error.message });
      }
    });
    
    /**
     * @swagger
     * /api/tasks/{id}:
     *   get:
     *     summary: Get task by ID
     *     operationId: getTaskById
     *     parameters:
     *       - in: path
     *         name: id
     *         required: true
     *         schema:
     *           type: string
     *     responses:
     *       200:
     *         description: Task details
     */
    router.get('/api/tasks/:id', async function(req, res, next) {
      try {
        const task = await Task.findById(req.params.id);
        res.json(task);
      } catch (error) {
        res.status(404).json({ error: error.message });
      }
    });
    
    /**
     * @swagger
     * /api/tasks:
     *   post:
     *     summary: Create a new task
     *     operationId: createTask
     *     requestBody:
     *       required: true
     *       content:
     *         application/json:
     *           schema:
     *             type: object
     *             properties:
     *               taskName:
     *                 type: string
     *     responses:
     *       201:
     *         description: Task created
     */
    router.post('/api/tasks', async function(req, res, next) {
      try {
        // Set createDate to current timestamp when creating a task
        const taskData = {
          ...req.body,
          createDate: new Date()
        };
    
        const task = new Task(taskData);
        await task.save();
        res.status(201).json(task);
      } catch (error) {
        res.status(400).json({ error: error.message });
      }
    });
    
    /**
     * @swagger
     * /api/tasks/{id}:
     *   put:
     *     summary: Update a task
     *     operationId: updateTask
     *     parameters:
     *       - in: path
     *         name: id
     *         required: true
     *         schema:
     *           type: string
     *     requestBody:
     *       required: true
     *       content:
     *         application/json:
     *           schema:
     *             type: object
     *             properties:
     *               taskName:
     *                 type: string
     *               completed:
     *                 type: boolean
     *     responses:
     *       200:
     *         description: Task updated
     */
    router.put('/api/tasks/:id', async function(req, res, next) {
      try {
        // If completed is being set to true, also set completedDate
        if (req.body.completed === true) {
          req.body.completedDate = new Date();
        }
    
        const task = await Task.findByIdAndUpdate(req.params.id, req.body, { new: true });
        res.json(task);
      } catch (error) {
        res.status(400).json({ error: error.message });
      }
    });
    
    /**
     * @swagger
     * /api/tasks/{id}:
     *   delete:
     *     summary: Delete a task
     *     operationId: deleteTask
     *     parameters:
     *       - in: path
     *         name: id
     *         required: true
     *         schema:
     *           type: string
     *     responses:
     *       200:
     *         description: Task deleted
     */
    router.delete('/api/tasks/:id', async function(req, res, next) {
      try {
        const task = await Task.findByIdAndDelete(req.params.id);
        res.json({ message: 'Task deleted successfully', task });
      } catch (error) {
        res.status(404).json({ error: error.message });
      }
    });
    

    このコードは既存のルートの機能を複製していますが、これは不要ですが、わかりやすくするために保持します。 ベスト プラクティスは、アプリ ロジックを共有関数に移動してから、MVC ルートと OpenAPI ルートの両方から呼び出すことです。

  3. codespace ターミナルで、 npm startを使用してアプリケーションを実行します。

  4. [ブラウザーで開く] を選択します。

  5. URL に /schema を追加して、OpenAPI スキーマを表示します。

  6. codespace ターミナルに戻り、変更をコミットして変更をデプロイするか (GitHub Actions メソッド)、または azd up (Azure Developer CLI メソッド) を実行します。

  7. 変更がデプロイされたら、 https://<your-app's-url>/schema に移動し、後で使用できるようにスキーマをコピーします。

Azure AI Foundry でエージェントを作成する

  1. クイック スタート: 新しいエージェントを作成する」の手順に従って、Azure AI Foundry ポータルでエージェントを作成します。

    使用できるモデルと使用可能なリージョンに注意してください。

  2. OpenAPI 仕様ツールの使用方法に関するページの手順に従って、新しいエージェントを選択し、OpenAPI 3.0 指定ツールでアクションを追加します。

  3. [ スキーマの定義 ] ページで、先ほどコピーしたスキーマを貼り付けます。 アクションを確認して保存します。

エージェントをテストする

  1. エージェントのプレイグラウンドがまだ Foundry ポータルで開いていない場合は、エージェントを選択し、[ プレイグラウンドで試す] を選択します。

  2. [手順] で、"todosApp ツールを使用してタスクを管理してください" などの簡単な手順を説明します。

  3. 次のプロンプトの提案を使用してエージェントとチャットします。

    • すべてのタスクを表示します。
    • 「3つのレタスジョークを思い付く」というタスクを作成します。
    • それを「3つのノックノックジョークを考えてください」に変えてください。

    OpenAPI ツールを使用してアクションを実行する会話の途中にあるエージェントのプレイグラウンドを示すスクリーンショット。

セキュリティのベスト プラクティス

Azure App Service で OpenAPI 経由で API を公開する場合は、次のセキュリティのベスト プラクティスに従います。

  • 認証と承認: Azure API Management の背後にある App Service の OpenAPI エンドポイントを Microsoft Entra ID で 保護し、承認されたユーザーまたはエージェントのみがツールにアクセスできるようにします。
  • 入力データを検証します。 無効または悪意のある入力を防ぐために、常に受信データを検証します。 Node.js アプリの場合は、 高速検証 などのライブラリを使用して、データ検証規則を適用します。 ベスト プラクティスと実装の詳細については、ドキュメントを参照してください。
  • HTTPS を使用する: このサンプルは、既定で HTTPS を適用し、転送中のデータを暗号化するための無料の TLS/SSL 証明書を提供する Azure App Service に依存しています。
  • CORS の制限: クロスオリジン リソース共有 (CORS) を信頼されたドメインのみに制限します。 詳細については、「 CORS を有効にする」を参照してください。
  • レート制限の適用:API Management またはカスタム ミドルウェアを使用して、不正使用やサービス拒否攻撃を防ぎます。
  • 機密性の高いエンドポイントを非表示にする: OpenAPI スキーマで内部 API または管理者 API を公開しないようにします。
  • OpenAPI スキーマを確認します。 OpenAPI スキーマが機密情報 (内部 URL、シークレット、実装の詳細など) を漏らさないようにします。
  • 依存関係を更新したままにする: NuGet パッケージを定期的に更新し、セキュリティ アドバイザリを監視します。
  • アクティビティの監視とログ記録: ログ記録を有効にし、アクセスを監視して疑わしいアクティビティを検出します。
  • マネージド ID を使用する: 他の Azure サービスを呼び出す場合は、ハードコーディングされた資格情報の代わりにマネージド ID を使用します。

詳細については、 App Service アプリのセキュリティ保護REST API セキュリティのベスト プラクティスに関する説明を参照してください。

Next step

これで、App Service アプリを Azure AI Foundry Agent Service のツールとして使用し、エージェントのプレイグラウンドで自然言語を使用してアプリの API と対話できるようになりました。 ここから、Foundry ポータルで引き続きエージェントに機能を追加したり、Azure AI Foundry SDK または REST API を使用して独自のアプリケーションに統合したり、大規模なソリューションの一部としてデプロイしたりできます。 Azure AI Foundry で作成されたエージェントは、クラウドで実行したり、チャットボットに統合したり、Web アプリやモバイル アプリに埋め込んだりすることができます。

次の手順を実行し、Azure App Service 内で直接エージェントを実行する方法については、次のチュートリアルを参照してください。

More resources