Skip to main content

LiteLLM Integration

Overview

LiteLLM provides a unified interface for calling 100+ LLM providers. Fiddler supports two integration modes:
ModeBest forExtra packages required
LiteLLM SDKApplications calling LLM providers directly via litellm.completion()None
LiteLLM ProxyTeams routing all LLM traffic through a centrally managed LiteLLM proxy gatewayNone
Both modes work by routing OpenTelemetry traces to Fiddler’s OTLP ingestion endpoint using standard environment variables.

LiteLLM SDK Integration

Overview

LiteLLM includes a built-in OpenTelemetry integration. When you enable it and point the OTLP exporter at Fiddler, every LLM call is automatically traced — with no Fiddler-specific package required. Fiddler natively ingests LiteLLM SDK-generated OTel traces and maps them to the Fiddler schema, giving you full observability over prompts, responses, and token usage across all LLM providers. The following SDK functions are supported:
SDK Functiongen_ai.operation.nameFiddler Span Type
litellm.completion() / litellm.acompletion()chat / completion / acompletionllm
litellm.text_completion() / litellm.atext_completion()text_completion / atext_completionllm
litellm.responses() / litellm.aresponses()responses / aresponsesllm
litellm.anthropic_interface.messages.create() / acreate()anthropic_messagesllm
litellm.generate_content() / litellm.agenerate_content()generate_content / agenerate_contentllm
litellm.embedding() / litellm.aembedding()embedding / aembeddingchain
litellm.image_generation() / litellm.aimage_generation()image_generation / aimage_generationchain
litellm.image_edit() / litellm.aimage_edit()image_edit / aimage_editchain
litellm.moderation() / litellm.amoderation()moderation / amoderationchain
litellm.transcription() / litellm.atranscription()transcription / atranscriptionchain
litellm.speech() / litellm.aspeech()speech / aspeechchain
litellm.rerank() / litellm.arerank()rerank / arerankchain
litellm.ocr() / litellm.aocr()ocr / aocrchain
Notes on the table above:
  • completion operation name: LiteLLM versions before 1.82.1 (released January 2026) emit gen_ai.operation.name = "completion" literally for litellm.completion() calls. Newer versions rewrite it to "chat". Both are classified identically as llm.
  • Non-text APIs classified as chain: Fiddler’s LLM observability currently focuses on text-based generative completions. Image, audio, embedding, moderation, ranking, and OCR operations are classified as chain so they remain visible in traces without being treated as LLM completions.
Conversation tracking is not currently supported for the LiteLLM integration. Session-level grouping of multi-turn conversations will be addressed in a future release as part of broader session attribute support.

Architecture

Prerequisites

  • Fiddler account with a GenAI application already created
  • pip install litellm (or uv add litellm)
  • A valid LLM provider API key (e.g. OPENAI_API_KEY for OpenAI models)

Quick Start

Step 1: Set environment variables

Set these before starting your application:
# Fiddler OTel ingestion
export OTEL_EXPORTER_OTLP_ENDPOINT="https://your-fiddler-instance.com"
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer <your-fiddler-token>,fiddler-application-id=<your-app-uuid>"
export OTEL_RESOURCE_ATTRIBUTES="application.id=<your-app-uuid>"

# LLM provider key (name varies by provider)
export OPENAI_API_KEY="your-openai-key"
To find your application UUID: navigate to your application in the Fiddler UI and copy the UUID from the URL or application settings.

Step 2: Enable the built-in OTel callback

Add one line to your application startup:
import litellm

litellm.callbacks = ["otel"]

Step 3: Make completions as normal

No other code changes are required:
response = litellm.completion(
    model="gpt-4o-mini",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "What is the capital of France?"},
    ],
)
print(response.choices[0].message.content)
Every call is now automatically traced and exported to Fiddler.

Step 4: Verify traces are arriving

Open the Fiddler UI and navigate to your application’s Trace Explorer. You should see the trace within a few seconds of making your first completion call.

What Gets Captured

Message Content
Fiddler FieldDescription
System promptThe system instructions sent to the model
User inputThe most recent user turn
Assistant outputThe model’s response
Token Usage
AttributeDescription
gen_ai.usage.input_tokensPrompt tokens consumed
gen_ai.usage.output_tokensCompletion tokens generated
gen_ai.usage.total_tokensTotal tokens
Model Information gen_ai.system and gen_ai.request.model are SDK first-class LLM attributes. They are stored at their unprefixed keys and resolved at query time by the Fiddler backend’s field registry, making them queryable via SpanAttribute::gen_ai.system and SpanAttribute::gen_ai.request.model.
AttributeDescription
gen_ai.request.modelModel requested (e.g. gpt-4o-mini)
gen_ai.response.modelModel actually used
gen_ai.systemProvider (e.g. openai, anthropic)

