Intelligence Artificielle

Claude API d'Anthropic : guide de démarrage

ClaudeAnthropicApiLlmClaude-ApiTool-UseStreaming-SseSystem-PromptTypescriptSdkIa-GenerativePrompt-EngineeringNode-Js
Claude API d'Anthropic : guide de démarrage

Intégrez l'API Claude d'Anthropic dans vos applications : messages, system prompt, streaming temps réel et tool use avec le SDK officiel TypeScript.

Installation et configuration

npm install @anthropic-ai/sdk

# TypeScript (recommandé)
npm install typescript @types/node
// anthropic.ts — Client configuré
import Anthropic from '@anthropic-ai/sdk';

// La clé API est lue depuis la variable d'environnement ANTHROPIC_API_KEY
// Ne jamais hardcoder la clé dans le code source
const client = new Anthropic({
    apiKey: process.env.ANTHROPIC_API_KEY,
    // Optionnel : timeout et retry
    timeout: 30_000,      // 30 secondes
    maxRetries: 2,        // Retry automatique sur erreurs réseau
});

export default client;
Sécurité : Récupère ta clé sur console.anthropic.com. Stocke-la dans .env (jamais dans le code). Pour les apps Angular, l'API doit être appelée côté serveur (Node.js/Express) — ne jamais exposer la clé côté client.

Messages et structure de réponse

import client from './anthropic.js';

// Appel simple
const message = await client.messages.create({
    model: 'claude-opus-4-6',
    max_tokens: 1024,
    messages: [
        { role: 'user', content: 'Explique les closures JavaScript en 3 points avec des exemples.' }
    ]
});

// Accès au texte de la réponse
const text = message.content[0].type === 'text' ? message.content[0].text : '';
console.log(text);
// Structure complète de la réponse Message
interface Message {
    id: string;           // 'msg_01XFDUDYJgAACzvnptvVoYEL'
    type: 'message';
    role: 'assistant';
    content: ContentBlock[];  // Tableau de blocs de contenu
    model: string;        // 'claude-opus-4-6'
    stop_reason: 'end_turn' | 'max_tokens' | 'stop_sequence' | 'tool_use';
    stop_sequence: string | null;
    usage: {
        input_tokens: number;   // Tokens dans le prompt
        output_tokens: number;  // Tokens générés
    };
}

// Content blocks typés
type ContentBlock =
    | { type: 'text'; text: string }
    | { type: 'tool_use'; id: string; name: string; input: Record<string, unknown> };

// Extraction sécurisée du texte
function extractText(message: Anthropic.Message): string {
    return message.content
        .filter(block => block.type === 'text')
        .map(block => (block as Anthropic.TextBlock).text)
        .join('\n');
}

System Prompt et conversations multi-tours

// Conversation multi-tours avec gestion de l'historique
class ConversationManager {
    private history: Anthropic.MessageParam[] = [];
    private systemPrompt: string;

    constructor(systemPrompt: string) {
        this.systemPrompt = systemPrompt;
    }

    async chat(userMessage: string): Promise<string> {
        // Ajouter le message utilisateur à l'historique
        this.history.push({ role: 'user', content: userMessage });

        const response = await client.messages.create({
            model: 'claude-sonnet-4-6',
            max_tokens: 2048,
            system: this.systemPrompt, // System prompt en dehors de messages[]
            messages: this.history,    // Historique complet à chaque requête
        });

        const assistantMessage = extractText(response);

        // Ajouter la réponse à l'historique pour le prochain tour
        this.history.push({ role: 'assistant', content: assistantMessage });

        // Truncation de l'historique si trop long (fenêtre de contexte)
        if (this.history.length > 20) {
            // Garder les 2 premiers (contexte initial) et les 18 derniers
            this.history = [...this.history.slice(0, 2), ...this.history.slice(-18)];
        }

        return assistantMessage;
    }

    clearHistory() { this.history = []; }
}

// Utilisation
const bot = new ConversationManager(`
    Tu es un expert Angular qui répond en français.
    Fournis toujours des exemples TypeScript avec commentaires.
    Sois précis, concis, et pratique.
`);

