構造化出力コンバーター
02.05.2024 以降、古い OutputParser 、BeanOutputParser 、ListOutputParser 、MapOutputParser クラスは廃止され、新しい StructuredOutputConverter 、BeanOutputConverter 、ListOutputConverter 、MapOutputConverter 実装が採用されました。後者は前者の代替であり、同じ機能を提供します。変更の理由は主に名前の変更で、解析は行われませんが、Spring org.springframework.core.convert.converter パッケージと連携して機能が向上しました。 |
構造化された出力を生成する LLM の機能は、出力値の確実な解析に依存する下流アプリケーションにとって重要です。開発者は、AI モデルからの結果を、他のアプリケーション関数やメソッドに渡すことができる JSON、XML、Java クラスなどのデータ型にすばやく変換したいと考えています。
Spring AI Structured Output Converters
は、LLM 出力を構造化形式に変換できます。次の図に示すように、このアプローチは LLM テキスト補完エンドポイントを中心に動作します。
汎用補完 API を使用して大規模言語モデル (LLM) から構造化された出力を生成するには、入力と出力を慎重に処理する必要があります。構造化出力コンバーターは、LLM 呼び出しの前後で重要なロールを果たし、目的の出力構造が確実に実現されるようにします。
LLM 呼び出しの前に、コンバーターはプロンプトにフォーマット指示を追加し、モデルに目的の出力構造を生成するための明確なガイダンスを提供します。これらの指示は青写真として機能し、指定されたフォーマットに準拠するようにモデルのレスポンスを形成します。
LLM 呼び出しの後、コンバーターはモデルの出力テキストを受け取り、それを構造化型のインスタンスに変換します。この変換プロセスでは、生のテキスト出力を解析し、JSON、XML、ドメイン固有のデータ構造などの対応する構造化データ表現にマッピングします。
StructuredOutputConverter は、モデル出力を構造化出力に変換するためのベストエフォートです。AI モデルがリクエストどおりに構造化出力を返すことは保証されません。モデルがプロンプトを理解しなかったり、リクエストどおりに構造化出力を生成できない場合があります。モデル出力が期待どおりであることを確認するために、検証メカニズムを実装することを検討してください。 |
StructuredOutputConverter は LLM 関数呼び出しでは使用されません。この機能は本質的にデフォルトで構造化された出力を提供するためです。 |
構造化出力 API
StructuredOutputConverter
インターフェースを使用すると、出力を Java クラスにマッピングしたり、テキストベースの AI モデル出力から値の配列をマッピングしたりするなど、構造化された出力を取得できます。インターフェース定義は次のとおりです。
public interface StructuredOutputConverter<T> extends Converter<String, T>, FormatProvider {
}
Spring コンバーター < 文字列、T> (Javadoc) インターフェースと FormatProvider
インターフェースを組み合わせたもの
public interface FormatProvider {
String getFormat();
}
次の図は、構造化出力 API を使用する場合のデータフローを示しています。
FormatProvider
は AI モデルに特定の書式設定ガイドラインを提供し、Converter
を使用して指定されたターゲット型 T
に変換できるテキスト出力を生成できるようにします。次に、このような書式設定指示の例を示します。
Your response should be in JSON format. The data structure for the JSON should match this Java class: java.util.HashMap Do not include any explanations, only provide a RFC8259 compliant JSON response following this format without deviation.
フォーマット指示は、ほとんどの場合、次のように PromptTemplate を使用してユーザー入力の末尾に追加されます。
StructuredOutputConverter outputConverter = ...
String userInputTemplate = """
... user text input ....
{format}
"""; // user input with a "format" placeholder.
Prompt prompt = new Prompt(
new PromptTemplate(
userInputTemplate,
Map.of(..., "format", outputConverter.getFormat()) // replace the "format" placeholder with the converter's format.
).createMessage());
Converter<String, T> は、モデルからの出力テキストを指定された型 T
のインスタンスに変換するロールを担います。
利用可能なコンバーター
現在、Spring AI は AbstractConversionServiceOutputConverter
、AbstractMessageOutputConverter
、BeanOutputConverter
、MapOutputConverter
、ListOutputConverter
実装を提供しています。
AbstractConversionServiceOutputConverter<T>
- LLM 出力を目的の形式に変換するための事前構成済みの GenericConversionService (Javadoc) を提供します。デフォルトのFormatProvider
実装は提供されていません。AbstractMessageOutputConverter<T>
- LLM 出力を目的の形式に変換するための事前構成済みの MessageConverter (Javadoc) を提供します。デフォルトのFormatProvider
実装は提供されていません。BeanOutputConverter<T>
- 指定された Java クラス (例: Bean) または ParameterizedTypeReference (Javadoc) で構成されたこのコンバーターは、指定された Java クラスから派生したDRAFT_2020_12
、JSON Schema
に準拠した JSON レスポンスを生成するように AI モデルに指示するFormatProvider
実装を使用します。その後、ObjectMapper
を使用して JSON 出力をターゲットクラスの Java オブジェクトインスタンスに逆直列化します。MapOutputConverter
- AI モデルが RFC8259 準拠の JSON レスポンスを生成するようにガイドするFormatProvider
実装により、AbstractMessageOutputConverter
の機能が拡張されます。さらに、提供されているMessageConverter
を使用して JSON ペイロードをjava.util.Map<String, Object>
インスタンスに変換するコンバーター実装も組み込まれています。ListOutputConverter
-AbstractConversionServiceOutputConverter
を拡張し、カンマ区切りリスト出力用にカスタマイズされたFormatProvider
実装が含まれます。コンバーター実装は、提供されたConversionService
を使用して、モデルテキスト出力をjava.util.List
に変換します。
コンバーターの使用
次のセクションでは、利用可能なコンバーターを使用して構造化された出力を生成する方法について説明します。
Bean 出力コンバーター
次の例は、BeanOutputConverter
を使用して俳優のフィルモグラフィーを生成する方法を示しています。
俳優のフィルモグラフィーを表す対象レコード:
record ActorsFilms(String actor, List<String> movies) {
}
高レベルで流れるような ChatClient
API を使用して BeanOutputConverter を適用する方法は次のとおりです。
ActorsFilms actorsFilms = ChatClient.create(chatModel).prompt()
.user(u -> u.text("Generate the filmography of 5 movies for {actor}.")
.param("actor", "Tom Hanks"))
.call()
.entity(ActorsFilms.class);
または、低レベルの ChatModel
API を直接使用します。
BeanOutputConverter<ActorsFilms> beanOutputConverter =
new BeanOutputConverter<>(ActorsFilms.class);
String format = beanOutputConverter.getFormat();
String actor = "Tom Hanks";
String template = """
Generate the filmography of 5 movies for {actor}.
{format}
""";
Generation generation = chatModel.call(
new PromptTemplate(template, Map.of("actor", actor, "format", format)).create()).getResult();
ActorsFilms actorsFilms = beanOutputConverter.convert(generation.getOutput().getContent());
汎用 Bean 型
より複雑なターゲットクラス構造を指定するには、ParameterizedTypeReference
コンストラクターを使用します。例: 俳優とそのフィルモグラフィーのリストを表すには、次のようにします。
List<ActorsFilms> actorsFilms = ChatClient.create(chatModel).prompt()
.user("Generate the filmography of 5 movies for Tom Hanks and Bill Murray.")
.call()
.entity(new ParameterizedTypeReference<List<ActorsFilms>>() {});
または、低レベルの ChatModel
API を直接使用します。
BeanOutputConverter<List<ActorsFilms>> outputConverter = new BeanOutputConverter<>(
new ParameterizedTypeReference<List<ActorsFilms>>() { });
String format = outputConverter.getFormat();
String template = """
Generate the filmography of 5 movies for Tom Hanks and Bill Murray.
{format}
""";
Prompt prompt = new PromptTemplate(template, Map.of("format", format)).create();
Generation generation = chatModel.call(prompt).getResult();
List<ActorsFilms> actorsFilms = outputConverter.convert(generation.getOutput().getContent());
マップ出力コンバーター
次のスニペットは、MapOutputConverter
を使用してモデル出力をマップ内の数値のリストに変換する方法を示しています。
Map<String, Object> result = ChatClient.create(chatModel).prompt()
.user(u -> u.text("Provide me a List of {subject}")
.param("subject", "an array of numbers from 1 to 9 under they key name 'numbers'"))
.call()
.entity(new ParameterizedTypeReference<Map<String, Object>>() {});
または、低レベルの ChatModel
API を直接使用します。
MapOutputConverter mapOutputConverter = new MapOutputConverter();
String format = mapOutputConverter.getFormat();
String template = """
Provide me a List of {subject}
{format}
""";
Prompt prompt = new PromptTemplate(template,
Map.of("subject", "an array of numbers from 1 to 9 under they key name 'numbers'", "format", format)).create();
Generation generation = chatModel.call(prompt).getResult();
Map<String, Object> result = mapOutputConverter.convert(generation.getOutput().getContent());
リスト出力コンバーター
次のスニペットは、ListOutputConverter
を使用してモデル出力をアイスクリームのフレーバーのリストに変換する方法を示しています。
List<String> flavors = ChatClient.create(chatModel).prompt()
.user(u -> u.text("List five {subject}")
.param("subject", "ice cream flavors"))
.call()
.entity(new ListOutputConverter(new DefaultConversionService()));
または、低レベルの ChatModel API
を直接使用します。
ListOutputConverter listOutputConverter = new ListOutputConverter(new DefaultConversionService());
String format = listOutputConverter.getFormat();
String template = """
List five {subject}
{format}
""";
Prompt prompt = new PromptTemplate(template,
Map.of("subject", "ice cream flavors", "format", format)).create();
Generation generation = this.chatModel.call(prompt).getResult();
List<String> list = listOutputConverter.convert(generation.getOutput().getContent());
Built-in JSON mode
一部の AI モデルでは、構造化された (通常は JSON) 出力を生成するための専用の構成オプションが提供されます。
OpenAI 構造化出力 can ensure your model generates responses conforming strictly to your provided JSON Schema. You can choose between the
JSON_OBJECT
that guarantees the message the model generates is valid JSON orJSON_SCHEMA
with a supplied schema that guarantees the model will generate a response that matches your supplied schema (spring.ai.openai.chat.options.responseFormat
option).Azure OpenAI - モデルが出力する必要がある形式を指定する
spring.ai.azure.openai.chat.options.responseFormat
オプションを提供します。{ "type": "json_object" }
に設定すると JSON モードが有効になり、モデルが生成するメッセージが有効な JSON であることが保証されます。Ollama - provides a
spring.ai.ollama.chat.options.format
option to specify the format to return a response in. Currently, the only accepted value isjson
.Mistral AI - provides a
spring.ai.mistralai.chat.options.responseFormat
option to specify the format to return a response in. Setting it to{ "type": "json_object" }
enables JSON mode, which guarantees the message the model generates is valid JSON.