Supported Features

FeatureSupportNotes
Chat/text completion tracing✅ FullPrompts, responses, token usage via completion(), text_completion()
Responses API tracing⚠️ PartialToken usage captured; output text and instructions system prompt not populated by LiteLLM — see Known LiteLLM Upstream Caveats
Anthropic Messages API tracing⚠️ Partialsystem prompt not populated by LiteLLM — see Known LiteLLM Upstream Caveats
Google GenAI native tracing⚠️ PartialsystemInstruction not populated by LiteLLM (chat-completion path is fine) — see Known LiteLLM Upstream Caveats
Embeddings, images, audio, rerank⚠️ As chainSpans captured with token/cost metadata but not classified as llm
Token usage✅ FullInput, output, and total tokens
Model information✅ FullRequested and actual model, provider
Cost tracking❌ Not supportedLiteLLM SDK does not emit gen_ai.cost.* attributes
Tool spans❌ Not supportedLiteLLM SDK does not emit tool spans
Conversation tracking❌ Not supportedSession-level grouping of multi-turn conversations is not available

Troubleshooting

Traces not appearing in Fiddler Check that all three environment variables are set correctly:
echo $OTEL_EXPORTER_OTLP_ENDPOINT
echo $OTEL_EXPORTER_OTLP_HEADERS
echo $OTEL_RESOURCE_ATTRIBUTES
Check that litellm.callbacks = ["otel"] is set before your first litellm.completion() call. Check the fiddler-application-id header and application.id resource attribute are both set Both are required. fiddler-application-id must be a valid UUID for an existing Fiddler application, otherwise spans will be dropped during ingestion.

LiteLLM Proxy Integration

Overview

LiteLLM is an OpenAI-compatible proxy gateway that lets you call 100+ LLM providers through a single API. When LiteLLM proxy is configured to emit OpenTelemetry traces, Fiddler automatically detects and ingests them — no additional SDK or code changes required. Fiddler includes a purpose-built mapper for LiteLLM proxy traces that handles the proxy’s specific span format, attribute layout, and operation naming conventions. This gives you full observability over every LLM call routed through your proxy: prompts, responses, token usage, cost metadata, and latency — across all models and providers in one place.

Architecture

When to Use This Integration

Use the LiteLLM proxy integration when:
  • You are already running LiteLLM proxy as your LLM gateway
  • You want to monitor all LLM traffic centrally regardless of underlying provider (OpenAI, Anthropic, Bedrock, etc.)
  • You want cost attribution and latency tracking without instrumenting individual applications

Quick Start

Step 1: Configure LiteLLM proxy to emit OpenTelemetry

Set the following environment variables before starting the proxy:
export OTEL_EXPORTER_OTLP_ENDPOINT="https://your-fiddler-instance.com"
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer <your-fiddler-token>,fiddler-application-id=<your-app-uuid>"
export OTEL_RESOURCE_ATTRIBUTES="application.id=<your-app-uuid>"

litellm --config config.yaml
Or set them inside your LiteLLM proxy config.yaml:
general_settings:
  otel: true

environment_variables:
  OTEL_EXPORTER_OTLP_ENDPOINT: "https://your-fiddler-instance.com"
  OTEL_EXPORTER_OTLP_HEADERS: "authorization=Bearer <your-fiddler-token>,fiddler-application-id=<your-app-uuid>"
  OTEL_RESOURCE_ATTRIBUTES: "application.id=<your-app-uuid>"

Step 2: Set your Fiddler application ID

Two environment variables carry your application ID and both are required:
  • OTEL_RESOURCE_ATTRIBUTES — sets application.id on every OTel resource, which Fiddler uses to route traces to the correct application
  • OTEL_EXPORTER_OTLP_HEADERS — includes fiddler-application-id as an HTTP header for authentication and routing at the ingestion endpoint
To find your application UUID: navigate to your application in the Fiddler UI and copy the UUID from the URL or application settings.

Step 3: Verify traces are arriving

Make a test request through your proxy:
curl -X POST https://your-litellm-proxy/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [{"role": "user", "content": "Hello"}]
  }'
Then open the Fiddler UI and navigate to your application’s Trace Explorer. You should see the trace within a few seconds.

Using with OpenAI Codex CLI

