Nous avons mis à niveau l'interface compatible avec OpenAI avec des optimisations plus profondes spécifiquement pour les modèles de la série Claude. Vous pouvez désormais contrôler la pensée et la mise en cache de manière plus précise et pratique. La pensée entrelacée dans les conversations à plusieurs tours est désormais plus conviviale, permettant une intégration transparente sans paramètres supplémentaires. Elle prend également en charge l'activation des fonctionnalités bêta proposées par Anthropic.
1. Pensée du Modèle (Pensée Étendue)
1.1 Avantages de la Pensée Entrelacée
Lorsque la pensée entrelacée n'est pas activée, le modèle effectue une pensée uniquement une fois au début d'un tour d'assistant ; les réponses suivantes sont générées directement après avoir reçu les résultats des outils, sans produire de nouveaux blocs de pensée :
User → [Thinking] → Tool Call → Tool Result → Response
Lorsque la pensée entrelacée est activée, le modèle insère un nouveau bloc de pensée chaque fois qu'il reçoit un résultat d'outil, formant une chaîne de raisonnement :
User → [Thinking] → Tool Call → Tool Result → [Thinking] → Response
↑ Pensée Entrelacée
Cela permet au modèle de :
- Effectuer un raisonnement secondaire basé sur les résultats des outils, plutôt que de simplement concaténer les sorties.
- Chaîner le raisonnement entre plusieurs appels d'outils, où chaque décision est basée sur l'analyse de l'étape précédente.
Référence : Pensée Entrelacée d'Anthropic
1.2 Activation de la Pensée
Vous pouvez activer la pensée de quatre manières, en choisissant l'une d'elles :
| Méthode | Exemple | Description |
|---|---|---|
reasoning_effort |
"reasoning_effort": "low" |
Paramètre standard d'OpenAI, placé au niveau supérieur du corps de la requête |
reasoning.effort |
"reasoning": {"effort": "low"} |
Équivalent à la méthode précédente, placé dans l'objet de raisonnement |
reasoning.max_tokens |
"reasoning": {"max_tokens": 1024} |
Contrôle précisément le nombre maximum de tokens pour la pensée |
Nom du modèle avec -think |
"model": "claude-sonnet-4-5-think" |
La méthode la plus simple, ne nécessite pas de paramètres supplémentaires |
Priorité (lorsque plusieurs méthodes sont utilisées) :reasoning_effort>reasoning.max_tokens>reasoning.effort>-thinksuffixe
Valeurs possibles pour l'effort : minimal / low / medium / high / xhigh
1.3 Retour de Pensée
Le message de réponse inclura deux nouveaux champs :
reasoning_content: Contenu de la pensée (chaîne), pour un affichage facile.reasoning_details: Informations structurées complètes sur la pensée, qui doivent être retournées telles quelles dans les conversations à plusieurs tours ; la structure interne peut différer entre les fournisseurs.
Exemple non en streaming (omettant les champs non pertinents) :
{
"choices": [{
"message": {
"role": "assistant",
"content": "Bonjour ! Comment puis-je vous aider aujourd'hui ?",
"reasoning_content": "L'utilisateur dit juste bonjour...",
"reasoning_details": {
"type": "thinking",
"thinking": "L'utilisateur dit juste bonjour...",
"signature": "Er8CCkYI..."
}
}
}]
}
Dans les réponses en streaming, le contenu de la pensée sera envoyé par morceaux via delta.reasoning_content et delta.reasoning_details. Pour la logique complète de concaténation en streaming, référez-vous à l'exemple complet ci-dessous.
1.4 Conservation de la Pensée dans les Conversations à Plusieurs Tours (La Pensée Entrelacée est intégrée, aucun paramètre supplémentaire n'est nécessaire)
Pour permettre au modèle de continuer ses capacités de raisonnement dans les conversations à plusieurs tours, il suffit de placer les reasoning_details retournés précédemment tels quels dans le message de l'assistant du tour suivant :
messages = [
{"role": "user", "content": "Quel temps fait-il à Boston ?"},
{
"role": "assistant",
"content": response.choices[0].message.content,
"tool_calls": response.choices[0].message.tool_calls,
"reasoning_details": response.choices[0].message.reasoning_details,
},
{
"role": "tool",
"tool_call_id": "toolu_xxx",
"content": '{"temperature": 45, "condition": "pluvieux"}',
}
]
AIHubMix activera automatiquement la pensée entrelacée lorsqu'il détecte des informations de pensée historiques dans la requête, permettant au modèle de continuer un raisonnement approfondi après avoir reçu les résultats des appels d'outils sans nécessiter de paramètres supplémentaires.
1.5 Exemple Complet
Les deux exemples suivants démontrent le processus complet d'appel d'outil à plusieurs tours + pensée entrelacée : demande de l'utilisateur → le modèle pense et appelle un outil → injecte les résultats de l'outil (préservant reasoning_details) → le modèle la pensée entrelacée donne la réponse finale.
Non-streaming · Pensée Entrelacée
import os
import json
from openai import OpenAI
client = OpenAI(
base_url="https://aihubmix.com/v1",
api_key=os.environ.get("AIHUBMIX_API_KEY", "sk-***"),
)
# ── Définition de l'outil ───────────────────────────────────────────
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Obtenir la météo actuelle pour un emplacement",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string", "description": "Nom de la ville"}},
"required": ["location"]
}
}
}]
# ── Exécution simulée de l'outil ─────────────────────────────────────
WEATHER_DB = {
"boston": {"temperature": "45°F (7°C)", "condition": "pluvieux", "humidity": "85%", "wind": "15 mph NE"},
"tokyo": {"temperature": "72°F (22°C)", "condition": "ensoleillé", "humidity": "45%", "wind": "5 mph S"},
}
def execute_tool(name: str, args: dict) -> str:
if name == "get_weather":
key = next((k for k in WEATHER_DB if k in args.get("location", "").lower()), None)
return json.dumps(WEATHER_DB.get(key, {"temperature": "65°F", "condition": "clair"}))
return "{}"
# ── Boucle de conversation à plusieurs tours ───────────────────────────
messages = [
{"role": "user", "content": "Quel temps fait-il à Boston ? Puis recommandez quoi porter."}
]
turn = 0
while True:
turn += 1
print(f"\n── Tour {turn} ──")
response = client.chat.completions.create(
model="claude-sonnet-4-5",
messages=messages,
tools=tools,
extra_body={"reasoning": {"max_tokens": 2000}},
)
msg = response.choices[0].message
# Imprimer le processus de pensée
if msg.reasoning_content:
label = "Pensée Entrelacée" if turn > 1 else "Pensée"
print(f"[{label}] {msg.reasoning_content}")
# Imprimer le contenu de la réponse
if msg.content:
print(f"[Réponse] {msg.content}")
# Imprimer les appels d'outils
if msg.tool_calls:
for tc in msg.tool_calls:
print(f"[Appel d'Outil : {tc.function.name}] {tc.function.arguments}")
# Construire le message de l'assistant, préserver reasoning_details (critique !)
assistant_msg = {"role": "assistant", "content": msg.content}
if msg.tool_calls:
assistant_msg["tool_calls"] = msg.tool_calls
if msg.reasoning_details:
assistant_msg["reasoning_details"] = msg.reasoning_details # passer sans modification
messages.append(assistant_msg)
# Pas d'appels d'outils signifie que la conversation est terminée
if not msg.tool_calls:
break
# Exécuter les outils et ajouter les résultats aux messages
for tc in msg.tool_calls:
args = json.loads(tc.function.arguments)
result = execute_tool(tc.function.name, args)
print(f"[Résultat de l'Outil : {tc.function.name}] {result}")
messages.append({"role": "tool", "tool_call_id": tc.id, "content": result})
Streaming · Pensée Entrelacée
import os
import sys
import json
from openai import OpenAI
client = OpenAI(
base_url="https://aihubmix.com/v1",
api_key=os.environ.get("AIHUBMIX_API_KEY", "sk-***"),
)
# ── Définition de l'outil & exécution simulée ─────────────────────────
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Obtenir la météo actuelle pour un emplacement",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string", "description": "Nom de la ville"}},
"required": ["location"]
}
}
}]
WEATHER_DB = {
"boston": {"temperature": "45°F (7°C)", "condition": "pluvieux", "humidity": "85%", "wind": "15 mph NE"},
"tokyo": {"temperature": "72°F (22°C)", "condition": "ensoleillé", "humidity": "45%", "wind": "5 mph S"},
}
def execute_tool(name: str, args: dict) -> str:
if name == "get_weather":
key = next((k for k in WEATHER_DB if k in args.get("location", "").lower()), None)
return json.dumps(WEATHER_DB.get(key, {"temperature": "65°F", "condition": "clair"}))
return "{}"
# ── Collecteur de réponse en streaming ────────────────────────────────
def stream_and_collect(turn: int, **kwargs):
"""Streamer la réponse, imprimer la pensée/contenu en temps réel, accumuler reasoning_details/tool_calls."""
rd = {} # détails de raisonnement accumulés
content = "" # texte de réponse accumulé
tc_map = {} # appels d'outils accumulés (par index)
cur = "none" # section de sortie actuelle : none / thinking / content
stream = client.chat.completions.create(stream=True, **kwargs)
for chunk in stream:
if not chunk.choices:
continue
delta = chunk.choices[0].delta
# ── Gérer la pensée ──
rd_delta = getattr(delta, "reasoning_details", None)
if rd_delta and isinstance(rd_delta, dict):
for k, v in rd_delta.items():
if k == "type":
rd[k] = v
elif isinstance(v, str):
rd[k] = rd.get(k, "") + v
elif v is not None:
rd[k] = v
# Imprimer les morceaux de pensée en temps réel
thinking_chunk = rd_delta.get("thinking", "")
if thinking_chunk:
if cur != "thinking":
cur = "thinking"
label = "Pensée Entrelacée" if turn > 1 else "Pensée"
sys.stdout.write(f"\n[{label}] ")
sys.stdout.write(thinking_chunk)
sys.stdout.flush()
# ── Gérer le contenu ──
if delta.content:
if cur != "content":
if cur == "thinking":
sys.stdout.write("\n")
cur = "content"
sys.stdout.write("\n[Réponse] ")
sys.stdout.write(delta.content)
sys.stdout.flush()
content += delta.content
# ── Gérer les appels d'outils ──
for tc in delta.tool_calls or []:
i = tc.index
if i not in tc_map:
tc_map[i] = {"id": "", "type": "function",
"function": {"name": "", "arguments": ""}}
if tc.id:
tc_map[i]["id"] = tc.id
if tc.function:
tc_map[i]["function"]["name"] += tc.function.name or ""
tc_map[i]["function"]["arguments"] += tc.function.arguments or ""
# Fin de la section de sortie actuelle
if cur in ("thinking", "content"):
sys.stdout.write("\n")
tool_calls = [tc_map[i] for i in sorted(tc_map)] if tc_map else None
return {
"content": content or None,
"reasoning_details": rd or None,
"tool_calls": tool_calls,
}
# ── Boucle de conversation à plusieurs tours ───────────────────────────
messages = [
{"role": "user", "content": "Quel temps fait-il à Boston ? Puis recommandez quoi porter."}
]
turn = 0
while True:
turn += 1
print(f"\n── Tour {turn} ──")
result = stream_and_collect(
turn,
model="claude-sonnet-4-5",
messages=messages,
tools=tools,
extra_body={"reasoning": {"max_tokens": 2000}},
)
# Imprimer les appels d'outils
if result["tool_calls"]:
for tc in result["tool_calls"]:
print(f"[Appel d'Outil : {tc['function']['name']}] {tc['function']['arguments']}")
# Construire le message de l'assistant, préserver reasoning_details (critique !)
assistant_msg = {"role": "assistant", "content": result["content"]}
if result["tool_calls"]:
assistant_msg["tool_calls"] = result["tool_calls"]
if result["reasoning_details"]:
assistant_msg["reasoning_details"] = result["reasoning_details"] # passer sans modification
messages.append(assistant_msg)
# Pas d'appels d'outils signifie que la conversation est terminée
if not result["tool_calls"]:
break
# Exécuter les outils et ajouter les résultats aux messages
for tc in result["tool_calls"]:
args = json.loads(tc["function"]["arguments"])
tool_result = execute_tool(tc["function"]["name"], args)
print(f"[Résultat de l'Outil : {tc['function']['name']}] {tool_result}")
messages.append({"role": "tool", "tool_call_id": tc["id"], "content": tool_result})
1.6 Règles de Cartographie de l'Intensité de Pensée
Mode Effort :
- Opus 4.6 / Sonnet 4.6 et supérieur : correspond au niveau d'effort Pensée Adaptative natif d'Anthropic.
- Autres modèles : calculé en utilisant la formule pour
budget_tokens:
budget_tokens = max(min(max_tokens × effort_ratio, 128000), 1024)
| effort | effort_ratio |
|---|---|
| xhigh | 0.95 |
| high | 0.80 |
| medium | 0.50 |
| low | 0.20 |
| minimal | 0.10 |
Cartographie de l'Effort de Pensée Adaptative :
| Effort Entrant | Opus 4.6 | Sonnet 4.6 |
|---|---|---|
| xhigh | max | high |
| high | high | high |
| medium | medium | medium |
| low | low | low |
| minimal | low | low |
Mode max_tokens : Assigné directement comme budget_tokens d'Anthropic.
-think suffixe : Opus/Sonnet 4.6+ utilise la pensée adaptative (effort=medium) ; d'autres modèles définissent budget_tokens = min(10240, max_tokens - 1), avec un max_tokens par défaut de 4096.
2. Mise en Cache des Invites
Vous pouvez utiliser la mise en cache des invites lors de l'envoi de requêtes au modèle Claude via l'interface de chat. En définissant des points de rupture cache_control dans les messages, de grands blocs de texte (comme des cartes de rôle, des données RAG, des chapitres de livres, etc.) peuvent être mis en cache pour réutilisation, permettant aux requêtes suivantes d'accéder directement au cache et de réduire considérablement les coûts.
Documentation Officielle de Claude : Mise en Cache des Invites
2.1 Coûts de Mise en Cache
| Opération | Multiplicateur de Prix (par rapport au prix d'entrée original) |
|---|---|
| Écriture de Cache (TTL de 5 minutes) | 1.25x |
| Écriture de Cache (TTL de 1 heure) | 2x |
| Lecture de Cache | 0.1x |
2.2 Modèles Supportés et Longueur Minimale de Cache
| Modèle | Nombre Minimum de Tokens de Cache |
|---|---|
| Claude Opus 4.8 | 1024 |
| Claude Opus 4.7 | 2048 |
| Claude Opus 4.6 / Opus 4.5 | 4096 |
| Claude Sonnet 4.6 / Sonnet 4.5 / Opus 4.1 / Opus 4 / Sonnet 4 / Sonnet 3.7 (déprécié) | 1024 |
| Claude Haiku 4.5 | 4096 |
| Claude Haiku 3.5 (déprécié) / Haiku 3 | 2048 |
Limite de Quantité de Points de Rupture : Un maximum de 4 points de rupture cache_control par requête.2.3 TTL de Cache
| TTL | Syntaxe | Scénarios Applicables |
|---|---|---|
| 5 minutes (par défaut) | "cache_control": {"type": "ephemeral"} |
Sessions courtes, requêtes de routine |
| 1 heure | "cache_control": {"type": "ephemeral", "ttl": "1h"} |
Longues sessions, pour éviter les écritures de cache répétées |
Les coûts d'écriture pour un TTL de 1 heure sont plus élevés, mais ils peuvent économiser des dépenses totales en réduisant les écritures répétées dans les longues sessions. Tous les modèles à partir de Claude 4.5 et plus de tous les fournisseurs (y compris Anthropic, Amazon Bedrock, Google Vertex AI) prennent en charge un TTL de 1 heure.
2.4 Utilisation
Vous pouvez définir des points de rupture de cache en utilisant le champ cache_control dans system, user (y compris les images), et tools. Les exemples suivants montrent uniquement la structure clé, omettant de grands blocs de texte.
Mise en Cache des Messages Système (TTL par défaut de 5 minutes) :
{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [
{"type": "text", "text": "Vous êtes un assistant IA"},
{
"type": "text",
"text": "(long contexte)",
"cache_control": {"type": "ephemeral"}
}
]
},
{
"role": "user",
"content": [{"type": "text", "text": "Bonjour"}]
}
]
}
Mise en Cache des Messages Utilisateurs (TTL de 1 heure) :
{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [{"type": "text", "text": "Vous êtes un assistant IA"}]
},
{
"role": "user",
"content": [
{
"type": "text",
"text": "(long contexte)",
"cache_control": {"type": "ephemeral", "ttl": "1h"}
},
{"type": "text", "text": "Bonjour"}
]
}
]
}
Mise en Cache des Messages d'Image :
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {"detail": "auto", "url": "data:image/jpeg;base64,/9j/4AAQ..."},
"cache_control": {"type": "ephemeral"}
},
{"type": "text", "text": "Qu'est-ce que c'est ?"}
]
}
Mise en Cache de la Définition de l'Outil :
cache_control est placé au niveau supérieur de l'objet outil (aux côtés de type et function) :
{
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Obtenir la météo actuelle pour un emplacement",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
},
"cache_control": {"type": "ephemeral", "ttl": "1h"}
}]
}
2.5 Visualisation de l'État du Cache
Le champ usage de la réponse retournera claude_cache_tokens_details, enregistrant des informations détaillées sur le cache :
Première Requête (Création du Cache) :
{
"usage": {
"prompt_tokens": 22,
"completion_tokens": 890,
"total_tokens": 912,
"claude_cache_tokens_details": {
"cache_creation_input_tokens": 6266,
"cache_read_input_tokens": 0,
"cache_write_5_minutes_input_tokens": 6266,
"cache_write_1_hour_input_tokens": 0
}
}
}
Requêtes Subséquentes (Accès au Cache) :
{
"usage": {
"prompt_tokens": 22,
"completion_tokens": 810,
"total_tokens": 832,
"prompt_tokens_details": {
"cached_tokens": 6266
},
"claude_cache_tokens_details": {
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 6266,
"cache_write_5_minutes_input_tokens": 0,
"cache_write_1_hour_input_tokens": 0
}
}
}
| Champ | Signification |
|---|---|
cache_creation_input_tokens |
Nombre de tokens écrits dans le cache lors de cette requête |
cache_read_input_tokens |
Nombre de tokens lus dans le cache lors de cette requête |
cache_write_5_minutes_input_tokens |
Nombre de tokens écrits dans le cache TTL de 5 minutes |
cache_write_1_hour_input_tokens |
Nombre de tokens écrits dans le cache TTL de 1 heure |
prompt_tokens_details.cached_tokens |
Nombre de tokens mis en cache lors de l'accès au cache, compatible avec le format OpenAI |
3. En-tête de Requête pour anthropic-beta
Vous pouvez activer les fonctionnalités bêta du modèle Claude via l'en-tête HTTP anthropic-beta, que AIHubMix transmettra à l'API Anthropic.
Utilisation
Ajoutez anthropic-beta à l'en-tête de la requête, avec la valeur étant l'identifiant de la fonctionnalité bêta correspondante :
curl "https://aihubmix.com/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AIHUBMIX_API_KEY" \
-H "anthropic-beta: context-1m-2025-08-07" \
-d '{
"model": "claude-opus-4-5",
"messages": [
{
"role": "system",
"content": [
{"type": "text", "text": "Vous êtes un assistant IA"},
{
"type": "text",
"text": "(long contexte)",
"cache_control": {"type": "ephemeral"}
}
]
},
{"role": "user", "content": [{"type": "text", "text": "bonjour"}]}
]
}'
Pour des identifiants bêta spécifiques disponibles, veuillez vous référer à la Documentation de l'API Anthropic.
Dernière mise à jour : 2026-06-01