console.log(await bot.chat('Comment créer un service Angular injectable ?'));
console.log(await bot.chat('Et comment l\´injecter dans un composant ?'));

Streaming avec SSE

Le streaming envoie les tokens au fur et à mesure, réduisant la latence perçue de 80% sur les longues réponses.

// Streaming avec SDK helper
const stream = await client.messages.stream({
    model: 'claude-opus-4-6',
    max_tokens: 2048,
    messages: [{ role: 'user', content: 'Explique le SSR Angular en détail.' }],
});

// Écouter les tokens en temps réel
stream.on('text', (text) => {
    process.stdout.write(text); // Affichage progressif
});

// Message final avec usage complet
const finalMessage = await stream.finalMessage();
console.log('\n\nUsage:', finalMessage.usage);
// Endpoint Express avec Server-Sent Events (SSE)
import express from 'express';
import client from './anthropic.js';

app.post('/api/chat/stream', async (req, res) => {
    const { messages, system } = req.body;

    // Configuration SSE
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Connection', 'keep-alive');
    res.setHeader('Access-Control-Allow-Origin', '*');

    try {
        const stream = await client.messages.stream({
            model: 'claude-sonnet-4-6',
            max_tokens: 2048,
            system,
            messages,
        });

        for await (const event of stream) {
            if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {
                // Envoyer chaque token au client
                res.write(`data: ${JSON.stringify({ text: event.delta.text })}\n\n`);
            }
        }

        const final = await stream.finalMessage();
        res.write(`data: ${JSON.stringify({ done: true, usage: final.usage })}\n\n`);
        res.end();

    } catch (error) {
        res.write(`data: ${JSON.stringify({ error: 'Erreur de streaming' })}\n\n`);
        res.end();
    }
});

Tool Use — cycle complet

Le Tool Use (function calling) permet à Claude d'appeler des fonctions définies par le développeur. Le cycle complet requiert plusieurs échanges : Claude demande l'outil → vous l'exécutez → vous renvoyez le résultat.

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic();

// Définition des outils disponibles
const tools: Anthropic.Tool[] = [
    {
        name: 'get_weather',
        description: 'Obtenir la météo actuelle pour une ville',
        input_schema: {
            type: 'object',
            properties: {
                city: { type: 'string', description: 'Nom de la ville' },
                unit: { type: 'string', enum: ['celsius', 'fahrenheit'], description: 'Unité de température' }
            },
            required: ['city']
        }
    },
    {
        name: 'search_web',
        description: 'Rechercher des informations sur le web',
        input_schema: {
            type: 'object',
            properties: {
                query: { type: 'string', description: 'Requête de recherche' }
            },
            required: ['query']
        }
    }
];

// Fonctions d'implémentation
async function executeToolCall(name: string, input: Record<string, unknown>): Promise<string> {
    switch (name) {
        case 'get_weather':
            // Appel API météo réel
            const weather = await fetchWeatherApi(input.city as string);
            return JSON.stringify(weather);
        case 'search_web':
            const results = await webSearch(input.query as string);
            return JSON.stringify(results);
        default:
            return JSON.stringify({ error: `Outil inconnu: ${name}` });
    }
}

// Cycle complet tool use
async function chatWithTools(userMessage: string): Promise<string> {
    const messages: Anthropic.MessageParam[] = [
        { role: 'user', content: userMessage }
    ];

    // Boucle : continuer tant que Claude appelle des outils
    while (true) {
        const response = await client.messages.create({
            model: 'claude-opus-4-6',
            max_tokens: 4096,
            tools,
            messages,
        });

        // Claude a terminé (pas d'appel d'outil)
        if (response.stop_reason === 'end_turn') {
            return extractText(response);
        }

        // Claude demande un ou plusieurs outils
        if (response.stop_reason === 'tool_use') {
            // Ajouter la réponse de Claude à l'historique
            messages.push({ role: 'assistant', content: response.content });

            // Exécuter TOUS les outils demandés (Claude peut en demander plusieurs)
            const toolResults: Anthropic.ToolResultBlockParam[] = [];

            for (const block of response.content) {
                if (block.type === 'tool_use') {
                    const result = await executeToolCall(block.name, block.input);
                    toolResults.push({
                        type: 'tool_result',
                        tool_use_id: block.id,
                        content: result,
                    });
                }
            }

            // Ajouter les résultats à l'historique pour le prochain tour
            messages.push({ role: 'user', content: toolResults });
        }
    }
}