OpenAI Codex CLI does not need its own Fiddler integration. Codex’s native OpenTelemetry traces carry only token counts — no prompt, response, or tool content. (That content exists only in Codex’s OpenTelemetry logs, which Fiddler does not ingest.) So the recommended way to observe Codex in Fiddler is to point it at your LiteLLM proxy. The proxy then emits full llm spans (prompt + response + token usage) that Fiddler ingests through the integration described above, with no Fiddler-side code.

Step 1: Use LiteLLM 1.88+ with a Codex-compatible model

Codex uses the OpenAI Responses API, and its streamed output is only captured by LiteLLM 1.88.0 or later. Ensure the proxy is on a supported version with the OTel exporter SDK installed:
pip install "litellm[proxy]>=1.88.0" opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
In your proxy config.yaml, map an alias (the name Codex will request) to a Codex-capable model. Use a current Codex-family model from your OpenAI account for the upstream model — for example gpt-5.2-codex. General chat models such as gpt-4o-mini will not work, because they reject Codex’s tool calls.
model_list:
  - model_name: codex-model               # alias Codex requests (any name; reused in Step 2)
    litellm_params:
      model: openai/<codex-capable-model> # e.g. gpt-5.2-codex — must accept Codex's tool calls
      api_key: os.environ/OPENAI_API_KEY
litellm_settings:
  callbacks: ["otel"]
  drop_params: true

Step 2: Point Codex at the proxy

Add a custom model provider to ~/.codex/config.toml so Codex sends requests to your LiteLLM proxy instead of OpenAI directly:
model = "codex-model"                     # must match the model_name alias from Step 1
model_provider = "fiddler-gw"

[model_providers.fiddler-gw]
name = "Fiddler GW"
base_url = "http://localhost:4000/v1"   # your LiteLLM proxy URL
wire_api = "responses"                   # Codex only supports the Responses API
env_key = "GW_KEY"                        # any non-empty value; LiteLLM holds the real provider key
export GW_KEY=any-non-empty-value

Step 3: Use Codex normally

codex exec "Plan a 4-day trip to Japan"
Each turn appears in your application’s Trace Explorer as an llm span with the full user prompt, assistant response, and token usage.
Codex uses the OpenAI Responses API. On the proxy path with LiteLLM ≥ 1.88.0, LiteLLM captures both the input and output messages for Responses-API calls, so prompts and responses appear in full. The /v1/responses content gap noted in Known LiteLLM Upstream Caveats applies only to earlier LiteLLM versions and does not affect this setup.
Requirements and limitations
  • API-key mode only. Routing through a proxy uses your OpenAI API key; it does not work with ChatGPT-subscription login.
  • The upstream model must accept Codex’s tool calls. Use a current Codex-family model from your OpenAI account (for example gpt-5.2-codex); general chat models such as gpt-4o-mini reject Codex’s tool format.

What Gets Captured

Span Types

LiteLLM proxy emits several span types per request. Fiddler classifies them based on the gen_ai.operation.name attribute: LLM endpoints — classified as llm (generative text completions):
Gateway Endpointgen_ai.operation.nameDescription
/chat/completionschat / acompletion / completionChat completion (most common)
/completionstext_completion / atext_completionLegacy text completion
/v1/responsesresponses / aresponsesOpenAI Responses API
/v1/messages, /anthropic/v1/messagesanthropic_messagesAnthropic Messages API
/generate_content, /models/{model}:generateContentgenerate_content / agenerate_contentGoogle Gemini native (non-streaming)
/generate_content_stream, /models/{model}:streamGenerateContentgenerate_content_stream / agenerate_content_streamGoogle Gemini native (streaming)
Non-LLM endpoints — classified as chain (not generative text completions):
Gateway Endpointgen_ai.operation.nameDescription
/embeddingsembedding / aembeddingText-to-vector conversion
/moderationsmoderation / amoderationContent safety scoring
/images/generationsimage_generation / aimage_generationImage generation
/images/editsimage_edit / aimage_editImage editing
/audio/speechspeech / aspeechText-to-speech
/audio/transcriptionstranscription / atranscriptionSpeech-to-text
/rerankrerank / arerankDocument relevance scoring
/ocrocr / aocrOptical character recognition
Infrastructure spans — classified as chain:
LiteLLM Span NameDescription
selfInternal LiteLLM API call timing
routerModel routing and deployment selection
proxy_pre_callPre-processing before LLM call
Each proxy request typically produces up to 3 spans:
LiteLLM Span NameDescription
Received Proxy Server RequestTop-level server span (parent)
litellm_requestPrimary span carrying all attributes
raw_gen_ai_requestChild span with raw provider-level request/response

Captured Attributes

