このバージョンはまだ開発中であり、まだ安定しているとは考えられていません。最新のスナップショットバージョンについては、Spring AI 1.0.3 を使用してください。 |
アドバイザー API
Spring AI アドバイザー API は、Spring アプリケーションで AI 主導のインタラクションをインターセプト、変更、強化するための柔軟で強力な方法を提供します。アドバイザー API を活用することで、開発者はより洗練され、再利用可能で、保守しやすい AI コンポーネントを作成できます。
主な利点としては、繰り返し発生する生成 AI パターンのカプセル化、大規模言語モデル (LLM) との間で送受信されるデータの変換、さまざまなモデルやユースケース間での移植性の提供などが挙げられます。
次の例に示すように、ChatClient API を使用して既存のアドバイザーを構成できます。
ChatMemory chatMemory = ... // Initialize your chat memory store
VectorStore vectorStore = ... // Initialize your vector store
var chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(chatMemory).build(), // chat-memory advisor
QuestionAnswerAdvisor.builder(vectorStore).build() // RAG advisor
)
.build();
var conversationId = "678";
String response = this.chatClient.prompt()
// Set advisor parameters at runtime
.advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, conversationId))
.user(userText)
.call()
.content(); ビルダーの defaultAdvisors() メソッドを使用して、ビルド時にアドバイザーを登録することをお勧めします。
アドバイザーは Observability スタックにも参加するため、その実行に関連するメトリクスとトレースを表示できます。
コアコンポーネント
API は、非ストリーミングシナリオ用の CallAdvisor と CallAdvisorChain、およびストリーミングシナリオ用の StreamAdvisor と StreamAdvisorChain で構成されています。また、封印されていないプロンプトリクエストを表す ChatClientRequest、チャット補完レスポンスを表す ChatClientResponse も含まれます。どちらもアドバイザーチェーン全体で状態を共有するために advise-context を保持しています。

adviseCall() と adviseStream() は主要なアドバイザーメソッドであり、通常は、封印されていないプロンプトデータの調査、プロンプトデータのカスタマイズと拡張、アドバイザーチェーン内の次のエンティティの呼び出し、オプションでのリクエストのブロック、チャット補完レスポンスの調査、処理エラーを示す例外のスローなどのアクションを実行します。
さらに、getOrder() メソッドは チェーン内のアドバイザーの順序を決定し、getName() は一意のアドバイザー名を提供します。
Spring AI フレームワークによって作成されたアドバイザーチェーンを使用すると、getOrder() 値順に複数のアドバイザーを順番に呼び出すことができます。値の低いアドバイザーが最初に実行されます。自動的に追加された最後のアドバイザーは、リクエストを LLM に送信します。
次のフロー図は、アドバイザーチェーンとチャットモデル間のやり取りを示しています。

