![]()
これまでのコースでは、ラップトップ上やノートブック内で、az login といくつかの環境変数で動くエージェントを構築してきました。それは学習には最適な方法です。しかし、深夜3時に何千人もの顧客が依存するエージェントを動かすには適切な方法ではありません。
このレッスンでは、「自分のマシンでは動く」から「本番環境で信頼性高く費用対効果良く動く」までのギャップを埋める方法を扱います。Microsoft Foundry と Microsoft Foundry Agent Service を用い、本物のカスタマーサポートエージェントを構築し、ツール、検索、メモリ、評価、モニタリングを組み込みます。
このレッスンでは以下をカバーします:
本レッスン修了後には以下が可能になります:
本レッスンは以前のレッスンを終えており、以下に慣れていることを想定しています:
さらに以下が必要です:
az login)。requirements.txt にあるパッケージ。プロトタイプエージェントと本番エージェントは核となるループ — 推論、ツール呼び出し、応答 — は同じです。ただしそのループを囲む運用部分が変わります。モデルは本番エージェントの約20%、残りの80%は運用の骨格です。
| 項目 | プロトタイプ | 本番 |
|---|---|---|
| ホスティング | ノートブック内で実行 | ホストされたサービスとして実行、バージョン管理・ロールアウトする |
| ID | あなたの az login トークン |
スコープ付き RBAC の管理ID |
| 状態 | インメモリ、再起動で消失 | 外部化(スレッドストア、メモリサービス) |
| 障害対応 | トレースバックを確認 | リトライ、フォールバック、デッドレター、アラート |
| コスト | 「数セント程度」 | リクエストごとに追跡、ルーティング、キャッシュ、予算管理 |
| 品質 | 出力を目視確認 | リリース前に自動評価 |
| 信頼 | すべて自身で承認 | ポリシー+リスクの高い操作は人間介入あり |
この表を心に留めてください。以下の各セクションはこの表のいずれかの行に対応しています。
よく使うパターンが三つあり、多くの場合は組み合わせて使います。
エージェントオブジェクトが あなたの アプリケーションプロセス内に存在します。コードは直接モデルプロバイダーを呼び出し、推論ループはあなたのサービスで実行されます。これまでの授業がまさにこの方法でした。
エージェントは Microsoft Foundry にリソースとして登録されます。Foundry が推論ループをホストし、スレッドを保存し、コンテンツ安全性とRBACを強制し、Foundryポータルにエージェントを表示します。アプリはスレッドを作成し応答を読む薄いクライアントになります。
複数のエージェント(とツール)が明示的な制御フローで合成されます — 逐次ステップ、分岐、人間の承認ノード、ポーズと再開が可能な耐久性のあるチェックポイント。これは Microsoft Agent Framework の Workflows 機能を大規模に適用したものです。
flowchart TB
subgraph P1[クライアントホスト型]
A1[あなたのアプリプロセス] --> M1[モデルプロバイダー]
end
subgraph P2[ホスト型エージェント]
A2[シンクライアント] --> F2[ファウンドリエージェントサービス]
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 から持ち越された重要な考え方は次の通りです:オフライン評価は付け足しではなくゲートです。 新しいエージェントバージョンは評価の敷居をクリアしないと出荷されません。オンライン監視は実際の故障をオフラインテストセットにフィードバックします。これが一連のループです。
エージェントのスケーリングはステートレスなウェブAPIのスケーリングとは異なります。なぜなら各リクエストが複数の高コストなモデルやツール呼び出しをトリガーする可能性があるためです。主に四つのテクニックがあります。
ステートレスリクエスト処理。 ユーザーごとの状態をプロセスメモリに持たず、会話スレッドは 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 のような属性は、膨大なトレースを意味のある問いに変えます(「エンタープライズ顧客は小さなモデルに送り過ぎていないか?」)。
本番エージェントのコストはトークンが支配的です。三つのレバーがあり、影響力の順に:
評価ゲートとコスト制御は同じ規律を異なる視点で見たものです:評価で品質の下限を定め、ルーティングとキャッシュでそのコストを可能な限り近づける。
ガバナンス。 Hosted Agents は Foundry の RBAC、コンテンツ安全性、監査ログを継承します。各エージェントに最小特権の管理IDを割り当てます — ナレッジベースへの読み取りのみアクセス、チケッティングAPIへのスコープ付きアクセス、不要な権限はなし。
人間の介入。 全自動では重大すぎる操作(返金発行、アカウント削除、法務チームへのエスカレーションなど)もあります。Microsoft Agent Framework は承認必須ツールをサポートし、エージェントが操作を提案し、実行を一時停止、人間が承認・拒否し、ワークフローが再開されます。レッスン6で基礎をご覧になりましたが、ここで実際にデプロイします。
本番での MCP。 MCP は標準インタフェースを通じて外部ツールを利用可能にします。本番ではすべての MCP サーバーを信頼できない境界として扱い、サーバーバージョンを固定し、スコープ付きIDで実行し、出力を検証、秘密情報を決して渡さないようにします。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 Search RAG]
F2 --> F5[メモリーサービス]
F2 --> F6[MCPツール]
F2 --> F7[OTel -> Foundryトレース]
F2 --> F8[人間の承認]
end
これら三つの図 — 開発、デプロイ、ランタイム — は同一エージェントの三段階の姿です。続くラボで構築方法を案内します。
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 プロジェクトのエンドポイントとエージェント名を入力してください。フェデレーテッド ID には Foundry プロジェクトのスコープで Azure AI User ロールが必要です。レイヤーをピラミッドのように考えてください。スモークテスト(到達可能で応答しているか?)はすべてのデプロイで実行され、オフライン評価(出荷に十分か?)は昇格前に実行され、オンライン評価(実際の運用でどうか?)は継続的に実行されます。
課題に進む前に理解度を確認しましょう。
1. 本番用エージェントのうち「モデル」は大まかにどれくらいの割合で、残りは何ですか?
2. クライアントホスト型エージェントよりホスト型エージェントを選ぶのはどんな時ですか?
3. なぜスケーラブルなエージェントではプロセスメモリ内でステートレスでなければならないのですか?
4. モデルルーティングはどんな問題を解決し、評価とはどう関係していますか?
5. 「評価ゲート(evaluation gate)」とは何で、ライフサイクルのどこに位置しますか?
6. なぜ MCP サーバーは本番環境で信頼されていない境界として扱うべきですか?
7. 本番エージェントのコストに最も大きな影響を与える単一の変更は何で、なぜですか?
8. customer.tier や routed.model のようなスパン属性は可観測性でどんな役割を果たしますか?
ラボのカスタマーサポートエージェントを取り、特定のシナリオに対して強化してください:SaaS 企業向けのサブスクリプション請求サポートエージェント。
提出内容は以下を含むべきです:
get_subscription_status、get_invoice、issue_credit(50ドル超のクレジットは人間の承認が必要)。どのモデルルーティングルールを選んだか、実際のトラフィックでどう検証するかを短い段落(マークダウンセル)で説明してください。正解は1つではなく、本番環境の課題を論理的に結びつけられているかが評価されます。
このレッスンでは Microsoft Foundry を使ってエージェントをプロトタイプから本番へ移行しました:
次のレッスンでは逆の道をたどります:エージェントをクラウドにスケールアップするのではなく、単一開発者のマシンにダウンサイズし、完全にローカルで実行します。
免責事項: 本書類は AI 翻訳サービス Co-op Translator を使用して翻訳されています。正確性を期していますが、自動翻訳には誤りや不正確な部分が含まれる可能性があることをご承知おきください。原文の原語版が正式な情報源とみなされるべきです。重要な情報については、専門の人間による翻訳を推奨します。本翻訳の利用により生じたいかなる誤解や解釈違いについても、当方は責任を負いかねます。