履歴書と求人情報をもとに AI が模擬面接を行い、回答内容を評価してフィードバックする面接練習サンプル web アプリ
AI エージェントを作ること自体は、以前よりも簡単になってきました。しかし、それらを実際の本番運用のアプリケーションの一部としてデプロイすること (複数のサービス、永続的な状態管理、本番向けのインフラを含めた形で運用すること) になると、途端に複雑になります。
.NET コミュニティの開発者からも、ローカル環境でもクラウドでも動作する、クラウドネイティブな実運用レベルのサンプルが見たいという声が多く寄せられていました。
その声に応え、私たちはオープンソースのサンプルアプリ『Interview Coach (面接コーチ)』を作りました。模擬就職面接を行う AI チャット web アプリです。
このサンプルでは、本番運用を想定したサービスにおいて、以下の技術がどのように組み合わさるのかを示しています:
このアプリは、実際に動作する 面接シミュレーター です。AI コーチがユーザーに対して行動面や技術面の質問を行い、最後に面接パフォーマンスのまとめをフィードバックとして提供します。
この記事では、このアプリで使用している設計パターンと、それらがどのような課題を解決するのかを紹介します。
こちらから Interview Coach デモアプリ を試すことができます。
なぜ Microsoft Agent Framework なのか?
もしこれまで .NET で AI エージェントを開発してきたなら、おそらく Semantic Kernel や AutoGen、あるいはその両方を使ったことがあるでしょう。 Microsoft Agent Framework は、それらの次のステップにあたるフレームワークです。 このフレームワークは、同じチームによって開発されており、両プロジェクトをうまく統合して、1つのフレームワークにまとめたものです。
具体的には、
- AutoGen のエージェント抽象化
- Semantic Kernel のエンタープライズ機能
(状態管理、型安全性、ミドルウェア、テレメトリーなど)
を統合し、さらにマルチエージェントのオーケストレーションのためのグラフベースのワークフローを追加しています。
.NET 開発者にとってのメリットは次のとおりです:
- フレームワークが1つに統合: Semantic Kernel と AutoGen のどちらを使うか悩む必要がありません。
- 馴染みのある開発パターン: エージェントは dependency injection、IChatClient、そして ASP.NET アプリと同じホスティングモデルを利用します。
- 本番運用を前提とした設計: OpenTelemetry、ミドルウェアパイプライン、Aspire との統合が最初から用意されています。
- マルチエージェントのオーケストレーション: 逐次ワークフロー、並列実行、handoff パターン、グループチャットなどをサポートします。
Interview Coach は、これらの機能を単なる Hello World ではなく、実際のアプリケーションとしてまとめたサンプルです。
なぜ Microsoft Foundry なのか?
AI エージェントには、単にモデルがあれば良いわけではありません。インフラも必要です。
Microsoft Foundry は、AI アプリケーションを構築・管理するための Azure のプラットフォームであり、Microsoft Agent Framework の推奨バックエンドでもあります。
Foundry を使うと、次のような機能を1つのポータルで利用できます:
- モデルアクセス: OpenAI、Meta、Mistral などのモデルを1つのエンドポイントから利用できるカタログ
- Content safety (安全性): モデレーションや個人情報(PII)検出が組み込まれており、エージェントが問題のある出力をしないように制御。
- コスト最適化ルーティング: リクエストがタスクに最適なモデルへ自動的にルーティングされる
- 評価とファインチューニング: エージェントの品質を測定し、継続的に改善できる
- エンタープライズ向けガバナンス: Entra ID や Microsoft Defender による認証、アクセス制御、コンプライアンス
Interview Coach では、Foundry がエージェントを動かすモデルエンドポイントを提供しています。
エージェントコードは IChatClient インターフェースを利用しているため、Foundry はあくまで設定の選択肢の 1 つですが、最初から豊富なツールが揃っている点で最も便利な選択肢です。
Interview Coach は何をするアプリなのか?
Interview Coach は、模擬就職面接を行う対話型 AI です。
ユーザーが 履歴書(resume) と 応募先の職務内容(job description)を入力すると、そこから先はエージェントが面接プロセスを進めていきます。
- 情報収集(Intake): 履歴書と応募先の職務内容を収集します。
- 行動面接(Behavioral interview): あなたの経験に合わせて、 STAR メソッド (過去の行動を構造的に説明するための回答フレームワークで、Situation, Task, Action, Result の頭文字から来ている) に基づいた質問を行います。
- 技術面接(Technical interview): 応募する職種に応じた技術的な質問を行います。
- まとめ(Summary): 面接のパフォーマンス (成績) を評価し、具体的なフィードバックを含むレビューを生成します。
ユーザーは、このシステムと Blazor の Web UI を通して対話します。 AI の回答は リアルタイムでストリーミング表示されます。
余談: Behavioral Interview とは
Behavioral Interview(行動面接/行動事例面接)とは、応募者の「過去の具体的な行動」を深掘りし、その人の行動特性、スキル、考え方が企業の求める人材像と適合しているかを判断する面接手法です。
単なる知識や志望動機ではなく、「ストレスを感じた時どう対処したか」など過去の事実に基づき、将来のパフォーマンスを予測します。
アーキテクチャ概要
このアプリケーションは、複数のサービスに分割されており、すべて Aspire によってオーケストレーションされています:
- LLM Provider: Microsoft Foundry(推奨)を利用し、さまざまなモデルへアクセスします。
- WebUI: 面接の対話を行うための Blazor ベースのチャットインターフェースです。
- Agent: 面接のロジックを担うコンポーネントで、Microsoft Agent Framework 上で構築されています。
- MarkItDown MCP Server: Microsoft の MarkItDown (なんでも Markdown にしてくれる Python ライブラリ) を利用し、履歴書(PDF や DOCX)を Markdown 形式に変換して解析します。
- InterviewData MCP Server: .NET で実装された MCP サーバーで、面接セッションのデータを SQLite に保存します。
Aspire は、サービスディスカバリ、ヘルスチェック、テレメトリーを管理します。 各コンポーネントは 独立したプロセスとして実行され、1 つのコマンドでアプリケーション全体を起動できます。
パターン 1 : マルチエージェントによるハンドオフ
このサンプルが特に興味深いのは、 ハンドオフ (handoff) パターン を採用している点です。
1 つのエージェントがすべてを処理するのではなく、面接のプロセスを 5 つの専門エージェントに分割しています:
| Agent | 役割 | Tools |
|---|---|---|
| Triage (トリアージ) | メッセージを適切な担当エージェントへ振り分ける | なし(ルーティングのみ) |
| Receptionist (受付) | セッションを作成し、履歴書と職務内容を収集 | MarkItDown + InterviewData |
| Behavioral Interviewer (行動面接官) | STAR メソッドを用いた行動面接を実施 | InterviewData |
| Technical Interviewer (技術面接官) | 職種に応じた技術面接の質問を行う | InterviewData |
| Summarizer (サマリー生成) | 面接の最終的なサマリーを生成 | InterviewData |
ハンドオフパターンでは、あるエージェントが会話の制御を次のエージェントに完全に引き渡します。
引き継いだエージェントが、その後の会話をすべて担当します。
これは 「agent-as-tools」パターンとは異なります。 (agent-as-tools では、メインのエージェントが他のエージェントを補助ツールとして呼び出しますが、会話の制御自体はメインエージェントが保持します。)
以下は、このハンドオフワークフローの構成例です:
var workflow = AgentWorkflowBuilder
.CreateHandoffBuilderWith(triageAgent)
.WithHandoffs(triageAgent, [receptionistAgent, behaviouralAgent, technicalAgent, summariserAgent])
.WithHandoffs(receptionistAgent, [behaviouralAgent, triageAgent])
.WithHandoffs(behaviouralAgent, [technicalAgent, triageAgent])
.WithHandoffs(technicalAgent, [summariserAgent, triageAgent])
.WithHandoff(summariserAgent, triageAgent)
.Build();
通常の処理フロー(happy path)は次の順序で進みます。
Receptionist → Behavioral → Technical → Summarizer
それぞれの専門エージェントが、次のエージェントへ直接ハンドオフします。 もし想定外の状況が発生した場合は、エージェントは Triage エージェントへ戻り、適切なルーティングを再度行います。
なお、このサンプルには 単一エージェントモードも用意されており、よりシンプルな構成でのデプロイも可能です。 これにより、単一エージェントとマルチエージェントのアプローチを比較することができます。
パターン2: ツール統合のための MCP
このプロジェクトでは、ツールはエージェントの内部に実装されていません。 それぞれが 独立した MCP(Model Context Protocol)サーバーとして提供されています。
例えば、MarkItDown サーバーはこのプロジェクトだけでなく、まったく別のエージェントプロジェクトでも再利用できます。また、ツール開発チームはエージェント開発チームとは独立してツールをリリースすることが可能です。
MCP は言語非依存(language-agnostic)であることも特徴です。 そのため、このサンプルでは MarkItDown が Python サーバーとして動作し、エージェントは .NET で実装されています。
エージェントは起動時に MCP クライアントを通じてツールを検出し、必要なエージェントにそれらを渡します。
var receptionistAgent = new ChatClientAgent(
chatClient: chatClient,
name: "receptionist",
instructions: "You are the Receptionist. Set up sessions and collect documents...",
tools: [.. markitdownTools, .. interviewDataTools]);
各エージェントには、必要なツールだけが割り当てられます:
- Triage エージェント:ツールなし(ルーティングのみを担当)
- インタビュアーエージェント:セッションデータへのアクセス
- Receptionist エージェント:ドキュメント解析 + セッションアクセス
これは 最小権限の原則(principle of least privilege) に基づいた設計です。
パターン3: Aspire によるオーケストレーション
Aspire は、アプリケーション全体をまとめて管理する役割を担います。
アプリホストはサービスのトポロジー(構成)を定義し、
- どのサービスが存在するのか
- それぞれがどのように依存しているのか
- どの設定を受け取るのか
を管理します。
これにより、次のような機能が利用できます:
- Service discovery. サービスは固定の URL ではなく、サービス名で互いを見つけることができます。
- Health checks. Aspire ダッシュボードで、各コンポーネントの状態を確認できます。
- Distributed tracing. 共通のサービス設定を通じて OpenTelemetry が組み込まれます。
- One-command startup. aspire run --file ./apphost.cs を実行するだけで、すべてのサービスが起動します。
デプロイ時には、azd up を実行することで、アプリケーション全体が Azure Container Apps にデプロイされます。
始めてみよう
事前準備
- .NET 10 SDK 以降
- Azure サブスクリプション
- Microsoft Foundry project
- Docker Desktop またはその他のコンテナランタイム
ローカルで実行する
git clone https://github.com/Azure-Samples/interview-coach-agent-framework.git
cd interview-coach-agent-framework
# Configure credentials
dotnet user-secrets --file ./apphost.cs set MicrosoftFoundry:Project:Endpoint "<your-endpoint>"
dotnet user-secrets --file ./apphost.cs set MicrosoftFoundry:Project:ApiKey "<your-key>"
# Start all services
aspire run --file ./apphost.cs
Aspire Dashboard を開き、すべてのサービスの状態が Running になるまで待ちます。 その後、WebUI のエンドポイントをクリックすると、模擬面接を開始できます。
以下は、ハンドオフパターンがどのように動作するかを DevUI 上で可視化したものです。
このチャット UI を使って、面接候補者としてエージェントと対話することができます。
Azure にデプロイする
azd auth login
azd up
Tこれだけで完了です。 残りの処理は Aspire と azd が自動で実行します。
デプロイとテストが完了したら、次のコマンドを実行することで、作成されたすべてのリソースを安全に削除できます。
azd down --force --purge
このサンプルから学べること
Interview Coach を実際に試すことで、次のような内容を理解できます:
- Microsoft Foundry を モデルバックエンドとして利用する方法
- Microsoft Agent Framework を使った 単一エージェントおよびマルチエージェントシステムの構築
- ハンドオフによるオーケストレーションを用いて、ワークフローを専門エージェントに分割する方法
- エージェントコードとは独立した MCP ツールサーバーの作成と利用
- Aspire を使った 複数サービスからなるアプリケーションのオーケストレーション
- 一貫性のある構造化された振る舞いを生み出すプロンプト設計
- azd up を使った アプリケーション全体のデプロイ方法
試してみよう
完全なソースコードは GitHub で公開されています: Azure-Samples/interview-coach-agent-framework
Microsoft Agent Framework を初めて使う場合は、まず次の資料から始めることをおすすめします。
その後、このサンプルに戻ってくると、これらの要素がより大きなプロジェクトの中でどのように組み合わさるのかが理解できるでしょう。
もしこれらのパターンを使って何か作った場合は、ぜひ Issue を作成して 教えてください。
次は? (What's Next?)
我々は、現在、次のような さらなる統合シナリオにも取り組んでいます:
などなど。
これらの機能がリリースされ次第、このサンプルも随時アップデートしていく予定です。
Resources
- Microsoft Agent Framework ドキュメント
- Introducing Microsoft Agent Framework preview
- Microsoft Agent Framework Reaches Release Candidate
- Microsoft Foundry ドキュメント
- Microsoft Foundry Agent Service
- Microsoft Foundry Portal
- Microsoft.Extensions.AI
- Model Context Protocol specification
- Aspire ドキュメント
- ASP.NET Blazor