LiteLlm with SSE streaming records the answer twice in gen_ai.output.messages
Maintainer thường phản hồi trong vòng 4 ngày
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 78/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- python
- Lĩnh vực
- backend, observability
Hướng nghiên cứu
Bắt đầu với src/google/adk/telemetry/_instrumentation.py, đặc biệt là record_llm_response, và so sánh cách đoạn mã xử lý các phản hồi một phần được truyền theo luồng với phản hồi đã tổng hợp. Sau đó đọc mã truyền luồng LiteLlm trong src/google/adk/models/lite_llm.py ở gần các dòng được liên kết. Tái hiện bằng ví dụ StreamingMode.SSE được cung cấp và xác minh đầu ra được ghi nhận có một thông điệp trả lời đầy đủ, khớp với StreamingMode.NONE.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
🔴 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
- Ngôn ngữ chính
- Python
- Star
- 22k
- Fork
- 4.2k
- Merge trung bình
- 3 ngày 11 giờ
- Pull request đã merge (30 ngày)
- 7
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của google/adk-python
-
gen_ai.choice log reports gen_ai.system=gemini for OpenAI and Groq models through LiteLlmCó thể đã có người làm @llalitkumarrr đã nhận 2 ngày trước. Đang mởmodels
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
google/adk-python#7631 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 4 ngày
-
Update opentelemetry-api and opentelemetry-sdk to 1.44.0Có thể đã có người làm @llalitkumarrr đã nhận 16 ngày trước. Đang mởrequest clarification tracing
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
google/adk-python#7433 · 5 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 4 ngày
-
CI Mypy Check flags an existing streaming_utils.py error as new because the PR run reuses the baseline's mypy cacheCó thể đã có người làm @DeanChensj đã nhận 18 ngày trước. Đang mởneeds review
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
google/adk-python#7409 · 1 bình luận · 2 người được giao ·
Maintainer thường phản hồi trong vòng 4 ngày
-
A2aAgentExecutor sends the raw exception text to the A2A caller when the run failsCó thể đã có người làm @sanketpatil06 đã nhận 18 ngày trước. Đang mởa2a request clarification
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
google/adk-python#7385 · 2 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 4 ngày
-
Please support mermaid 12 (inbuild elk) in `adk web`Có thể đã có người làm @sanketpatil06 đã nhận 19 ngày trước. Đang mởneeds review web
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
google/adk-python#7381 · 1 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 4 ngày
Tất cả issue của google/adk-python
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 77/100
AstrBotDevs/AstrBot#10720 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
fix(xiaomi): curated picker list still offers six ids that return 400 (plan-limited vs retired)Đang mởcause/upstream comp/cli P2 provider/other tool/file type/bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
NousResearch/hermes-agent#143900 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 85/100
WLAN-Pi/wlanpi-profiler#341 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 77/100
Maintainer thường phản hồi trong vòng 1 ngày