langgenius / langgenius/dify

[OTel] Emit gen_ai.response.model on LLM node spans (GenAI semconv conformance)

Open Beginner friendly
#40,635 0 comments 1 reaction 0 assignees View on GitHub
Dominant language
TypeScript
Stars
156k
Forks
24.6k
Avg merge
22h 9m
Merged PRs (30d)
610

Description

### Summary

The native OTel instrumentation (`api/extensions/otel/`) sets
`gen_ai.request.model` on LLM node spans but never sets `gen_ai.response.model`.

`gen_ai.response.model` is a first-class attribute in the OpenTelemetry GenAI
semantic conventions registry
(https://github.com/open-telemetry/semantic-conventions-genai). Several
observability backends key their GenAI model-level aggregations on
`gen_ai.response.model` specifically, not on `gen_ai.request.model`. In
practice this means the model breakdown views in those backends render empty
for Dify workloads, even though Dify is emitting otherwise-correct GenAI spans.

We hit this while building an open-source OTel conformance bridge for Dify
(https://github.com/obs-plugins/dynatrace-otel-bridge) and currently patch it
in the OTel Collector with an OTTL processor. Fixing it at the source in Dify
would benefit every backend, not just ours.

### Proposed change

Add `RESPONSE_MODEL = "gen_ai.response.model"` to `LLMAttributes` in
`api/extensions/otel/semconv/gen_ai.py`, and set it in
`api/extensions/otel/parser/llm.py` alongside the existing `REQUEST_MODEL`.

This is purely additive — no existing attribute is renamed or removed — so it
is backward-compatible with all current consumers (Langfuse, Arize Phoenix,
Opik) and does not require an `OTEL_SEMCONV_STABILITY_OPT_IN` gate.

### Known limitation (worth discussing)

Dify currently derives the model name from `process_data["model_name"]`, which
is the *requested* model. The model actually returned by the provider
(`LLMResult.model`) is not surfaced in `NodeRunResult`. The GenAI spec allows
`gen_ai.response.model` to be set on the instrumentation's best knowledge, so
using the same source is valid and immediately useful. The complete fix would
be for `graphon` to expose `LLMResult.model` in `process_data`. Happy to follow
up with a separate issue there if maintainers agree.

### Scope

I have a broader GenAI semconv conformance audit of the current OTel layer
(missing `gen_ai.workflow.name`, singular `gen_ai.response.finish_reason` vs.
the spec's plural array, absent GenAI metrics, non-spec `gen_ai.operation.name`
values). I'm intentionally keeping this issue narrow and additive. If
maintainers are open to it, I'd be glad to open a tracking issue for the rest.

### Request

Please assign this issue to me so I can open the PR, per CONTRIBUTING.md.

Contributor guide

Open the contributing guide

Research direction

Start by reading api/extensions/otel/semconv/gen_ai.py and api/extensions/otel/parser/llm.py, then trace how process_data["model_name"] is used for LLM node span attributes. Add the response-model attribute alongside the request-model attribute and verify that generated LLM spans contain both attributes without removing existing ones.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
observability-sre
Issue type
Feature
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.