プロンプト

プロンプトは、AI モデルが特定の出力を生成するようにガイドする入力です。これらのプロンプトのデザインと表現は、モデルのレスポンスに大きな影響を与えます。

Spring AI の AI モデルとの対話の最も低いレベルでは、Spring AI でのプロンプトの処理は、Spring MVC の「ビュー」の管理にある程度似ています。これには、動的コンテンツのプレースホルダーを使用した詳細なテキストの作成が含まれます。これらのプレースホルダーは、ユーザーのリクエストまたはアプリケーション内の他のコードに基づいて置き換えられます。もう 1 つの類似点は、特定の式のプレースホルダーを含む SQL ステートメントです。

Spring AI が進化するにつれて、AI モデルと対話するための抽象化のレベルが高くなります。このセクションで説明する基本クラスは、そのロールと機能の点で JDBC に似ています。たとえば、ChatModel クラスは、JDK のコア JDBC ライブラリに類似しています。ChatClient クラスは、ChatModel 上に構築され、Advisor を介してより高度な構造を提供し、モデルとの過去の対話を考慮し、追加のコンテキストドキュメントでプロンプトを拡張し、エージェントの動作を導入する JdbcClient に似ています。

AI フィールドでは、プロンプトの構造が時間の経過とともに進化してきました。当初、プロンプトは単純な文字列でした。時間の経過とともに、AI モデルが認識する "USER:" などの特定の入力用のプレースホルダーが含まれるようになりました。OpenAI は、AI モデルで処理される前に複数のメッセージ文字列を個別のロールに分類することで、プロンプトにさらに構造を導入しました。

API の概要

プロンプト

Prompt インスタンスを受け取って ChatResponse を返す ChatModel の call() メソッドを使用するのが一般的です。

Prompt クラスは、整理された一連の Message オブジェクトとリクエスト ChatOptions のコンテナーとして機能します。すべての Message は、プロンプト内でコンテンツと意図が異なる独自のロールを体現します。これらのロールには、ユーザーからの問い合わせから AI が生成したレスポンス、関連する背景情報まで、さまざまな要素が含まれます。この配置により、プロンプトが複数のメッセージで構成され、それぞれにダイアログで果たす特定のロールが割り当てられるため、AI モデルとの複雑で詳細な対話が可能になります。

以下は Prompt クラスの短縮版であり、簡潔にするためにコンストラクターとユーティリティメソッドが省略されています。

public class Prompt implements ModelRequest<List<Message>> {

    private final List<Message> messages;

    private ChatOptions chatOptions;
}

メッセージ

Message インターフェースは、Prompt テキストコンテンツ、メタデータ属性のコレクション、MessageType と呼ばれる分類をカプセル化します。

インターフェースは次のように定義されます。

public interface Content {

	String getContent();

	Map<String, Object> getMetadata();
}

public interface Message extends Content {

	MessageType getMessageType();
}

マルチモーダルメッセージ型は、Media コンテンツオブジェクトのリストを提供する MediaContent インターフェースも実装します。

public interface MediaContent extends Content {

	Collection<Media> getMedia();

}

Message インターフェースのさまざまな実装は、AI モデルが処理できるさまざまなメッセージのカテゴリに対応しています。モデルは、会話のロールに基づいてメッセージカテゴリを区別します。

Spring AI Message API

これらのロールは、以下で説明するように、MessageType によって効果的にマッピングされます。

ロール

各メッセージには特定のロールが割り当てられています。これらのロールによってメッセージが分類され、AI モデルに対するプロンプトの各セグメントのコンテキストと目的が明確になります。この構造化されたアプローチにより、プロンプトの各部分が対話において明確で明確なロールを果たすため、AI とのコミュニケーションのニュアンスと有効性が向上します。

