Aller au contenu principal

Sorties structurees avec les outils

Objectifs

  • Comprendre comment utiliser les outils pour forcer une reponse structuree
  • Generer du JSON avec un format garanti grace au Tool Use

Le concept

Une utilisation astucieuse du Tool Use consiste a “tromper” Claude pour obtenir des reponses structurees. Quand Claude veut utiliser un outil, il repond deja dans un format parfaitement structure. On peut exploiter cela pour forcer un format JSON precis sans jamais executer l’outil.

Le principe :

  1. On definit un outil dont le schema correspond au format JSON qu’on veut obtenir
  2. On dit a Claude d’utiliser cet outil
  3. On extrait les donnees structurees de la reponse de Claude
  4. On n’appelle jamais la fonction sous-jacente

Exemple : analyse de sentiment

On veut obtenir un JSON comme celui-ci :

{
  "negative_score": 0.6,
  "neutral_score": 0.3,
  "positive_score": 0.1
}

Definir l’outil “fictif”

tools = [
    {
        "name": "print_sentiment_scores",
        "description": "Affiche les scores de sentiment pour un texte donne.",
        "input_schema": {
            "type": "object",
            "properties": {
                "positive_score": {
                    "type": "number",
                    "description": "Score de sentiment positif (0 a 1)"
                },
                "negative_score": {
                    "type": "number",
                    "description": "Score de sentiment negatif (0 a 1)"
                },
                "neutral_score": {
                    "type": "number",
                    "description": "Score de sentiment neutre (0 a 1)"
                }
            },
            "required": ["positive_score", "negative_score", "neutral_score"]
        }
    }
]

Forcer l’utilisation avec tool_choice

Plutot que de demander a Claude dans le prompt d’utiliser l’outil, on peut le forcer via le parametre tool_choice :

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1000,
    tools=tools,
    tool_choice={"type": "tool", "name": "print_sentiment_scores"},
    messages=[{
        "role": "user",
        "content": "Analyse le sentiment de ce texte : 'Ce produit est absolument horrible, je suis tres decu.'"
    }]
)

Extraire le JSON

import json

# Trouver le bloc ToolUse dans la reponse
tool_use_block = next(
    block for block in response.content if block.type == "tool_use"
)

# Les donnees sont directement dans input
sentiment_data = tool_use_block.input
print(json.dumps(sentiment_data, indent=2))

Resultat :

{
  "positive_score": 0.0,
  "negative_score": 0.85,
  "neutral_score": 0.15
}

Version fonction reutilisable

def analyze_sentiment(text):
    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1000,
        tools=tools,
        tool_choice={"type": "tool", "name": "print_sentiment_scores"},
        messages=[{
            "role": "user",
            "content": f"Analyse le sentiment de ce texte : '{text}'"
        }]
    )
    tool_block = next(b for b in response.content if b.type == "tool_use")
    return tool_block.input

# Utilisation
result = analyze_sentiment("J'adore ce restaurant, le service est impeccable !")
print(json.dumps(result, indent=2))

Exemple : extraction d’entites

On peut appliquer la meme technique pour extraire des entites nommees :

entity_tool = {
    "name": "print_entities",
    "description": "Affiche les entites extraites d'un texte.",
    "input_schema": {
        "type": "object",
        "properties": {
            "persons": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Liste des personnes mentionnees"
            },
            "organizations": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Liste des organisations mentionnees"
            },
            "locations": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Liste des lieux mentionnes"
            }
        },
        "required": ["persons", "organizations", "locations"]
    }
}

Exercice

Ecrivez une fonction translate qui utilise cette technique pour generer un JSON de traduction :

{
  "english": "how much does this cost",
  "spanish": "cuanto cuesta esto?",
  "french": "combien ca coute ?",
  "japanese": "korehaikuradesuka",
  "arabic": "kam tukallif hadha?"
}
Voir la solution
translate_tool = {
    "name": "print_translation",
    "description": "Affiche la traduction d'une phrase en plusieurs langues.",
    "input_schema": {
        "type": "object",
        "properties": {
            "english": {"type": "string", "description": "La phrase en anglais"},
            "spanish": {"type": "string", "description": "Traduction en espagnol"},
            "french": {"type": "string", "description": "Traduction en francais"},
            "japanese": {"type": "string", "description": "Traduction en japonais"},
            "arabic": {"type": "string", "description": "Traduction en arabe"}
        },
        "required": ["english", "spanish", "french", "japanese", "arabic"]
    }
}

def translate(phrase):
    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1000,
        tools=[translate_tool],
        tool_choice={"type": "tool", "name": "print_translation"},
        messages=[{
            "role": "user",
            "content": f"Traduis cette phrase : '{phrase}'"
        }]
    )
    block = next(b for b in response.content if b.type == "tool_use")
    return block.input