// Usage
const answer = await chatWithTools('Quel temps fait-il à Paris aujourd\'hui ?');
console.log(answer);

Vision — analyse d'images

Claude supporte l'analyse d'images (Vision) via des blocs image dans les messages. Supporte JPG, PNG, GIF, WebP et les URLs.

import * as fs from 'fs';

// Vision avec image en base64
const imageData = fs.readFileSync('./screenshot.png').toString('base64');

const response = await client.messages.create({
    model: 'claude-opus-4-6',
    max_tokens: 1024,
    messages: [{
        role: 'user',
        content: [
            {
                type: 'image',
                source: {
                    type: 'base64',
                    media_type: 'image/png',
                    data: imageData,
                }
            },
            {
                type: 'text',
                text: 'Analyse cette capture d\'écran d\'interface. Quels problèmes UX vois-tu ?'
            }
        ]
    }]
});

// Vision avec URL (image publique)
const responseUrl = await client.messages.create({
    model: 'claude-opus-4-6',
    max_tokens: 1024,
    messages: [{
        role: 'user',
        content: [
            { type: 'image', source: { type: 'url', url: 'https://example.com/diagram.png' } },
            { type: 'text', text: 'Explique ce diagramme d\'architecture.' }
        ]
    }]
});

Modèles et paramètres

Modèle Points forts Contexte Usage recommandé
claude-opus-4-6 Raisonnement avancé, code complexe 200k tokens Analyse, architecture, debug difficile
claude-sonnet-4-6 Équilibre perf/vitesse/coût 200k tokens Chatbots, génération de contenu
claude-haiku-4-5-20251001 Ultra rapide, faible coût 200k tokens Classification, extraction, fort volume
// Paramètres importants de messages.create()
await client.messages.create({
    model: 'claude-sonnet-4-6',
    max_tokens: 2048,          // Tokens maximum à générer (obligatoire)
    temperature: 0.7,          // 0 = déterministe, 1 = créatif (défaut: 1)
    top_p: 0.9,                // Nucleus sampling (alternatif à temperature)
    top_k: 40,                 // Limite le vocabulaire (moins courant)
    stop_sequences: ['', 'FIN'], // Arrêter la génération sur ces séquences
    system: 'Tu es un expert Angular.',
    messages: [...],
    metadata: {
        user_id: 'user_123'    // Traçabilité (non envoyé au modèle)
    }
});

Service Angular avec Claude API

En production Angular, l'appel à l'API Claude doit passer par un backend Node.js. Voici l'architecture complète :

// === BACKEND : api.service.ts (Node.js/Express) ===
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });

app.post('/api/ai/chat', async (req, res) => {
    const { messages, system } = req.body;
    const response = await client.messages.create({
        model: 'claude-sonnet-4-6',
        max_tokens: 2048,
        system,
        messages,
    });
    res.json({ text: extractText(response), usage: response.usage });
});

// === FRONTEND Angular : claude.service.ts ===
import { Injectable, inject, signal } from '@angular/core';
import { HttpClient } from '@angular/common/http';

interface ChatMessage {
    role: 'user' | 'assistant';
    content: string;
}

@Injectable({ providedIn: 'root' })
export class ClaudeService {
    private http = inject(HttpClient);

    readonly isLoading = signal(false);
    readonly history = signal<ChatMessage[]>([]);
    readonly error = signal<string | null>(null);

    async sendMessage(userMessage: string, systemPrompt?: string): Promise<string> {
        this.isLoading.set(true);
        this.error.set(null);

        // Ajouter le message utilisateur à l'historique
        this.history.update(h => [...h, { role: 'user', content: userMessage }]);

        try {
            const response = await this.http.post<{ text: string }>('/api/ai/chat', {
                messages: this.history(),
                system: systemPrompt ?? 'Tu es un assistant Angular expert.'
            }).toPromise();

            const assistantText = response!.text;

            // Ajouter la réponse à l'historique
            this.history.update(h => [...h, { role: 'assistant', content: assistantText }]);

            return assistantText;
        } catch (err) {
            const msg = 'Erreur de communication avec l\'assistant IA';
            this.error.set(msg);
            throw new Error(msg);
        } finally {
            this.isLoading.set(false);
        }
    }

