LiteLlm with SSE streaming records the answer twice in gen_ai.output.messages
維護者通常 4 天內回覆
還沒有人認領這個 Issue。
評估
- 難度
- 2/5
- 預估耗時
- 1-3 小時
- 新手友好度
- 78/100
- Issue 類型
- 缺陷
- 描述清晰度
- 描述清楚
- 活躍度
- 活躍
- 技術堆疊
- python
- 領域
- backend, observability
研究方向
從 src/google/adk/telemetry/_instrumentation.py 開始,特別查看 record_llm_response,並比較它如何處理串流傳輸的部分回應與彙總後的回應。接著閱讀 src/google/adk/models/lite_llm.py 中連結行附近的 LiteLlm 串流程式碼。使用提供的 StreamingMode.SSE 範例重現,並驗證擷取的輸出包含一則完整的回答訊息,與 StreamingMode.NONE 相符。
由索引模型根據 Issue 內容生成。
描述
🔴 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
- 主要語言
- Python
- 星號
- 21.9k
- 分支
- 4.2k
- 平均合併
- 3 天 16 小時
- 30 天內合併 PR
- 6
環境準備
- 沒有 Dockerfile 或 Docker Compose 檔案
- 有 Pull Request 範本
- 閱讀貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
google/adk-python 的其他 Issue
-
gen_ai.choice log reports gen_ai.system=gemini for OpenAI and Groq models through LiteLlm可能已有人在做 @Hugo-DDT 於 1 天前認領。 未關閉
難度 2/5 1-3 小時 新手友好度 82/100
google/adk-python#7631 ·
維護者通常 4 天內回覆
-
Update opentelemetry-api and opentelemetry-sdk to 1.44.0可能已有人在做 @llalitkumarrr 於 14 天前認領。 未關閉request clarification tracing
難度 2/5 1-3 小時 新手友好度 70/100
google/adk-python#7433 · 5 則留言 · 已指派 1 人 ·
維護者通常 4 天內回覆
-
CI Mypy Check flags an existing streaming_utils.py error as new because the PR run reuses the baseline's mypy cache可能已有人在做 @DeanChensj 於 16 天前認領。 未關閉needs review
難度 2/5 1-3 小時 新手友好度 72/100
google/adk-python#7409 · 1 則留言 · 已指派 2 人 ·
維護者通常 4 天內回覆
-
A2aAgentExecutor sends the raw exception text to the A2A caller when the run fails可能已有人在做 @sanketpatil06 於 16 天前認領。 未關閉a2a request clarification
難度 2/5 1-3 小時 新手友好度 84/100
google/adk-python#7385 · 2 則留言 · 已指派 1 人 ·
維護者通常 4 天內回覆
-
Please support mermaid 12 (inbuild elk) in `adk web`可能已有人在做 @sanketpatil06 於 17 天前認領。 未關閉needs review web
難度 2/5 1-3 小時 新手友好度 62/100
google/adk-python#7381 · 1 則留言 · 已指派 1 人 ·
維護者通常 4 天內回覆
查看 google/adk-python 的全部 Issue
相似的 Issue
-
comp/tools P2 type/bug
難度 2/5 1-3 小時 新手友好度 78/100
NousResearch/hermes-agent#142908 · 1 則留言 ·
-
[oblt-aw][autodoc] Fix malformed headings in new Buildkite docs pages可能已有人在做 @github-actions 今天認領。 未關閉documentation
難度 1/5 1 小時以內 新手友好度 83/100
維護者通常 1 天內回覆
-
[Bug]: fileUploadMatrix.test.ts URL case does a real DNS lookup and fails offline可能已有人在做 @r2jaff 今天認領。 未關閉
難度 2/5 1-3 小時 新手友好度 72/100
ComposioHQ/composio#5054 ·
維護者通常 1 天內回覆
-
難度 1/5 1 小時以內 新手友好度 88/100
維護者通常 1 天內回覆
-
bug
難度 2/5 1-3 小時 新手友好度 82/100
pytorch/tensordict#3286 ·
維護者通常 1 天內回覆