Spring AI フレームワークは、ユーザーの
Promptと空のアドバイザーcontextオブジェクトからChatClientRequestを作成します。チェーンの各アドバイザーはリクエストを処理し、場合によってはリクエストを変更します。または、次のエンティティを呼び出す呼び出しを行わないことでリクエストをブロックすることもできます。後者の場合、アドバイザーはレスポンスを入力する責任があります。
フレームワークによって提供される最終アドバイザーは、リクエストを
Chat Modelに送信します。チャットモデルのレスポンスはアドバイザーチェーンを介して返され、
ChatClientResponseに変換されます。その後、共有アドバイザーcontextインスタンスが追加されます。各アドバイザーはレスポンスを処理または変更できます。
最終的な
ChatClientResponseは、ChatCompletionを抽出することによってクライアントに返されます。
アドバイザーのオーダー
チェーンのアドバイザーの実行順序は、getOrder() メソッドによって決定されます。理解すべき重要なポイント:
順序値の低いアドバイザーが最初に実行されます。
アドバイザーチェーンはスタックとして動作します。
チェーンの最初のアドバイザーが最初にリクエストを処理します。
また、レスポンスを処理するのも最後です。
実行順序を制御するには:
アドバイザーが チェーンで最初に実行されるようにするには (リクエスト処理の場合は最初に、レスポンス処理の場合は最後に)、順序を
Ordered.HIGHEST_PRECEDENCEに近い値に設定します。アドバイザーが チェーンで最後に実行されるようにするには (リクエスト処理の場合は最後に、レスポンス処理の場合は最初に)、順序を
Ordered.LOWEST_PRECEDENCEに近い値に設定します。
値が大きいほど優先度は低くなると解釈されます。
複数のアドバイザーが同じ順序値を持つ場合、実行順序は保証されません。
順序と実行シーケンスの間に矛盾があるように見えるのは、アドバイザーチェーンのスタックのような性質によるものです。
|
念のため、Spring Ordered インターフェースのセマンティクスを以下に示します。
public interface Ordered {
/**
* Constant for the highest precedence value.
* @see java.lang.Integer#MIN_VALUE
*/
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
/**
* Constant for the lowest precedence value.
* @see java.lang.Integer#MAX_VALUE
*/
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
/**
* Get the order value of this object.
* <p>Higher values are interpreted as lower priority. As a consequence,
* the object with the lowest value has the highest priority (somewhat
* analogous to Servlet {@code load-on-startup} values).
* <p>Same order values will result in arbitrary sort positions for the
* affected objects.
* @return the order value
* @see #HIGHEST_PRECEDENCE
* @see #LOWEST_PRECEDENCE
*/
int getOrder();
}入力側と出力側の両方で チェーンの先頭にする必要のあるユースケースの場合:
|
API の概要
主要なアドバイザーインターフェースはパッケージ org.springframework.ai.chat.client.advisor.api にあります。独自のアドバイザーを作成するときに使用する主要なインターフェースは次のとおりです。
public interface Advisor extends Ordered {
String getName();
}同期アドバイザーとリアクティブアドバイザーの 2 つのサブインターフェースは
public interface CallAdvisor extends Advisor {
ChatClientResponse adviseCall(
ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain);
}および
public interface StreamAdvisor extends Advisor {
Flux<ChatClientResponse> adviseStream(
ChatClientRequest chatClientRequest, StreamAdvisorChain streamAdvisorChain);
} アドバイスの チェーンを継続するには、アドバイスの実装で CallAdvisorChain と StreamAdvisorChain を使用します。
インターフェースは
public interface CallAdvisorChain extends AdvisorChain {
/**
* Invokes the next {@link CallAdvisor} in the {@link CallAdvisorChain} with the given
* request.
*/
ChatClientResponse nextCall(ChatClientRequest chatClientRequest);
/**
* Returns the list of all the {@link CallAdvisor} instances included in this chain at
* the time of its creation.
*/
List<CallAdvisor> getCallAdvisors();
}および
public interface StreamAdvisorChain extends AdvisorChain {
/**
* Invokes the next {@link StreamAdvisor} in the {@link StreamAdvisorChain} with the
* given request.
*/
Flux<ChatClientResponse> nextStream(ChatClientRequest chatClientRequest);
/**
* Returns the list of all the {@link StreamAdvisor} instances included in this chain
* at the time of its creation.
*/
List<StreamAdvisor> getStreamAdvisors();
}アドバイザーの導入
アドバイザーを作成するには、CallAdvisor または StreamAdvisor (あるいはその両方) を実装します。実装する主要な方法は、非ストリーミングアドバイザーの場合は nextCall()、ストリーミングアドバイザーの場合は nextStream() です。
サンプル
ユースケースを観測および拡張するためのアドバイザーを実装する方法を説明するために、いくつかの実践的な例を紹介します。
ログ記録アドバイザー
チェーンの次のアドバイザーへの呼び出し前の ChatClientRequest と呼び出し後の ChatClientResponse をログに記録する、シンプルなログアドバイザーを実装できます。アドバイザーはリクエストとレスポンスを監視するだけで、変更は行わないことに注意してください。この実装は、非ストリーミングシナリオとストリーミングシナリオの両方をサポートします。
public class SimpleLoggerAdvisor implements CallAdvisor, StreamAdvisor {
private static final Logger logger = LoggerFactory.getLogger(SimpleLoggerAdvisor.class);
@Override
public String getName() { (1)
return this.getClass().getSimpleName();
}
@Override
public int getOrder() { (2)
return 0;
}
@Override
public ChatClientResponse adviseCall(ChatClientRequest chatClientRequest, CallAdvisorChain callAdvisorChain) {
logRequest(chatClientRequest);
ChatClientResponse chatClientResponse = callAdvisorChain.nextCall(chatClientRequest);
logResponse(chatClientResponse);
return chatClientResponse;
}
@Override
public Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest,
StreamAdvisorChain streamAdvisorChain) {
logRequest(chatClientRequest);
Flux<ChatClientResponse> chatClientResponses = streamAdvisorChain.nextStream(chatClientRequest);
return new ChatClientMessageAggregator().aggregateChatClientResponse(chatClientResponses, this::logResponse); (3)
}
private void logRequest(ChatClientRequest request) {
logger.debug("request: {}", request);
}
private void logResponse(ChatClientResponse chatClientResponse) {
logger.debug("response: {}", chatClientResponse);
}
}| 1 | アドバイザーに一意の名前を提供します。 |
| 2 | 順序値を設定することで実行順序を制御できます。値が小さいほど先に実行されます。 |
| 3 | MessageAggregator は、Flux レスポンスを 1 つの ChatClientResponse に集約するユーティリティクラスです。これは、ストリーム内の個々の項目ではなくレスポンス全体を監視するログ記録やその他の処理に役立ちます。MessageAggregator は読み取り専用操作であるため、レスポンスを変更できないことに注意してください。 |
再読(Re2)アドバイザー
"再読により大規模言語モデルの推論機能が向上する (英語) " の記事では、大規模言語モデルの推論機能を向上させる Re-Reading (Re2) と呼ばれる手法を紹介しています。Re2 手法では、次のように入力プロンプトを拡張する必要があります。
{Input_Query}
Read the question again: {Input_Query}Re2 テクニックをユーザーの入力クエリに適用するアドバイザーを実装するには、次のようにします。
public class ReReadingAdvisor implements BaseAdvisor {
private static final String DEFAULT_RE2_ADVISE_TEMPLATE = """
{re2_input_query}
Read the question again: {re2_input_query}
""";
private final String re2AdviseTemplate;
private int order = 0;
public ReReadingAdvisor() {
this(DEFAULT_RE2_ADVISE_TEMPLATE);
}
public ReReadingAdvisor(String re2AdviseTemplate) {
this.re2AdviseTemplate = re2AdviseTemplate;
}
@Override
public ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain) { (1)
String augmentedUserText = PromptTemplate.builder()
.template(this.re2AdviseTemplate)
.variables(Map.of("re2_input_query", chatClientRequest.prompt().getUserMessage().getText()))
.build()
.render();
return chatClientRequest.mutate()
.prompt(chatClientRequest.prompt().augmentUserMessage(augmentedUserText))
.build();
}
@Override
public ChatClientResponse after(ChatClientResponse chatClientResponse, AdvisorChain advisorChain) {
return chatClientResponse;
}
@Override
public int getOrder() { (2)
return this.order;
}
public ReReadingAdvisor withOrder(int order) {
this.order = order;
return this;
}
}| 1 | before メソッドは、再読み取りテクニックを適用してユーザーの入力クエリを拡張します。 |
| 2 | 順序値を設定することで実行順序を制御できます。値が小さいほど先に実行されます。 |
Spring AI 組み込みアドバイザー
Spring AI フレームワークには、AI のインタラクションを強化するための組み込みアドバイザーがいくつか用意されています。利用可能なアドバイザーの概要は次のとおりです。
チャットメモリアドバイザー
これらのアドバイザーは、チャットメモリストア内の会話履歴を管理します。
MessageChatMemoryAdvisorメモリを取得し、それをメッセージのコレクションとしてプロンプトに追加します。このアプローチでは、会話履歴の構造が維持されます。すべての AI モデルがこのアプローチをサポートしているわけではないことに注意してください。
PromptChatMemoryAdvisorメモリを取得し、プロンプトのシステムテキストに組み込みます。
VectorStoreChatMemoryAdvisorVectorStore からメモリを取得し、プロンプトのシステムテキストに追加します。このアドバイザーは、大規模なデータセットから関連情報を効率的に検索および取得できます。
質問回答アドバイザー
QuestionAnswerAdvisorこのアドバイザーは、ベクトルストアを使用して質問応答機能を提供し、Naive RAG (Retrieval-Augmented Generation) パターンを実装します。
RetrievalAugmentationAdvisorAdvisor that implements common Retrieval Augmented Generation (RAG) flows using the building blocks defined in the `org.springframework.ai.rag` package and following the Modular RAG Architecture.
推論アドバイザー
ReReadingAdvisorLLM 推論のための再読戦略(RE2)を実装し、入力フェーズでの理解を強化します。論文「再読は LLM における推論力を向上させる」(arxiv.org/pdf/2309.06275 (英語) )に基づいています。
ストリーミング vs 非ストリーミング

