Aller au contenu principal

Nombre maximal de tokens et séquences d'arrêt

Définition

Le nombre maximal de tokens, les séquences d'arrêt et les pénalités de répétition sont des paramètres de contrôle de génération qui déterminent quand le modèle cesse de générer et comment il gère le contenu répété. Tandis que les paramètres d'échantillonnage comme la température façonnent ce que dit le modèle, les paramètres de contrôle de génération façonnent combien il dit, il s'arrête et à quel point il reste varié au cours d'une longue réponse. Chaque API de LLM expose une version de ces contrôles, et les comprendre est essentiel pour construire des pipelines fiables et rentables.

Le nombre maximal de tokens fixe une limite supérieure stricte sur le nombre de tokens que le modèle peut générer dans une seule réponse. Il agit comme un plafond de sécurité : le modèle s'arrête dès qu'il émettrait un token qui dépasse ce budget. Ce n'est pas une longueur cible — le modèle peut s'arrêter plus tôt s'il génère naturellement un token de fin de séquence. Choisir une valeur appropriée de nombre maximal de tokens est important à la fois pour le coût (vous êtes généralement facturé par token de sortie) et pour la correction (une réponse tronquée peut laisser des objets JSON ouverts, interrompre une chaîne de raisonnement, ou livrer des résultats partiels aux systèmes en aval).

Les séquences d'arrêt fournissent des conditions d'arrêt sémantiques : une ou plusieurs chaînes qui, une fois générées, font immédiatement s'arrêter le modèle (la chaîne d'arrêt elle-même est exclue de la sortie). Elles sont indispensables pour la génération structurée — entourer la sortie du LLM dans un délimiteur connu et utiliser le délimiteur de fermeture comme séquence d'arrêt rend l'extraction triviale et robuste. Les pénalités de répétition (pénalité de fréquence et pénalité de présence dans OpenAI ; non exposées nativement dans l'API messages d'Anthropic) réduisent la probabilité de regénérer des tokens qui sont déjà apparus, décourageant les boucles et le texte de remplissage qui peuvent émerger dans les générations longues.

Comment ça fonctionne

Chaque token généré passe par trois points de contrôle en séquence : détection de fin de séquence, application du budget maximal de tokens et correspondance des séquences d'arrêt. Si aucune des conditions d'arrêt ne se déclenche, la pénalité de répétition est appliquée aux logits du prochain token avant que l'échantillonnage ne reprenne.

Nombre maximal de tokens

Le paramètre max_tokens (appelé max_tokens_to_sample dans les anciens SDK Anthropic, maintenant max_tokens) est un champ requis ou fortement recommandé dans la plupart des API de LLM. Le fixer trop bas risque de tronquer la sortie ; le fixer inutilement haut gaspille du calcul et augmente la latence sur les endpoints de streaming. Une heuristique pratique : estimer la longueur de sortie attendue, puis fixer max_tokens à 1,5–2× cette estimation comme plafond de sécurité. Pour les sorties structurées comme JSON, profiler le nombre de tokens dans le pire cas de votre schéma et ajouter une marge de 20 %.

Séquences d'arrêt

Les séquences d'arrêt sont définies comme une liste de chaînes. Le modèle scanne sa sortie après chaque token et s'arrête dès que le texte généré se termine par une entrée de la liste. Les patterns courants incluent ["###", "\n\n", "</answer>", "```"] pour les templates de prompts structurés, ["\nHuman:", "\nUser:"] pour les simulateurs de chat qui ne doivent pas générer le prochain tour de l'utilisateur, et des délimiteurs de fermeture comme ["</json>"] pour l'extraction balisée. Les séquences d'arrêt sont comparées au texte brut généré, pas aux limites tokenisées, donc les chaînes multi-tokens fonctionnent correctement. Un point important : la séquence d'arrêt n'est pas incluse dans le texte retourné, donc votre logique d'analyse doit tenir compte de son absence.

Pénalités de répétition

L'API d'OpenAI expose deux paramètres de pénalité distincts. La pénalité de fréquence (frequency_penalty, plage −2,0 à 2,0) réduit le logit d'un token proportionnellement au nombre de fois qu'il est déjà apparu dans le texte généré — décourageant la répétition des mots fréquemment utilisés. La pénalité de présence (presence_penalty, plage −2,0 à 2,0) applique une réduction de logit forfaitaire à tout token apparu au moins une fois, indépendamment de la fréquence — décourageant la réutilisation de tout token déjà vu. Les valeurs positives réduisent la répétition ; les valeurs négatives l'encouragent. Des valeurs dans la plage 0,1–0,5 sont généralement suffisantes pour supprimer les boucles sans dégrader significativement la qualité de la sortie. Les valeurs supérieures à 1,0 peuvent amener le modèle à éviter des mots de liaison utiles et dégrader la cohérence.

