可観測性
AI サービスの可観測性
AI サービスの可観測性は実験的な機能です。その API と動作は将来のバージョンで変更される可能性があります。
AI サービスの可観測性メカニズムにより、ユーザーは AiService の呼び出し中に何が起こっているかを追跡できます。 1 つの呼び出しに複数の LLM 呼び出しが含まれる場合があり、そのいずれかが成功または失敗する可能性があります。 AI サービスの可観測性により、ユーザーは呼び出しの完全なシーケンスとその結果を追跡できます。
AI サービスの可観測性機能は、AI サービス を使用する場合にのみ利用可能です。これらは、ChatModel や StreamingChatModel には適用できない上位レベルの構成要素です。
この実装は元々 Quarkus LangChain4j extension に実装されており、ここにバックポートされました。
イベントの種類
イベントの各タイプには一意の識別子があり、これを使用して複数の呼び出し間でイベントを関連付けることができます。
各タイプのイベントには、イベント内にカプセル化された情報が含まれています。
InvocationContext。
現在、次のタイプのイベントが利用可能です。
| イベント名 | 説明 |
|---|---|
AiServiceStartedEvent | LLM 呼び出しが開始されたときに呼び出されます。 |
AiServiceRequestIssuedEvent | LLM へのリクエストが送信される直前に呼び出されます。行われたリクエストの詳細が含まれます。ツールまたはガードレールが存在する場合、これは 1 回の AiService 呼び出し中に複数回呼び出される可能性があることに注意することが重要です。 システム メッセージやユーザー メッセージなどの情報が含まれます。 |
AiServiceResponseReceivedEvent | LLM からの応答を受信したときに呼び出されます。 LLM 応答と対応する要求が含まれます。ツールまたはガードレールが存在する場合、これは 1 回の AiService 呼び出し中に複数回呼び出される可能性があることに注意することが重要です。 システム メッセージやユーザー メッセージなどの情報が含まれます。 すべての呼び出しがこのイベントを受け取るわ けではありません。呼び出しが失敗した場合は、代わりに AiServiceErrorEvent を受け取ります。 |
AiServiceErrorEvent | LLM による呼び出しが失敗したときに発生します。障害の原因としては、ネットワーク障害、AiService の利用不可、入出力ガードレールによるリクエストのブロック、またはその他のさまざまな理由が考えられます。 発生した障害に関する情報が含まれています。 |
AiServiceCompletedEvent | LLM 呼び出しが正常に完了すると呼び出されます。 すべての呼び出しがこのイベントを受け取るわけではありません。呼び出しが失敗した場合は、代わりに AiServiceErrorEvent を受け取ります。呼び出しの結果に関する情報が含まれます。 |
ToolExecutedEvent | ツールの呼び出しが完了すると呼び出されます。これは、1 回の LLM 呼び出し内で複数回呼び出すことができることに注意することが重要です。 ツールのリクエストと結果に関する情報が含まれます。 |
InputGuardrailExecutedEvent | input guardrail 検証が実行されたときに呼び出されます。これらのイベントの 1 つは、ガードレールの呼び出しごとに発生します。 個々の入力ガードレールへの入力、その出力 (つまり、成功か失敗か)、および実行期間に関する情報が含まれます。 |
OutputGuardrailExecutedEvent | output guardrail 検証が実行されたときに呼び出されます。これらのイベントの 1 つは、ガードレールの呼び出しごとに発生します。 個々の出力ガードレールへの入力、その出力 (つまり、成功か、失敗か、再試行か、再プロンプトか)、および実行期間に関する情報が含まれます。 |
イベントをリッスンする
それぞれの イベントの種類 には、イベントを受信するために実装できる独自のリスナーがあります。聞きたいイベントを選択できます。
イベントをリッスンするには、リッスンしたいリスナー インターフェイスを実装する独自のクラスを作成します。使用可能なリスナー インターフェイスは次のとおりです。
リスナーを定義したら、AI サービス を作成するときにリスナーを登録します。 AiServices クラス には、さまざまな registerListener メソッドのバリアントがあります。
たとえば、次のようにして AiServiceCompletedEvent のリスナーを作成して登録できます。
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import dev.langchain4j.observability.api.AiServiceListenerRegistrar;
import dev.langchain4j.observability.api.event.AiServiceCompletedEvent;
import dev.langchain4j.observability.api.listener.AiServiceCompletedListener;
import dev.langchain4j.invocation.InvocationContext;
public class MyAiServiceCompletedListener implements AiServiceCompletedListener {
@Override
public void onEvent(AiServiceCompletedEvent event) {
InvocationContext invocationContext = event.invocationContext();
Optional<Object> result = event.result();
// The invocationId will be the same for all events related to the same LLM invocation
UUID invocationId = invocationContext.invocationId();
String aiServiceInterfaceName = invocationContext.interfaceName();
String aiServiceMethodName = invocationContext.methodName();
List<Object> aiServiceMethodArgs = invocationContext.methodArguments();
Object chatMemoryId = invocationContext.chatMemoryId();
Instant eventTimestamp = invocationContext.timestamp();
// Do something with the data
}
}
// When creating your AI Service
MyAiServiceCompletedListener myListener = new MyAiServiceCompletedListener();
var myService = AiServices.builder(MyAiService.class)
.chatModel(chatModel) // Could also be .streamingChatModel(...)
.registerListener(myListener)
.build();
独自のイベントとリスナーの作成
AI サービスの可観測性機能は、拡張できるように設計されています。独自のイベントを作成したい場合は、AiServiceEvent インターフェースを実装して独自のイベントを定義することで作成できます。
次に、AiServiceListener インターフェースを実装して独自のイベント リスナーを作成します。
イベントとリスナーを取得したら、AiServiceListenerRegistrar のインスタンスを取得/管理し、fireEvent(event) メソッドを呼び出してイベントを起動する必要があ ります。
イベントが発生すると、組み込みイベントの場合と同様に、リスナーを作成してリスナーを登録できます。
拡張ポイント
AiServiceListenerRegistrarFactory を実装し、Java Service Provider Interface (Java SPI) に登録することで、独自のカスタム AiServiceListenerRegistrar を作成することもできます。
これは、リスナーの登録/登録解除方法やイベントの発生方法を管理する場合に便利です。
チャットモデルの可観測性
Certain ChatModel および StreamingChatModel の実装
(「可観測性」列を参照) ChatModelListener(s) が次のようなイベントをリッスンするように構成できるようにします。
- LLM へのリクエスト
- LLM からの応答
- エラー
これらのイベントには、「 」で説明されているように、さまざまな属性が含まれます。 OpenTelemetry Generative AI Semantic Conventions、たとえば:
- リクエスト:
- メッセージ
- モデル
- 温度
- トップP
- 最大トークン数
- ツール
- 応答フォーマット -など
- 応答:
- アシスタントメッセージ
- ID
- モデル
- トークンの使用法
- 終了理由 -など
ChatModelListener の使用例を次に示します。
ChatModelListener listener = new ChatModelListener() {
@Override
public void onRequest(ChatModelRequestContext requestContext) {
ChatRequest chatRequest = requestContext.chatRequest();
List<ChatMessage> messages = chatRequest.messages();
System.out.println(messages);
ChatRequestParameters parameters = chatRequest.parameters();
System.out.println(parameters.modelName());
System.out.println(parameters.temperature());
System.out.println(parameters.topP());
System.out.println(parameters.topK());
System.out.println(parameters.frequencyPenalty());
System.out.println(parameters.presencePenalty());
System.out.println(parameters.maxOutputTokens());
System.out.println(parameters.stopSequences());
System.out.println(parameters.toolSpecifications());
System.out.println(parameters.toolChoice());
System.out.println(parameters.responseFormat());
if (parameters instanceof OpenAiChatRequestParameters openAiParameters) {
System.out.println(openAiParameters.maxCompletionTokens());
System.out.println(openAiParameters.logitBias());
System.out.println(openAiParameters.parallelToolCalls());
System.out.println(openAiParameters.seed());
System.out.println(openAiParameters.user());
System.out.println(openAiParameters.store());
System.out.println(openAiParameters.metadata());
System.out.println(openAiParameters.serviceTier());
System.out.println(openAiParameters.reasoningEffort());
}
System.out.println(requestContext.modelProvider());
Map<Object, Object> attributes = requestContext.attributes();
attributes.put("my-attribute", "my-value");
}
@Override
public void onResponse(ChatModelResponseContext responseContext) {
ChatResponse chatResponse = responseContext.chatResponse();
AiMessage aiMessage = chatResponse.aiMessage();
System.out.println(aiMessage);
ChatResponseMetadata metadata = chatResponse.metadata();
System.out.println(metadata.id());
System.out.println(metadata.modelName());
System.out.println(metadata.finishReason());
if (metadata instanceof OpenAiChatResponseMetadata openAiMetadata) {
System.out.println(openAiMetadata.created());
System.out.println(openAiMetadata.serviceTier());
System.out.println(openAiMetadata.systemFingerprint());
}
TokenUsage tokenUsage = metadata.tokenUsage();
System.out.println(tokenUsage.inputTokenCount());
System.out.println(tokenUsage.outputTokenCount());
System.out.println(tokenUsage.totalTokenCount());
if (tokenUsage instanceof OpenAiTokenUsage openAiTokenUsage) {
System.out.println(openAiTokenUsage.inputTokensDetails().cachedTokens());
System.out.println(openAiTokenUsage.outputTokensDetails().reasoningTokens());
}
ChatRequest chatRequest = responseContext.chatRequest();
System.out.println(chatRequest);
System.out.println(responseContext.modelProvider());
Map<Object, Object> attributes = responseContext.attributes();
System.out.println(attributes.get("my-attribute"));
}
@Override
public void onError(ChatModelErrorContext errorContext) {
Throwable error = errorContext.error();
error.printStackTrace();
ChatRequest chatRequest = errorContext.chatRequest();
System.out.println(chatRequest);
System.out.println(errorContext.modelProvider());
Map<Object, Object> attributes = errorContext.attributes();
System.out.println(attributes.get("my-attribute"));
}
};
ChatModel model = OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName(GPT_4_O_MINI)
.listeners(List.of(listener))
.build();
model.chat("Tell me a joke about Java");
attributes マップにより、同じメソッドの onRequest、onResponse、および onError メソッド間で情報を受け渡すことができます。
ChatModelListener、および複数のChatModelListener間。
呼び出しごとのメタデータをリスナーに提供する必要がある場合は、ChatRequestOptions を使用します。
たとえば、テナントまたは相関識別子を ChatModelListener に渡すことができます。
listenerAttributes 経由。これらのオプションは、LangChain4j 呼び出しチェーン内でのみ使用されます。
これらは LLM プロバイダーには送信されません。
ChatRequest chatRequest = ChatRequest.builder()
.messages(UserMessage.from("Tell me a joke about Java"))
.build();
ChatRequestOptions options = ChatRequestOptions.builder()
.addListenerAttribute("tenantId", "tenant-123")
.addListenerAttribute("correlationId", "corr-456")
.build();
model.chat(chatRequest, options);
StreamingChatModel.chat(chatRequest, options, handler)も同様です。