可观测性(Observability)
聊天模型可观测性(Chat Model Observability)
部分 ChatModel
和 StreamingChatModel
的实现
(参见“Observability”列)允许配置 ChatModelListener
来监听如下事件:
- 对 LLM 的请求
- 来自 LLM 的响应
- 错误
这些事件包含多种属性,如
OpenTelemetry Generative AI 语义约定 中描述的那样,例如:
- 请求:
- 消息
- 模型
- 温度(Temperature)
- Top P
- 最大 tokens 数
- 工具(Tools)
- 响应格式
- 等等
- 响应:
- 助手消息
- ID
- 模型
- Token 使用情况
- 结束原因
- 等等
下面是使用 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
映射(map)允许在同一个 ChatModelListener
的onRequest
、onResponse
和 onError
方法之间传递信息,
也可以在多个 ChatModelListener
之间传递。
监听器的工作方式
- 监听器被指定为
List<ChatModelListener>
,会按照迭代顺序依次调用。 - 监听器是同步调用的,并且运行在同一个线程中。有关流式情况的更多细节见下文。
在第一个监听器返回之前,第二个监听器不会被调用。 ChatModelListener.onRequest()
方法在调用 LLM 提供商 API 之前被调用。ChatModelListener.onRequest()
方法每次请求只会调用一次。
如果调用 LLM 提供商 API 时发生错误并进行了重试,
不会为每次重试都调用onRequest()
。ChatModelListener.onResponse()
方法只会调用一次,
即在从 LLM 提供商成功接收到响应之后立即调用。ChatModelListener.onError()
方法只会调用一次。
如果调用 LLM 提供商 API 时发生错误并进行了重试,
不会为每次重试都调用onError()
。- 如果某个监听器方法抛出异常,该异常会以
WARN
级别记录日志。
后续监听器的执行仍会照常进行。 - 通过
ChatModelRequestContext
、ChatModelResponseContext
和ChatModelErrorContext
提供的ChatRequest
是最终请求,
它包含了ChatModel
上配置的默认ChatRequestParameters
与请求特定的ChatRequestParameters
合并后的结果。 - 对于
StreamingChatModel
,ChatModelListener.onResponse()
和ChatModelListener.onError()
会在与ChatModelListener.onRequest()
不同的线程中被调用。
线程上下文目前不会自动传播,因此你可能需要使用attributes
映射
将所需数据从onRequest()
传递到onResponse()
或onError()
。 - 对于
StreamingChatModel
,ChatModelListener.onResponse()
会在StreamingChatResponseHandler.onCompleteResponse()
被调用之前调用。ChatModelListener.onError()
会在StreamingChatResponseHandler.onError()
被调用之前调用。
在 Spring Boot 应用中的可观测性
更多详情参见 这里。