ai-agents-for-beginners

Microsoft Foundryでスケーラブルなエージェントをデプロイする

スケーラブルなエージェントのデプロイ

このコースのここまでで、az loginといくつかの環境変数により駆動される、ラップトップ上やノートブック内で動作するエージェントを構築してきました。それは学習にはまさに正しい方法です。しかし、何千もの顧客が午前3時に依存するエージェントを実行するための正しい方法ではありません。

このレッスンは、「自分のマシンでは動く」ことと「本番環境で安定的かつ手頃に動作する」ことのギャップについてです。このギャップをMicrosoft FoundryMicrosoft Foundry Agent Serviceを使って埋め、ツール、検索、メモリ、評価、モニタリングを備えた実際のカスタマーサポートエージェントを構築することで実現します。

はじめに

このレッスンでは以下を扱います:

学習目標

このレッスンを終えると、以下ができるようになります:

前提条件

このレッスンは、以下に精通していることを前提とします:

また、以下も必要です:

プロトタイプから本番へ:実際に何が変わるのか

プロトタイプエージェントと本番エージェントは、同じコアループ — 推論、ツール呼び出し、応答 — を共有します。変わるのはそのループの周りにあるすべてです。モデルは本番エージェントの20%程度で、残りの80%は運用の骨格です。

関心事 プロトタイプ 本番
ホスティング ノートブック内で動作 ホストされたサービスとして動作、バージョン管理とローリングアウト有り
アイデンティティ あなたのaz loginトークン スコープ付きRBACを持つマネージドアイデンティティ
状態 メモリ上、一旦再起動すると消える 外部化(スレッドストア、メモリサービス)
失敗時 トレースバックを確認可能 リトライ、フォールバック、デッドレター、アラート
コスト 「数セント程度」 リクエスト単位で追跡、ルーティング、キャッシュ、予算管理
品質 出力を目視確認 毎リリース前に自動評価
信頼 あなたがすべてのアクションを承認 ポリシーとリスクのあるアクションに対する人間の確認

この表を心に留めておいてください。以下の各セクションはこれらの行のいずれかに対応しています。

エージェントのデプロイメントパターン

よく使われる3つのパターンがあり、組み合わせて使うことも多いです。

1. クライアントホスト型エージェント

エージェントオブジェクトはあなたのアプリケーションプロセス内にあります。コードがモデルプロバイダーを直接呼び出し、推論ループはあなたのサービス内で動作します。これがこれまでのすべてのレッスンで行ってきた方法です。

2. ホスト型エージェント(Foundry Agent Service)

エージェントはMicrosoft Foundryのリソースとして登録されます。Foundryが推論ループをホストし、スレッドを保存し、コンテンツの安全性とRBACを適用し、エージェントをFoundryポータルで可視化します。あなたのアプリはスレッドを作成し応答を読む薄いクライアントになります。

3. エージェントワークフロー

複数のエージェント(およびツール)が明示的な制御フローを持つグラフに構成されます — 順次ステップ、分岐、人間承認ノード、および一時停止・再開可能な耐久チェックポイント。これはMicrosoft Agent FrameworkのWorkflows機能をデプロイメント規模に適用したものです。

flowchart TB
    subgraph P1[クライアントホスト型]
        A1[あなたのアプリプロセス] --> M1[モデルプロバイダー]
    end
    subgraph P2[ホストエージェント]
        A2[シンクライアント] --> F2[Foundryエージェントサービス]
        F2 --> M2[モデル+ツール+スレッドストア]
    end
    subgraph P3[エージェントワークフロー]
        A3[オーケストレーター] --> S1[トリアージエージェント]
        S1 --> S2[リゾルバーエージェント]
        S2 --> H[人間承認ノード]
        H --> S3[アクションエージェント]
    end

Microsoft Foundryにおけるエージェントライフサイクル

エージェントをデプロイすることは一度きりのpushではありません。ループであり、まさにソフトウェアのリリースサイクルととても似ています。

