AI をアプリケーションに統合することは、ユーザーの創造性、生産性、健康目標の達成を支援しようとする開発者にとって、急速に必須の要件となりつつあります。 インテリジェントなチャットボット、パーソナライズされたおすすめ機能、文脈に応じた応答など、AI 搭載の機能は、最新のアプリに大きな付加価値を与えます。 ChatGPT が私たちの想像力を掻き立てて以降登場した AI 搭載アプリは、主に 1 人のユーザーと 1 人の AI アシスタントの間で使用されるものでした。 しかし、開発者が AI をより使いこなせるようになるにつれ、AI を搭載したアプリをチーム全体で活用できないかと模索され始めています。 彼らが考えているのは、「AI は、チームで共同作業を行うユーザーにどのような付加価値を与えることができるのだろうか」という点です。
このチュートリアルでは、リアルタイムのグループ チャット アプリケーションを構築する手順について説明します。 このチャットには、共同作業をしている人間のユーザー紛れて、AI アシスタントが追加されます。この AI アシスタントはチャット履歴にアクセスできるだけでなく、冒頭に @gpt
が付いている任意のユーザーのメッセージに対して、支援を提供することができます。 完成したアプリは次のようになります。
ここでは、OpenAI を使用して文脈に応じたインテリジェントな応答を生成し、SignalR を使用してグループ内のユーザーに応答を配信します。 完全なコードは、こちらのリポジトリにあります。
依存関係
このプロジェクトには、Azure OpenAI または OpenAI のいずれかを使用できます。 appsetting.json
で endpoint
と key
を更新してください。 OpenAIExtensions
は、アプリの起動時に構成を読み取り、認証していずれかのサービスを使用する必要があります。
このアプリケーションを構築するには、次のものが必要です。
- ASP.NET Core: Web アプリケーションを作成し、SignalR ハブをホストするため
- SignalR: クライアントとサーバー間のリアルタイム通信に使用
- Azure SignalR: SignalR 接続を大規模に管理するため
- OpenAI クライアント: OpenAI の API と対話し、AI 応答を生成するためため
実装
このセクションでは、SignalR と OpenAI を統合して AI 搭載のグループ チャット エクスペリエンスを実現するコードの主要部分について説明します。
データ フロー
SignalR Hub の統合
GroupChatHub
クラスは、ユーザー接続、メッセージ ブロードキャスト、AI 対話を管理します。 ユーザーが冒頭に @gpt
を付けてメッセージを送信すると、ハブによってメッセージが OpenAI に転送され、応答が生成されます。 AI の応答は、リアルタイムでグループにストリーミングされます。
var chatClient = _openAI.GetChatClient(_options.Model);
await foreach (var completion in chatClient.CompleteChatStreamingAsync(messagesIncludeHistory))
{
// ...
// Buffering and sending the AI's response in chunks
await Clients.Group(groupName).SendAsync("newMessageWithId", "ChatGPT", id, totalCompletion.ToString());
// ...
}
履歴を使用して文脈を保持する
OpenAI の Chat Completions API に対するすべての要求はステートレスです。OpenAI 側に、過去の対話は保存されません。 チャット アプリケーションでは、ユーザーまたはアシスタントの発言内容は、文脈に適した応答を生成するために重要です。 これを実現するには、Completions API に対するすべての要求にチャット履歴を含めます。
各グループのチャット履歴は、GroupHistoryStore
クラスで管理します。 これにはユーザーと AI アシスタントの両方によって投稿されたメッセージが格納され、対話を通して会話の文脈が保持されます。 この文脈は、一貫した AI 応答を生成するために不可欠です。
// Store message generated by AI-assistant in memory
public void UpdateGroupHistoryForAssistant(string groupName, string message)
{
var chatMessages = _store.GetOrAdd(groupName, _ => InitiateChatMessages());
chatMessages.Add(new AssistantChatMessage(message));
}
// Store message generated by users in memory
_history.GetOrAddGroupHistory(groupName, userName, message);
AI 応答をストリーミングする
CompleteChatStreamingAsync()
メソッドは、OpenAI からの応答を段階的にストリーミングします。これにより、部分的な応答が生成されるごとに、アプリケーションからクライアントに応答を送信できます。
このコードでは、StringBuilder
を使用して AI の応答を蓄積します。 バッファリングされたコンテンツの長さをチェックし、特定のしきい値 (20 文字など) を超えたときにクライアントに送信します。 このアプローチにより、ユーザーに AI の応答が生成される過程を見せ、人間が実際に入力しているような効果を演出することができます。
totalCompletion.Append(content);
if (totalCompletion.Length - lastSentTokenLength > 20)
{
await Clients.Group(groupName).SendAsync("newMessageWithId", "ChatGPT", id, totalCompletion.ToString());
lastSentTokenLength = totalCompletion.Length;
}
さらに深堀する
このプロジェクトは、次のようなさらなる強化のための素晴らしい可能性を開きます。
- 高度な AI 機能: 感情分析、翻訳、要約といった、他の OpenAI 機能を活用します。
- 複数の AI エージェントを組み込む: 同じチャット内に、異なる役割または専門知識領域を持つ複数の AI エージェントを導入することができます。 たとえば、1 つのエージェントがテキスト生成に重点を置き、もう 1 つは画像生成や音声生成の機能を提供するなどです。 この対話により、異なる AI エージェントがユーザーと相互にシームレスに対話する、より豊富で動的なユーザー エクスペリエンスを実現できます。
- サーバー インスタンス間でチャット履歴を共有する: データベース レイヤーを実装してセッション間でチャット履歴を保持し、切断後でも会話を再開できるようにします。 SQL または NO SQL ベースのソリューション以外に、Redis などのキャッシュ サービスの利用を検討することもできるでしょう。 チャット履歴や AI 応答などの頻繁にアクセスされるデータをメモリに格納することで、パフォーマンスを大幅に向上させることができます。 これにより、待機時間が短縮され、データベース操作の負荷が軽減されるため、特にトラフィックの多いシナリオでは応答時間を短縮できます。