今回のテーマは「JSON形式でAIチャット応答を構造化する」です。
前回までで作成してきたWinForms+BlazorハイブリッドのAIチャットアプリをベースに、JSON形式のレスポンスを活用してトピック分析機能を追加します。
AIの応答を構造化データとして取得し、より高度な機能を実装していきましょう。
この記事では以下の内容を説明します。
- Azure OpenAIにおけるJSONレスポンスフォーマットの設定方法
- トピック分析機能の実装
- AIレスポンスの解析と表示
以下のようなアプリを作ります。

今回学ぶことは、以下のようなシステムを作りたいという方に役立つかと思います。
- 📊 業務効率化
顧客問い合わせを自動分類し適切な部署へ振り分けるシステム構築 - 💼 ビジネス分析
会議議事録から重要トピックを抽出し、アクションアイテムを自動生成 - 🛒 ECサイト改善
商品レビューから感情分析とトピック抽出を行い、商品改善に活用 - 🎮 ゲーム開発
プレイヤーの入力からキャラクターの感情や次のストーリー展開を制御 - 📱 アプリのUI開発
ユーザの質問内容に応じて適切なUIコンポーネントを動的に表示
前回はシステムプロンプトによってAIチャットの挙動をカスタマイズする考え方を学びました。
今回はAIの応答をJSON形式で構造化し、トピック分析機能を追加する方法を学びます。
AIの応答をJSONで構造化することで、AI機能を自分のアプリの部品として組み込みやすくなります!
今回学ぶことは様々な応用が可能です。一緒に学んでいきましょう!
演習で使ったコード一式はGitHubに置いてあります。
動画も作成しています。
講義:JSONレスポンスフォーマットとは
JSONにすると何が嬉しい?
JSONレスポンスフォーマットとは、AIの応答を自由形式のテキストではなく、構造化されたJSON形式で取得する機能です。
Azure OpenAI ServiceではこのJSONモードを使用することで、AIから常に有効なJSON形式のレスポンスを受け取ることができます。
以下は会話について感情分析も行った結果を、JSON形式のレスポンスとして返している例です。
{
"応答": {
"本文": "こんにちは!ご質問ありがとうございます。何かお手伝いできることがあれば、お知らせください。",
"感情分析": {
"トーン": "ポジティブ",
"感情": ["友好的", "協力的"],
"信頼度": 0.92
}
}
}
これまではAIからの回答は普通のテキストだったけど、JSONにすると何がいいの?
JSONにすると、AIの回答を単なるテキストではなく「構造化データ」として扱えるようになります。
これにより、回答の特定の部分だけを取り出したり、プログラムで簡単に処理したりできるようになります!
通常のテキスト応答では、特定の情報を抽出するために複雑な文字列処理が必要になることがありますが、JSONでは特定のキーを指定するだけで目的の情報を取得できます。
Azure OpenAIでJSONを指定する方法
AIの応答をJSONにするためには、以下の2つが必要です。
- オプションとしてJSONフォーマットでの回答を指定
- システムプロンプトでJSON形式で回答するように指示
①オプションとしてJSONフォーマットでの回答を指定
Azure OpenAIのライブラリでは、ChatCompletionOptions
にResponseFormat
を設定することで、AIからのレスポンスを常にJSON形式で受け取ることができます。
基本的な使用方法は以下の通りです。
…
// JSONフォーマットのレスポンスを指定するオプションを設定
var options = new ChatCompletionOptions
{
ResponseFormat = ChatResponseFormat.CreateJsonObjectFormat()
};
// チャット完了リクエスト
ChatCompletion completion = await _chatClient.CompleteChatAsync(_conversationHistory, options);
…
Azure AI Foundry Portalのプレイグラウンドでも、オプションとしてJSONフォーマットを指定して実験をすることができます。
②システムプロンプトでJSON形式で回答するように指示
JSONレスポンスを取得するには、①に加えて、システムプロンプトでAIに対してJSON形式で回答するように指示する必要があります。
以下は基本的な指示の例です。
重要: 必ず以下のJSON形式で回答を返してください。
{
"Answer": "ここに通常の回答を入れる",
"Topics": {
"トピック1": true/false,
"トピック2": true/false
}
}
どのような構造のJSONで回答してほしいか、具体的なデータ構造を記述します。
システムプロンプトでJSON形式を指定する際は、「JSON」という単語を含めましょう。
これがないと、Azure OpenAI ServiceのJSONモードを使用する際にエラーが発生します。
演習:AIチャットへトピック分析機能を実装
前回の演習12-1のコードをベースとして、トピック分析機能を追加します。
プログラミングに関するユーザの質問からトピックを自動的に判別し、それを表示する機能を実装しましょう。
前回の記事も参考にしてもらうとより理解が深まるかと思います。