flowchart LR
    Create[作成 / 作者] --> Version[バージョン]
    Version --> Evaluate[オフラインで評価]
    Evaluate -->|ゲートを通過| Deploy[ホスティングにデプロイ]
    Evaluate -->|ゲートに失敗| Create
    Deploy --> Observe[オンラインで監視]
    Observe --> Improve[失敗を収集]
    Improve --> Create
    Deploy --> Retire[古いバージョンを廃止]

レッスン10から引き継がれた重要な考え方:オフライン評価は後回しではなくゲートである。 新しいエージェントバージョンは評価基準をクリアしない限りリリースされません。オンラインの可観測性がリアルな障害をオフラインのテストセットにフィードバックします。これがループの全体像です。

スケーリング戦略

エージェントのスケールはステートレスなWeb APIのスケールとは異なります。なぜなら、各リクエストが複数の高コストなモデルやツール呼び出しを引き起こす可能性があるためです。主な4つの技法があります。

ステートレスなリクエスト処理。 プロセスメモリにユーザーごとの状態を持たないようにします。会話のスレッドはFoundryのスレッドストアやメモリサービスに永続化し、どのインスタンスでも任意のリクエストを処理できるようにします。これにより水平スケールが可能になります — インスタンスを追加し、スティッキーセッションは不要です。

モデルルーティング。 すべてのリクエストで最も高性能かつ高価なモデルが必要とは限りません。シンプルなリクエスト(意図分類、短い事実回答など)を小型で高速なモデルに振り向け、本格的な推論には大型モデルを予約します。FoundryのModel Routerがこれを行うか、軽量な分類器を自作できます。ラボでDIY版を作ります。

応答キャッシュ。 多くのサポート問い合わせはほぼ重複しています(「パスワードをリセットするには?」など)。共通質問の答えをキャッシュし、モデルを呼び出さずに提供します。適度なキャッシュヒット率でもコストとレイテンシーを大幅に削減可能です。

同時実行とバックプレッシャー。 モデルプロバイダーにはレート制限があります。同時実行数を制限し、指数関数的バックオフを伴うリトライを使い、500エラーよりは「対応中」応答などで優雅に失敗します。

flowchart LR
    Q[ユーザーの問い合わせ] --> C{キャッシュヒット?}
    C -->|はい| R[キャッシュされた回答を返す]
    C -->|いいえ| Router{複雑さ?}
    Router -->|簡単| SLM[小規模モデル]
    Router -->|複雑| LLM[大規模モデル]
    SLM --> Out[応答]
    LLM --> Out
    Out --> Store[キャッシュ + トレース]

本番環境での可観測性

見えないものは運用できません。レッスン10で扱ったように、Microsoft Agent FrameworkはOpenTelemetryトレースをネイティブに出力します — すべてのモデル呼び出し、ツール呼び出し、オーケストレーションステップがスパンになります。本番環境ではこれらのスパンをMicrosoft Foundry(または任意のOTel互換バックエンド)にエクスポートし、以下を実現します:

from agent_framework.observability import get_tracer

tracer = get_tracer()

with tracer.start_as_current_span("support_request") as span:
    span.set_attribute("customer.tier", "enterprise")
    span.set_attribute("routed.model", "gpt-5-nano")
    # このスパン内でエージェントの実行が自動的にトレースされます

customer.tierrouted.modelといった属性が、単なるトレースの塊を「企業顧客が小型モデルに過剰にルーティングされていないか?」のような答えを導く問いに変えます。

コスト最適化

本番エージェントのコストはトークンに支配されます。影響の大きい順に三つのレバー:

  1. モデルの適正サイズ。 評価ゲートを通過する小型モデルは、同様に通過する大型モデルよりほぼ常に安価です。最大モデルを無用に使うのではなく、小型モデルが十分良いことを評価で証明しましょう。
  2. 複雑度によるルーティング。 先述の通り、大型モデルの価格は大型推論をするリクエストのみに支払います。
  3. 積極的なキャッシュ。 最も安いモデル呼び出しは、一度も呼び出さないことです。

