Setup: opentelemetry-instrumentation-langchain 0.62.1, langchain-core 1.4.8, a plain agent loop (model.invoke -> execute tool -> repeat) with no @workflow decorator and no enclosing span.
Observed: every chat span and every execute_tool span lands in its own trace (9 spans -> 9 distinct trace ids, all parentless). Reproduction script here: https://github.com/Dnakitare/kagua/blob/main/fixtures/otel/generate_openllmetry.py
I understand why: with no active span at invoke time, each callback root starts a fresh trace. And wrapping the loop in @workflow (or any parent span) fixes it. So this may be entirely by design.
Two questions:
- Is this the intended behavior for bare loops, or would you take a change that keeps a session-scoped parent so consecutive invocations in one loop share a trace?
- If it's intended, would you take a docs PR that calls it out? For anyone doing trace-level analysis downstream (in my case, replaying traces for authority verification, where within-task correlation is the whole game), the fragmentation is easy to miss and quietly breaks cross-span reasoning. A one-paragraph note in the LangChain instrumentation docs would save people the debugging session.
Happy to write the docs PR if that's the preferred resolution.
Setup:
opentelemetry-instrumentation-langchain0.62.1, langchain-core 1.4.8, a plain agent loop (model.invoke-> execute tool -> repeat) with no@workflowdecorator and no enclosing span.Observed: every chat span and every
execute_toolspan lands in its own trace (9 spans -> 9 distinct trace ids, all parentless). Reproduction script here: https://github.com/Dnakitare/kagua/blob/main/fixtures/otel/generate_openllmetry.pyI understand why: with no active span at invoke time, each callback root starts a fresh trace. And wrapping the loop in
@workflow(or any parent span) fixes it. So this may be entirely by design.Two questions:
Happy to write the docs PR if that's the preferred resolution.