Skip to content

Commit 436b802

Browse files
google-genai-botcopybara-github
authored andcommitted
feat: Update token usage reporting to include thoughts and cache tokens
PiperOrigin-RevId: 935139729
1 parent 2c1b7ab commit 436b802

2 files changed

Lines changed: 59 additions & 2 deletions

File tree

core/src/main/java/com/google/adk/telemetry/Tracing.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ public class Tracing {
114114
AttributeKey.longKey("gen_ai.usage.input_tokens");
115115
private static final AttributeKey<Long> GEN_AI_USAGE_OUTPUT_TOKENS =
116116
AttributeKey.longKey("gen_ai.usage.output_tokens");
117+
private static final AttributeKey<Long> GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS =
118+
AttributeKey.longKey("gen_ai.usage.cache_read.input_tokens");
119+
private static final AttributeKey<Long> GEN_AI_USAGE_REASONING_OUTPUT_TOKENS =
120+
AttributeKey.longKey("gen_ai.usage.reasoning.output_tokens");
117121

118122
private static final AttributeKey<String> ADK_TOOL_CALL_ARGS =
119123
AttributeKey.stringKey("gcp.vertex.agent.tool_call_args");
@@ -335,10 +339,23 @@ public static void traceCallLlm(
335339
usage
336340
.promptTokenCount()
337341
.ifPresent(tokens -> span.setAttribute(GEN_AI_USAGE_INPUT_TOKENS, (long) tokens));
342+
// According to OpenTelemetry Semantic Conventions:
343+
// https://github.com/open-telemetry/semantic-conventions/blob/v1.41.0/docs/registry/attributes/gen-ai.md
344+
// gen_ai.usage.reasoning.output_tokens (thoughts_token_count) SHOULD be included in
345+
// gen_ai.usage.output_tokens.
346+
Optional<Integer> candidates = usage.candidatesTokenCount();
347+
Optional<Integer> thoughts = usage.thoughtsTokenCount();
348+
if (candidates.isPresent() || thoughts.isPresent()) {
349+
span.setAttribute(
350+
GEN_AI_USAGE_OUTPUT_TOKENS, (long) candidates.orElse(0) + thoughts.orElse(0));
351+
}
352+
thoughts.ifPresent(
353+
tokens -> span.setAttribute(GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, (long) tokens));
338354
usage
339-
.candidatesTokenCount()
355+
.cachedContentTokenCount()
340356
.ifPresent(
341-
tokens -> span.setAttribute(GEN_AI_USAGE_OUTPUT_TOKENS, (long) tokens));
357+
tokens ->
358+
span.setAttribute(GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, (long) tokens));
342359
});
343360
llmResponse
344361
.finishReason()

core/src/test/java/com/google/adk/telemetry/ContextPropagationTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,46 @@ public void testTraceCallLlm() {
358358
assertTrue(attrs.get(AttributeKey.stringKey("gcp.vertex.agent.llm_response")).contains("STOP"));
359359
}
360360

361+
@Test
362+
public void testTraceCallLlm_withReasoningAndCacheTokens() {
363+
Span span = tracer.spanBuilder("test-reasoning").startSpan();
364+
try (Scope scope = span.makeCurrent()) {
365+
LlmRequest llmRequest =
366+
LlmRequest.builder()
367+
.model("gemini-pro")
368+
.contents(ImmutableList.of(Content.fromParts(Part.fromText("hello"))))
369+
.config(GenerateContentConfig.builder().topP(0.9f).maxOutputTokens(100).build())
370+
.build();
371+
LlmResponse llmResponse =
372+
LlmResponse.builder()
373+
.content(Content.builder().parts(Part.fromText("world")).build())
374+
.finishReason(new FinishReason(FinishReason.Known.STOP))
375+
.usageMetadata(
376+
GenerateContentResponseUsageMetadata.builder()
377+
.promptTokenCount(10)
378+
.cachedContentTokenCount(5)
379+
.candidatesTokenCount(20)
380+
.thoughtsTokenCount(15)
381+
.totalTokenCount(50)
382+
.build())
383+
.build();
384+
Tracing.traceCallLlm(
385+
span, buildInvocationContext(), "event-1", llmRequest, llmResponse, null);
386+
} finally {
387+
span.end();
388+
}
389+
List<SpanData> spans = openTelemetryRule.getSpans();
390+
assertThat(spans).hasSize(1);
391+
SpanData spanData = spans.get(0);
392+
Attributes attrs = spanData.getAttributes();
393+
assertEquals(10L, (long) attrs.get(AttributeKey.longKey("gen_ai.usage.input_tokens")));
394+
assertEquals(35L, (long) attrs.get(AttributeKey.longKey("gen_ai.usage.output_tokens")));
395+
assertEquals(
396+
5L, (long) attrs.get(AttributeKey.longKey("gen_ai.usage.cache_read.input_tokens")));
397+
assertEquals(
398+
15L, (long) attrs.get(AttributeKey.longKey("gen_ai.usage.reasoning.output_tokens")));
399+
}
400+
361401
@Test
362402
public void testTraceSendData() {
363403
Span span = tracer.spanBuilder("test").startSpan();

0 commit comments

Comments
 (0)