評価ゲートとコスト管理は二つの視点から見た同じ disciplina です:評価は品質の最低ラインを示し、ルーティングとキャッシュはそのコストを最低限に抑えます。

エンタープライズ向けデプロイメント配慮事項

ガバナンス。 Hosted AgentsはFoundryのRBAC、コンテンツ安全性、監査ログを受け継ぎます。各エージェントには必要最小限の権限を持つマネージドアイデンティティを付与します — ナレッジベースへの読み取り専用アクセス、チケットAPIへのスコープ付きアクセス、それ以上はなし。

人間による介入。 一部のアクションは完全自動化には重大すぎます — 返金発行、アカウント削除、法務チームへのエスカレーションなど。Microsoft Agent Frameworkは承認必須のツールをサポートします:エージェントがアクションを提案し、実行を一時停止、人間が承認または拒否し、ワークフローを再開。このプリミティブをレッスン6で見ましたが、ここでデプロイします。

本番環境でのMCP。 MCPは標準インターフェイスを通じて外部ツールを消費可能にします。本番ではすべてのMCPサーバーを信用されない境界として扱い、サーバーバージョンを固定し、スコープ付きアイデンティティで実行し、出力を検証し、秘密情報を渡さないようにします。MCPサーバーは依存関係であり、依存関係はパッチ適用、監査、レート制限されます。

flowchart TB
    subgraph Dev[開発アーキテクチャ]
        D1[ノートブック] --> D2[エージェントフレームワーク]
        D2 --> D3[モデルプロバイダー]
        D2 --> D4[ローカルツール]
    end
    subgraph Deploy[展開アーキテクチャ]
        E1[CIパイプライン] --> E2[評価ゲート]
        E2 -->|合格| E3[Foundry エージェントサービス]
        E3 --> E4[バージョン管理されたホストエージェント]
    end
    subgraph Run[ランタイムアーキテクチャ]
        F1[クライアントアプリ] --> F2[ホストエージェント]
        F2 --> F3[モデルルーター]
        F2 --> F4[Azure AI 検索 RAG]
        F2 --> F5[メモリーサービス]
        F2 --> F6[MCPツール]
        F2 --> F7[OTel -> Foundry トレーシング]
        F2 --> F8[人間の承認]
    end

これら3つの図 — 開発、デプロイメント、ランタイム — は同一エージェントの3段階の姿です。続くラボで構築を体験します。

実践ラボ:本番対応カスタマーサポートエージェント

code_samples/16-python-agent-framework.ipynb を開き、最初から最後まで実行してください。すべての本番上の懸念が組み込まれたContosoカスタマーサポートエージェントを組み立てます:

  1. ツール呼び出し — 注文状況の確認とサポートチケットの発行。
  2. RAG — ナレッジベース(Azure AI Searchを使用、メモリ内フォールバックも含むのでノートブック単独でも実行可能)からのポリシー質問への回答。
  3. メモリ — 会話のターン間で顧客を記憶。
  4. モデルルーティング — 複雑度分類器がリクエストを小型モデルまたは大型モデルへ振り分け。
  5. 応答キャッシュ — 繰り返される質問はキャッシュから提供。
  6. 人間承認 — 閾値を超える返金は人間の承認で一時停止。
  7. 評価パイプライン — 小規模なオフラインテストセットがエージェントを評価し、リリースゲートとして機能。
  8. 可観測性 — すべてのリクエストに対してOpenTelemetryトレース。

説明

ノートブックは各本番懸念が自己完結した実行可能なセクションになるように整理されています。中心はルーティングとキャッシュを組み合わせたリクエストハンドラーです:

async def handle_support_request(query: str, customer_id: str) -> str:
    # 1. 可能な場合はキャッシュから提供します。
    cached = response_cache.get(normalize(query))
    if cached:
        return cached

    # 2. コストを制御するために複雑さでルーティングします。
    model = "gpt-5-nano" if is_simple(query) else "gpt-5-mini"

    # 3. 可観測性のためにトレーススパン内でエージェントを実行します。
    with tracer.start_as_current_span("support_request") as span:
        span.set_attribute("routed.model", model)
        span.set_attribute("customer.id", customer_id)
        response = await support_agent.run(query, model=model)

    # 4. キャッシュして返します。
    response_cache.set(normalize(query), response.text)
    return response.text