非ストリーミングアドバイザーは、完全なリクエストとレスポンスを扱います。
ストリーミングアドバイザーは、リアクティブプログラミングの概念 (レスポンスの場合は Flux など) を使用して、リクエストとレスポンスを連続ストリームとして処理します。
@Override
public Flux<ChatClientResponse> adviseStream(ChatClientRequest chatClientRequest, StreamAdvisorChain chain) {
return Mono.just(chatClientRequest)
.publishOn(Schedulers.boundedElastic())
.map(request -> {
// This can be executed by blocking and non-blocking Threads.
// Advisor before next section
})
.flatMapMany(request -> chain.nextStream(request))
.map(response -> {
// Advisor after next section
});
}破壊的な API 変更
アドバイザーインターフェース
1.0 M2 には、
RequestAdvisorとResponseAdvisorのインターフェースが別々にありました。RequestAdvisorは、ChatModel.callメソッドとChatModel.streamメソッドの前に呼び出されました。これらのメソッドの後に
ResponseAdvisorが呼び出されました。
1.0 M3 では、これらのインターフェースは次のように置き換えられました。
CallAroundAdvisorStreamAroundAdvisor
以前は
ResponseAdvisorの一部であったStreamResponseModeは削除されました。1.0.0 では、次のインターフェースが置き換えられました。
CallAroundAdvisor→CallAdvisor、StreamAroundAdvisor→StreamAdvisor、CallAroundAdvisorChain→CallAdvisorChain、StreamAroundAdvisorChain→StreamAdvisorChain。AdvisedRequest→ChatClientRequestおよびAdivsedResponse→ChatClientResponse。