Skip to content

[opentelemetry-instrumentation-genai-langchain] Record streaming telemetry for the LangChain instrumentation - #482

Open
sfc-gh-zeningchen wants to merge 3 commits into
open-telemetry:mainfrom
sfc-gh-zeningchen:langchain-streaming-telemetry
Open

[opentelemetry-instrumentation-genai-langchain] Record streaming telemetry for the LangChain instrumentation#482
sfc-gh-zeningchen wants to merge 3 commits into
open-telemetry:mainfrom
sfc-gh-zeningchen:langchain-streaming-telemetry

Conversation

@sfc-gh-zeningchen

Copy link
Copy Markdown

Description

Streamed LangChain calls never set gen_ai.request.stream or
gen_ai.response.time_to_first_chunk, and never recorded the
time_to_first_chunk / time_per_output_chunk histograms added in #269,
because the shared stream wrappers are the only producers of those values and a
callback-based instrumentation has no stream to wrap. This adds
GenAIInvocation.record_stream_chunk() to opentelemetry-util-genai as the
entry point for reporting chunk arrival without a stream, and implements
on_llm_new_token to call it once per output chunk. The capability lives in the
util rather than the instrumentation, per the direction on #8.

Fixes #481

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How has this been tested?

New tests/test_streaming.py in the langchain package covers .stream(),
.astream(), a non-streamed .invoke() asserting no stream attributes or
metric points appear, and a parametrized case separating LangChain's
end-of-stream marker from a genuinely content-free chunk. These patch the
model's _stream / _astream rather than replaying a cassette, because the
assertions are about chunk timing, which a cassette does not reproduce. Two
tests in test_handler_metrics.py cover record_stream_chunk() directly.

  • util-genai suite: 332 passed
  • langchain suite: 239 passed
  • Both matrix legs: verified at the declared floor (langchain==0.3.21,
    langchain-core 0.3.86, where chunk_position does not exist) and at
    latest (langchain==1.3.16, langchain-core 1.6.0)
  • tox -e precommit (ruff, ruff-format) and pyright clean

Checklist

  • Followed the style guidelines of this project
  • Changelog updated if the change requires an entry
  • Unit tests added
  • Documentation updated

A streamed call was indistinguishable from a synchronous one. The
callback-based handler never routes chunks through util-genai's stream
wrappers, so gen_ai.request.stream and gen_ai.response.time_to_first_chunk
were never set and the gen_ai.client.operation.time_to_first_chunk and
time_per_output_chunk histograms never recorded a point.

The wrappers own that bookkeeping for instrumentations that receive an SDK
stream to proxy, which a callback handler never does. Add
GenAIInvocation.record_stream_chunk() as the public entry point for
reporting chunk arrival without a stream, and implement on_llm_new_token
to call it once per output chunk.

Streaming is inferred from a token arriving rather than from the stream
invocation param, which LangChain derives from the model's streaming
field and leaves False for a plain .stream() call. LangChain's contentless
end-of-stream marker is skipped so it does not contribute a spurious
near-zero inter-chunk gap.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for streaming timing telemetry to the callback-based LangChain instrumentation by introducing a util-level API (GenAIInvocation.record_stream_chunk()) that can be invoked from token callbacks, enabling gen_ai.request.stream, gen_ai.response.time_to_first_chunk, and the streaming timing histograms to be emitted for LangChain .stream() / .astream().

Changes:

  • Add GenAIInvocation.record_stream_chunk() in opentelemetry-util-genai to record per-chunk arrival timing without wrapping an SDK stream.
  • Implement on_llm_new_token in the LangChain callback handler to call record_stream_chunk() for each real output chunk (skipping LangChain’s end-of-stream marker).
  • Add unit tests in both util-genai and langchain packages to validate streamed vs non-streamed behavior and marker handling.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
util/opentelemetry-util-genai/src/opentelemetry/util/genai/_invocation.py Adds record_stream_chunk() to mark streaming and record per-chunk timing.
util/opentelemetry-util-genai/tests/test_handler_metrics.py Adds direct tests for record_stream_chunk() and its metric/span effects.
util/opentelemetry-util-genai/.changelog/461.added Towncrier fragment documenting the new util entry point.
instrumentation/opentelemetry-instrumentation-genai-langchain/src/opentelemetry/instrumentation/genai/langchain/utils.py Adds is_stream_end_marker() helper for filtering LangChain’s contentless terminal marker.
instrumentation/opentelemetry-instrumentation-genai-langchain/src/opentelemetry/instrumentation/genai/langchain/callback_handler.py Implements on_llm_new_token to report streaming chunk arrivals.
instrumentation/opentelemetry-instrumentation-genai-langchain/tests/test_streaming.py Adds streaming/non-streaming tests and an end-of-stream marker regression test.
instrumentation/opentelemetry-instrumentation-genai-langchain/.changelog/461.fixed Towncrier fragment documenting the LangChain streaming telemetry fix.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread util/opentelemetry-util-genai/src/opentelemetry/util/genai/_invocation.py Outdated
@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Aug 25, 2026

Copy link
Copy Markdown

Pull request dashboard status

Waiting on reviewers · refreshed 2026-08-26 00:18 UTC

Review the latest changes.

Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Anything look wrong? Report it with what you expected; it helps us improve the dashboard.

sfc-gh-zeningchen and others added 2 commits August 25, 2026 17:00
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

langchain: streamed calls are not marked as streaming, thus no streaming timing signals emitted

2 participants