![]()
このコースのここまでで、ノートパソコンやノートブック内で動作し、az loginやいくつかの環境変数により動作するエージェントを構築してきました。それは学習を進めるうえで正しい方法ですが、何千人もの顧客が午前3時に依存するエージェントを動かす上では正しい方法ではありません。
このレッスンは「私のマシンでは動く」と「本番環境で信頼性とコスト効率を持って動く」とのギャップについての話です。このギャップをMicrosoft FoundryとMicrosoft Foundry Agent Serviceを使って埋め、ツール、検索、メモリ、評価、モニタリングを備えた実際のカスタマーサポートエージェントを構築していきます。
このレッスンで学ぶ内容は次の通りです:
このレッスンを終了すると、以下ができるようになります:
このレッスンは以下を完了し、慣れていることを前提としています:
さらに以下が必要です:
az login)requirements.txtプロトタイプエージェントと本番エージェントは同じコアループ — 推論、ツール呼び出し、応答 — を共有します。変わるのはそのループを取り囲むすべての部分です。モデルは本番エージェントの約20%で、残りの80%は運用の骨組みです。
| 懸念事項 | プロトタイプ | 本番 |
|---|---|---|
| ホスティング | ノートブック内で動作 | ホストサービスとして動作し、バージョン管理と展開がされる |
| ID | あなたの az login トークン |
スコープ付きRBACのマネージドID |
| 状態 | メモリ上にあり、再起動で失われる | 外部化(スレッドストア、メモリサービス) |
| 障害 | トレースバックを見られる | リトライ、フォールバック、デッドレター、アラート |
| コスト | 「数セント程度」 | リクエストごとに追跡し、ルーティング、キャッシュ、予算管理 |
| 品質 | 出力を目視で確認 | リリース前に自動評価される |
| 信頼 | すべての操作を承認する | ポリシー + リスクの高い操作には人間のインザループ |
この表を覚えておいてください。以下の各セクションはこの表のいずれかの行に対応しています。
よく使われるパターンは3つあり、しばしば組み合わせて使います。
エージェントオブジェクトはあなたのアプリケーションプロセス内に存在します。あなたのコードがモデルプロバイダを直接呼び出し、推論ループはあなたのサービス内で動作します。これがこれまでのすべてのレッスンで行ってきたことです。
エージェントはMicrosoft Foundry上で「リソースとして登録」されます。Foundryが推論ループをホストし、スレッドを保存し、コンテンツの安全性とRBACを強制し、Foundryポータル上にエージェントを可視化します。あなたのアプリはスレッドを作成し応答を読み取る薄いクライアントになります。
複数のエージェント(およびツール)を明確な制御フローでグラフ状に組み合わせます — 順次ステップ、分岐、人間の承認ノード、途中で一時停止/再開可能な永続的チェックポイント。これはMicrosoft Agent FrameworkのWorkflows機能をデプロイ規模に応用したものです。
flowchart TB
subgraph P1[Client-Hosted]
A1[Your App Process] --> M1[Model Provider]
end
subgraph P2[Hosted Agent]
A2[Thin Client] --> F2[Foundry Agent Service]
F2 --> M2[Model + Tools + Thread Store]
end
subgraph P3[Agent Workflow]
A3[Orchestrator] --> S1[Triage Agent]
S1 --> S2[Resolver Agent]
S2 --> H[Human Approval Node]
H --> S3[Action Agent]
end
エージェントのデプロイは一度きりのpushではありません。ループであり、ソフトウェアリリースサイクルに非常によく似ています。なぜならまさにそれだからです。
flowchart LR
Create[Create / Author] --> Version[Version]
Version --> Evaluate[Evaluate offline]
Evaluate -->|passes gate| Deploy[Deploy hosted]
Evaluate -->|fails gate| Create
Deploy --> Observe[Observe online]
Observe --> Improve[Collect failures]
Improve --> Create
Deploy --> Retire[Retire old version]
レッスン10からの重要な考え方:オフライン評価は後付けではなくゲートである。 新しいエージェントバージョンは評価の閾値をクリアしなければ出荷されません。オンライン可観測性は実際の失敗をオフラインテストセットにフィードバックします。これが全体のループです。
エージェントのスケーリングはステートレスなWeb APIのスケーリングと異なります。各リクエストが複数のコストが高いモデルやツール呼び出しを引き起こす可能性があるためです。主に4つの技術で対応します。
ステートレスリクエスト処理。 ユーザーごとの状態をプロセスメモリに保持せず、Foundryのスレッドストアやメモリサービスに会話スレッドを保持してどのインスタンスでもリクエストを処理可能にします。これにより水平スケールが可能になり、インスタンス追加とステッキーセッション不要になります。
モデルルーティング。 すべてのリクエストが最も高機能で高コストなモデルを使う必要はありません。単純なリクエスト(意図分類や短い事実回答)は小さく高速なモデルへ、複雑な推論は大きなモデルへルーティングします。FoundryのModel Routerがこれをサポートします。実習で軽量の分類器を自作します。
応答キャッシュ。 多くのサポート問い合わせはほぼ同じ内容(「パスワードをリセットするには?」)。よくある質問の回答をキャッシュし、モデルを呼ばずに応答します。適度なキャッシュヒット率でもコストと遅延を大きく削減できます。
同時実行制御とバックプレッシャー。 モデルプロバイダはレート制限を持ちます。同時実行数を制限し、指数的バックオフ付きリトライを使い、優雅に失敗する(キューイングされた「対応中」応答は500エラーより良い)よう設計します。
flowchart LR
Q[User query] --> C{Cache hit?}
C -->|yes| R[Return cached answer]
C -->|no| Router{Complexity?}
Router -->|simple| SLM[Small model]
Router -->|complex| LLM[Large model]
SLM --> Out[Response]
LLM --> Out
Out --> Store[Cache + trace]
見えないものは運用できません。レッスン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")
# agent execution is traced automatically inside this span
customer.tierやrouted.modelのような属性は、トレースの山を答えの出る質問に変えます(「企業顧客は小さいモデルに偏りすぎていないか?」など)。
本番エージェントのコストはトークン数が主因です。影響の大きい順に3つのレバーがあります:
評価ゲートとコスト管理は2つの視点からみた同じ教訓:評価は品質の底上げ、ルーティングとキャッシュはこの底のコストをできる限り押さえる。
ガバナンス。 Hosted AgentsはFoundryのRBAC、コンテンツ安全性、監査ログを受け継ぎます。各エージェントに必要最低限の権限のマネージドIDを付与します — ナレッジベースへの読み取り専用アクセス、チケッティングAPIへのスコープ付きアクセスそれ以上は不要。
人間を介した承認。 返金発行、アカウント削除、法務チームへのエスカレーションなどは自動化に不向きです。Microsoft Agent Frameworkは承認必須ツールをサポート:エージェントが操作を提案し、実行は一時停止、人間が承認または拒否し、ワークフローが継続します。レッスン6でプリミティブを見ましたが、ここで実際にデプロイします。
本番環境のMCP。 MCPは標準インターフェースで外部ツール利用を可能にします。本番ではMCPサーバを信頼できない境界として扱い、サーバーバージョンを固定し、スコープ付きIDで実行し、出力を検証し、秘密情報を渡さないようにします。MCPサーバは依存関係であり、パッチ、監査、レート制限がかかります。
flowchart TB
subgraph Dev[Development Architecture]
D1[Notebook] --> D2[Agent Framework]
D2 --> D3[Model Provider]
D2 --> D4[Local tools]
end
subgraph Deploy[Deployment Architecture]
E1[CI pipeline] --> E2[Evaluation gate]
E2 -->|pass| E3[Foundry Agent Service]
E3 --> E4[Versioned hosted agent]
end
subgraph Run[Runtime Architecture]
F1[Client app] --> F2[Hosted agent]
F2 --> F3[Model Router]
F2 --> F4[Azure AI Search RAG]
F2 --> F5[Memory service]
F2 --> F6[MCP tools]
F2 --> F7[OTel -> Foundry tracing]
F2 --> F8[Human approval]
end
これら3つの図 — 開発、デプロイ、ランタイム — は同一エージェントの3つのライフステージを表します。続く実習で構築を案内します。
code_samples/16-python-agent-framework.ipynbを開き、最初から最後まで取り組んでください。すべての本番課題が組み込まれたContosoカスタマーサポートエージェントを組み立てます:
ノートブックは各本番課題ごとに独立した実行可能セクションとして構成されています。中心となるのはルーティングとキャッシュを組み合わせたリクエストハンドラです:
async def handle_support_request(query: str, customer_id: str) -> str:
# 1. Serve from cache when we can.
cached = response_cache.get(normalize(query))
if cached:
return cached
# 2. Route by complexity to control cost.
model = "gpt-5-nano" if is_simple(query) else "gpt-5-mini"
# 3. Run the agent inside a trace span for observability.
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. Cache and return.
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 # only deploy if the gate passes
すべての行を読むこと — ノートブックはプリミティブをあえて小さくして、フレームワーク呼び出しの背後に何も隠さないようにしています。
上の評価ゲートはエージェントオブジェクトに対してオフラインで実行されます。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. 「評価ゲート」とは何で、ライフサイクルのどこに位置しますか?
6. なぜMCPサーバーは本番環境で信頼できない境界として扱うべきですか?
7. 通常、プロダクションエージェントのコストに最も大きな影響を与える単一の変更は何で、なぜですか?
8. customer.tier や routed.model のようなスパン属性は可観測性でどんな役割を果たしますか?
ラボのカスタマーサポートエージェントを特定のシナリオ用に強化してください:SaaS企業向けのサブスクリプション請求サポートエージェント。
提出内容は以下を含みます:
get_subscription_status、get_invoice、issue_credit(50ドル超えのクレジットは人の承認が必要)。短い段落(マークダウンセル)で、選んだモデルルーティングルールと実際のトラフィックでの検証方法を説明してください。正解は一つではなく、プロダクションの懸念が一貫しているかどうかで評価します。
このレッスンでは、Microsoft Foundry を使ってエージェントをプロトタイプからプロダクションへ移行しました:
次のレッスンは逆の旅をたどります:エージェントをクラウドでスケールアップする代わりに、一台の開発者マシンにダウンさせ、完全にローカルで実行します。
免責事項: 本書類は AI 翻訳サービス Co-op Translator を使用して翻訳されています。正確性を期していますが、自動翻訳には誤りや不正確な部分が含まれる可能性があることをご承知おきください。原文の原語版が正式な情報源とみなされるべきです。重要な情報については、専門の人間による翻訳を推奨します。本翻訳の利用により生じたいかなる誤解や解釈違いについても、当方は責任を負いかねます。