Message Content LiteLLM writes full conversation history as JSON on the span (not as span events). Fiddler extracts:
Fiddler FieldSourceDescription
System promptFirst role: system message in gen_ai.input.messagesThe system instructions sent to the model
User inputLast role: user message in gen_ai.input.messagesThe most recent user turn
Assistant outputFirst role: assistant message in gen_ai.output.messagesThe model’s response
If you have disabled message logging in LiteLLM (turn_off_message_logging: true), the message content fields will be absent from traces. Token counts and cost metadata are still captured.
Token Usage
AttributeDescription
gen_ai.usage.input_tokensPrompt tokens consumed
gen_ai.usage.output_tokensCompletion tokens generated
gen_ai.usage.total_tokensTotal tokens
Model Information gen_ai.system and gen_ai.request.model are SDK first-class LLM attributes. They are stored at their unprefixed keys and resolved at query time by the Fiddler backend’s field registry, making them queryable via SpanAttribute::gen_ai.system and SpanAttribute::gen_ai.request.model.
AttributeDescription
gen_ai.request.modelModel requested (e.g. gpt-4o-mini)
gen_ai.response.modelModel actually used (may differ from requested)
gen_ai.systemProvider (e.g. openai, anthropic)
Cost Metadata (stored as fiddler.span.user.*) LiteLLM emits cost fields under gen_ai.cost.*. These are preserved in Fiddler as user-visible span attributes:
AttributeDescription
gen_ai.cost.total_costTotal cost of the request
gen_ai.cost.prompt_costCost attributed to prompt tokens
gen_ai.cost.completion_costCost attributed to completion tokens
Proxy Metadata (stored as fiddler.span.user.*) LiteLLM proxy emits metadata.* attributes containing API key, team, user, and routing information. These are preserved as user-visible span attributes for auditing and cost attribution.

Supported Features

Endpoint Coverage

EndpointSpan TypeMessagesTokensCostNotes
/chat/completionsllmFull support — prompts, responses, all metadata
/completionsllmLegacy text completion, full content extraction
/v1/responses, /responsesllmBoth gen_ai.input.messages and gen_ai.output.messages are absent — LiteLLM’s OTel callback reads kwargs["messages"] / response["choices"], but the Responses API uses input / output. instructions system prompt and provider attribution also missing — see Known LiteLLM Upstream Caveats
/v1/messages (Anthropic)llmpartial (no system prompt)system prompt not populated by LiteLLM’s OTel integration; provider attribution missing — see Known LiteLLM Upstream Caveats
/v1beta/...:generateContent (Gemini)llmpartial (no system prompt)systemInstruction not populated by LiteLLM’s OTel integration; provider attribution missing — see Known LiteLLM Upstream Caveats
/embeddingschainNot a generative completion — no messages to extract
/moderationschainContent safety scoring; no generative output
/images/generationschainImage generation; no text output
/images/editschainImage editing; no text output
/audio/speechchainText-to-speech; no text output
/audio/transcriptionschainSpeech-to-text; transcription not extracted
/rerankchainDocument relevance scoring
/ocrchainOptical character recognition

Platform Features

FeatureSupportNotes
Cost tracking✅ FullVia gen_ai.cost.* attributes
Provider attribution✅ FullVia gen_ai.system
Proxy metadata✅ FullAPI key, team, user, routing info
Tool spans❌ Not supportedLiteLLM does not emit tool spans natively
Infrastructure spans⚠️ As chainself, router, proxy_pre_call are captured but classified as generic chains
Conversation tracking❌ Not supportedSession-level grouping of multi-turn conversations is not available

Troubleshooting

Traces not appearing in Fiddler Check that OTel is enabled in LiteLLM:
echo $OTEL_EXPORTER_OTLP_ENDPOINT
echo $OTEL_EXPORTER_OTLP_HEADERS
echo $OTEL_RESOURCE_ATTRIBUTES
Check the fiddler-application-id header and application.id resource attribute are both set: Both are required. fiddler-application-id must be a valid UUID for an existing Fiddler application, otherwise spans will be dropped during ingestion. Check service.name is "litellm" Fiddler detects LiteLLM proxy spans by service.name. LiteLLM proxy sets this to "litellm" by default. If you have overridden OTEL_SERVICE_NAME, ensure it is set to "litellm" or "litellm-proxy":
export OTEL_SERVICE_NAME="litellm"
Message content missing from traces LiteLLM’s message logging may be disabled. Check your config for:
litellm_settings:
  turn_off_message_logging: true  # This suppresses gen_ai.input/output.messages