リリースを守る評価ゲートは以下のようになります:

async def evaluation_gate(agent, test_cases, threshold: float = 0.8) -> bool:
    passed = 0
    for case in test_cases:
        result = await agent.run(case["input"])
        if score_response(result.text, case["expected"]) >= 0.8:
            passed += 1
    pass_rate = passed / len(test_cases)
    print(f"Evaluation pass rate: {pass_rate:.0%} (gate: {threshold:.0%})")
    return pass_rate >= threshold  # ゲートを通過した場合のみデプロイする

各行を読みましょう — ノートブックはプリミティブを意図的に小さくし、フレームワーク呼び出しの背後に隠れないようにしています。

デプロイ済みエージェントのスモークテストによる検証

上記の評価ゲートはエージェントオブジェクトに対してオフラインで実行されます。エージェントがHosted Agentとしてデプロイされたら、さらにもう一つ、さらに安価なチェックが必要です:デプロイされたエンドポイントが実際に応答しているか?

「正常に」デプロイされたことは、定義がコントロールプレーンに受け入れられただけを証明します — エージェントが応答していることは証明しません。依存関係欠如、誤ったモデルルーティング、切れた接続により、何も返さないグリーンデプロイメントになることがあります。スモークテストは数秒でそれを見抜き、すべてのデプロイで実行可能で、完全な評価より低コストです。

このリポジトリはAI Smoke Test GitHub Actionを利用した使い勝手の良いスモークテストパイプラインを提供しています:

- name: Smoke-test hosted agent
  uses: JFolberth/ai-smoketest@v1
  with:
    project_endpoint: $
    agent_name: ContosoSupportAgent
    tests_file: tests/lesson-16-smoke-tests.json

エージェントがデプロイされたら、Actions タブから実行し、Foundry プロジェクトのエンドポイントとエージェント名を指定します。フェデレーテッドアイデンティティには Foundry プロジェクトスコープでの Azure AI User ロールが必要です。これらのレイヤーはピラミッドのように考えてください:スモークテスト(到達可能かつ応答中?)はすべてのデプロイで実行され、オフライン評価(出荷に十分か?)は昇格前に実行され、オンライン評価(実際の環境での状況は?)は継続的に実行されます。

知識確認

課題に進む前に理解度をテストしましょう。

1. プロダクションエージェントのうち、「モデル」はおおよそどの程度の割合で、残りは何ですか?

回答 モデルはシステムの少数派で、一般的に約20%と言われています。残りは運用の骨格であり、ホスティングとバージョニング、アイデンティティとRBAC、外部化された状態、障害対応、コスト追跡、評価、そしてヒューマンインザループの制御です。プロダクションへの移行は主に推論ループの周囲にあるすべてを構築することです。

2. クライアントホスト型エージェントよりも Hosted Agent を選ぶのはどんな場合ですか?

回答 内蔵の耐久性(スレッドが持続し再開可能)、可観測性、コンテンツ安全性、RBAC を持つ管理されたランタイムが欲しく、推論ループの低レベル制御をある程度犠牲にしてでも運用面を減らしたい場合に適しています。完全なループ制御が必要な場合や既存バックエンドにエージェントを組み込む場合はクライアントホスト型が好ましいです。

3. なぜスケーラブルなエージェントは自身のプロセスメモリにステートレスである必要がありますか?

回答 どのインスタンスでも任意のリクエストを処理できるようにするためであり、これによりスティッキーセッションなしで水平スケーリングが可能になります。ユーザーごとの会話状態はスレッドストアやメモリサービスに外部化されます。状態がプロセスメモリ内にあった場合、再起動時に失われロード分散もできなくなります。

4. モデルルーティングはどんな問題を解決し、評価とどう関連していますか?

