Skip to content

Commit 7afb64d

Browse files
author
Meridian
committed
fix: DeepSeek pricing + correct vendor attribution in OpenAI instrumentor
pricing.py: - Add deepseek vendor to MODEL_PRICING (deepseek-chat, deepseek-reasoner, deepseek-coder) - Add deepseek to DEFAULT_PRICING fallback - Add DeepSeek fuzzy matching to normalize_model_name() openai_instr.py: - Add _detect_vendor() to identify DeepSeek calls by model prefix - OpenAICostAdapter.calculate_cost() now uses correct vendor pricing per call - Span name, llm.vendor and llm.system now reflect actual provider (openai or deepseek) - No separate instrumentor needed — DeepSeek uses OpenAI SDK, patch fires automatically - OpenAI calls unchanged in behavior, DeepSeek calls no longer misattributed
1 parent df634af commit 7afb64d

2 files changed

Lines changed: 60 additions & 17 deletions

File tree

kalibr/instrumentation/openai_instr.py

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,54 @@
1717
from .base import BaseCostAdapter, BaseInstrumentation
1818

1919

20+
def _detect_vendor(model: str) -> str:
21+
"""Detect the actual vendor from model name.
22+
23+
The OpenAI Python SDK is used by multiple providers (OpenAI, DeepSeek, etc.)
24+
via base_url overrides. We detect the real vendor from the model name so spans
25+
and cost calculations are attributed correctly.
26+
27+
Args:
28+
model: Model identifier from the API response
29+
30+
Returns:
31+
Vendor string: "openai" or "deepseek"
32+
"""
33+
model_lower = model.lower()
34+
if model_lower.startswith("deepseek-"):
35+
return "deepseek"
36+
return "openai"
37+
38+
2039
class OpenAICostAdapter(BaseCostAdapter):
21-
"""Cost calculation adapter for OpenAI models.
22-
23-
Uses centralized pricing from kalibr.pricing module.
40+
"""Cost calculation adapter for OpenAI-compatible models.
41+
42+
Handles OpenAI and any provider that uses the OpenAI SDK (e.g. DeepSeek).
43+
Vendor is detected from the model name so cost is always attributed correctly.
2444
"""
2545

2646
def get_vendor_name(self) -> str:
27-
"""Return vendor name for OpenAI."""
47+
"""Return vendor name — overridden per-call via calculate_cost."""
2848
return "openai"
2949

3050
def calculate_cost(self, model: str, usage: Dict[str, int]) -> float:
31-
"""Calculate cost in USD for an OpenAI API call.
32-
51+
"""Calculate cost using the correct vendor pricing for this model.
52+
3353
Args:
34-
model: Model identifier (e.g., "gpt-4o", "gpt-4o-2024-05-13")
54+
model: Model identifier (e.g., "gpt-4o", "deepseek-chat")
3555
usage: Token usage dict with prompt_tokens and completion_tokens
36-
56+
3757
Returns:
3858
Cost in USD (rounded to 6 decimal places)
3959
"""
40-
# Get pricing from centralized module (handles normalization)
41-
pricing = self.get_pricing_for_model(model)
60+
from kalibr.pricing import get_pricing
61+
62+
vendor = _detect_vendor(model)
63+
pricing, _ = get_pricing(vendor, model)
4264

4365
prompt_tokens = usage.get("prompt_tokens", 0)
4466
completion_tokens = usage.get("completion_tokens", 0)
4567

46-
# Calculate cost (pricing is per 1M tokens)
4768
input_cost = (prompt_tokens / 1_000_000) * pricing["input"]
4869
output_cost = (completion_tokens / 1_000_000) * pricing["output"]
4970

@@ -124,14 +145,17 @@ def wrapper(self_instance, *args, **kwargs):
124145
# Extract model from kwargs
125146
model = kwargs.get("model", "unknown")
126147

148+
# Detect actual vendor — OpenAI SDK is used by multiple providers
149+
vendor = _detect_vendor(model)
150+
127151
# Create span with initial attributes
128152
with self.tracer.start_as_current_span(
129-
"openai.chat.completions.create",
153+
f"{vendor}.chat.completions.create",
130154
kind=SpanKind.CLIENT,
131155
attributes={
132-
"llm.vendor": "openai",
156+
"llm.vendor": vendor,
133157
"llm.request.model": model,
134-
"llm.system": "openai",
158+
"llm.system": vendor,
135159
},
136160
) as span:
137161
start_time = time.time()
@@ -167,14 +191,17 @@ async def wrapper(self_instance, *args, **kwargs):
167191
# Extract model from kwargs
168192
model = kwargs.get("model", "unknown")
169193

194+
# Detect actual vendor — OpenAI SDK is used by multiple providers
195+
vendor = _detect_vendor(model)
196+
170197
# Create span with initial attributes
171198
with self.tracer.start_as_current_span(
172-
"openai.chat.completions.create",
199+
f"{vendor}.chat.completions.create",
173200
kind=SpanKind.CLIENT,
174201
attributes={
175-
"llm.vendor": "openai",
202+
"llm.vendor": vendor,
176203
"llm.request.model": model,
177-
"llm.system": "openai",
204+
"llm.system": vendor,
178205
},
179206
) as span:
180207
start_time = time.time()

kalibr/pricing.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@
6060
"mistralai/mixtral-8x7b-instruct-v0.1": {"input": 0.60, "output": 0.60},
6161
# Default fallback for unknown HuggingFace models
6262
},
63+
"deepseek": {
64+
# Prices in USD per 1M tokens — https://platform.deepseek.com/docs/pricing
65+
"deepseek-chat": {"input": 0.27, "output": 1.10}, # DeepSeek-V3
66+
"deepseek-reasoner": {"input": 0.55, "output": 2.19}, # DeepSeek-R1
67+
"deepseek-coder": {"input": 0.27, "output": 1.10}, # DeepSeek-Coder-V2
68+
},
6369
"google": {
6470
# Gemini 2.5 models
6571
"gemini-2.5-pro": {"input": 1.25, "output": 5.00},
@@ -83,6 +89,7 @@
8389
"anthropic": {"input": 15.00, "output": 75.00}, # Claude 3 Opus pricing
8490
"google": {"input": 1.25, "output": 5.00}, # Gemini 1.5 Pro pricing
8591
"huggingface": {"input": 1.00, "output": 1.00}, # Conservative default
92+
"deepseek": {"input": 0.55, "output": 2.19}, # DeepSeek-R1 pricing
8693
}
8794

8895

@@ -187,6 +194,15 @@ def normalize_model_name(vendor: str, model_name: str) -> str:
187194
elif "gemini-1.0-pro" in model_lower or "gemini-pro" in model_lower:
188195
return "gemini-pro"
189196

197+
# DeepSeek fuzzy matching
198+
elif vendor == "deepseek":
199+
if "deepseek-reasoner" in model_lower or "deepseek-r1" in model_lower:
200+
return "deepseek-reasoner"
201+
elif "deepseek-coder" in model_lower:
202+
return "deepseek-coder"
203+
elif "deepseek-chat" in model_lower or "deepseek-v" in model_lower:
204+
return "deepseek-chat"
205+
190206
# Return original if no match found
191207
return model_lower
192208

0 commit comments

Comments
 (0)