    clearHistory() { this.history.set([]); }
}

Gestion d'erreurs et rate limits

import Anthropic from '@anthropic-ai/sdk';

// Le SDK gère les retries automatiquement, mais voici la gestion manuelle
async function callWithRetry(fn: () => Promise<Anthropic.Message>, maxRetries = 3): Promise<Anthropic.Message> {
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
        try {
            return await fn();
        } catch (error) {
            if (error instanceof Anthropic.RateLimitError) {
                // 429 — attendre avant de réessayer
                const waitMs = Math.pow(2, attempt) * 1000; // Backoff exponentiel
                console.warn(`Rate limit atteint, attente ${waitMs}ms...`);
                await new Promise(resolve => setTimeout(resolve, waitMs));
            } else if (error instanceof Anthropic.APIError) {
                // Erreurs non-retryables
                if (error.status === 401) throw new Error('Clé API invalide');
                if (error.status === 400) throw new Error(`Requête invalide: ${error.message}`);
                if (attempt === maxRetries) throw error;
            } else {
                throw error;
            }
        }
    }
    throw new Error('Nombre maximum de tentatives atteint');
}

// Gestion des types d'erreurs Anthropic
try {
    const response = await client.messages.create({ ... });
} catch (error) {
    if (error instanceof Anthropic.AuthenticationError) {
        console.error('401: Clé API invalide ou expirée');
    } else if (error instanceof Anthropic.RateLimitError) {
        console.error('429: Quota dépassé — attendre ou upgrader');
    } else if (error instanceof Anthropic.APIConnectionError) {
        console.error('Erreur réseau — vérifier la connexion');
    } else if (error instanceof Anthropic.APIError) {
        console.error(`Erreur API ${error.status}: ${error.message}`);
    }
}

Conclusion

L'API Claude via le SDK @anthropic-ai/sdk couvre tous les cas d'usage d'une application IA moderne. Points clés à retenir :

  • client.messages.create() — appel simple et conversations multi-tours
  • messages.stream() — streaming SSE pour l'UX temps réel
  • Tool Use : cycle demander → exécuter → renvoyer pour connecter Claude à des APIs externes
  • Vision : blocs image (base64 ou URL) pour l'analyse d'images
  • Ne jamais exposer la clé API côté client Angular — toujours via un backend Node.js
  • Gérer les RateLimitError avec backoff exponentiel

Questions fréquentes

Créez un compte sur console.anthropic.com, générez une clé API dans Settings → API Keys. Installez le SDK : npm install @anthropic-ai/sdk. Initialisez le client avec votre clé : const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }). Envoyez votre premier message avec anthropic.messages.create(). La documentation complète est sur docs.anthropic.com.

Anthropic propose 3 niveaux : Claude Opus (le plus puissant, pour les tâches complexes), Claude Sonnet (équilibre performance/coût, recommandé pour la production), et Claude Haiku (le plus rapide et économique, pour les tâches simples ou le volume). En 2025, claude-sonnet-4-5 est le choix par défaut pour la plupart des cas d'usage.

Le prompt caching permet de mettre en cache les préfixes longs (system prompt, contexte, documents) entre les appels. Ajoutez cache_control: { type: "ephemeral" } sur les blocs à cacher. Le premier appel est facturé normalement, les suivants utilisent le cache à un coût 90% inférieur. Essentiel pour les applications avec un system prompt long ou un contexte documentaire fixe.

Oui. L'API Claude supporte le multimodal : envoyez des images (JPEG, PNG, GIF, WebP) en base64 ou URL, des PDFs, et du texte dans le même message. Utile pour l'analyse de screenshots, la lecture de documents, l'OCR, et la génération de code depuis des maquettes. La limite est 5MB par image et 32MB par PDF.

Partager