Hacktoberfest 2026:維護者為十月標記出來的 issue,仍然開放、適合新手。 瀏覽 Hacktoberfest issue

auto_instrument() creates duplicate LLM spans for Google ADK Gemini calls

已關閉
#896 1 則留言 0 個 reaction 已指派 1 人 在 GitHub 檢視

維護者通常 1 天內回覆

@AbhiPrasad 已經在處理了。

開始於 2026年10月8日。

  • #897 來自 @AbhiPrasad —— 已合併

評估

這個 Issue 還沒有評估資料。

描述

bug python

With braintrust.auto_instrument(), a Google ADK Gemini request produces two nested llm spans with identical token usage: ADK's llm_call [direct_response] and Google GenAI's generate_content.

Reproduction

Install:

pip install braintrust==0.45.0 google-adk==2.11.0 google-genai==2.28.0

Configure BRAINTRUST_API_KEY, BRAINTRUST_PROJECT, and GOOGLE_API_KEY through environment variables. Use a test project: this example makes a Gemini request and uploads its trace to Braintrust.

import asyncio
import os

import braintrust
from google.adk.agents import LlmAgent
from google.adk.runners import InMemoryRunner
from google.genai import types

logger = braintrust.init_logger(project=os.environ["BRAINTRUST_PROJECT"])
braintrust.auto_instrument()

async def main():
    agent = LlmAgent(
        name="hello",
        model="gemini-2.5-flash",
        instruction="Reply with one word.",
    )
    runner = InMemoryRunner(agent=agent, app_name="repro")
    session = await runner.session_service.create_session(
        app_name="repro", user_id="u"
    )
    msg = types.Content(
        role="user", parts=[types.Part(text="Say hello.")]
    )
    with braintrust.start_span(name="adk_duplicate_span_repro"):
        async for _ in runner.run_async(
            user_id="u", session_id=session.id, new_message=msg
        ):
            pass

asyncio.run(main())
logger.flush()

Observations and validation

Originally observed with Braintrust 0.41.0, Google ADK 1.14.1, and Google GenAI 1.75.0.

Also reproduced on October 7, 2026 using the latest stable versions available that day: Braintrust 0.45.0, Google ADK 2.11.0, and Google GenAI 2.28.0, on Python 3.13.12/macOS.

The latest-version test used the real ADK runner, Gemini adapter, GenAI SDK, and Braintrust instrumentation, with only the provider network response mocked. Spans were captured in memory without uploading. It did not verify live Gemini calls or Braintrust dashboard aggregation on these newer versions.

A synthetic response containing 23 prompt tokens and 62 completion tokens produced:

Instrumentation Provider requests LLM spans Summed prompt tokens Summed completion tokens
Both enabled 1 2 46 124
ADK only 1 1 23 62
GenAI only 1 1 23 62

Each configuration ran in a fresh process. Assertions confirmed that both spans carried identical usage and that generate_content was a direct child of llm_call [direct_response]. Dependency validation with pip check passed.

In the original live traces, trace summaries counted both spans and reported duplicated LLM-call and token totals. Exact token values can vary between live runs.

Expected behavior

Each underlying Gemini request should contribute usage and LLM-call count once, while retaining ADK agent/tool tracing and instrumentation of Gemini calls made outside ADK.

Suspected cause

_flow_call_llm_async_wrapper in py/src/braintrust/integrations/adk/tracing.py opens an llm span around BaseLlmFlow._call_llm_async and logs response usage.

The nested Google GenAI generate_content call is separately instrumented as an llm span and logs usage for the same request.

Impact and possible approach

Duplicated usage inflates token totals and can affect cost reporting based on those totals. Disabling ADK instrumentation loses its agent/tool tracing; disabling Google GenAI instrumentation loses automatic tracing of direct Gemini calls outside ADK in the same process.

One possible approach is to suppress the redundant provider span within an ADK model call, or retain it as a non-llm span without duplicated usage. Removing usage alone would leave the duplicate LLM-call count.

Related: #878, fixed by PR #880, concerns a different duplication mechanism involving wrap_openai() and auto_instrument().

主要語言
Python
星號
22
分支
27
平均合併
14 小時 49 分鐘
30 天內合併 PR
126

環境準備

  • 提供 Dockerfile 或 Docker Compose 檔案
  • 沒有 Pull Request 範本
  • 閱讀貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

braintrustdata/braintrust-sdk-python 的其他 Issue

查看 braintrustdata/braintrust-sdk-python 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。