-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Description
Describe the bug
The .NET Gemini connector emits OpenTelemetry token usage metrics for every streaming chunk instead of only once at the end. This causes inflated token usage and cost tracking in downstream telemetry systems.
To Reproduce
- Use
GeminiChatCompletionClientwith streaming enabled - Monitor the OpenTelemetry counters (
s_promptTokensCounter,s_completionTokensCounter,s_totalTokensCounter) which expose the metricsMicrosoft.SemanticKernel.Connectors.Google.tokens.prompt,Microsoft.SemanticKernel.Connectors.Google.tokens.completion, andMicrosoft.SemanticKernel.Connectors.Google.tokens.total. - Observe metrics are emitted for every chunk (e.g., 30 chunks = 30 metric events for a single API call)
Expected: Token usage metrics emitted once per API call
Actual: Token usage metrics emitted once per streaming chunk
Root Cause
In ProcessChatResponseStreamAsync (around line 540 in commit 5948dbc), the method calls ProcessChatResponse() for every streaming chunk, which in turn calls LogUsage() (around line 568).
The Gemini API sends accumulated token counts in every chunk (not deltas), so each LogUsage() call emits the full token count to the OpenTelemetry counters (around lines 600–602).
File: dotnet/src/Connectors/Connectors.Google/Core/Gemini/Clients/GeminiChatCompletionClient.cs
Comparison with OpenAI Connector
The OpenAI connector does not call LogUsage() during streaming—only after non-streaming completion (see GetChatMessageContentsAsync around line 173 in the same commit).
File: dotnet/src/Connectors/Connectors.OpenAI/Core/ClientCore.ChatCompletion.cs
Related
This appears to be the same bug pattern that was fixed for Python/OpenAI in #12977 (merged Sep 3, 2025).
Impact
Production systems show inflated costs (e.g., $0.40 logged vs. $0.02 actual API cost) due to duplicate telemetry.
Environment
- SK Version: 1.66.0 (commit 5948dbc)
- Connector:
Microsoft.SemanticKernel.Connectors.Google - Models: All Gemini models (observed with
gemini-2.5-pro) - .NET: 8+