主なロールは次のとおりです。

  • システムのロール: AI の動作とレスポンススタイルをガイドし、AI が入力を解釈してレスポンスする方法に関するパラメーターまたはルールを設定します。これは、会話を開始する前に AI に指示を与えるのと似ています。

  • ユーザーのロール: ユーザーの入力、つまり AI に対する質問、コマンド、ステートメントを表します。このロールは、AI のレスポンスの基礎を形成するため、基本的なものです。

  • アシスタントのロール: ユーザーの入力に対する AI のレスポンス。単なる回答や反応ではなく、会話の流れを維持するために重要です。AI の以前のレスポンス (「アシスタントロール」メッセージ) を追跡することで、システムは一貫性があり、状況に適した対話を保証します。アシスタントメッセージには、関数ツール呼び出しリクエスト情報も含まれる場合があります。これは AI の特別な機能のようなもので、計算、データの取得、会話以外のタスクなど、特定の機能を実行する必要があるときに使用されます。

  • ツール / 機能のロール: ツール / 機能ロールは、ツール呼び出しアシスタントメッセージにレスポンスして追加情報を返すことに重点を置いています。

Spring AI では、ロールは以下に示すように列挙として表されます。

public enum MessageType {

	USER("user"),

	ASSISTANT("assistant"),

	SYSTEM("system"),

	TOOL("tool");

    ...
}

PromptTemplate

Spring AI のプロンプトテンプレートの主要コンポーネントは、PromptTemplate クラスです。このクラスは、プロンプトの構築と管理に Terence Parr が開発した OSS StringTemplate (英語) エンジンを使用します。PromptTemplate クラスは、構造化されたプロンプトの作成を容易にし、AI モデルに送信して処理するように設計されています。

public class PromptTemplate implements PromptTemplateActions, PromptTemplateMessageActions {

    // Other methods to be discussed later
}

このクラスによって実装されたインターフェースは、プロンプト作成のさまざまな側面をサポートします。

PromptTemplateStringActions は、プロンプト生成の最も基本的な形式を表すプロンプト文字列の作成とレンダリングに重点を置いています。

PromptTemplateMessageActions は、Message オブジェクトの生成と操作を通じて迅速な作成を行うように調整されています。

PromptTemplateActions は、レスポンスを生成するために ChatModel に渡すことができる Prompt オブジェクトを返すように設計されています。

これらのインターフェースは多くのプロジェクトで広く使用されるわけではありませんが、作成を促すためのさまざまなアプローチを示しています。

実装されているインターフェース

public interface PromptTemplateStringActions {

	String render();

	String render(Map<String, Object> model);

}

メソッド String render(): プロンプトテンプレートを外部入力なしで最終的な文字列形式にレンダリングします。これは、プレースホルダーや動的コンテンツのないテンプレートに適しています。

メソッド String render(Map<String, Object> model): レンダリング機能を拡張して動的コンテンツを含めます。マップキーがプロンプトテンプレートのプレースホルダー名で、値が挿入される動的コンテンツである Map<String, Object> を使用します。

public interface PromptTemplateMessageActions {

	Message createMessage();

    Message createMessage(List<Media> mediaList);

	Message createMessage(Map<String, Object> model);

}

メソッド Message createMessage(): 静的または定義済みのメッセージコンテンツに使用される、追加データなしの Message オブジェクトを作成します。

メソッド Message createMessage(List<Media> mediaList): 静的なテキストとメディアコンテンツを含む Message オブジェクトを作成します。

メソッド Message createMessage(Map<String, Object> model): メッセージ作成を拡張して動的コンテンツを統合し、各エントリがメッセージテンプレートのプレースホルダーとそれに対応する動的値を表す Map<String, Object> を受け入れます。

public interface PromptTemplateActions extends PromptTemplateStringActions {

	Prompt create();

	Prompt create(ChatOptions modelOptions);

	Prompt create(Map<String, Object> model);

	Prompt create(Map<String, Object> model, ChatOptions modelOptions);

}

メソッド Prompt create(): 外部データ入力なしで Prompt オブジェクトを生成します。静的または定義済みのプロンプトに最適です。

メソッド Prompt create(ChatOptions modelOptions): 外部データ入力なしで、チャットリクエストの特定のオプションを使用して Prompt オブジェクトを生成します。

メソッド Prompt create(Map<String, Object> model): プロンプト作成機能を拡張して動的コンテンツを含め、各マップエントリがプロンプトテンプレートのプレースホルダーであり、それに関連付けられた動的値である Map<String, Object> を使用します。

メソッド Prompt create(Map<String, Object> model, ChatOptions modelOptions): プロンプト作成機能を拡張して、各マップエントリがプロンプトテンプレートのプレースホルダーであり、それに関連付けられた動的な値と、チャットリクエストの特定のオプションである Map<String, Object> を採用して、動的コンテンツを含めます。