Quand utiliser / Quand NE PAS utiliser

ScénarioParamètres recommandésÉviter
Réponses factuelles courtes ou classificationsmax_tokens=50–150 ; pas besoin de séquences d'arrêtmax_tokens très élevé ; gaspille le budget et peut inviter au rembourrage
Extraction JSON structurée ou baliséeArrêt sur le délimiteur de fermeture (ex. ["</json>"]) ; max_tokens dimensionné au schéma du pire casOmission des séquences d'arrêt ; le modèle peut ajouter de la prose après l'accolade fermante
Simulation de chat multi-toursSéquences d'arrêt ["\nHuman:", "\nUser:"] pour empêcher le modèle de générer le prochain tour de l'utilisateurPas de séquences d'arrêt ; le modèle va halluciner le prochain tour de conversation
Génération longue forme (essais, rapports)max_tokens élevé (2048–4096+) ; frequency_penalty=0,2 léger pour éviter les formulations répétitivesfrequency_penalty > 1,0 ; casse la cohérence stylistique et évite les termes répétés légitimes
Génération de codeArrêt sur des délimiteurs appropriés au langage (ex. triple backtick) ; max_tokens dimensionné à la longueur de la fonctionpresence_penalty > 0,5 ; les noms de variables et les mots-clés doivent se répéter — les pénalités nuisent à la correction
Inférence par lot sensible aux coûtsFixer max_tokens au plus proche du 95e percentile de la longueur de sortie attendueLaisser max_tokens au maximum de l'API (ex. 4096) quand la sortie typique est de 100 tokens

Exemples de code

OpenAI — max_tokens, stop et frequency_penalty

# OpenAI SDK: max_tokens, stop sequences, and repetition penalties
# pip install openai

import os
from openai import OpenAI

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])


def extract_with_controls(
text: str,
max_tokens: int = 512,
stop: list[str] | None = None,
frequency_penalty: float = 0.0,
presence_penalty: float = 0.0,
) -> str:
"""Call the chat API with full generation-control parameters."""
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "system",
"content": (
"You are a structured data extractor. "
"Output only valid JSON between <json> and </json> tags."
),
},
{"role": "user", "content": f"Extract key facts from:\n\n{text}"},
],
max_tokens=max_tokens,
stop=stop or ["</json>"],
frequency_penalty=frequency_penalty,
presence_penalty=presence_penalty,
temperature=0,
)
raw = response.choices[0].message.content
# Strip the opening tag; closing tag was consumed by stop sequence
return raw.replace("<json>", "").strip()


if __name__ == "__main__":
article = (
"SpaceX launched its Starship rocket on March 14, 2024. "
"The vehicle reached an altitude of 210 km before completing a controlled reentry. "
"It was the third integrated flight test of the system."
)

# Tight budget extraction
result = extract_with_controls(
article,
max_tokens=256,
stop=["</json>"],
frequency_penalty=0.1,
)
print(result)

# Long-form summary with anti-repetition penalty
summary_resp = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": f"Write a 3-paragraph summary of: {article}"}],
max_tokens=600,
frequency_penalty=0.4,
presence_penalty=0.1,
temperature=0.6,
)
print(summary_resp.choices[0].message.content)

Anthropic — max_tokens et stop_sequences

# Anthropic SDK: max_tokens and stop_sequences
# pip install anthropic

import os
import anthropic

client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])


def generate_with_controls(
prompt: str,
max_tokens: int = 512,
stop_sequences: list[str] | None = None,
) -> tuple[str, str]:
"""
Returns (text_content, stop_reason).
stop_reason is 'end_turn', 'max_tokens', or 'stop_sequence'.
"""
message = client.messages.create(
model="claude-opus-4-5",
max_tokens=max_tokens,
stop_sequences=stop_sequences or [],
messages=[{"role": "user", "content": prompt}],
temperature=0,
)
text = "".join(block.text for block in message.content if hasattr(block, "text"))
return text, message.stop_reason


if __name__ == "__main__":
# JSON extraction with stop sequence on closing delimiter
json_prompt = (
"Extract the event name, date, and location from the following text as JSON "
"between <json> and </json> tags:\n\n"
"The annual PyCon US conference will be held in Pittsburgh, PA on May 14-22, 2025."
)
output, reason = generate_with_controls(
json_prompt,
max_tokens=256,
stop_sequences=["</json>"],
)
print(f"Stop reason: {reason}")
print(output)

# Constrained generation — stop before model generates a second answer
answer_prompt = "Answer in one sentence: What is gradient descent?"
answer, reason = generate_with_controls(
answer_prompt,
max_tokens=100,
stop_sequences=["\n\n"],
)
print(f"Stop reason: {reason}")
print(answer)

Ressources pratiques

Voir aussi