![]()
このコースのここまでで、az loginといくつかの環境変数により駆動される、ラップトップ上やノートブック内で動作するエージェントを構築してきました。それは学習にはまさに正しい方法です。しかし、何千もの顧客が午前3時に依存するエージェントを実行するための正しい方法ではありません。
このレッスンは、「自分のマシンでは動く」ことと「本番環境で安定的かつ手頃に動作する」ことのギャップについてです。このギャップをMicrosoft FoundryとMicrosoft Foundry Agent Serviceを使って埋め、ツール、検索、メモリ、評価、モニタリングを備えた実際のカスタマーサポートエージェントを構築することで実現します。
このレッスンでは以下を扱います:
このレッスンを終えると、以下ができるようになります:
このレッスンは、以下に精通していることを前提とします:
また、以下も必要です:
az login)。requirements.txt に記載されたパッケージ。プロトタイプエージェントと本番エージェントは、同じコアループ — 推論、ツール呼び出し、応答 — を共有します。変わるのはそのループの周りにあるすべてです。モデルは本番エージェントの20%程度で、残りの80%は運用の骨格です。
| 関心事 | プロトタイプ | 本番 |
|---|---|---|
| ホスティング | ノートブック内で動作 | ホストされたサービスとして動作、バージョン管理とローリングアウト有り |
| アイデンティティ | あなたのaz loginトークン |
スコープ付きRBACを持つマネージドアイデンティティ |
| 状態 | メモリ上、一旦再起動すると消える | 外部化(スレッドストア、メモリサービス) |
| 失敗時 | トレースバックを確認可能 | リトライ、フォールバック、デッドレター、アラート |
| コスト | 「数セント程度」 | リクエスト単位で追跡、ルーティング、キャッシュ、予算管理 |
| 品質 | 出力を目視確認 | 毎リリース前に自動評価 |
| 信頼 | あなたがすべてのアクションを承認 | ポリシーとリスクのあるアクションに対する人間の確認 |
この表を心に留めておいてください。以下の各セクションはこれらの行のいずれかに対応しています。
よく使われる3つのパターンがあり、組み合わせて使うことも多いです。
エージェントオブジェクトはあなたのアプリケーションプロセス内にあります。コードがモデルプロバイダーを直接呼び出し、推論ループはあなたのサービス内で動作します。これがこれまでのすべてのレッスンで行ってきた方法です。
エージェントはMicrosoft Foundryのリソースとして登録されます。Foundryが推論ループをホストし、スレッドを保存し、コンテンツの安全性とRBACを適用し、エージェントをFoundryポータルで可視化します。あなたのアプリはスレッドを作成し応答を読む薄いクライアントになります。
複数のエージェント(およびツール)が明示的な制御フローを持つグラフに構成されます — 順次ステップ、分岐、人間承認ノード、および一時停止・再開可能な耐久チェックポイント。これは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
エージェントをデプロイすることは一度きりの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.tierやrouted.modelといった属性が、単なるトレースの塊を「企業顧客が小型モデルに過剰にルーティングされていないか?」のような答えを導く問いに変えます。
本番エージェントのコストはトークンに支配されます。影響の大きい順に三つのレバー:
評価ゲートとコスト管理は二つの視点から見た同じ 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カスタマーサポートエージェントを組み立てます:
ノートブックは各本番懸念が自己完結した実行可能なセクションになるように整理されています。中心はルーティングとキャッシュを組み合わせたリクエストハンドラーです:
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を利用した使い勝手の良いスモークテストパイプラインを提供しています:
tests/lesson-16-smoke-tests.json はContosoサポートエージェント用のプロンプトとアサーションを含みます(原則に基づくポリシー回答、注文検索、話題維持、複数ターンスレッドの継続性)。他のレッスンのカタログも並存しています — 詳細はtests/README.mdをご覧ください。.github/workflows/smoke-test.yml はAzure OIDCでログインし、すべてのプロンプトをエージェントのResponsesエンドポイントにPOSTし、アサーション失敗時はジョブを失敗させます。- 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. プロダクションエージェントのうち、「モデル」はおおよそどの程度の割合で、残りは何ですか?
2. クライアントホスト型エージェントよりも Hosted Agent を選ぶのはどんな場合ですか?
3. なぜスケーラブルなエージェントは自身のプロセスメモリにステートレスである必要がありますか?
4. モデルルーティングはどんな問題を解決し、評価とどう関連していますか?
5. 「評価ゲート」とは何で、ライフサイクルのどこに位置しますか?
6. なぜ MCP サーバーはプロダクションで信頼できない境界として扱うべきですか?
7. プロダクションエージェントのコストに通常最も大きな影響を与える単一の変更は何で、なぜですか?
8. customer.tier や routed.model といったスパン属性は可観測性でどんな役割を果たしますか?
ラボのカスタマーサポートエージェントを取り、ある特定のシナリオで強化してください:SaaS 会社のサブスクリプション請求サポートエージェント。
提出には次を含めてください:
get_subscription_status、get_invoice、issue_credit ($50 以上のクレジットは人の承認が必要)。どのモデルルーティングルールを選び、それを実際のトラフィックでどう検証するかを説明する短いパラグラフ(マークダウンセル)を書いてください。正解は一つとは限らず、プロダクション上の懸念が一貫して組み合わされているかどうかが評価されます。
このレッスンでは、Microsoft Foundry を使いエージェントをプロトタイプからプロダクションに移行しました:
次のレッスンでは逆の旅をします:クラウドでエージェントをスケールアップする代わりに、単一の開発者マシン上で完全にローカルに実行します。
Building Computer Use Agents (CUA)
免責事項: 本書類は AI 翻訳サービス Co-op Translator を使用して翻訳されています。正確性を期していますが、自動翻訳には誤りや不正確な部分が含まれる可能性があることをご承知おきください。原文の原語版が正式な情報源とみなされるべきです。重要な情報については、専門の人間による翻訳を推奨します。本翻訳の利用により生じたいかなる誤解や解釈違いについても、当方は責任を負いかねます。