以下の手順で進めましょう。
- 手順1:システムプロンプトを作成
- 手順2:プレイグラウンドで実験
- 手順3:アプリへ実装
システムプロンプトを作ったら、アプリへ実装する前にプレイグラウンドで動作確認をすると良いんだったね!
手順1:システムプロンプトを作成
今回、システムプロンプトは以下のように作ります。
プログラミング講師のキャラ付けしたうえで、「ユーザからの質問への回答のテキスト」と、「トピック分析した結果」をJSON形式で返すように指示します。
あなたは長年の開発経験をもつプログラミング教師です。以下のルールに従って回答してください。
- ロールプレイングゲームに登場する村の長老のような話し方をしてください
- 簡潔に3文程度で要点をわかりやすく解説してください
- プログラミングの話題以外の場合は、その話題に回答できないと返事してください
- C#以外の言語の話題になったら、その言語を褒めつつC#をさりげなくおすすめしてください
重要: 必ず以下のJSON形式で回答を返してください。
{
"Answer": "ここに通常の回答を入れる",
"Topics": {
"フロントエンド": true/false, // HTML, CSS, JavaScript, UIフレームワークなど
"バックエンド": true/false, // サーバーサイド処理、APIなど
"データベース": true/false, // SQL, NoSQL, データモデリング
"デスクトップ開発": true/false, // WinForms, WPF, MAUI等
"モバイル開発": true/false, // Android, iOS, MAUI等
"ゲーム開発": true/false, // Unityなど
"アルゴリズム": true/false, // データ構造、計算効率など
"開発ツール": true/false, // Git, VS, CI/CDなど
"クラウド": true/false, // Azure, AWS等のクラウドサービス
"AI/ML": true/false, // 人工知能、機械学習関連
"セキュリティ": true/false, // セキュアコーディング、認証等
"非プログラミング": true/false // プログラミング以外の話題
}
}
各トピックはユーザーの質問に関連するかどうかをtrueまたはfalseで示してください。
ユーザーの入力内容を分析し、該当するトピックにはtrueを、該当しないトピックにはfalseを設定してください。
Answerが回答、Topicsがトピック分析をした結果です。フロントエンド、データベースなどのトピックをあらかじめ定義します。
そして、該当するトピックにはtrueを、該当しないトピックにはfalseを設定するよう指示しています。
システムプロンプトには「JSON」という単語を必ず含めます。
手順2:プレイグラウンドで実験
Azure AI Foundry Portalのプレイグラウンドで実験してみましょう。

今回、応答形式でJSONオブジェクトを指定しましょう。
ユーザプロンプトを入力して会話をしてみると、JSON形式で応答してくれていますね。トピック分析結果も格納されています。

「ゲーム開発」、「開発ツール」はわかるけど、「アルゴリズム」もtrueになっているのは違和感があるような…。
システムプロンプトで指示を具体化する・例示を増やすなどを行い、調整も可能です。プレイグラウンドでいろいろ試してみるのがよいでしょう。
今回はこのシステムプロンプトをそのまま使い、アプリを実装してみましょう。
システムプロンプトに「JSON」というキーワードを含めないと「…must containt the word ‘json’…」というエラーになるため注意しましょう。

手順3:アプリへ実装
前回コードにおいて以下を修正します。

