LiteLlm with SSE streaming records the answer twice in gen_ai.output.messages
Los mantenedores suelen responder en 4 días
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 78/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- python
- Área
- backend, observability
Línea de trabajo
Empieza por src/google/adk/telemetry/_instrumentation.py, especialmente por record_llm_response, y compara cómo gestiona las respuestas parciales transmitidas en streaming frente a la respuesta agregada. Después, lee el código de streaming de LiteLlm en src/google/adk/models/lite_llm.py, en torno a las líneas enlazadas. Reproduce el caso con el ejemplo proporcionado de StreamingMode.SSE y verifica que la salida capturada contenga un único mensaje de respuesta completo, coincidente con StreamingMode.NONE.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
🔴 Required Information
Describe the Bug:
with StreamingMode.SSE and a LiteLlm model the generate_content span ends up with every streamed chunk in gen_ai.output.messages and then the full answer again at the end. so the answer shows up twice and all the chunks have an empty finish_reason. without streaming its one message like expected. only visible with message content capture on (OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT)
looks like the text chunks get yielded as partial responses with no finish reason (lite_llm.py#L4475-L4485) and only the final aggregated response gets one (#L4556-L4558). record_llm_response keeps recording until it sees a finish reason (_instrumentation.py#L568-L595) so every chunk plus the aggregate goes in. since its in the LiteLlm wrapper i'd expect real providers to do the same but i only tested with litellm's mock_response
Steps to Reproduce:
pip install google-adk litellm- run this (no api key needed, it uses litellm's
mock_response)
import asyncio
import json
import os
os.environ["OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"] = "SPAN_ONLY"
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
spans = InMemorySpanExporter()
provider = TracerProvider()
provider.add_span_processor(SimpleSpanProcessor(spans))
trace.set_tracer_provider(provider)
from google.adk.agents import Agent
from google.adk.agents.run_config import RunConfig, StreamingMode
from google.adk.models.lite_llm import LiteLlm
from google.adk.runners import InMemoryRunner
from google.genai import types
async def run(mode):
spans.clear()
model = LiteLlm(model="openai/gpt-4o", mock_response="Oslo is 4C and cloudy today.", api_key="unused")
runner = InMemoryRunner(agent=Agent(name="a", model=model), app_name="p")
session = await runner.session_service.create_session(app_name="p", user_id="u")
msg = types.Content(role="user", parts=[types.Part(text="weather?")])
async for _ in runner.run_async(user_id="u", session_id=session.id, new_message=msg,
run_config=RunConfig(streaming_mode=mode)):
pass
await runner.close()
span = next(s for s in spans.get_finished_spans() if s.name.startswith("generate_content"))
messages = json.loads(span.attributes["gen_ai.output.messages"])
print(f"{mode.name}: {len(messages)} output message(s)")
for m in messages:
print(" ", repr(m.get("finish_reason")), "".join(p.get("content", "") for p in m["parts"]))
asyncio.run(run(StreamingMode.NONE))
asyncio.run(run(StreamingMode.SSE))
Expected Behavior:
one output message with the full answer, same as without streaming
Observed Behavior:
NONE: 1 output message(s)
'stop' Oslo is 4C and cloudy today.
SSE: 11 output message(s)
'' Osl
'' o i
'' s 4
'' C a
'' nd
'' clo
'' udy
'' to
'' day
'' .
'stop' Oslo is 4C and cloudy today.
Environment Details:
- ADK Library Version (pip show google-adk): 2.12.0 (main at 77a74f0)
- Desktop OS: macOS
- Python Version (python -V): 3.12.15
Model Information:
- Are you using LiteLLM: Yes
- Which model is being used: openai/gpt-4o via litellm
mock_response
🟡 Optional Information
Regression:
havent checked older versions
maybe skip the partial chunks when recording output messages and keep just the aggregate? happy to send a PR if that sounds right
- Lenguaje dominante
- Python
- Estrellas
- 21.9k
- Forks
- 4.2k
- Merge medio
- 3 d 16 h
- PR fusionados (30 d)
- 6
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de google/adk-python
-
gen_ai.choice log reports gen_ai.system=gemini for OpenAI and Groq models through LiteLlmPosiblemente ocupada @Hugo-DDT la tomó hace 1 día. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
google/adk-python#7631 ·
Los mantenedores suelen responder en 4 días
-
Update opentelemetry-api and opentelemetry-sdk to 1.44.0Posiblemente ocupada @llalitkumarrr la tomó hace 14 días. Abiertorequest clarification tracing
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
google/adk-python#7433 · 5 comentarios · 1 asignado ·
Los mantenedores suelen responder en 4 días
-
CI Mypy Check flags an existing streaming_utils.py error as new because the PR run reuses the baseline's mypy cachePosiblemente ocupada @DeanChensj la tomó hace 16 días. Abiertoneeds review
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
google/adk-python#7409 · 1 comentario · 2 asignados ·
Los mantenedores suelen responder en 4 días
-
A2aAgentExecutor sends the raw exception text to the A2A caller when the run failsPosiblemente ocupada @sanketpatil06 la tomó hace 16 días. Abiertoa2a request clarification
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
google/adk-python#7385 · 2 comentarios · 1 asignado ·
Los mantenedores suelen responder en 4 días
-
Please support mermaid 12 (inbuild elk) in `adk web`Posiblemente ocupada @sanketpatil06 la tomó hace 17 días. Abiertoneeds review web
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
google/adk-python#7381 · 1 comentario · 1 asignado ·
Los mantenedores suelen responder en 4 días
Todos los issues de google/adk-python
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
volcengine/OpenViking#6445 ·
Los mantenedores suelen responder en 1 día
-
BUG:Edit Album strips spaces from the password so albums with a leading/trailing space in the password can't be editedPosiblemente ocupada @ManyaJain111 la tomó hoy. Abiertobug enhancement possible-duplicate
Dificultad 2/5 1-3 horas Aptitud para principiantes 77/100
AOSSIE-Org/PictoPy#1637 · 4 comentarios ·
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
deepspeedai/DeepSpeed#8884 ·
Los mantenedores suelen responder en 3 días
-
Flaky: test_advisor_live_calibrates_an_unmeasured_circuit ranks engines by a 1.8ms sleep marginAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
flagos-ai/FlagQuantum#718 ·
Los mantenedores suelen responder en 1 día
-
bug CI-failure high priority
Dificultad 1/5 Menos de una hora Aptitud para principiantes 86/100
vllm-project/afd-plugin#483 ·
Los mantenedores suelen responder en 1 día