gen_ai.response.model Is Only Recommended, Which Is Why Nobody Can Prove Which Model Answered
OpenTelemetry's GenAI convention asks harder for the model you requested than for the model that replied. Here is what that costs you the first time somebody asks.
OpenTelemetry's GenAI span convention carries two fields for the model. gen_ai.request.model is the one you asked for, and the spec marks it Conditionally Required. gen_ai.response.model is the one that actually generated the answer, and that one is only Recommended. Both still carry the Development stability badge, which means neither is frozen yet.
Put those two requirement levels side by side and you have the reason nobody can currently prove which model served a given request. The standard asks harder about intent than about outcome.
The spec is not confused about why the two can differ. Its own note on the response field says the value "must be the exact name of the model actually used," and the distinction exists precisely because a provider might route your request somewhere other than where you pointed it. The convention understood the failure mode. It just declined to require the field that catches it. (OpenTelemetry GenAI spans)
The gap stopped being theoretical on Friday
On September 25 a researcher named Peter James published a finding about Meta's Muse assistant. A session log routed to an internal model name, azure/muse-special, instead of Meta's own Avocado. He had no vendor statement and no API documentation. What he had was format evidence: tool call IDs matching OpenAI's shape of call_ plus 24 mixed-case characters, a signature tagged gpt_responses_v1 carrying an encrypted payload starting with gAAAAA, a model catalogue listing both Claude and GPT variants, and Anthropic client files sitting in the codebase.
He hedged the conclusion himself, and the hedges belong with the claim. "Possibly an OpenAI model." "My best guess is that muse-special is an OpenAI model." And the sentence that names the actual problem: "The files and logs don't tell me exactly which GPT model, or why it was selected by the subagent." (mouse.dev)
One session log is one session log, and none of this is proof. That is the point. The most credible public attempt to identify a production model this month was reverse engineering from an ID prefix, because the field designed to carry that answer is optional.
Why anyone would pay for the answer now
Two days before the Muse post, the question stopped being an engineering curiosity.
On Friday, September 25, the D.C. Circuit upheld the Pentagon's designation of Anthropic as a supply chain risk in a 2-1 decision. According to reporting on the ruling, the majority concluded the Pentagon "had enough evidence to conclude that Claude's built-in restrictions and the unresolved contract dispute could make it unreliable for military operations." Anthropic's response points at a split in the courts: "Another federal court has already held the government's parallel designation unlawful. We remain confident in our position and are considering all options, including further review." (ABC News)
Set the legal merits aside, because they are not what should worry a builder. Look at what the reasoning treats as a fact about a product. A model's built-in refusal behavior became a supply chain characteristic that a buyer can be judged on. Refusal behavior belongs to a specific model at a specific version, trained under a specific policy. Which means the question "whose policy was in this request path, at what version" is now a question a procurement officer, an auditor, or opposing counsel can reasonably ask about your product.
Most teams cannot answer it. Not because they are careless, but because their traces record the response text and the request they intended to make, and stop there.
I have gone looking for this field in real systems more than once. The pattern is consistent: the request model is there, because the client library set it when you called it. The response model is missing, because nobody wired it, because nothing required it, because it never broke anything.
What the field actually catches
The response model field earns its place in four situations, and all four are common.
Provider-side routing. You ask for a model family and the provider serves a specific dated checkpoint. The spec's own example makes this literal: the request example is gpt-4 and the response example is gpt-4-0613. Without the response field, your logs claim you ran a model name that does not identify a weight set.
Fallback chains. Your harness retries on a cheaper or a different model when the primary is unavailable. Every fallback is a silent substitution unless the response is labeled. If an evaluation run silently included fallback traffic, every conclusion drawn from it describes a mixture nobody wrote down.
Gateways and resellers. A gateway between you and the lab can route anywhere it likes. If the gateway does not report the responding model, you are trusting a routing table you cannot see. That is exactly the shape of the Muse case, and it is exactly the shape of most enterprise AI procurement right now.
Fine-tunes. The spec says a fine-tuned custom model "should have a more specific name than the base model that's been fine-tuned." A trace that records only the base model for a fine-tune has thrown away the part that identifies what actually ran.
Put this into practice
Start with the cheapest version that produces a usable record. This is an afternoon, not a project.
Set both attributes on every model call, at the edge where you already build the span. The request model you almost certainly have. The response model comes from the provider's own response body, under the model key on OpenAI-compatible and Anthropic responses, and it is the value the provider reports rather than the one you sent.
span.set_attribute("gen_ai.request.model", requested) # what you asked for
span.set_attribute("gen_ai.response.model", resp.model) # what answered
span.set_attribute("gen_ai.provider.name", provider)
span.set_attribute("gen_ai.response.id", resp.id)
Then add one assertion that costs nothing and catches the interesting case: when resp.model does not start with the string you requested, count it. Not an alert, a counter. You want to know your substitution rate before somebody else discovers it. On a well-behaved direct provider it sits near zero, and the number stops being boring the moment a gateway enters the path.
Keep the pair for as long as you keep the response. A trace that expires in seven days answers no question that arrives in month four, and every question worth asking about model provenance arrives late.
If you run through a gateway or a reseller, ask them today, in writing, whether they pass the upstream model identifier through in the response body. A vendor who cannot answer that question has told you something useful about what else they cannot tell you.
And if you are about to fine-tune on collected trajectories, check the response model distribution in that collection window first. LangSmith shipped exactly this workflow on September 25, with a smithtune CLI that "helps turn trajectories into useful training data" and training run through Baseten or Fireworks. That is a real convenience. It also means whatever your router happened to do during the collection period gets baked into weights permanently, and you will not see it later unless the traces recorded which model produced each turn. (LangChain)
Honest limitations
This does not give you provenance. It gives you the provider's claim about provenance, which is a much weaker thing, and worth being clear-eyed about.
The value in gen_ai.response.model is self-reported by the same party whose routing you are trying to audit. A provider that wants to obscure a substitution can report whatever it likes. Nothing in the record is signed, nothing is attestable, and no third party countersigns it. The field turns an unanswerable question into a verifiable-by-cross-check question, and that is the whole improvement.
It also does not cover the layers underneath. It tells you a model name. It tells you nothing about which system prompt was in front of it, which safety policy version applied, or which sandbox it ran in. DeepSeek's DSec paper, submitted September 19 and surfaced this weekend, describes a training platform running roughly 3 million sandboxes a day across about 160 nodes, with over 380,000 concurrent. Those figures are the company measuring its own infrastructure, and there is no equivalent field for "which one of these ran my job." (arXiv 2609.22978)
And the convention itself is unsettled. Both attributes carry the Development badge, and the GenAI conventions recently moved out of the main semantic-conventions repository into their own. Names can still change. That argues for writing the attributes through a small wrapper in your own code rather than scattering the literal strings across forty call sites, not for waiting.
The part you control
Nobody is shipping a provenance standard this quarter. There is no signed attestation format for "this response came from this model version under this policy," and the incentives to build one point in the wrong direction for everyone who would have to implement it.
What exists is a field that is already in your tracing library, already named, already specified, and currently optional. The gap between a team that sets it and a team that does not is one line per call site and about an afternoon of care.
The Muse story is the whole argument in miniature. A stranger with no access to Meta's infrastructure got closer to answering "which model is running here" than most teams can get about their own stack, and he did it by reading the shape of an ID string. You have better evidence available than he did. Write it down.
Sources: OpenTelemetry GenAI spans, mouse.dev on muse-special, ABC News on the D.C. Circuit ruling, LangChain on LangSmith Fine-Tuning, DeepSeek DSec.
Medium metadata
- Title: gen_ai.response.model Is Only Recommended, Which Is Why Nobody Can Prove Which Model Answered
- Subtitle: OpenTelemetry's GenAI convention asks harder for the model you requested than for the model that replied. Here is what that costs you the first time somebody asks.
- Tags: OpenTelemetry, AI Agents, Observability, LLM, Software Engineering
- Canonical: fervorai.dev