Skip to content

Commit 81295b9

Browse files
committed
TestOpenAiLlmObs::test_chat_completion[java-test-ml-app-tcp-True] PASSED
1 parent 57212c6 commit 81295b9

File tree

3 files changed

+57
-9
lines changed

3 files changed

+57
-9
lines changed

dd-java-agent/instrumentation/openai-java/openai-java-1.0/src/main/java/datadog/trace/instrumentation/openai_java/ChatCompletionServiceAsyncInstrumentation.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public static AgentScope enter(
5656
AgentSpan span = startSpan(OpenAiDecorator.INSTRUMENTATION_NAME, OpenAiDecorator.SPAN_NAME);
5757
DECORATE.afterStart(span);
5858
DECORATE.decorateWithClientOptions(span, clientOptions);
59-
DECORATE.decorateChatCompletion(span, params);
59+
DECORATE.decorateChatCompletion(span, params, false);
6060
return activateSpan(span);
6161
}
6262

@@ -91,7 +91,7 @@ public static AgentScope enter(
9191
AgentSpan span = startSpan(OpenAiDecorator.INSTRUMENTATION_NAME, OpenAiDecorator.SPAN_NAME);
9292
DECORATE.afterStart(span);
9393
DECORATE.decorateWithClientOptions(span, clientOptions);
94-
DECORATE.decorateChatCompletion(span, params);
94+
DECORATE.decorateChatCompletion(span, params, true);
9595
return activateSpan(span);
9696
}
9797

dd-java-agent/instrumentation/openai-java/openai-java-1.0/src/main/java/datadog/trace/instrumentation/openai_java/ChatCompletionServiceInstrumentation.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public static AgentScope enter(
5555
AgentSpan span = startSpan(OpenAiDecorator.INSTRUMENTATION_NAME, OpenAiDecorator.SPAN_NAME);
5656
DECORATE.afterStart(span);
5757
DECORATE.decorateWithClientOptions(span, clientOptions);
58-
DECORATE.decorateChatCompletion(span, params);
58+
DECORATE.decorateChatCompletion(span, params, false);
5959
return activateSpan(span);
6060
}
6161

@@ -91,7 +91,7 @@ public static AgentScope enter(
9191
AgentSpan span = startSpan(OpenAiDecorator.INSTRUMENTATION_NAME, OpenAiDecorator.SPAN_NAME);
9292
DECORATE.afterStart(span);
9393
DECORATE.decorateWithClientOptions(span, clientOptions);
94-
DECORATE.decorateChatCompletion(span, params);
94+
DECORATE.decorateChatCompletion(span, params, true);
9595
return activateSpan(span);
9696
}
9797

dd-java-agent/instrumentation/openai-java/openai-java-1.0/src/main/java/datadog/trace/instrumentation/openai_java/OpenAiDecorator.java

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import datadog.trace.bootstrap.instrumentation.api.Tags;
2828
import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString;
2929
import datadog.trace.bootstrap.instrumentation.decorator.ClientDecorator;
30+
import java.util.ArrayList;
3031
import java.util.Collections;
3132
import java.util.HashMap;
3233
import java.util.List;
@@ -192,7 +193,7 @@ public void decorateWithClientOptions(AgentSpan span, ClientOptions clientOption
192193
// clientOptions.queryParams().values("api-version")
193194
}
194195

195-
public void decorateChatCompletion(AgentSpan span, ChatCompletionCreateParams params) {
196+
public void decorateChatCompletion(AgentSpan span, ChatCompletionCreateParams params, boolean stream) {
196197
span.setResourceName(CHAT_COMPLETIONS_CREATE);
197198
span.setTag("openai.request.endpoint", "v1/chat/completions");
198199
span.setTag("openai.request.method", "POST");
@@ -206,9 +207,17 @@ public void decorateChatCompletion(AgentSpan span, ChatCompletionCreateParams pa
206207
params.messages().stream().map(OpenAiDecorator::llmMessage).collect(Collectors.toList()));
207208

208209
Map<String, Object> metadata = new HashMap<>();
210+
// maxTokens is deprecated but integration tests missing to provide maxCompletionTokens
209211
params.maxTokens().ifPresent(v -> metadata.put("max_tokens", v));
210-
// params.maxCompletionTokens().ifPresent(v -> metadata.put("max_tokens", v));
211212
params.temperature().ifPresent(v -> metadata.put("temperature", v));
213+
if (stream) {
214+
metadata.put("stream", true);
215+
}
216+
params.streamOptions().ifPresent(v -> {
217+
if (v.includeUsage().orElse(false)) {
218+
metadata.put("stream_options", Collections.singletonMap("include_usage", true));
219+
}
220+
});
212221
span.setTag("_ml_obs_tag.metadata", metadata);
213222
}
214223

@@ -270,11 +279,50 @@ private static LLMObs.LLMMessage llmMessage(ChatCompletion.Choice choice) {
270279
}
271280

272281
public void decorateWithChatCompletionChunks(AgentSpan span, List<ChatCompletionChunk> chunks) {
273-
if (!chunks.isEmpty()) {
274-
span.setTag(RESPONSE_MODEL, chunks.get(0).model());
282+
if (chunks.isEmpty()) {
283+
return;
275284
}
285+
ChatCompletionChunk firstChunk = chunks.get(0);
286+
String modelName = firstChunk.model();
287+
span.setTag(RESPONSE_MODEL, modelName);
276288

277-
// TODO set LLMObs tags
289+
span.setTag("_ml_obs_tag.model_name", modelName);
290+
span.setTag("_ml_obs_tag.model_provider", "openai");
291+
// span.setTag("_ml_obs_tag.model_version", ); // TODO split and set version, e.g.
292+
// gpt-3.5-turbo-instruct:20230824-v2
293+
294+
// assume that number of choices is the same for each chunk
295+
final int choiceNum = firstChunk.choices().size();
296+
// collect roles by choices by the first chunk
297+
String[] roles = new String[choiceNum];
298+
for (int i=0; i < choiceNum; i++) {
299+
ChatCompletionChunk.Choice choice = firstChunk.choices().get(i);
300+
Optional<String> role = choice.delta().role().flatMap(r -> r._value().asString());
301+
if (role.isPresent()) {
302+
roles[i] = role.get();
303+
}
304+
}
305+
// collect content by choices for all chunks
306+
StringBuilder[] contents = new StringBuilder[choiceNum];
307+
for (int i=0; i < choiceNum; i++) {
308+
contents[i] = new StringBuilder(128);
309+
}
310+
for (ChatCompletionChunk chunk : chunks) {
311+
// choices can be empty for the last chunk
312+
List<ChatCompletionChunk.Choice> choices = chunk.choices();
313+
for (int i=0; i < choiceNum && i < choices.size(); i++) {
314+
ChatCompletionChunk.Choice choice = choices.get(i);
315+
ChatCompletionChunk.Choice.Delta delta = choice.delta();
316+
delta.content().ifPresent(contents[i]::append);
317+
}
318+
chunk.usage().ifPresent(usage -> OpenAiDecorator.annotateWithCompletionUsage(span, usage));
319+
}
320+
// build LLMMessages
321+
List<LLMObs.LLMMessage> llmMessages = new ArrayList<>(choiceNum);
322+
for (int i=0; i < choiceNum; i++) {
323+
llmMessages.add(LLMObs.LLMMessage.from(roles[i], contents[i].toString()));
324+
}
325+
span.setTag("_ml_obs_tag.output", llmMessages);
278326
}
279327

280328
public void decorateEmbedding(AgentSpan span, EmbeddingCreateParams params) {

0 commit comments

Comments
 (0)