Remove or set to false to re-enable message capture. Spans classified as chain instead of llm This happens for internal LiteLLM infrastructure spans (self, router, proxy_pre_call) and for non-completion operations (embeddings, image generation, speech, etc.). This is expected behavior — only completion-generating endpoints (/chat/completions, /completions, /v1/responses) are classified as llm spans. /v1/responses spans are missing message content See the Known LiteLLM Upstream Caveats section below for details. Token counts, costs, and span-type classification are unaffected.

Known LiteLLM Upstream Caveats

While integrating with LiteLLM, several gaps were identified in LiteLLM’s own OpenTelemetry callback (litellm/integrations/opentelemetry.py). These are not Fiddler issues — they affect every downstream OTel consumer (Datadog, Honeycomb, Phoenix, etc.). Fiddler classifies the spans correctly and surfaces every attribute that LiteLLM does emit, but the gaps below mean some content is simply absent from the trace at the source.

/v1/responses and /responses — input and output messages both missing

LiteLLM’s OTel callback reads input messages from kwargs["messages"] and output messages from response["choices"] — both shapes specific to /chat/completions. The Responses API uses kwargs["input"] and response["output"] instead, so neither extraction block runs.
What you seeWhat’s missing
gen_ai.usage.*gen_ai.input.messages
gen_ai.cost.*gen_ai.output.messages
Span correctly typed as llmgen_ai.response.finish_reasons
tool call attributes (if any) ❌
Where the data does exist: the raw_gen_ai_request child span (a sibling of the parent litellm_request span) carries both the request and response under llm.<provider>.input / llm.<provider>.output. It is currently surfaced as a chain span without content extraction. Tracking: BerriAI/litellm#25840

/v1/responses, /responses, /v1/messages, /v1beta/...:generateContent — system prompt missing

LiteLLM’s OTel callback writes gen_ai.system_instructions only when the kwarg name is exactly system_instructions. Other endpoints use different field names for the same concept:
EndpointKwarg name LiteLLM uses internallyOTel callback reads it?
Vertex AI Gemini chat-completion pathsystem_instructions
OpenAI Responses API (/v1/responses, /responses)instructions
Anthropic Messages API (/v1/messages)system
Gemini direct pass-through (/v1beta/...:generateContent)systemInstruction (nested)
The system prompt does reach LiteLLM and is included in the actual LLM request — it just never lands on gen_ai.system_instructions in the OTel trace. As with the output-text gap, the data is visible on the raw_gen_ai_request child span (llm.<provider>.instructions / llm.<provider>.system / llm.<provider>.systemInstruction). Tracking: BerriAI/litellm#25840 (follow-up comment)

Non-chat-completion endpoints — gen_ai.system empty and llm.None.* attribute prefix

For every endpoint family except /chat/completions, LiteLLM’s custom_llm_provider is not propagated into the OTel callback’s view of litellm_params. This causes two visible symptoms:
  • gen_ai.system is set to an empty string instead of the provider (e.g. "openai", "vertex_ai", "anthropic").
  • Raw provider attributes on the raw_gen_ai_request child span use a llm.None.* prefix (e.g. llm.None.output, llm.None.model) instead of llm.openai.* or llm.vertex_ai.*.
Tracking: BerriAI/litellm#25240; fix in flight via PR #25309 (scoped to the Responses API; /v1/messages and Gemini may need follow-up after merge).

Gemini streaming variant — gen_ai.response.model not set

/v1beta/models/{model}:streamGenerateContent does not emit gen_ai.response.model on the parent span, even though the non-streaming :generateContent variant does. Likely lives in LiteLLM’s Gemini streaming aggregation path. Low impact; not yet filed upstream.

Summary — what works and what doesn’t, by endpoint

EndpointSpan typeTokensCostInput messagesOutput messagesSystem promptProvider
/chat/completionsllm✅ (in messages)
/completions (text)llmn/a
/v1/responses, /responsesllm
/v1/messages (Anthropic)llm
/v1beta/...:generateContentllm
/v1beta/...:streamGenerateContentllm❌ (also missing response.model)
/embeddings, /moderations, /images/*, /audio/*, /rerankchain✅ where applicablen/a (no text completion)n/a✅ for /chat/completions, ❌ elsewhere
Internal infra (self, router, proxy_pre_call)chainn/an/an/an/an/an/a
These caveats will resolve as the upstream LiteLLM PRs land. Fiddler will pick up the improvements automatically — no Fiddler-side changes will be needed when LiteLLM fixes ship.

Guardrails

Fiddler implements the LiteLLM Generic Guardrail API spec, letting you plug Fiddler’s real-time guardrails directly into the LiteLLM proxy gateway. Once configured, every request routed through the proxy is checked for secrets, PII, and unsafe content before it reaches the model. See LiteLLM Guardrails for setup instructions, check behavior, and the full API reference.