使用例

PromptTemplates に関する AI ワークショップ [GitHub] (英語) から抜粋した簡単な例を以下に示します。

PromptTemplate promptTemplate = new PromptTemplate("Tell me a {adjective} joke about {topic}");

Prompt prompt = promptTemplate.create(Map.of("adjective", adjective, "topic", topic));

return chatModel.call(prompt).getResult();
String userText = """
    Tell me about three famous pirates from the Golden Age of Piracy and why they did.
    Write at least a sentence for each pirate.
    """;

Message userMessage = new UserMessage(userText);

String systemText = """
  You are a helpful AI assistant that helps people find information.
  Your name is {name}
  You should reply to the user's request with your name and also in the style of a {voice}.
  """;

SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText);
Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", name, "voice", voice));

Prompt prompt = new Prompt(List.of(userMessage, systemMessage));

List<Generation> response = chatModel.call(prompt).getResults();

これは、SystemPromptTemplate を使用して Prompt インスタンスを構築し、プレースホルダー値を渡すシステムロールを持つ Message を作成する方法を示しています。次に、ロール user のメッセージがロール system のメッセージと結合されて、プロンプトが形成されます。次に、プロンプトは ChatModel に渡され、生成レスポンスが得られます。

生の文字列の代わりにリソースを使用する

Spring AI は org.springframework.core.io.Resource 抽象化をサポートしているため、PromptTemplate で直接使用できるファイルにプロンプトデータを配置できます。たとえば、Spring 管理コンポーネントでフィールドを定義して、Resource を取得できます。

@Value("classpath:/prompts/system-message.st")
private Resource systemResource;

そして、そのリソースを SystemPromptTemplate に直接渡します。

SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource);

迅速なエンジニアリング

生成 AI では、プロンプトの作成は開発者にとって重要なタスクです。これらのプロンプトの品質と構造は、AI の出力の有効性に大きく影響します。思慮深いプロンプトの設計に時間と労力を投資することで、AI からの結果を大幅に向上させることができます。

プロンプトを共有して議論することは、AI コミュニティでは一般的な習慣です。この協力的なアプローチは、共有学習環境を構築するだけでなく、非常に効果的なプロンプトの特定と使用にもつながります。

この分野の研究では、さまざまなプロンプトを分析および比較して、さまざまな状況におけるその有効性を評価することがよく行われます。例: 重要な研究では、「深呼吸して、この問題に一歩ずつ取り組んでください」用語でプロンプトを開始すると、問題解決の効率が大幅に向上することが実証されました。これは、適切に選択された言語が生成 AI システムのパフォーマンスに影響を与える可能性があることを浮き彫りにしています。

特に AI テクノロジーの急速な進歩により、プロンプトを最も効果的に使用する方法を把握することは継続的な課題です。プロンプトエンジニアリングの重要性を認識し、コミュニティや調査からのインサイトを活用してプロンプト作成戦略を改善することを検討する必要があります。

効果的なプロンプトの作成

プロンプトを開発するときは、明確さと有効性を確保するためにいくつかの主要なコンポーネントを統合することが重要です。

  • 命令 : 人間とコミュニケーションをとるのと同じように、AI に明確で直接的な指示を与えます。この明確さは、AI が期待されていることを「理解」する上で不可欠です。

  • 外部コンテキスト : 必要に応じて、AI のレスポンスに関連する背景情報や具体的なガイダンスを含めます。この「外部コンテキスト」はプロンプトの枠組みとなり、AI が全体的なシナリオを把握できます。

  • ユーザー入力 : これは単純な部分であり、プロンプトの中核を形成するユーザーの直接のリクエストまたは質問です。

  • 出力インジケーター : この点は難しいかもしれません。これには、AI のレスポンスに必要な形式 (JSON など) を指定することが含まれます。ただし、AI が常にこの形式に厳密に準拠するとは限らないことに注意してください。たとえば、実際の JSON データの前に「ここに JSON があります」のようなフレーズが付加されたり、不正確な JSON のような構造が生成される場合があります。

予想される質問と回答の形式の例を AI に提供することは、プロンプトを作成するときに非常に役立ちます。この方法により、AI はクエリの構造と意図を「理解」し、より正確で適切なレスポンスを得ることができます。このドキュメントではこれらの手法について詳しく説明しません。ただし、AI プロンプトエンジニアリングをさらに探求するための出発点となります。

