Comment limiter le coût d’un agent IA sur un VPS
Un agent sans surveillance facture chaque boucle. Découvrez les plafonds, budgets de tâches, prompt caching, batch et champs d’usage pour suivre vos dépenses.
Comment éviter qu’un agent IA toujours actif fasse exploser la facture
Le contrôle des coûts d’un agent IA sur un VPS (serveur privé virtuel) repose sur des plafonds définis avant son démarrage, car personne ne surveille le compteur pendant son exécution. Limitez chaque réponse avec max_tokens, bornez le nombre d’itérations de la boucle dans votre propre code, mettez en cache la partie du prompt qui ne change jamais et journalisez les statistiques d’utilisation de chaque réponse pour identifier les tâches qui consomment le plus. La location du serveur est facturée à un prix mensuel fixe. L’API du modèle est facturée au nombre de tokens, et une boucle sans supervision est très efficace pour consommer des tokens discrètement.
Cette section suppose que vous disposez déjà d’un agent qui appelle l’API Messages depuis une machine que vous contrôlez. Créer un agent IA avec Claude sur un VPS explique la mise en place elle-même.
Pourquoi le coût d’un agent sans supervision évolue différemment
Une session interactive implique une personne. Lorsque le modèle prend une mauvaise direction ou lit un journal de 40,000 lignes, la personne qui le surveille l’arrête. Un agent sans supervision ne dispose d’aucun tel frein : il s’exécute jusqu’à la fin de la boucle, puis un timer le relance.
La fréquence est le multiplicateur souvent oublié. Une tâche planifiée toutes les cinq minutes s’exécute 288 fois par jour et environ 8,640 fois par mois. Quel que soit le coût d’une exécution, c’est cette valeur qu’il faut multiplier. De nombreux agents « toujours actifs » n’ont pas besoin de fonctionner en permanence. Ils doivent répondre dans un délai donné, exprimé en minutes. Il s’agit d’une planification.
Un agent consomme également des ressources qu’une fenêtre de chat n’utilise pas.
- Les définitions des outils sont transmises avec chaque requête. Le prompt système d’utilisation des outils consomme 290 tokens avec Claude Opus 4.8 et
tool_choicedeautoounone, et 410 avecanyoutool. L’outil bash en ajoute 325. Chaque serveur MCP que vous attachez ajoute ses schémas à ce volume. MCP signifie model context protocol. - Les résultats des outils sont des tokens d’entrée. Une commande qui affiche 8,000 lignes place ces 8,000 lignes dans la requête suivante, puis dans chaque requête suivante de ce tour.
- Les pages récupérées sont des tokens d’entrée. Une page web moyenne de 10 kB représente environ 2,500 tokens, et un PDF de recherche de 500 kB environ 125,000.
max_content_tokenstronque uniquement le texte, car il « s’applique au contenu textuel, et non au contenu binaire tel que les PDF ». Limitez plutôt un PDF avecmax_usesetallowed_domains. - La recherche web est facturée par recherche, à raison de $10 pour 1,000 recherches, quel que soit le nombre de résultats renvoyés. Une recherche qui échoue n’est pas facturée.
Aucun de ces éléments n’est coûteux une seule fois. Ils le sont tous 8,640 fois.
Les plafonds stricts et les plafonds souples répondent à des problèmes différents
max_tokens est appliqué. Il s’agit d’une limite stricte sur la sortie totale d’une requête, c’est-à-dire le raisonnement et le texte de réponse. Claude ne la dépasse jamais, et le modèle ne peut pas voir cette valeur. Lorsque cette limite est atteinte, stop_reason: "max_tokens" est renvoyé et la réponse est tronquée. Pour les agents, le point important est le suivant : chaque requête d’une boucle d’utilisation d’outils possède son propre max_tokens. Cette limite s’applique donc à une réponse, et non à la tâche entière. Dix appels d’outils à 4,000 tokens donnent un plafond de 40,000 tokens pour le tour.
Le budget de tâche est indicatif. task_budget se trouve dans output_config et indique au modèle le nombre de tokens disponibles pour toute la boucle agentique, en comptant le raisonnement, les appels d’outils, les résultats des outils et la sortie.
resp = client.beta.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
betas=["task-budgets-2026-03-13"],
output_config={"task_budget": {"type": "tokens", "total": 64000}},
messages=messages,
)« Les budgets de tâche sont une indication souple, et non une limite stricte. » Claude peut dépasser ce budget pendant une action, tandis que la limite appliquée à la sortie reste max_tokens. « Le compte à rebours n’est visible que par le modèle » et les réponses ne contiennent aucun champ indiquant le budget restant. La valeur minimale acceptée pour task_budget.total est de 20,000 tokens. Une valeur inférieure renvoie une erreur 400. Un budget trop faible pour la tâche entraîne un comportement proche d’un refus : le modèle réduit la portée de la tâche ou s’arrête prématurément.
Un détail entraîne une dépense au lieu de la réduire. Si votre client décrémente task_budget.remaining à chaque requête de suivi, la valeur modifiée invalide tout préfixe mis en cache qui la contient. Définissez cette valeur une seule fois, lors de la première requête.
Les budgets de tâche sont en version bêta sur Claude Fable 5, Claude Opus 4.8 et Claude Opus 4.7. Claude Sonnet 5 et Claude Haiku 4.5 sont répertoriés comme Not supported, et les budgets de tâche ne s’appliquent pas à Claude Code. Une session Claude Code détachée dans tmux dépend donc plutôt d’une bonne gestion de la session.
Le troisième plafond se trouve dans la Claude Console : attribuez à l’agent son propre espace de travail, puis définissez une limite mensuelle de dépenses et des limites de débit par minute pour cet espace. « Vous ne pouvez pas définir de limites sur l’espace de travail Default » et « les limites appliquées à toute l’organisation s’appliquent toujours, même si la somme des limites des espaces de travail est supérieure ». Ajoutez des notifications de dépenses afin d’être alerté lorsqu’un seuil est atteint, avant que le plafond ne soit dépassé.
Choix du modèle par tâche et effet réel du niveau d’effort
Le choix du modèle dépend de chaque tâche. En juillet 2026, le prix par million de tokens, pour les entrées puis les sorties, est le suivant : Claude Fable 5 coûte $10 et $50, Claude Opus 4.8 et Opus 4.7 coûtent $5 et $25, Claude Sonnet 5 coûte $3 et $15, et Claude Haiku 4.5 coûte $1 et $5. Sonnet 5 est actuellement facturé sous son prix affiché, car « Introductory pricing of $2/$10 per million input/output tokens is in effect through August 31, 2026 ». Une étape qui se contente de classer des lignes de journal n’a pas besoin d’Opus. Il n’existe pas non plus de quota gratuit pour absorber une charge importante, car l’API Claude n’a pas de formule gratuite au-delà du petit crédit accordé à l’inscription.
Le niveau d’effort est le deuxième levier. output_config.effort accepte low, medium, high, xhigh et max, et la valeur par défaut est high. Définir explicitement high revient donc à ne pas le définir. Un niveau d’effort plus faible réduit davantage que la longueur du raisonnement : la documentation indique qu’il demande à Claude d’effectuer moins d’appels d’outils et de regrouper les opérations en une seule. Pour un agent, l’économie est plus importante, car chaque appel d’outil évité correspond à une requête complète qui n’est jamais envoyée.
Le piège est que le niveau d’effort perturbe le cache. Modifier sa valeur entre deux requêtes invalide la mise en cache du prompt. Dans l’exemple documenté, la requête 2 indiquait cache_read_input_tokens: 3546 ; la requête 3, après un changement du niveau d’effort de high à medium, indiquait cache_creation_input_tokens sur 3546 et cache_read_input_tokens sur 0. Faites donc varier le niveau d’effort selon les charges de travail, jamais au sein d’une même conversation mise en cache. Pour ajuster la profondeur sans invalider le cache, faites-le dans le prompt : une ligne telle que « Answer directly without deliberating. » dans le dernier message utilisateur conserve les points de rupture précédents.
Les tokens de réflexion sont facturés au tarif des sorties et déduits de max_tokens. C’est pourquoi une réponse tronquée signifie souvent que la réflexion a consommé le budget. Consultez usage.output_tokens_details.thinking_tokens pour connaître le nombre de tokens. Ce qui alimente réellement la facture de tokens Claude détaille le calcul.
Mettre en cache le préfixe stable et éviter de le modifier par accident
Une écriture dans le cache coûte 1.25 fois le prix de base des entrées avec le cache de cinq minutes, et 2 fois ce prix avec le cache d’une heure. Une lecture dans le cache coûte 0.1 fois ce prix. Le cache devient donc rentable après une seule lecture pour la durée de 5 minutes (écriture à 1.25x), ou après deux lectures pour la durée d’une heure (écriture à 2x).
Une ligne explique pourquoi ce mécanisme convient à un agent toujours actif : « Le cache est actualisé sans coût supplémentaire chaque fois que le contenu mis en cache est utilisé. » Une tâche exécutée toutes les deux minutes avec le cache de cinq minutes maintient son préfixe en cache toute la journée avec une seule écriture.
Voici trois façons de perdre le cache sans s’en rendre compte.
Un préfixe qui change. « Les préfixes du cache sont créés dans l’ordre suivant : tools, system, puis messages. » Toute modification d’un octet situé plus tôt dans cet ordre invalide tout ce qui suit. La modification des définitions d’outils invalide également l’intégralité du cache. L’erreur classique consiste à ajouter un horodatage ou un identifiant d’exécution dans l’invite système : chaque requête utilise alors un préfixe différent, écrit une nouvelle entrée à 1.25x et ne réutilise rien. Le signe révélateur est usage.cache_read_input_tokens à 0 pour des appels qui semblent identiques. Déplacez le texte variable dans le dernier message utilisateur.
Un préfixe trop court. Chaque modèle possède une longueur minimale pouvant être mise en cache. En dessous de cette longueur, la requête est traitée sans mise en cache et « aucune erreur n’est renvoyée ». Les valeurs indiquées sont notamment 1,024 tokens pour Claude Opus 4.8 et Claude Sonnet 5, et 4,096 pour Claude Haiku 4.5. Déplacer une tâche de Sonnet vers Haiku peut donc désactiver la mise en cache sans aucun avertissement.
Une conversation qui dépasse la fenêtre de recherche. « La fenêtre de recherche contient 20 blocs. » Pour chaque point de rupture, le système vérifie au maximum 20 positions, puis s’arrête. Dans l’exemple documenté, un tour contenant 35 blocs et un point de rupture sur le bloc 35 vérifie les blocs 35 à 16. L’entrée du tour précédent, située sur le bloc 15, est en dehors de la fenêtre. Il n’y a donc aucun accès au cache. Un agent qui ajoute plusieurs blocs d’utilisation d’outils et de résultats d’outils à chaque tour dépasse 20 blocs en deux ou trois tours. Vous disposez de quatre points de rupture par requête. Utilisez-en un pour les messages récents.
Envoyez à l’API Batches tout ce qui peut attendre
« Toutes les utilisations sont facturées à 50 % des tarifs standard de l’API », pour les entrées comme pour les sorties. Le traitement par lots est asynchrone, « la plupart des lots étant terminés en moins d’une heure ». Les résultats sont disponibles lorsque toutes les requêtes sont terminées ou après 24 heures, selon la première éventualité. Cette durée est indicative et non garantie.
Interrogez processing_status jusqu’à ce qu’il indique ended. Les requêtes qui renvoient errored, canceled ou expired ne sont pas facturées. Attention si vous utilisez un plafond de dépenses : « les lots peuvent dépasser légèrement la limite de dépenses configurée pour votre espace de travail ».
Les remises sont cumulables. Comme un lot peut durer plus de cinq minutes, la documentation recommande le cache d’une heure pour les lots qui partagent un contexte. Séparez donc les traitements : tout ce qu’une personne ou un webhook attend reste sur le chemin synchrone, tandis qu’un récapitulatif nocturne ou la classification des journaux de la veille passe par un lot à moitié prix.
Journalisez les champs d’utilisation de chaque réponse dans votre propre stockage
Vous ne pouvez pas attribuer une dépense que vous n’avez jamais enregistrée. Chaque réponse indique ce qu’elle a coûté.
u = resp.usage
row = {
"job": job_name,
"model": resp.model,
"uncached_input": u.input_tokens,
"cache_write": u.cache_creation_input_tokens,
"cache_read": u.cache_read_input_tokens,
"output": u.output_tokens,
"stop_reason": resp.stop_reason,
}Ajoutez une ligne par appel d’API dans un fichier JSON Lines, avec le nom de votre tâche. Une semaine plus tard, vous pourrez déterminer quelle tâche consomme réellement et laquelle semble seulement active. Surveillez cache_read : une colonne remplie de zéros est le bug de coût le plus fréquent dans un agent auto-hébergé.
Un champ est facile à mal interpréter. input_tokens compte uniquement les tokens situés après le dernier point de cache. La taille réelle du prompt est donc total_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens. Un agent qui indique input_tokens: 400 pour un prompt volumineux n’est pas économique : le reste provenait du cache.
Comptez avant l’envoi. Le comptage des tokens est gratuit et ses limites de débit sont distinctes de celles de la création de messages. Utilisez donc count_tokens pour refuser une pièce jointe trop volumineuse au lieu de payer pour le découvrir. Le résultat reste une estimation : mesurez à nouveau pour chaque modèle et ne réutilisez jamais un comptage effectué avec le tokenizer d’un autre fournisseur. Claude Opus 4.7 et les modèles Opus ultérieurs, Claude Fable 5 et Claude Sonnet 5 utilisent un tokenizer plus récent qui « produit environ 30 % de tokens supplémentaires pour le même texte ». Claude Sonnet 4.6 et les versions antérieures, dont Claude Haiku 4.5, utilisent le tokenizer précédent.
Pour obtenir la vue de référence, l’Admin API indique l’utilisation à https://api.anthropic.com/v1/organizations/usage_report/messages et le coût à https://api.anthropic.com/v1/organizations/cost_report. Les deux requêtes utilisent une clé d’administration (sk-ant-admin01-...) comme x-api-key: $ANTHROPIC_ADMIN_KEY avec anthropic-version: 2023-06-01, et acceptent bucket_width=1d, group_by[]=model et api_key_ids[]=. Une limitation subsiste : « L’Admin API n’est pas disponible pour les comptes individuels. »
Ce dernier paramètre fournit une méthode simple pour attribuer les coûts : donnez à chaque tâche sa propre clé d’API, filtrez avec api_key_ids[], puis répartissez le rapport par clé avec group_by[]=api_key_id. Le filtre est pluriel, tandis que la dimension de regroupement est singulière. Conservez les clés dans l’environnement plutôt que dans le code, comme le fait une première application Claude API sur un VPS pour les gérer.
Limitez la boucle, car rien d’autre ne le fera
Un nombre maximal d’itérations est indispensable ici. La boucle vous appartient, donc le compteur aussi :
for step in range(MAX_STEPS): # MAX_STEPS = 12, never "while True"
resp = client.messages.create(...)
if resp.stop_reason != "tool_use":
break
else:
log.warning("job %s hit MAX_STEPS=%d, giving up", job_name, MAX_STEPS)Aucune des deux limites précédentes ne suffit : max_tokens plafonne une réponse, et le modèle est seulement informé d’un budget de tâches. Un produit hébergé arrêterait le traitement à ce stade, comme la limite de Claude sur les appels d’outils au cours d’un même tour interrompt une session qui en a effectué trop, mais une boucle que vous avez écrite vous-même ne dispose d’aucun mécanisme de secours tant que vous n’en ajoutez pas un.
Ajoutez un second mécanisme d’arrêt à l’extérieur du processus. Exécutez la tâche avec un timer systemd plutôt qu’avec un processus permanent, et définissez RuntimeMaxSec= dans son unité de service. Avec RuntimeMaxSec=600, une exécution bloquée est tuée après dix minutes au lieu de continuer jusqu’à ce que vous le remarquiez. Exécuter un programme comme service et timer systemd décrit les fichiers d’unité eux-mêmes. Consultez le résultat d’une exécution avec journalctl -u triage-agent.service --since "1 hour ago".
Limitez également les nouvelles tentatives, car un gestionnaire qui réessaie indéfiniment facture chaque tentative. Une erreur 429 ou 500 justifie quelques tentatives avec backoff. Une erreur 400 n’en justifie aucune, car la même requête échouera de la même manière.
Le contrôle des coûts d’un agent IA commence par la lecture de vos propres chiffres
Personne ne peut vous dire combien coûte un agent actif en permanence, car le coût correspond au nombre de tokens par exécution multiplié par le nombre d’exécutions par jour. Ces deux valeurs dépendent de vous. Exécutez-le une fois, lisez la ligne d’utilisation que vous avez enregistrée, puis multipliez-la par votre planification. Deux jours plus tard, comparez le rapport de coûts avec ce calcul. En cas d’écart, il s’agit presque toujours d’un cache défaillant ou d’une boucle qui a duré plus longtemps que prévu.
Cela suppose l’utilisation d’une clé d’API, car l’agent est votre propre programme qui appelle l’API Messages. Pour votre travail interactif, quel forfait Claude correspond à votre façon de travailler couvre l’aspect abonnement. Tous les prix et toutes les limites indiqués ici ont été vérifiés dans la documentation d’Anthropic en juillet 2026. Consultez donc à nouveau la page des tarifs avant d’établir un budget.
FAQ
Combien coûte l’exécution permanente d’un agent IA sur un VPS ?
Il y a deux factures, mais une seule est prévisible. Le serveur a un prix mensuel fixe. L’API du modèle est facturée au token : le coût correspond à la consommation d’une exécution multipliée par sa fréquence. Anthropic ne publie aucun chiffre pour un agent permanent auto-hébergé. Considérez donc tout montant indiqué comme une estimation. Journalisez usage lors d’une exécution réelle, puis multipliez cette valeur par votre planification.
Quelle est la différence entre max_tokens et un budget de tâche ?
max_tokens est imposé et invisible pour le modèle. Il limite la sortie d’une requête, réflexion comprise, et l’atteindre renvoie stop_reason: "max_tokens". Un budget de tâche fonctionne à l’inverse : le modèle en connaît la valeur et adapte la boucle agentique en conséquence. Toutefois, « Task budgets are a soft hint, not a hard cap » et la limite imposée reste max_tokens.
Pourquoi cache_read_input_tokens vaut-il toujours zéro pour mon agent ?
Parce que le préfixe change entre les appels, ou parce qu’il est trop court pour être mis en cache. La cause habituelle est un horodatage ou un identifiant d’exécution interpolé dans le system prompt : le cache est indexé sur le préfixe, donc toute modification d’un octet invalide tout ce qui suit. Modifier les définitions des outils ou la valeur effort produit le même effet. Sinon, le problème vient de la taille : les prompts plus courts ne sont pas mis en cache et aucune erreur n’est renvoyée.
Comment empêcher un agent IA de boucler indéfiniment ?
Comptez les itérations dans le code de la boucle et arrêtez-la après un maximum fixe, car max_tokens limite une réponse alors qu’un agent en produit plusieurs. Ajoutez une limite de temps réelle en dehors du processus : lancez le job depuis un timer systemd avec RuntimeMaxSec= défini, afin qu’une exécution bloquée soit arrêtée selon la planification. Limitez également les retries, car une boucle de retry facture chaque tentative.
Puis-je définir une limite de dépenses pour une seule clé d’API Claude ?
La limite de dépenses documentée s’applique à un workspace et non à une clé. Attribuez donc à l’agent un workspace dédié et définissez-y une limite mensuelle. « You cannot set limits on the Default Workspace ». Ajoutez des notifications de dépenses afin d’être alerté lorsqu’un seuil est atteint. Pour attribuer les coûts, utilisez une clé distincte pour chaque job, puis regroupez le rapport d’utilisation avec group_by[]=api_key_id.