Repository navigation
Conversation
Pull request dashboard statusWaiting on maintainers · refreshed 2026-11-09 17:41 UTC Merge when ready. Status above doesn't look right?
|
7528d97 to
5b7ad0c
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Agent call counts can miss direct model calls or callbacks from retained managers, and can overcount calls inside tools or retrievers.
3 open issues
What changed in this PR
Adds per-agent inference and tool call metrics to LangChain instrumentation, addressing #598 through the shared GenAI invocation utilities.
Changes:
- Initializes agent call counts and increments them from model and tool callbacks.
- Adds metric assertions for agent classification, nested agents, tool failures, and conformance scenarios.
- Raises the shared utility dependency floor and adds a changelog entry.
All paths below are under instrumentation/opentelemetry-instrumentation-genai-langchain/.
| File | Description |
|---|---|
tests/test_tools.py |
Checks tool counts on failures and nearest-agent attribution. |
tests/test_callback_handler.py |
Checks zero counts and unnamed-agent inference metrics. |
tests/requirements.oldest.txt |
Uses the local utility package pending release. |
tests/conformance/agent.py |
Validates both call-count histograms and expected totals. |
src/opentelemetry/instrumentation/genai/langchain/invocation_manager.py |
Initializes counts and resolves the nearest parent agent. |
src/opentelemetry/instrumentation/genai/langchain/callback_handler.py |
Counts text-model, chat-model, and tool starts. |
pyproject.toml |
Raises the utility dependency minimum to 1.4b0.dev. |
.changelog/1001.added |
Documents the new agent call-count feature. |
Review effort: Balanced
There was a problem hiding this comment.
🟡 Changes recommended
Agent call counts can be omitted for AgentExecutor, lost under concurrency, or double-counted for delegated models, with missing failure and oldest-version test coverage.
5 open issues
Enable call counting for identifiable AgentExecutor runs · New Synchronize shared agent and inference counter updates · New Stop delegated inference calls from being counted twice · New Add oldest-version create_react_agent call-count coverage · New Test failed tool and model calls under an announced agent · New
3 resolved since last review
Review effort: Balanced
71e3eda to
362c7bc
Compare
8b01ee1 to
cf8a014
Compare
cf8a014 to
53e21f2
Compare
| if token is not None: | ||
| context.run(detach, token) | ||
|
|
||
| def _wrap_attempt_config( |
There was a problem hiding this comment.
Sorry, my earlier retry comment sent this in the wrong direction. LangChain retries/fallbacks each produce their own chat span, so every traced inference is already one logical call from our side. Could we drop the retry dedup (_InferenceCallScope, the patch_config/BaseChatModel.invoke/middleware patches, start_inference_attempt) and just increment the agent counter in on_chat_model_start when we start an inference span? That keeps the metric consistent with the spans.
There was a problem hiding this comment.
Makes sense, made revisions to the code.
| ): | ||
| for method in ( | ||
| "on_chat_model_start", | ||
| "on_llm_start", |
There was a problem hiding this comment.
question: this looks unrelated now that on_llm_start isn't counted. Is it left over from the earlier version? If so, could we drop it along with the llm case in test_execution_context.py, and send it as a separate fix if it's still needed?
There was a problem hiding this comment.
Yes, it was left over from the previous iteration. Removed it in the updated version.
53e21f2 to
e955027
Compare
| @pytest.mark.asyncio | ||
| @pytest.mark.parametrize("asynchronous", [False, True], ids=["sync", "async"]) | ||
| @pytest.mark.parametrize("streaming", [False, True], ids=["invoke", "stream"]) | ||
| @pytest.mark.parametrize("strategy", ["retry", "fallback"]) | ||
| @pytest.mark.parametrize("failure", [False, True]) | ||
| @pytest.mark.parametrize("use_tool", [False, True]) | ||
| @pytest.mark.parametrize( | ||
| "use_middleware", | ||
| [ | ||
| False, | ||
| pytest.param( | ||
| True, | ||
| marks=pytest.mark.skipif( | ||
| not hasattr(langchain.agents, "create_agent"), | ||
| reason="Model middleware requires LangChain 1.x", | ||
| ), | ||
| ), | ||
| ], | ||
| ) | ||
| async def test_native_agent_retries_count_traced_inferences( |
There was a problem hiding this comment.
Now that retry dedup is gone, counting is just "one per chat span", so this 64-case retry/fallback/middleware matrix (plus test_agent_inference_counts_direct_fallback_stream and test_independent_model_calls_share_one_agent_node) mostly re-tests the old design. Could we drop them and keep test_native_agent_call_counts with a single retry case? Those tests would also fit better in an agent test module than in test_tools.py.
There was a problem hiding this comment.
Addressed. Created a new test_agent suite and added the test there.
13102fe to
a7ea024
Compare


Description
Fixes #598
Type of change
Please delete options that are not relevant.
How has this been tested?
Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. List any relevant details for your test
configuration.
Checklist
See CONTRIBUTING.md
for the style guide, changelog guidance, and more.