以下は、さらなる調査のためのリソースのリストです。

簡単なテクニック

  • テキストの要約 (英語) :
    膨大なテキストを簡潔な要約にまとめ、重要度の低い詳細を省略しながら重要なポイントと主要なアイデアを捉えます。

  • 質問への回答 (英語) :
    ユーザーが提示した質問に基づいて、提供されたテキストから具体的な回答を導き出すことに重点を置きます。それは、クエリに応じて関連情報を正確に特定して抽出することです。

  • テキストの分類 (英語) :
    テキストを事前定義されたカテゴリまたはグループに体系的に分類し、テキストを分析し、その内容に基づいて最も適切なカテゴリに割り当てます。

  • 会話 (英語) :
    AI がユーザーとやり取りを行って、自然な会話の流れをシミュレートできるインタラクティブなダイアログを作成します。

  • コード生成 (英語) :
    特定のユーザー要件または説明に基づいて機能コードスニペットを生成し、自然言語命令を実行可能コードに変換します。

高度なテクニック

  • ゼロショット (英語) 少数ショット学習 (英語) :
    モデルは、特定の問題型の事前の例が最小限、またはまったくない場合でも正確な予測やレスポンスを行うことができ、学習した一般化を使用して新しいタスクを理解し、行動することができます。

  • 思考の連鎖 (英語) :
    複数の AI レスポンスをリンクして、一貫した状況を認識した会話を作成します。これは、AI がディスカッションのスレッドを維持し、関連性と継続性を確保できます。

  • ReAct (理由 + 行動) (英語) :
    この手法では、AI はまず入力を分析 (理由づけ) し、次に最適な行動方針またはレスポンスを決定します。理解と意思決定を組み合わせます。

マイクロソフトのガイダンス

  • フレームワークによるプロンプトの作成と最適化 [GitHub] (英語) :
    Microsoft は、プロンプトを開発および改善するための構造化されたアプローチを提供しています。このフレームワークは、AI モデルから望ましいレスポンスを引き出す効果的なプロンプトをユーザーが作成できるようにガイドし、インタラクションを最適化して明確さと効率を実現します。

トークン

トークンは、AI モデルがテキストを処理する方法に不可欠であり、(理解している)単語を AI モデルが処理できる形式に変換する橋渡しのロールを果たします。この変換は 2 段階で行われます。入力時に単語がトークンに変換され、その後、これらのトークンが出力で単語に変換されます。

テキストをトークンに分解するプロセスであるトークン化は、AI モデルが言語を理解して処理する方法の基礎となります。AI モデルはこのトークン化された形式で動作し、プロンプトを理解して応答します。

トークンをより深く理解するには、トークンを単語の一部として考えてください。通常、トークンは単語の約 4 分の 3 を表します。たとえば、シェイクスピアの全作品は、合計およそ 900,000 ワードに相当し、約 1.2 百万トークンに相当します。

OpenAI トークナイザー UI (英語) を試して、単語がどのようにトークンに変換されるかを確認してください。

トークンは、AI 処理における技術的なロールを超えて、特に請求とモデルの機能に関して実用的な意味を持ちます。

  • 請求する: AI モデルサービスは、多くの場合、トークンの使用量に基づいて請求されます。入力 (プロンプト) と出力 (レスポンス) の両方が合計トークン数にコントリビュートするため、短いプロンプトの方がコスト効率が高くなります。

  • モデルの制限: AI モデルによってトークン制限が異なり、一度に処理できる情報の最大量である「コンテキストウィンドウ」が定義されます。例: GPT-3 の制限は 4K トークンですが、Claude 2 や Meta Llama 2 などの他のモデルでは 100K トークンの制限があり、一部の研究モデルでは最大 100 万トークンを処理できます。

  • コンテキストウィンドウ: モデルのトークン制限により、コンテキストウィンドウが決まります。この制限を超える入力はモデルによって処理されません。処理のために最小限の効果的な情報セットのみを送信することが重要です。例: 「ハムレット」について問い合わせる場合、シェイクスピアの他のすべての作品のトークンを含める必要はありません。

  • レスポンスメタデータ: AI モデルからのレスポンスのメタデータには、使用されたトークンの数が含まれており、使用量とコストを管理するための重要な情報となります。