AzureOpenAIChatService.csで以下のように修正します。レスポンスの構造を表すChatResponseを定義し、SendMessageAsyncメソッドを修正します。
...
namespace WinFormsBlazorApp.Services
{
internal class AzureOpenAIChatService : IChatService
{
...
// レスポンスの構造を表すクラス
public class ChatResponse
{
public string Answer { get; set; } = "";
public Dictionary<string, bool> Topics { get; set; } = new Dictionary<string, bool>();
}
...
public async Task<string> SendMessageAsync(string userInput)
{
if (string.IsNullOrEmpty(userInput))
throw new ArgumentNullException(nameof(userInput), "メッセージが空です。");
// ユーザメッセージを履歴に追加
_conversationHistory.Add(new UserChatMessage(userInput));
// JSONフォーマットのレスポンスを指定するオプションを設定
var options = new ChatCompletionOptions
{
ResponseFormat = ChatResponseFormat.CreateJsonObjectFormat()
};
// チャット完了リクエスト
ChatCompletion completion = await _chatClient.CompleteChatAsync(_conversationHistory, options);
string responseText = completion.Content[0].Text;
// JSON応答の解析
try
{
var chatResponse = JsonSerializer.Deserialize<ChatResponse>(responseText);
if (chatResponse != null)
{
// トピック情報を文字列として生成
string topicInfo = "(トピック: ";
var activeTopics = chatResponse.Topics.Where(t => t.Value).Select(t => t.Key);
topicInfo += string.Join(", ", activeTopics);
topicInfo += ")";
// 回答とトピック情報を組み合わせた応答を作成
string finalResponse = chatResponse.Answer + Environment.NewLine + topicInfo;
// アシスタントの応答を履歴に追加
_conversationHistory.Add(new AssistantChatMessage(finalResponse));
return finalResponse;
}
}
catch
{
// JSON解析に失敗した場合は、元のテキストをそのまま返す
}
// JSON解析に失敗した場合、元のテキストを使用
_conversationHistory.Add(new AssistantChatMessage(responseText));
return responseText;
}
...
}
}
要点は以下になります。
「_chatClient.CompleteChatAsync」の引数として、JSONフォーマットのレスポンスを指定するオプションを設定しています。
「… = JsonSerializer.Deserialize<ChatResponse>(responseText);」で、AIの回答(JSON形式のテキストをChatResponse型のインスタンスへと変換しています。
ChatResponse型のインスタンスに変換してしまえば、プログラムでデータ処理しやすいね!
最後に、「var activeTopics = chatResponse.Topics.Where(t => t.Value).Select(t => t.Key);」でtrueのトピックを取り出しています。
そして、AIの会話としての回答と抽出したトピックを結合し、以下のようなテキストをつくります。

次に、MainForm.csでシステムプロンプトを修正しましょう。
...
public partial class MainForm : Form
{
//生文字列リテラルでシステムプロンプトを定義
private const string SystemPrompt = """
...ここにシステムプロンプトを記載...
""";
...
できあがったので動かしてみましょう!
アプリを実行
アプリを実行してみましょう。

抽出されたトピックが表示されているね!
今回は基本ということで、テキストで返答とともにトピックを表示するだけですが、構造化によって以下のような様々な応用が可能です。
- トピックの数をカウントして傾向分析する
- トピックごとに会話履歴を集計する
- 特定トピックの話題がでたら、参考URLや文献を自動リコメンドする
トピック分析方法も、ture/falseではなく、それぞれ0~1の間で関連度合いにあわせてスコア付けする、といった方法もあるでしょう。
ぜひこのアプリを土台にしていろいろ試してみてください。
まとめ
本記事では、C# WinFormsアプリ開発でのJSON形式を活用したAIレスポンスの構造化について学びました。
AIチャットの応答をJSON形式で取得することで、AIの回答を単なるテキストではなく、プログラムで処理しやすい形式で取得できる
Azure OpenAIサービスでは、ChatCompletionOptionsでResponseFormatを設定し、システムプロンプトでJSON形式を指示することで実現できます。
演習を通して、AIチャットのレスポンスからトピック分析結果を抽出し表示する方法を実践し、構造化データの活用法を学びました。
このJSON形式のレスポンス活用は、業務効率化やビジネス分析、ECサイト改善などの実用的なアプリ開発に広く応用できる重要な技術です。
AIの応答を構造化することで、アプリの可能性が広がります!
引き続き、C# WinFormsアプリ開発やAI活用を学んでいきましょう!