次の方法で共有


Foundry Agent Service (.NET) で App Service アプリをツールとして追加する

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

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

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

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

[前提条件]

このチュートリアルでは、「 チュートリアル: ASP.NET Core と Azure SQL Database アプリを Azure App Service にデプロイする」で使用するサンプルを使用していることを前提としています。

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

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

ヒント

エージェント モードで GitHub Copilot に指示することで、次のすべての変更を行うことができます。

I'd like to add OpenAPI functionality to all the methods in Controllers/TodosController.cs, but I don't want to change the existing functionality with MVC. Please also generate the server URL and operation ID in the schema.

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

    dotnet add package Swashbuckle.AspNetCore --version 6.5.0
    dotnet add package Swashbuckle.AspNetCore.Annotations --version 6.5.0
    
  2. Controllers/TodosController.cs で、次の API メソッドを追加します。 Foundry Agent Service と互換性を持たさせるには、OperationId属性で SwaggerOperation プロパティを指定する必要があります (OpenAPI 指定ツールで Foundry Agent Service を使用する方法: 前提条件を参照)。

        // GET: api/todos
        [HttpGet("api/todos")]
        [SwaggerOperation(Summary = "Gets all Todo items", OperationId = "GetTodos")]
        [ProducesResponseType(typeof(IEnumerable<Todo>), 200)]
        public async Task<ActionResult<IEnumerable<Todo>>> GetTodos()
        {
            return await _context.Todo.ToListAsync();
        }
    
        // GET: api/todos/5
        [HttpGet("api/todos/{id}")]
        [SwaggerOperation(Summary = "Gets a Todo item by ID", OperationId = "GetTodoById")]
        [ProducesResponseType(typeof(Todo), 200)]
        [ProducesResponseType(404)]
        public async Task<ActionResult<Todo>> GetTodo(int id)
        {
            var todo = await _context.Todo.FindAsync(id);
    
            if (todo == null)
            {
                return NotFound();
            }
    
            return todo;
        }
    
    
    // POST: api/todos
    [HttpPost("api/todos")]
    [ProducesResponseType(StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [SwaggerOperation(Summary = "Creates a new todo item.", Description = "Creates a new todo item and returns it.", OperationId = "CreateTodo")]
    public async Task<IActionResult> CreateTodo([FromBody] Todo todo)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        _context.Add(todo);
        await _context.SaveChangesAsync();
        return CreatedAtAction(nameof(GetTodo), new { id = todo.ID }, todo);
    }
    
    // PUT: api/todos/{id}
    [HttpPut("api/todos/{id}")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [SwaggerOperation(Summary = "Updates a todo item.", Description = "Updates an existing todo item by ID.", OperationId = "UpdateTodo")]
    public async Task<IActionResult> UpdateTodo(int id, [FromBody] Todo todo)
    {
        // Use the id from the URL fragment only, ignore mismatching check
        if (!TodoExists(id))
        {
            return NotFound();
        }
        todo.ID = id;
        _context.Entry(todo).State = EntityState.Modified;
        await _context.SaveChangesAsync();
        return NoContent();
    }
    
    // DELETE: api/todos/{id}
    [HttpDelete("api/todos/{id}")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [SwaggerOperation(Summary = "Deletes a todo item.", Description = "Deletes a todo item by ID.", OperationId = "DeleteTodo")]
    public async Task<IActionResult> DeleteTodo(int id)
    {
        var todo = await _context.Todo.FindAsync(id);
        if (todo == null)
        {
            return NotFound();
        }
        _context.Todo.Remove(todo);
        await _context.SaveChangesAsync();
        return NoContent();
    }
    
  3. Controllers/TodosController.cs の上部に、次のコマンドを追加します。

    using Swashbuckle.AspNetCore.Annotations;
    

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

  4. Program.csで、Swagger ジェネレーター サービスを登録します。 これにより、API の OpenAPI ドキュメントが有効になり、Foundry Agent Service が API を理解できるようになります。 サーバーの URL を必ず指定してください。 Foundry Agent Service には、サーバー URL を含むスキーマが必要です。

    builder.Services.AddSwaggerGen(c =>
    {
        c.EnableAnnotations();
        var websiteHostname = Environment.GetEnvironmentVariable("WEBSITE_HOSTNAME");
        if (!string.IsNullOrEmpty(websiteHostname))
        {
            c.AddServer(new Microsoft.OpenApi.Models.OpenApiServer { Url = $"https://{websiteHostname}" });
        }
    });
    
  5. Program.csで、Swagger ミドルウェアを有効にします。 このミドルウェアは、生成された OpenAPI ドキュメントを実行時に提供し、ブラウザー経由でアクセスできるようにします。

    app.UseSwagger();
    app.UseSwaggerUI();
    
  6. codespace ターミナルで、 dotnet runを使用してアプリケーションを実行します。

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

  8. URL に /swagger/index.html を追加して、Swagger UI に移動します。

  9. Swagger UI で試して、API 操作が機能することを確認します。

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

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

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

これらの手順では、新しい Foundry ポータルを使用します。

  1. Foundry ポータルの右上のメニューで、[New Foundry] を選択します。

  2. 新しい Foundry ポータルでこれが初めての場合は、プロジェクト名を選択し、[ 新しいプロジェクトの作成] を選択します。

  3. プロジェクトに名前を付け、[ 作成] を選択します。

  4. [ ビルドの開始]、[ エージェントの作成] の順に選択します。

  5. エージェントに名前を付け、[ 作成] を選択します。 エージェントの準備ができたら、エージェントのプレイグラウンドが表示されます。

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

  6. エージェントのプレイグラウンドで、[ ツール ] を展開し、[ 追加>Custom>OpenAPI ツール>Create を選択します。

  7. ツールに名前と説明を付けます。 OpenAPI 3.0 以降のスキーマ ボックスに、先ほどコピーしたスキーマを貼り付けます。

  8. [ 作成ツール] を選択します。

  9. 保存 を選択します。

ヒント

このチュートリアルでは、認証なしでアプリを匿名で呼び出すように OpenAPI ツールを構成します。 運用シナリオでは、マネージド ID 認証を使用してツールをセキュリティで保護する必要があります。 詳細な手順については、「 Foundry Agent Service の OpenAPI エンドポイントをセキュリティで保護する」を参照してください。

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

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

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

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

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

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

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

  • 認証と承認: Microsoft Entra 認証を使用して OpenAPI エンドポイントを保護します。 詳細な手順については、「 Foundry Agent Service の OpenAPI エンドポイントをセキュリティで保護する」を参照してください。 また、 Microsoft Entra ID を使用して Azure API Management の背後にあるエンドポイントを保護し、承認されたユーザーまたはエージェントのみがツールにアクセスできるようにすることもできます。
  • 入力データを検証します。このサンプル コードでは、ModelState.IsValid メソッドのCreateTodoをチェックします。これにより、受信データがモデルの検証属性と一致することを確認します。 詳細については、「 ASP.NET Core でのモデルの検証」を参照してください。
  • 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 セキュリティのベスト プラクティスに関する説明を参照してください。

次のステップ

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

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

その他のリソース