回答 ルーティングは単純なリクエストを小さく安価で高速なモデルに送信し、本格的な推論には大きなモデルを予約します。これによりレイテンシとコストの両方を制御します。評価は、小さいモデルがあるカテゴリーのリクエストに十分かを証明するもので、評価なしのルーティングは推測に過ぎません。

5. 「評価ゲート」とは何で、ライフサイクルのどこに位置しますか?

回答 評価ゲートは新しいエージェントバージョンに対してオフラインのテストセットを実行し、合格率が閾値をクリアしなければデプロイをブロックします。ライフサイクルの「バージョン」と「デプロイ」の間に位置し、品質を出荷後にチェックするのではなくリリースの前提条件にします。

6. なぜ MCP サーバーはプロダクションで信頼できない境界として扱うべきですか?

回答 それはエージェントが呼び出す外部依存だからです。バージョンを固定し、スコープ付きアイデンティティで実行し、出力を検証し、レート制限し、秘密情報を絶対に渡してはいけません—すべて他のサードパーティ依存に適用するのと同じ規律です。その出力はエージェントの推論に流れ込むため、未検証の信頼はセキュリティリスクになります。

7. プロダクションエージェントのコストに通常最も大きな影響を与える単一の変更は何で、なぜですか?

回答 適切なモデルサイズの選択—評価ゲートを通過する最小のモデルを使用することです。コストはトークンに支配されており、品質基準を満たす小さいモデルのほうが大きいモデルよりほぼ常に安価です。キャッシュやルーティングもコストをさらに減らしますが、最初の大きな効果は基本モデルの選択にあります。

8. customer.tierrouted.model といったスパン属性は可観測性でどんな役割を果たしますか?

回答 これらは生のトレースを答え可能なビジネス上の質問に変えます。属性がなければ膨大なスパンの壁ですが、あれば「エンタープライズ顧客は小さいモデルに送りすぎていないか?」「どのモデルが最も遅いリクエストを処理しているか?」などを問えます。属性は運用に重要な次元でテレメトリをスライスする方法です。

課題

ラボのカスタマーサポートエージェントを取り、ある特定のシナリオで強化してください:SaaS 会社のサブスクリプション請求サポートエージェント。

提出には次を含めてください:

  1. ツールを請求関連のものに置き換えるget_subscription_statusget_invoiceissue_credit ($50 以上のクレジットは人の承認が必要)。
  2. 3つの RAG ドキュメントを追加:会社の返金ポリシー、請求サイクル、キャンセルポリシーに関して。
  3. 評価セットを少なくとも8ケースに拡張し、そのうち最低2つは人の承認経路を必ずトリガーすること、評価ゲートが正しく合格または不合格を判定することを確認。
  4. 1つのコストレポートを追加:混合クエリを10回エージェントに通した後、小さいモデルに行った回数、大きいモデルに行った回数、キャッシュからサービスされた回数を表示。

どのモデルルーティングルールを選び、それを実際のトラフィックでどう検証するかを説明する短いパラグラフ(マークダウンセル)を書いてください。正解は一つとは限らず、プロダクション上の懸念が一貫して組み合わされているかどうかが評価されます。

まとめ

このレッスンでは、Microsoft Foundry を使いエージェントをプロトタイプからプロダクションに移行しました:

次のレッスンでは逆の旅をします:クラウドでエージェントをスケールアップする代わりに、単一の開発者マシン上で完全にローカルに実行します。

追加リソース

前のレッスン

Building Computer Use Agents (CUA)

次のレッスン

Creating Local AI Agents


免責事項: 本書類は AI 翻訳サービス Co-op Translator を使用して翻訳されています。正確性を期していますが、自動翻訳には誤りや不正確な部分が含まれる可能性があることをご承知おきください。原文の原語版が正式な情報源とみなされるべきです。重要な情報については、専門の人間による翻訳を推奨します。本翻訳の利用により生じたいかなる誤解や解釈違いについても、当方は責任を負いかねます。