← Retour aux articles
IA LLMTypeScript

LLM pour les développeurs : intégrer l'IA dans de vraies applications

· 5 min de lecture

Les grands modèles de langage sont passés de curiosité de recherche à outil de production en moins de deux ans. Chaque produit SaaS ajoute des fonctionnalités IA, et les développeurs qui les construisent ont besoin de plus que des clés API et des prompts copiés-collés. Les LLM nécessitent une intégration structurée : appels API fiables, prompts bien construits, gestion du contexte et validation des sorties. La différence entre une démo et une feature de production, c’est le sérieux avec lequel on traite ces sujets.

Appeler l’API depuis un backend TypeScript

Les SDK Anthropic et OpenAI sont simples d’utilisation. La complexité réside dans la façon dont on structure l’appel, gère les erreurs et parse la réponse. Le streaming est essentiel pour les features côté utilisateur parce qu’attendre 10 secondes une réponse complète tue l’expérience.

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

const client = new Anthropic();

async function generateSummary(content: string): Promise<string> {
  const message = await client.messages.create({
    model: 'claude-sonnet-4-20250514',
    max_tokens: 1024,
    messages: [
      {
        role: 'user',
        content: `Summarize this article in 2-3 sentences:\n\n${content}`,
      },
    ],
  });

  const block = message.content[0];
  if (block.type === 'text') return block.text;
  throw new Error('Unexpected response type');
}

Type-checker le bloc de réponse compte. L’API renvoie un tableau de content blocks qui peuvent être du texte ou des résultats d’appels d’outils. Supposer que le premier bloc est toujours du texte sans vérifier mène à des erreurs runtime en production.

Du prompt engineering qui fonctionne

L’écart entre un prompt médiocre et un bon prompt est l’écart entre une feature inutile et une feature fiable. Les system prompts définissent le comportement du modèle, ses contraintes et le format de sortie. Les user prompts fournissent la tâche spécifique.

const systemPrompt = `You are a code review assistant for a TypeScript/React codebase.
Rules:
- Focus on bugs, security issues, and performance problems
- Ignore style preferences
- Return JSON with this shape: { issues: Array<{ line: number, severity: "error" | "warning", message: string }> }
- If no issues found, return { issues: [] }`;

async function reviewCode(code: string, filename: string) {
  const message = await client.messages.create({
    model: 'claude-sonnet-4-20250514',
    max_tokens: 2048,
    system: systemPrompt,
    messages: [{ role: 'user', content: `Review this file (${filename}):\n\n${code}` }],
  });

  const block = message.content[0];
  if (block.type !== 'text') throw new Error('Unexpected response type');
  return JSON.parse(block.text);
}

Spécifier la shape JSON exacte dans le system prompt et parser la sortie avec JSON.parse est le minimum. En production, valider la sortie parsée avec Zod pour attraper les cas où le modèle dérive du format attendu.

Retrieval-Augmented Generation

Les LLM hallucinent quand ils manquent de contexte. Le RAG résout ça en récupérant les documents pertinents avant de générer une réponse. Le modèle répond sur la base de vos données au lieu de ses données d’entraînement.

async function answerQuestion(question: string) {
  const embedding = await generateEmbedding(question);
  const relevantDocs = await vectorDb.search(embedding, { limit: 5 });

  const context = relevantDocs.map((doc) => doc.content).join('\n\n---\n\n');

  const message = await client.messages.create({
    model: 'claude-sonnet-4-20250514',
    max_tokens: 1024,
    system:
      'Answer based only on the provided context. If the context does not contain the answer, say so.',
    messages: [
      {
        role: 'user',
        content: `Context:\n${context}\n\nQuestion: ${question}`,
      },
    ],
  });

  const block = message.content[0];
  if (block.type !== 'text') throw new Error('Unexpected response type');
  return block.text;
}

La base de données vectorielle stocke les embeddings de vos documents. Au moment de la requête, la question est embeddée, les documents similaires sont récupérés, et le modèle génère une réponse ancrée dans ce contexte. Ce pattern alimente les chatbots de documentation, les assistants support et les bases de connaissances internes.

Gestion des coûts et de la latence

Les appels API LLM sont chers et lents comparés aux opérations backend traditionnelles. Une implémentation naïve qui envoie le contenu complet de la page à chaque frappe clavier va brûler le budget et frustrer les utilisateurs.

import { useRef, useCallback } from 'react';

function useDebouncedAI(delay: number) {
  const timeoutRef = useRef<NodeJS.Timeout>();
  const abortRef = useRef<AbortController>();

  const request = useCallback(
    async (input: string, onResult: (text: string) => void) => {
      clearTimeout(timeoutRef.current);
      abortRef.current?.abort();

      timeoutRef.current = setTimeout(async () => {
        abortRef.current = new AbortController();
        const response = await fetch('/api/ai/suggest', {
          method: 'POST',
          body: JSON.stringify({ input }),
          signal: abortRef.current.signal,
        });
        const data = await response.json();
        onResult(data.suggestion);
      }, delay);
    },
    [delay]
  );

  return request;
}

Le debouncing empêche les appels redondants. Annuler les requêtes en cours évite que des réponses périmées écrasent les plus récentes. Cacher les prompts identiques dans Redis élimine les appels API répétés pour la même entrée. Ces patterns sont standards en développement web mais critiques avec les LLM où chaque appel coûte de l’argent et prend des secondes.

Conclusion

Les LLM sont une primitive puissante pour les développeurs, pas une solution magique. Une intégration API structurée, des sorties validées, du RAG pour des réponses ancrées et des patterns conscients des coûts sont ce qui transforme un prototype en feature de production. L’outillage est assez mature pour de vraies applications, et les développeurs qui comprennent à la fois les capacités et les contraintes construiront les produits les plus utiles.