# Ne pas repayer deux fois le même appel à un LLM : un cache applicatif simple

> Un endpoint interroge un LLM à chaque affichage de page, sans jamais réutiliser une réponse déjà générée. Voici comment y remédier avec un cache applicatif simple et une durée d'expiration adaptée.

- Auteur : WordPress Développement
- Publié le : 2024-09-02
- Mis à jour le : 2024-09-02
- Catégorie : IA &amp; MCP
- URL : https://www.wpmoderne.fr/ia-mcp/cache-applicatif-appel-llm-wp-cache-set/

## L’essentiel

- Une réponse identique ne doit jamais être régénérée si le contenu source n'a pas changé
- La durée d'expiration du cache dépend de la volatilité du contenu, pas d'une valeur par défaut
- Un cache mal invalidé affiche un contenu obsolète plus longtemps qu'un appel manquant

« Fatal error: Allowed memory size exhausted » n'est pas le message qui a alerté cette fois-ci : c'est une facture mensuelle d'API de LLM anormalement élevée, alors que le nombre de visiteurs du site n'avait pas augmenté. En creusant, la cause s'est révélée triviale : un endpoint de résumé automatique interrogeait le LLM à chaque affichage de page, y compris quand le contenu résumé n'avait pas changé depuis la veille.

Le correctif ne demande ni infrastructure supplémentaire ni service tiers : un cache applicatif simple, construit avec les fonctions de cache natives de WordPress, suffit à éviter qu'une même requête ne parte deux fois vers l'API tant que le contenu source reste identique.

## Identifier ce qui doit être mis en cache

Avant d'ajouter la moindre ligne de code, il faut répondre à une question précise : qu'est-ce qui détermine que deux appels au LLM produiront la même réponse ? Dans le cas de cet endpoint de résumé, la réponse dépendait uniquement du contenu de l'article et de la version du prompt utilisé. Une clé de cache construite à partir de l'identifiant de l'article et d'un hash du contenu suffit donc à garantir qu'un même texte ne génère jamais deux appels distincts.

Cette étape d'analyse est souvent négligée au profit d'une mise en cache générique par URL, ce qui pose problème dès qu'un même endpoint sert des réponses différentes selon des paramètres qui ne figurent pas dans l'URL elle-même.

## Mise en œuvre avec wp_cache_set

> L'essentiel à retenir : Une réponse identique ne doit jamais être régénérée si le contenu source n'a pas changé ; La durée d'expiration du cache dépend de la volatilité du contenu, pas d'une valeur par défaut ; Un cache mal invalidé affiche un contenu obsolète plus longtemps qu'un appel manquant

La fonction `wp_cache_set`, couplée à `wp_cache_get`, permet de construire ce cache sans dépendance externe. Sur une installation sans objet de cache persistant, ce cache reste limité à la durée de la requête ; avec un objet de cache persistant (Redis ou Memcached), il survit d'une requête à l'autre, ce qui est précisément l'effet recherché ici.

```
function get_summary_cached( $post_id, $content ) {
    $cache_key = 'llm_summary_' . $post_id . '_' . md5( $content );
    $cached = wp_cache_get( $cache_key, 'llm_summaries' );

    if ( false !== $cached ) {
        return $cached;
    }

    $summary = call_llm_summary_api( $content );

    wp_cache_set( $cache_key, $summary, 'llm_summaries', HOUR_IN_SECONDS * 12 );

    return $summary;
}
```

Le hash du contenu dans la clé de cache résout un problème fréquent : si l'article est modifié, la clé change automatiquement, et le résumé sera régénéré à la prochaine consultation sans qu'il soit nécessaire d'invalider explicitement l'ancienne entrée.

## Choisir la bonne durée d'expiration

Une durée fixe appliquée sans réflexion, du type `DAY_IN_SECONDS` partout, ignore une réalité simple : tous les contenus n'ont pas la même volatilité. Un résumé d'article de blog, rarement modifié après publication, peut rester en cache plusieurs jours sans risque. Un résumé de fil de discussion en support client, en revanche, doit expirer beaucoup plus vite, car son contenu source évolue en continu.

- Contenu éditorial stable (articles publiés) : cache de plusieurs jours, invalidé uniquement lors d'une modification.
- Contenu semi-dynamique (fiches produit avec avis) : cache de quelques heures.
- Contenu très volatile (conversations en cours) : cache de quelques minutes, ou absence de cache si la fraîcheur prime sur le coût.

## Le risque inverse : un cache trop long

Un cache mal calibré ne se contente pas de faire économiser des appels : il peut aussi afficher un contenu obsolète pendant une durée bien supérieure à ce qu'aurait produit l'absence totale de cache. Sur l'endpoint de résumé étudié ici, une première tentative avec une durée d'expiration de sept jours a conduit à afficher un résumé périmé après une correction éditoriale importante sur l'article source, le hash n'ayant pas été recalculé correctement dans une version antérieure du code.

Ce type d'incident rappelle qu'un cache applicatif doit toujours être testé avec un scénario de modification du contenu source, pas seulement avec un scénario de lecture répétée.

> Un cache qui économise des appels mais affiche un contenu faux pendant plusieurs jours coûte, au final, plus cher qu'un endpoint sans cache du tout : le calcul de coût ne s'arrête jamais au prix de l'API.

## En résumé

Un cache applicatif simple, construit avec `wp_cache_set` et une clé qui intègre un hash du contenu source, a permis d'éviter neuf appels sur dix vers l'API de résumé sans changer une ligne du comportement visible par les visiteurs. La question du cache distribué sur plusieurs serveurs, avec Redis partagé entre plusieurs instances, reste un sujet distinct qui dépasse ce cas d'usage précis.
