fix: store OpenAI agent Generation span attributes under correct SpanAttributeKey constants#24290
Conversation
…teKey.CHAT_USAGE Signed-off-by: Rudra Dudhat <[email protected]>
Install mlflow from this PR
Install mlflow from this PR# mlflow
pip install git+https://github.com/mlflow/mlflow.git@refs/pull/24290/merge
# mlflow-skinny
pip install git+https://github.com/mlflow/mlflow.git@refs/pull/24290/merge#subdirectory=libs/skinnyFor Databricks, use the following command: %sh curl -LsSf https://raw.githubusercontent.com/mlflow/mlflow/HEAD/dev/install-skinny.sh | sh -s pull/24290/mergePR author's recent activityIn the last 14 days, @RudraDudhat2509 opened 15 PRs across 4 repos:
|
There was a problem hiding this comment.
Pull request overview
This PR fixes a data-correctness issue in MLflow’s OpenAI Agents SDK tracing integration where token usage recorded on GENERATION spans was stored under the wrong attribute key, preventing trace-level token aggregation (and related downstream consumers) from seeing those tokens.
Changes:
- Update
_parse_span_data()forGENERATIONspans to store usage underSpanAttributeKey.CHAT_USAGEinstead of a plain"usage"attribute. - Add
_parse_generation_usage()helper to normalize usage dicts into MLflow’sTokenUsageKeyschema. - Add unit tests covering both the span attribute behavior and the usage parsing helper.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
mlflow/openai/_agent_tracer.py |
Writes Generation span usage under SpanAttributeKey.CHAT_USAGE via a new parsing helper. |
tests/openai/test_openai_agent_autolog.py |
Adds tests ensuring usage is stored under CHAT_USAGE and validating _parse_generation_usage(). |
Co-authored-by: Copilot Autofix powered by AI <[email protected]> Signed-off-by: Rudra Dudhat <[email protected]>
|
opened #24393 to address copilot comments |
|
Following @joshuawong-db's note on #24393 (closed into this PR): could you also fold in the model-key fix here? The |
…MODEL
Using a plain string key "model" instead of SpanAttributeKey.MODEL
("mlflow.llm.model") caused calculate_span_cost() to silently skip
cost calculation for Generation spans because the attribute was never
found via get_attribute().
Signed-off-by: Rudra Dudhat <[email protected]>
|
hey @PattaraS ! pushed the changes, also updated the test file, lmk if anything else is required from my end, thx |
Merged model-key and token-usage assertions into one test (test_generation_span_attributes_stored_under_span_attribute_keys) to verify both fixes together; mocked cost calculation in test_calculate_span_cost_uses_generation_span_model_attribute to avoid coupling to LiteLLM pricing data. Signed-off-by: Rudra Dudhat <[email protected]>
Signed-off-by: Rudra Dudhat <[email protected]>
|
/review-v2 |
|
Documentation preview for d06cc26 is available at: More info
|
joshuawong-db
left a comment
There was a problem hiding this comment.
Thank you, in general this looks good, pending one comment on cached tokens nesting. Could you also update the PR description? It references tests that do not exist in the code.
…tion span usage Signed-off-by: Rudra Dudhat <[email protected]>
Generation span token usage under SpanAttributeKey.CHAT_USAGE
joshuawong-db
left a comment
There was a problem hiding this comment.
LGTM, thanks for the contribution @RudraDudhat2509
|
Appreciate the quick review thx! |
…AttributeKey constants (#24290) Signed-off-by: Rudra Dudhat <[email protected]> Co-authored-by: Copilot Autofix powered by AI <[email protected]> Co-authored-by: mprahl <[email protected]>
Related Issues/PRs
Closes #24059
What changes are proposed in this pull request?
MlflowOpenAgentTracingProcessor._parse_span_data()wrote token usage forGENERATIONspans under the plain key"usage". However,aggregate_usage_from_spans()andcalculate_span_cost()both readSpanAttributeKey.CHAT_USAGE("mlflow.chat.tokenUsage"). The key mismatch silently dropped all token counts fromtrace.info.token_usage. Streaming calls were hit hardest since the Agents SDK is the only source of usage data for those spans.Two fixes in this PR:
Added
_parse_generation_usage()helper that maps the Agents SDK usage dict toTokenUsageKey-keyed values and sets the result underSpanAttributeKey.CHAT_USAGEinside_parse_span_data(). Matches the existing pattern inmlflow/groq/_groq_autolog.pyandmlflow/anthropic/autolog.py._parse_span_data()now setsSpanAttributeKey.MODEL(not plain"model") forGENERATIONspans, socalculate_span_cost()can read the model name and compute cost correctly.No API changes are needed.
How is this PR tested?
test_generation_span_attributes_stored_under_span_attribute_keys: mocks aGenerationSpanData, calls_parse_span_data(), asserts attributes contain bothSpanAttributeKey.MODELandSpanAttributeKey.CHAT_USAGEwith correct values, and that neither plain"model"nor"usage"keys exist.test_parse_generation_usage: parametrized over full dict, partial dict, nestedinput_tokens_detailswith both cache keys, partial cache details (only one key present),None, and empty dict.test_calculate_span_cost_uses_generation_span_model_attribute: verifies cost calculation reads the model fromSpanAttributeKey.MODELand not the plain"model"key.Does this PR require documentation update?
Does this PR require updating the MLflow Skills repository?
Release Notes
Is this a user-facing change?
Token usage from OpenAI Agents SDK
GENERATIONspans (including streamed runs) now correctly rolls up intotrace.info.token_usageand is used bycalculate_span_cost(). Cached token counts (read and creation) are now captured from the nestedinput_tokens_detailsfield. Model name is now stored under the correct attribute key so span cost is no longer silently skipped.What component(s), interfaces, languages, and integrations does this PR affect?
Components
area/tracking: Tracking Service, tracking client APIs, autologgingarea/models: MLmodel format, model serialization/deserialization, flavorsarea/model-registry: Model Registry service, APIs, and the fluent client calls for Model Registryarea/scoring: MLflow Model server, model deployment tools, Spark UDFsarea/evaluation: MLflow model evaluation features, evaluation metrics, and evaluation workflowsarea/gateway: MLflow AI Gateway client APIs, server, and third-party integrationsarea/prompts: MLflow prompt engineering features, prompt templates, and prompt managementarea/tracing: MLflow Tracing features, tracing APIs, and LLM tracing functionalityarea/projects: MLproject format, project running backendsarea/uiux: Front-end, user experience, plotting, JavaScript, JavaScript dev serverarea/build: Build and test infrastructure for MLflowarea/docs: MLflow documentation pagesHow should the PR be classified in the release notes? Choose one:
rn/none- No description will be included. The PR will be mentioned only by the PR number in the "Small Bugfixes and Documentation Updates" sectionrn/breaking-change- The PR will be mentioned in the "Breaking Changes" sectionrn/feature- A new user-facing feature worth mentioning in the release notesrn/bug-fix- A user-facing bug fix worth mentioning in the release notesrn/documentation- A user-facing documentation change worth mentioning in the release notesIs this PR a critical bugfix or security fix that should go into the next patch release?
What is a minor/patch release?
Minor releases are expected to contain larger changes, such as new features and improvements. Non-critical bug fixes and doc updates can be included as well. By default, your PR should target the next minor release.
Patch releases are typically only performed when there has been a major regression or bug in the latest release. For the sake of stability, your PR should not be included in a patch release unless it is a critical fix, or if the risk level of your PR is exceedingly low.