LM Warden

Une clé par application, et une page pour chaque clé.

Donnez à chaque collègue, ordinateur portable, tâche de CI et agent sa propre clé. La page d’une clé montre ce qu’elle a consommé et combien de temps ses requêtes ont attendu dans la file, en médiane et en p95, sur n’importe quelle période que vous sélectionnez ou saisissez. Renouvelez une clé avec un délai de grâce, et fixez sa priorité de P0 à P9 : une requête P9 en attente passe toujours avant une requête P8.

Suspendez-la, et les nouvelles requêtes sont refusées pendant que celles déjà en cours se terminent :

$ curl -i http://gpu-box:8080/v1/chat/completions \
    -H "Authorization: Bearer vw_…" -d '{…}'
HTTP/1.1 403 Forbidden
content-type: application/json

{"detail":"token paused"}

Relevé sur une instance locale le 23 septembre 2026. Hôte et clé remplacés, autres en-têtes supprimés.

Fig. 13La page de demo-agent, la clé qui a généré la charge de la fig. 1 : 37 requêtes et 43 k jetons générés dans l’heure affichée. Puis son panneau God mode s’ouvre (une vue en direct, facultative et désactivée par défaut, des prompts et réponses d’une clé) et ses réponses s’affichent au fur et à mesure de leur génération. Les prompts sont les nôtres.
Le graphique Requests de la page Stats sur les 7 derniers jours, du 16 au 23 septembre : un repère par requête, coloré selon la clé API, dimensionné selon les jetons générés et dont la forme dépend du motif de fin, en fonction de la durée sur une échelle logarithmique de 100 ms à 10 000 s. La plupart des repères se situent entre 3 et 100 secondes ; une clé présente deux colonnes denses allant de moins d’une seconde à plusieurs centaines de secondes.
Fig. 14Les requêtes de toutes les clés sur un seul graphique, issu de la même page Stats : les 7 derniers jours, 28 906 requêtes, une sur quinze affichée. Chaque repère représente une requête, coloré selon sa clé, dimensionné selon les jetons qu’elle a générés, avec une forme qui dépend de la façon dont elle s’est terminée, et placé en hauteur selon sa durée sur une échelle logarithmique. L’ambre régulier correspond à opencode-laptop, les deux colonnes roses denses à research-notebook. Relevé le 23 septembre 2026 ; les noms des clés ont été remplacés. Faites défiler l’image horizontalement pour voir toute la semaine.

Pour partir, il suffit de changer base_url.

Il expose /v1/chat/completions et /v1/models, et /v1/models indique le max_model_len de chaque modèle. Il prend aussi en charge l’API Anthropic Messages sur /v1/messages, si bien que Claude Code peut faire pointer ANTHROPIC_BASE_URL vers l’URL racine d’un warden (Claude Code ajoute lui-même le chemin /v1/messages), ainsi que l’OpenAI Responses API sur /v1/responses, pour que Codex CLI puisse utiliser un modèle que vous avez chargé. Les poids sont stockés dans un cache HuggingFace ordinaire, que make export-hf-cache vous remet sous forme d’archive tar, et l’argv exact de lancement de chaque moteur s’obtient par une simple requête GET : une installation fonctionnelle peut donc être reconstruite sans nous. Pour partir, il suffit d’appliquer à rebours le diff ci-dessous.

  import os
  from openai import OpenAI

  client = OpenAI(
-     base_url="https://api.openai.com/v1",
-     api_key=os.environ["OPENAI_API_KEY"],
+     base_url="http://gpu-box:8080/v1",
+     api_key=os.environ["LM_WARDEN_KEY"],   # a vw_ key from API tokens
  )

  reply = client.chat.completions.create(
-     model="gpt-4o-mini",
+     model="gpt-oss-20b",   # the served name of a model you loaded
      messages=[{"role": "user", "content": "What is a KV cache?"}],
  )