構造的出力は、NPC とのゲームプレイにより深い次元を与えます。 構造的出力は、NPC の基盤となる LLM がユーザー定義 LLM インスタンス化構造体を返してゲームプレイ ロジックを制御するメカニズムです。
これにより、LLM キャラクターは、多肢選択式質問に回答を返したり、アイテムの価格がコストに見合うかどうかを判断したりするなど、より深いインタラクションを行うことができます。
レスポンスと構造的出力はいずれも英語である必要があります。
概要
このセクションでは、ペルソナ用の単一の構造的出力を使用して、persona_npc_behavior をカスタマイズします。 interactions_response 構造体:
この NPC がプレイヤーとインタラクトした回数を記録します。
ペルソナがプレイヤーとのこのインタラクションについて現在抱いている感情。
プレイヤーとの全てのインタラクションに関するペルソナの感情の履歴を記録する配列。
構造的出力では、次の操作を行う必要があります。
構造的出力を定義する構造体を作成する。
ペルソナが構造的出力構造体に入力する方法を指示する。
構造的出力の受信時にシグナルされるイベントを定義し、サブスクライブする。
1 つのペルソナで複数の構造的出力を同時に構成し、ペルソナの構造的出力の型ごとに異なるサブスクリプションを指定できます。
サポートされている型
構造的出力は、構造体内のフィールドとして以下の Verse 型をサポートしています。
intfloatboolenummessage
メッセージを表示する
ログまたはゲーム内で出力されるとき、メッセージ タイプは編集されますが、メッセージ タイプを表示するように設計された仕掛けを使用してメッセージ タイプを表示できます。以下に例を示します。
billboard_devicehud_message_devicepopup_dialog_device
前提条件
NPC の挙動スクリプトに構造的出力を追加する
以下のコードは、構造的出力を使用して、prompt_binding_definition 型と RegisterAction() 関数を使用して、プレイヤーのプロンプトに基づいて新しいレスポンス タイプを導入することで、複数の LLM の機能を拡張します。
プロンプト バインディングは、RegisterAction() 関数で定義されているアクションを登録するために AI に渡される構造体です。 これらを組み合わせることで、LLM に、プレイヤーのプロンプトに基づいて特定のアクションをいつ実行するか、または特定のアクションをなぜ使用すべきなのかを伝えることができます。
以下は、セクション persona_npc_behavior.verse 内に展開された persona_npc_behavior を含む Verse スクリプトです。 これは、構造的出力を含む、「会話に NPC を追加する」のドキュメントにあるコードを拡張したものです。
既存の persona_npc_behavior でコードを修正するには、次の手順を実行します。
Verse プロジェクトが VS コードで開いていることを確認します。
メニュー バーで、[Verse] > [Open Project in VS Code… (VS Code でプロジェクトを開く…)] を選択します。
VS Code が開いたら、VS Code Explorer で
persona_npc_behavior.verseファイルを見つけます。
以下の
persona_npc_behavior.verseの内容をコピーして、プロジェクトの Verse ファイルに貼り付けます。Verse コードを UEFN のツールバー、または VS Code 内でコンパイルします。
Verse スクリプトの順を追ったウォークスルーについては、スクリプトの変更の説明のステップに従ってください。 このセクションでは、「NPC キャラクターにペルソナを追加する」 の スクリプトの説明の続きとなります。
persona_npc_behavior.verse
using { /Fortnite.com/AI }
using { /Fortnite.com/Devices }
using { /Fortnite.com/Playspaces }
using { /UnrealEngine.com/Conversations }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Verse.org/Chat }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
スクリプトの変更の説明
interactions_responseという名前の構造体は、関数が LLM に渡す変数を保持します。 LLM は変数を使用してプロンプトとそのレスポンスを評価します。Verseinteractions_response := struct: @ai_description("Use the Number field to output the number of times you have spoken to this player.") Number:int @ai_description("Use the Feeling field to output how you are feeling about your current interaction with the player.") Feeling:message2 つの異なる
@ai_descriptionsは、変数が何であるか、および LLM がレスポンスを作成する際にその変数を使用すべき理由を LLM に伝えます。Verse@ai_description("Use the Number field to output the number of times you have spoken to this player.") Number:int @ai_description("Use the Feeling field to output how you are feeling about your current interaction with the player.") Feeling:messageOnInteractionsResponseは、Structured Output を使用してゲームプレイ ロジックを制御する機能です。 AI セッションがinteractions_response構造体に一致する構造的出力を生成するたびに呼び出されるコールバック。 これは、AddStructuredOutput()内のRegisterActionによって登録されたハンドラであり、その Response パラメータにはモデルが入力したデータが含まれています。VerseOnInteractionsResponse(Response:interactions_response):void = Logger.Print("Structured response received") Logger.Print("Number of Interactions: {Response.Number}") Logger.Print("Feeling: {Localize(Response.Feeling)}") # Drive gameplay logic hereAddStructuredOutput関数は、NPC の構造的出力アクションをその AI セッションに登録します。 これにより、モデルがインタラクション データをゲームプレイにレポートできます。 このコードは 2 つの処理を実行します。 まず、アクションにNameとDescriptionを付与する小さな記述子であるprompt_binding_definitionをビルドします (どちらもMakeMessageヘルパーを通じてラップされ、文字列リテラルをメッセージ値に変換します)。 説明テキストは、このアクションをいつ使用するかをモデルに指示するものです。ここでは、プレイヤーが NPC に話しかけたときに使用します。次に、バインディング、true、
interactions_response構造体型、およびOnInteractionsResponseハンドラを渡して、Session.RegisterActionを呼び出します。 これは、interactions_responseのような形状の構造的出力を出力するときに、そのデータをOnInteractionsResponseにルーティングする必要があることを、セッションに伝えます。RegisterActionはキャンセル可能なものを返します。これはoption (オプション){}でラップされ、InteractionsResponseSubscriptionに格納されるため、サブスクリプションはOnEndメソッドで破棄できます。VerseAddStructuredOutput():void = if: NPCEntity := GetEntity[] PersonaComponent := NPCEntity.GetComponent[persona_component] Session := PersonaComponent.GetAISession() then: # Create a prompt_binding so that we can use it on RegisterAction InteractionBinding:prompt_binding_definition = prompt_binding_definition: Name := MakeMessage("InteractionBinding") Description := MakeMessage("Signals whenever the player has spoken to you.")OnBeginは、セッションに構造的出力を追加し、プレイヤーを会話ターゲットとして設定します。 プレイヤーが途中から参加できるゲームでは、PlayerAddedEventで追加するか、プレイヤーがトリガーを介して NPC に近づいたときに、プレイヤーを確実に追加してください。VerseOnBegin<override>()<suspends>:void= AddStructuredOutput() AddPlayersAsConversationTarget()OnEndでは、InteractionsResponseSubscriptionがクリーンされ、全てのプレイヤーから削除されます。 これは良い習慣です。VerseOnEnd<override>():void= if (Subscription := InteractionsResponseSubscription?): Subscription.Cancel() for (Player : GetEntity[].GetPlayspaceForEntity[].GetPlayers()): RemovePlayerAsConversationTarget(Player)
構造的出力をテストする
NPC は構造的出力で構成されるようになりました。 ペルソナが話すたびに、interactions_response がシグナルされます。
ゲーム内でのプロンプトに対するレスポンスとリアクションをより魅力的にするために、LLM キャラクターの挙動をテストします。