-
Notifications
You must be signed in to change notification settings - Fork 678
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LLM Observability: Part 1 (OpenAI) #1058
Conversation
(cherry picked from commit 83294cb)
@brunobat could you please take a look? 🙏 |
I'm also very interested in this so we can augment in the already present observability features in the Quarkus implementation. I also think that having something like this in sooner that rather than later would be very helpful as these new integration points could definitely prove useful for various tasks. |
I believe that |
@geoand yeah I was just adding it :) |
💪🏼 |
@geoand do you think |
I very much doubt it's useful |
… streaming mode, added onError
… streaming mode, added onError
...j-core/src/main/java/dev/langchain4j/model/chat/observability/ChatLanguageModelListener.java
Outdated
Show resolved
Hide resolved
langchain4j-open-ai/src/main/java/dev/langchain4j/model/openai/OpenAiStreamingChatModel.java
Outdated
Show resolved
Hide resolved
...j-core/src/main/java/dev/langchain4j/model/chat/observability/ChatLanguageModelListener.java
Outdated
Show resolved
Hide resolved
...j-core/src/main/java/dev/langchain4j/model/chat/observability/ChatLanguageModelListener.java
Outdated
Show resolved
Hide resolved
...j-core/src/main/java/dev/langchain4j/model/chat/observability/ChatLanguageModelListener.java
Outdated
Show resolved
Hide resolved
I am actually thinking that the listener might need to be changed to: public interface ModelListener<Request, Response> {
default OnRequestResult<Request> onRequest(Request request) {
return null;
}
default void onResponse(Response response, OnRequestResult<Request> onRequestResult) {
}
default void onError(Throwable error, Response response, OnRequestResult<Request> onRequestResult) {
}
/**
* This name is horrible, and should replaced by something better
*/
interface OnRequestResult<Request> {
Request request();
}
} The reason is that an integration might want to include some custom data when the request is created and that data might need to be accessible when the result comes back (or an error occurs). WDYT? |
@geoand can you provide an example when this might be required? |
I am thinking that with OpenTelemetry if I want to open a new span on request and close it on end, I need a way to keep hold of that. Now OTel might have a way to do that already (with ThreadLocal, or some pluggable strategy), but other APIs might not. |
We can add to the request object the OTel context |
Right, but other APIs might not have that kind of capability |
Here is another example: With the current API, how would one use Micrometer to add a timed metric of the operation? P.S. I take complete responsibility for not spotting this issue earlier. |
Looking at this more, I don't see how one could close the |
I have a draft proposal of what I would like to do here. Using that in Quarkus LangChain4j I would utilize it like so: public class OpenTelemetryChatLanguageModelListener implements ModelListener<ChatLanguageModelRequest, OpenTelemetryChatLanguageModelListener.ScopeHoldingOnRequestResult, ChatLanguageModelResponse> {
private final Tracer tracer;
@Inject
public OpenTelemetryChatLanguageModelListener(Tracer tracer) {
this.tracer = tracer;
}
@Override
public ScopeHoldingOnRequestResult onRequest(ChatLanguageModelRequest request) {
String name = "ChatCompletions " + request.model();
Span span = tracer.spanBuilder(name).startSpan();
Scope scope = span.makeCurrent();
// TODO: implement
return new ScopeHoldingOnRequestResult(request, scope);
}
@Override
public void onResponse(ChatLanguageModelResponse chatLanguageModelResponse, ScopeHoldingOnRequestResult request) {
// TODO: implement
request.scope.close();
}
@Override
public void onError(Throwable error, ChatLanguageModelResponse chatLanguageModelResponse,
ScopeHoldingOnRequestResult request) {
// TODO: implement
request.scope.close();
}
public static class ScopeHoldingOnRequestResult implements OnRequestResult<ChatLanguageModelRequest> {
private final ChatLanguageModelRequest request;
private final Scope scope;
private ScopeHoldingOnRequestResult(ChatLanguageModelRequest request, Scope scope) {
this.request = request;
this.scope = scope;
}
@Override
public ChatLanguageModelRequest request() {
return null;
}
}
} |
Will comment on the PR |
Issue
#199
Change
ModelListener
,ChatLanguageModelRequest
, andChatLanguageModelResponse
that are compatible (have all the required attributes) with OTEL LLM semconv draft.ModelListener<ChatLanguageModelRequest, ChatLanguageModelResponse>
toOpenAiChatModel
andOpenAiStreamingChatModel
(pilot module).ChatLanguageModelRequest
ChatLanguageModelResponse
Example
General checklist