Dataiku + carbon-llm — tracker chaque LLM call dans vos recipes Python
Guide pas à pas pour mesurer le CO₂e de chaque appel LLM dans vos flows Dataiku DSS. Python recipe carbon-llm-track, hook sur les LLM Mesh recipes, multi-projet + multi-tenant. Prêt CSRD ESRS E1-6.
Dataiku est l'une des plateformes les plus utilisées dans les grandes équipes data en France (BNP, AXA, Total, Pernod Ricard, Decathlon...). Chaque flow qui appelle un LLM — via le LLM Mesh natif depuis 2024 ou via un client Python custom — produit des inférences qui doivent apparaître dans le poste 'émissions IA' du Scope 3 CSRD.
L'avantage de Dataiku pour le tracking : tout passe par un nombre limité de recipes (versus du code dispersé dans 50 microservices). Une intégration carbon-llm en un seul Python recipe utilitaire couvre l'intégralité de vos flows.
Bonus : le system de variables Dataiku permet de tagger automatiquement les events par projet, par environnement (DEV / PROD) et par utilisateur — ce qui donne un dashboard naturellement multi-tenant côté carbon-llm.
Deux niveaux possibles selon votre besoin :
1. Variable d'INSTANCE (Administration → Variables) — accessible à tous les projets de l'instance Dataiku. Idéal si vous gérez carbon-llm de manière centrale (DSI/RSE).
2. Variable de PROJECT (Project Settings → Variables) — scope projet uniquement. Idéal si chaque équipe data gère sa propre clé.
Dans les deux cas, la valeur est chiffrée au repos et n'apparaît pas dans les logs DSS.
Variables — onglet Settings
# Variable name Variable value
CARBON_LLM_API_KEY live_xxxxxxxxxxxxxxxxxxxx
CARBON_LLM_BASE_URL https://carbon-llm.com
CARBON_LLM_DEFAULT_TENANT_ID ${dataiku.project_key}Créez un Python recipe (n'importe quel input/output, peu importe — c'est juste une bibliothèque utilitaire) qui définit une fonction réutilisable depuis tous vos autres recipes via `from <recipe_name> import track_llm_call` n'est pas possible directement, mais Dataiku permet la création de Python libraries projet (Project libraries) qui exposent du code partageable.
Pattern recommandé : créer un module Python dans la project library, pas un recipe.
Project library → carbon_llm.py
"""
carbon-llm helper — appelable depuis n'importe quel Python recipe ou notebook DSS.
Stockez ce fichier dans le project library : Settings → Code → Libraries → Edit lib.
Usage :
from carbon_llm import track_llm_call
track_llm_call(model="gpt-4o", prompt_tokens=1240, completion_tokens=580)
"""
import dataiku
import requests
from typing import Optional
# Lire les variables Dataiku — niveau project en priorité, puis instance
_client = dataiku.api_client()
_proj = dataiku.Project()
_vars = {**_client.get_general_settings().get_raw().get("studioGlobalSettings", {}).get("variables", {}),
**_proj.get_variables().get("standard", {})}
API_KEY = _vars.get("CARBON_LLM_API_KEY")
BASE_URL = _vars.get("CARBON_LLM_BASE_URL", "https://carbon-llm.com")
DEFAULT_TENANT = _vars.get("CARBON_LLM_DEFAULT_TENANT_ID", _proj.project_key)
def track_llm_call(
model: str,
prompt_tokens: int,
completion_tokens: int,
tenant_id: Optional[str] = None,
ingestion_source: str = "dataiku",
) -> None:
"""Fire-and-forget POST vers carbon-llm. Ne lève jamais d'exception
— les events ratés sont loggés stderr uniquement."""
if not API_KEY:
# Pas configuré → no-op silencieux (utile en dev local sans clé)
return
try:
requests.post(
f"{BASE_URL}/api/v1/track",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json={
"model": model,
"prompt_tokens": prompt_tokens,
"completion_tokens": completion_tokens,
"tenant_id": tenant_id or DEFAULT_TENANT,
"ingestion_source": ingestion_source,
},
timeout=5.0,
)
except Exception as e:
# Best-effort. Pas de raise — un échec carbon-llm ne casse pas votre flow data.
print(f"[carbon-llm] track failed: {e}")Le LLM Mesh est l'abstraction native Dataiku qui unifie l'accès à OpenAI, Anthropic, Bedrock, Vertex, Azure OpenAI, Mistral, etc. Chaque appel retourne un objet `LLMResponse` avec un attribut `usage` standard.
Wrapper minimal :
Recipe Python utilisant le LLM Mesh
import dataiku
from carbon_llm import track_llm_call
# Récupérer une connexion LLM Mesh configurée dans Administration
client = dataiku.api_client()
project = dataiku.Project()
llm = project.get_llm("openai:my-openai-connection:gpt-4o")
# Appel standard LLM Mesh
response = llm.new_completion()\
.with_message("Résume ce texte en 3 lignes : ...")\
.execute()
# Track — l'objet usage est exposé par LLMResponse
track_llm_call(
model="gpt-4o",
prompt_tokens=response.usage.prompt_tokens,
completion_tokens=response.usage.completion_tokens,
tenant_id=f"{project.project_key}:{dataiku.api_client().get_auth_info()['authIdentifier']}",
)
print(response.text)Si votre équipe utilise directement openai, anthropic ou un autre client Python (cas fréquent dans les notebooks exploratoires), le pattern est identique :
Notebook DSS — client OpenAI direct
import os
from openai import OpenAI
from carbon_llm import track_llm_call
import dataiku
# Récupérer la clé OpenAI depuis les variables Dataiku
client = OpenAI(api_key=dataiku.get_custom_variables()["OPENAI_API_KEY"])
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Résume ce CR de réunion : ..."}],
)
# Track immédiatement après la réponse
track_llm_call(
model="gpt-4o",
prompt_tokens=response.usage.prompt_tokens,
completion_tokens=response.usage.completion_tokens,
tenant_id=dataiku.Project().project_key,
)
print(response.choices[0].message.content)Les Dataiku Scenarios qui appellent des LLM en batch (résumé en masse, classification, RAG indexing) doivent aussi être tracés.
Pattern : ajoutez un step Python step en fin de scenario qui agrège les usages collectés pendant le run.
Scenario step Python
import dataiku
from carbon_llm import track_llm_call
# Si vos recipes ont logué les usages dans une dataset commune (recommandé pour batch) :
client = dataiku.api_client()
project = dataiku.Project()
usage_ds = dataiku.Dataset("llm_usage_log") # une dataset DSS qui collecte les rows
df = usage_ds.get_dataframe()
for _, row in df.iterrows():
track_llm_call(
model=row["model"],
prompt_tokens=int(row["prompt_tokens"]),
completion_tokens=int(row["completion_tokens"]),
tenant_id=f"{project.project_key}:scenario:{row['scenario_run_id']}",
ingestion_source="dataiku_scenario",
)
# Vide la dataset après tracking — évite les double-compte au prochain scenario
usage_ds.write_with_schema(df.iloc[0:0])tenant_id est libre — adaptez-le à votre besoin :
• 1 dashboard global par instance Dataiku → tenant_id = nom du projet (ex: 'risque_credit')
• 1 dashboard par utilisateur final (cabinet de conseil) → tenant_id = 'projet:client' (ex: 'risque_credit:bnp_2026')
• 1 dashboard par environnement → tenant_id = 'projet:env' (ex: 'risque_credit:prod')
Côté carbon-llm, chaque tenant_id distinct apparaît dans /dashboard/tenants. PDF mensuel filtrable, export ESRS E1-6 par tenant — exactement ce qu'un commissaire aux comptes attend.
1. **Variables non lues côté recipe** — Dataiku Project libraries n'ont pas accès à `dataiku.get_custom_variables()` directement. Utilisez `dataiku.api_client()` + `Project().get_variables()` comme dans le helper ci-dessus.
2. **LLM Mesh sans usage** — certains backends (Bedrock historiquement) ne retournent pas l'objet usage. Vérifiez avec `print(response.usage)` avant track. Solution de secours : passer par l'admin API du provider et utiliser le connecteur Pro carbon-llm.
3. **Usage qui double** — si vous tracez à la fois dans le recipe ET via un connecteur OpenAI Admin Pro, vous comptez deux fois. Choisissez une seule source par environnement.
4. **tenant_id trop long** — limite 64 chars alphanum + tirets. Hashez si vous concaténez plusieurs niveaux.
Prêt à tracer vos flows Dataiku ?
Gratuit pendant l'early access. Toutes les features Pro débloquées (export ESRS E1-6, bundle audit signé) — sans CB, sans engagement.