このバージョンはまだ開発中であり、まだ安定しているとは見なされていません。最新の安定バージョンについては、Spring AI 2.0.1 を使用してください! |
プロンプト
プロンプトは、AI モデルが特定の出力を生成するようにガイドする入力です。これらのプロンプトのデザインと表現は、モデルのレスポンスに大きな影響を与えます。
Spring AI における AI モデルとのインタラクションの最も低いレベルでは、Spring AI におけるプロンプトの処理は、Spring MVC における「ビュー」の管理とある程度似ています。これには、動的なコンテンツのためのプレースホルダーを含む長文テキストの作成が含まれます。これらのプレースホルダーは、ユーザーのリクエストやアプリケーション内の他のコードに基づいて置き換えられます。別の例としては、特定の式のためのプレースホルダーを含む SQL 文が挙げられます。
Spring AI の進化に伴い、AI モデルとの対話のためのより高度な抽象化が導入されます。このセクションで説明する基本クラスは、そのロールと機能の点で JDBC に例えることができます。たとえば、ChatModel クラスは、JDK のコア JDBC ライブラリに相当します。ChatClient クラスは、ChatModel をベースに構築された JdbcClient に例えることができ、Advisor を介してより高度な構造を提供することで、モデルとの過去の対話を考慮したり、プロンプトに追加のコンテキストドキュメントを追加したり、エージェント的な動作を導入したりすることができます。
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;
}便利なメソッド
Prompt クラスは、ロール別にメッセージにアクセスするための便利なメソッドをいくつか提供します。
単一メッセージアクセス:
getUserMessage(): プロンプト内の最後のユーザーメッセージを返します。存在しない場合は空のUserMessageを返しますgetSystemMessage(): プロンプトの最初のシステムメッセージを返します。存在しない場合は空のSystemMessageを返しますgetLastUserOrToolResponseMessage(): 会話の継続性を保つために役立つ、最後のユーザーまたはツールのレスポンスメッセージを返します。
複数のメッセージへのアクセス:
getUserMessages(): プロンプト内のすべてのユーザーメッセージのリストを、順序を維持して返します。getSystemMessages(): プロンプト内のすべてのシステムメッセージのリストを、順序を維持して返します。
これらのメソッドは、マルチターンの会話を扱う場合や、ロールごとにメッセージを処理する必要がある場合に特に便利です。
メッセージ
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();
}All subclasses of AbstractMessage hold their content as an ordered list of MessagePart entries, available through getParts(). getText() joins the TextPart entries and getMedia() (in UserMessage) selects the MediaPart entries, in part order, so the two accessors stay valid views over the parts. Text and media can therefore interleave in a user message: add the parts in the order they should reach the model.
UserMessage message = UserMessage.builder()
.part(TextPart.of("What is in this picture?"))
.part(MediaPart.of(image))
.part(TextPart.of("Answer in one sentence."))
.build();The text(…) and media(…) builder methods keep working and replace the corresponding parts, so an advisor that rewrites the question through mutate().text(…) keeps the media. A builder without explicit parts produces the legacy order, text then media. The getMedia() list is an unmodifiable view; add media through the builder.
Message インターフェースのさまざまな実装は、AI モデルが処理できるさまざまなメッセージのカテゴリに対応しています。モデルは、会話のロールに基づいてメッセージカテゴリを区別します。

これらのロールは、以下で説明するように、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 クラスであり、構造化されたプロンプトの作成を容易にし、それらのプロンプトを AI モデルに送信して処理するように設計されています。
public class PromptTemplate implements PromptTemplateActions, PromptTemplateMessageActions {
// Other methods to be discussed later
} このクラスは、TemplateRenderer API を使用してテンプレートをレンダリングします。デフォルトでは、Spring AI は Terence Parr 氏が開発したオープンソースの StringTemplate (英語) エンジンをベースにした StTemplateRenderer 実装を使用します。テンプレート変数は {} 構文で識別されますが、区切り文字を設定して他の構文を使用することもできます。
public interface TemplateRenderer extends BiFunction<String, Map<String, Object>, String> {
@Override
String apply(String template, Map<String, Object> variables);
}Spring AI は、TemplateRenderer インターフェースを使用して、テンプレート文字列への変数の実際の置換を処理します。デフォルトの実装では [ 文字列テンプレート ] が使用されます。カスタムロジックが必要な場合は、独自の TemplateRenderer 実装を提供できます。テンプレートのレンダリングが不要なシナリオ (たとえば、テンプレート文字列がすでに完成している場合) では、提供されている NoOpTemplateRenderer を使用できます。
PromptTemplate promptTemplate = PromptTemplate.builder()
.renderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build())
.template("""
Tell me the names of 5 movies whose soundtrack was composed by <composer>.
""")
.build();
String prompt = promptTemplate.render(Map.of("composer", "John Williams"));このクラスによって実装されたインターフェースは、プロンプト作成のさまざまな側面をサポートします。
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();ロールに関する AI ワークショップ [GitHub] (英語) の別の例を以下に示します。
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 に渡され、生成レスポンスが得られます。
カスタムテンプレートレンダラーの使用
TemplateRenderer インターフェースを実装し、それを PromptTemplate コンストラクターに渡すことで、カスタムテンプレートレンダラーを使用できます。また、カスタム設定を使用してデフォルトの StTemplateRenderer を使い続けることもできます。
デフォルトでは、テンプレート変数は {} 構文で識別されます。プロンプトに JSON を含める予定の場合は、JSON 構文との競合を避けるため、別の構文を使用することをお勧めします。たとえば、< や > といった区切り文字を使用できます。
PromptTemplate promptTemplate = PromptTemplate.builder()
.renderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build())
.template("""
Tell me the names of 5 movies whose soundtrack was composed by <composer>.
""")
.build();
String prompt = promptTemplate.render(Map.of("composer", "John Williams"));生の文字列の代わりにリソースを使用する
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 モデルからのレスポンスのメタデータには、使用されたトークンの数が含まれており、使用量とコストを管理するための重要な情報となります。