Cache pour l'API Gemini

VérifiéSûr

Bonnes pratiques de mise en cache pour l'API Gemini avec clés versionnées et identifiants stables pour réduire les coûts et la latence.

Spar Skills Guide Bot
DeveloppementIntermédiaire
09/08/2026
Claude CodeCursorWindsurfCopilotCodex
#caching#gemini-api#localstorage#cache-invalidation#typescript

Recommandé pour

Synthèse automatique

Décrit une stratégie de cache multi-niveaux pour les appels à l'API Gemini, fondée sur une version globale, des clés stables par entité et plusieurs mécanismes d'invalidation.

Points forts

  • Fournit des clés de cache préfixées par une constante de version, ce qui permet d'invalider tout le cache en une seule modification
  • Recommande des clés basées sur l'identifiant d'entité plutôt que sur le texte du prompt, afin d'éviter les régénérations inutiles
  • Montre des exemples TypeScript complets pour la lecture, l'écriture et la purge du cache localStorage
  • Couvre trois méthodes de cache busting : drapeau forceRebuild, suppression ciblée et purge par préfixe

Limites

  • Le document est tronqué et certaines sections (purge globale, gestion du quota) sont incomplètes
  • Repose entièrement sur localStorage, sans évoquer les limites de taille, l'expiration ni le cache serveur partagé
  • Les exemples citent des services et composants propres à WescoBar (geminiService, Character) qui ne sont pas génériques
Quand l'utiliser

À utiliser lorsqu'on ajoute ou modifie une fonctionnalité qui appelle l'API Gemini et qu'on veut éviter de régénérer du contenu déjà produit.

Quand l'éviter

À éviter si l'application n'utilise pas localStorage ou si le contenu généré doit rester frais à chaque appel.

Analyse de sécurité

Sûr
Score qualité92/100

The skill contains only instructional content for implementing client-side caching using localStorage and TypeScript. It does not instruct or perform any destructive, exfiltrating, or obfuscated actions, nor does it use shell, network, or other powerful tools. The code examples are straightforward and safe.

Aucun point d'attention détecté

Comment cette analyse est faite

Exemples

Add portrait caching
Add caching for the character portrait generation calls using the Gemini API caching skill: versioned keys, entity-stable IDs, and a forceRebuild option.
Invalidate cache after prompt change
I updated the world-scene prompt template. Show me how to bump the cache version so all cached world images are invalidated at once.
Fix over-eager cache misses
Our Gemini image cache keeps missing after small prompt edits. Refactor the cache keys to be entity-stable instead of prompt-based.

name: gemini-api-caching description: Best practices for Gemini API caching strategy including cache versioning, entity-stable keys, and cache busting for WescoBar

Gemini API Caching

Purpose

Implement robust caching strategies for Gemini API calls to reduce cost, improve latency, and provide better user experience while supporting cache invalidation when needed.

When to Use

  • Implementing any Gemini API feature
  • Generating character portraits or world images
  • Caching AI-generated content
  • Reducing API quota usage
  • Improving app performance

Caching Strategy

From AGENTS.md Section 3: "A robust, multi-layered local storage cache"

1. Cache Versioning

2. Entity-Stable Keys

3. Cache Busting

Instructions

Step 1: Define Cache Version

// Global cache version constant
const CACHE_VERSION = 'v2';

// Prepend to all cache keys
const getCacheKey = (entity: string, id: string) => {
  return `${CACHE_VERSION}-${entity}:${id}`;
};

// Example
const portraitKey = getCacheKey('character-portrait', 'core-pablo');
// Result: "v2-character-portrait:core-pablo"

Purpose: Instant global cache invalidation by bumping version

When to bump:

  • Prompt template changes
  • Image generation model updates
  • Quality improvements needed
  • Global regeneration required

Step 2: Use Entity-Stable Keys

// ✅ CORRECT: Entity-based key (stable)
const cacheKey = `${CACHE_VERSION}-character-portrait:${character.id}`;

// ❌ WRONG: Prompt-based key (invalidates on prompt changes)
const cacheKey = `${CACHE_VERSION}-${fullPromptText}`;

Why entity-stable:

  • Same character = same cache key
  • Minor prompt tweaks don't invalidate cache
  • Consistent across sessions
  • Reduces unnecessary regeneration

Entity Types:

  • character-portrait:<id> - Character portraits
  • world-scene:<id> - World/location images
  • story-illustration:<id> - Story illustrations
  • ui-element:<name> - UI-generated images

Step 3: Implement Cache Read

async function getCharacterPortrait(
  character: Character,
  options?: { forceRebuild?: boolean }
): Promise<string> {
  // Check force rebuild flag
  if (options?.forceRebuild) {
    return await generateNewPortrait(character);
  }

  // Build cache key
  const cacheKey = `${CACHE_VERSION}-character-portrait:${character.id}`;

  // Check localStorage cache
  const cached = localStorage.getItem(cacheKey);

  if (cached) {
    console.log(`✅ Cache hit: ${cacheKey}`);
    return cached; // Return cached URL
  }

  console.log(`⚠️ Cache miss: ${cacheKey}`);

  // Generate new image
  const imageUrl = await generateNewPortrait(character);

  // Store in cache
  localStorage.setItem(cacheKey, imageUrl);

  return imageUrl;
}

Step 4: Implement Cache Write

async function generateAndCachePortrait(
  character: Character
): Promise<string> {
  // Generate image via Gemini API
  const imageUrl = await geminiService.generateImage({
    prompt: buildCharacterPrompt(character),
    // ... other options
  });

  // Cache the result
  const cacheKey = `${CACHE_VERSION}-character-portrait:${character.id}`;
  localStorage.setItem(cacheKey, imageUrl);

  console.log(`💾 Cached: ${cacheKey}`);

  return imageUrl;
}

Step 5: Implement Cache Busting

// Option 1: Force rebuild via flag
async function regeneratePortrait(character: Character) {
  const imageUrl = await getCharacterPortrait(character, {
    forceRebuild: true // Bypass cache
  });
  return imageUrl;
}

// Option 2: Clear specific cache entry
function clearPortraitCache(character: Character) {
  const cacheKey = `${CACHE_VERSION}-character-portrait:${character.id}`;
  localStorage.removeItem(cacheKey);
  console.log(`🗑️ Cleared cache: ${cacheKey}`);
}

// Option 3: Clear all portraits
function clearAllPortraits() {
  const prefix = `${CACHE_VERSION}-character-portrait:`;

  Object.keys(localStorage)
    .filter(key => key.startsWith(prefix))
    .forEach(key => localStorage.removeItem(key));

  console.log(`🗑️ Cleared all portrait cache`);
}

// Option 4: Bump global version
// Change CACHE_VERSION = 'v2' → 'v3'
// All old caches become stale automatically

Step 6: Handle Cache Expiration (Optional)

interface CachedImage {
  url: string;
  timestamp: number;
  version: string;
}

function getCachedImage(key: string, maxAge: number = 7 * 24 * 60 * 60 * 1000): string | null {
  const cached = localStorage.getItem(key);

  if (!cached) return null;

  try {
    const data: CachedImage = JSON.parse(cached);

    // Check version
    if (data.version !== CACHE_VERSION) {
      localStorage.removeItem(key);
      return null;
    }

    // Check age
    const age = Date.now() - data.timestamp;
    if (age > maxAge) {
      localStorage.removeItem(key);
      return null;
    }

    return data.url;
  } catch {
    // Invalid format - clear cache
    localStorage.removeItem(key);
    return null;
  }
}

function setCachedImage(key: string, url: string) {
  const data: CachedImage = {
    url,
    timestamp: Date.now(),
    version: CACHE_VERSION
  };

  localStorage.setItem(key, JSON.stringify(data));
}

Integration Patterns

With Rate Limiting Skill

Combine with gemini-api-rate-limiting skill:

async function generateImagesSequentially(characters: Character[]) {
  for (const character of characters) {
    // Check cache first (from this skill)
    const cached = await getCharacterPortrait(character);

    if (cached) {
      updateCharacterImage(character.id, cached);
      continue; // Skip API call
    }

    // Cache miss - generate with rate limiting
    // (from gemini-api-rate-limiting skill)
    try {
      const imageUrl = await generateWithTimeout(character, 30000);
      updateCharacterImage(character.id, imageUrl);
    } catch (error) {
      handleGenerationError(character.id, error);
    }

    // Delay between calls (rate limiting)
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
}

UI Integration

// In React component
function CharacterCard({ character }: { character: Character }) {
  const [imageUrl, setImageUrl] = useState<string | null>(null);
  const [isRegenerating, setIsRegenerating] = useState(false);

  useEffect(() => {
    // Load from cache or generate
    getCharacterPortrait(character).then(setImageUrl);
  }, [character.id]);

  const handleRegenerate = async () => {
    setIsRegenerating(true);

    // Force rebuild (cache busting)
    const newUrl = await regeneratePortrait(character);
    setImageUrl(newUrl);

    setIsRegenerating(false);
  };

  return (
    <div>
      <img src={imageUrl || placeholderImage} alt={character.name} />
      <button onClick={handleRegenerate} disabled={isRegenerating}>
        {isRegenerating ? 'Regenerating...' : 'Regenerate Portrait'}
      </button>
    </div>
  );
}

Cache Management UI

// Admin/settings panel for cache management
function CacheManagement() {
  const [stats, setStats] = useState({ portraits: 0, scenes: 0, total: 0 });

  useEffect(() => {
    // Calculate cache stats
    const portraitKeys = Object.keys(localStorage)
      .filter(key => key.includes('character-portrait'));

    setStats({
      portraits: portraitKeys.length,
      scenes: 0, // Add scene counting
      total: localStorage.length
    });
  }, []);

  const clearAllCache = () => {
    const confirmed = window.confirm('Clear all cached images? This will regenerate on next load.');

    if (confirmed) {
      Object.keys(localStorage)
        .filter(key => key.startsWith(CACHE_VERSION))
        .forEach(key => localStorage.removeItem(key));

      alert('Cache cleared!');
      window.location.reload();
    }
  };

  return (
    <div>
      <h3>Gemini API Cache</h3>
      <p>Cached portraits: {stats.portraits}</p>
      <p>Total cached items: {stats.total}</p>
      <button onClick={clearAllCache}>Clear All Cache</button>
    </div>
  );
}

Best Practices

  1. Always check cache first - Reduce API calls
  2. Use entity-stable keys - Don't invalidate on prompt changes
  3. Version globally - Easy bulk invalidation
  4. Provide regenerate option - Let users force refresh
  5. Consider expiration - For time-sensitive content
  6. Monitor cache size - localStorage has limits (~5-10MB)
  7. Handle cache errors - Fallback to generation

Related Skills

  • gemini-api-rate-limiting - Combine cache with rate limiting
  • gemini-api-error-handling - Handle cache failures

Storage Limits

localStorage Limits

  • Size: ~5-10MB depending on browser
  • Monitor usage: Track total cache size
  • Cleanup strategy: Remove oldest entries when full
function getCacheSize(): number {
  let total = 0;

  for (const key in localStorage) {
    if (localStorage.hasOwnProperty(key)) {
      total += localStorage[key].length + key.length;
    }
  }

  return total; // bytes
}

// If approaching limit, clear old entries
if (getCacheSize() > 5 * 1024 * 1024) { // 5MB
  clearOldestEntries();
}

Notes

  • Caching reduces API costs significantly
  • Entity-stable keys prevent unnecessary cache invalidation
  • Global version bumping enables instant cache refresh
  • Force rebuild option gives users control
  • Combine with rate limiting for complete API management

Du fichier au premier essai

Le téléchargement contient exactement le contenu affiché sur cette fiche. Cette copie peut différer de la dernière version du dépôt source.

Consulter la source et ses fichiers annexes

Ce téléchargement contient uniquement SKILL.md. Les scripts, références, modèles et dépendances éventuels ne sont pas inclus. Récupérez les fichiers nécessaires depuis la source en conservant leur arborescence avant de poursuivre.

1. Télécharger le fichier

Télécharger SKILL.md

Depuis la racine d’un projet de test, enregistrez le fichier sous .skill-downloads/gemini-api-caching-best-practices-msl9cevl/SKILL.md, ou utilisez la commande suivante. Ce dossier sert à examiner la skill avant son installation.

Commande pour macOS/Linux ou WSL : un shell POSIX et curl sont nécessaires. Sous Windows sans WSL, utilisez le bouton de téléchargement et créez le dossier manuellement.

mkdir -p '.skill-downloads/gemini-api-caching-best-practices-msl9cevl' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/gemini-api-caching-best-practices-msl9cevl/download' --output '.skill-downloads/gemini-api-caching-best-practices-msl9cevl/SKILL.md.part' && mv '.skill-downloads/gemini-api-caching-best-practices-msl9cevl/SKILL.md.part' '.skill-downloads/gemini-api-caching-best-practices-msl9cevl/SKILL.md'

2. Vérifier les prérequis

Lisez SKILL.md avant de l’utiliser. Si le fichier cite des scripts ou services externes, examinez-les et préparez les accès nécessaires dans votre environnement de test.

Aucune section de prérequis reconnue dans ce fichier. Cela ne signifie pas qu’il est autonome : les bibliothèques, outils et accès peuvent être cités ailleurs dans le contenu ou dans le dépôt source.

Les plateformes de la fiche sont des indications du catalogue. Les chemins ci-dessous suivent la documentation des outils ; ils ne prouvent pas que cette skill y a été exécutée. Aucune version minimale de ces outils n’est attestée pour cette fiche.

3. Charger la skill

Après vérification, copiez le dossier complet dans le projet avec l’une des commandes ci-dessous, puis ouvrez une nouvelle session de l’outil. La commande s’arrête si un dossier du même nom existe déjà : comparez les fichiers avant de le remplacer.

Claude Code
test -f '.skill-downloads/gemini-api-caching-best-practices-msl9cevl/SKILL.md' && test -s '.skill-downloads/gemini-api-caching-best-practices-msl9cevl/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/gemini-api-caching' && cp -R '.skill-downloads/gemini-api-caching-best-practices-msl9cevl' '.claude/skills/gemini-api-caching'

Cursor
test -f '.skill-downloads/gemini-api-caching-best-practices-msl9cevl/SKILL.md' && test -s '.skill-downloads/gemini-api-caching-best-practices-msl9cevl/SKILL.md' && mkdir -p '.cursor/skills' && test ! -e '.cursor/skills/gemini-api-caching' && cp -R '.skill-downloads/gemini-api-caching-best-practices-msl9cevl' '.cursor/skills/gemini-api-caching'

Codex
test -f '.skill-downloads/gemini-api-caching-best-practices-msl9cevl/SKILL.md' && test -s '.skill-downloads/gemini-api-caching-best-practices-msl9cevl/SKILL.md' && mkdir -p '.agents/skills' && test ! -e '.agents/skills/gemini-api-caching' && cp -R '.skill-downloads/gemini-api-caching-best-practices-msl9cevl' '.agents/skills/gemini-api-caching'

OpenSkills

OpenSkills doit déjà être installé. La procédure locale install/read est contrôlée avec OpenSkills 1.5.0, qui exige Node.js ≥ 20.6.0. Aucun slug du catalogue n’est résolu automatiquement.

Installation officielle d’OpenSkills
openskills install './.skill-downloads/gemini-api-caching-best-practices-msl9cevl'

openskills read 'gemini-api-caching-best-practices-msl9cevl'

La lecture doit afficher le contenu du fichier installé et son dossier de base. Elle ne lance ni la skill ni ses dépendances.

Pour un agent qui lit AGENTS.md, synchronisez ensuite l’index. Cette commande modifie AGENTS.md : relisez le diff avant de l’utiliser.

openskills sync

Mode manuel ou autre outil : joignez SKILL.md à une conversation, ou ouvrez-le dans un agent capable de lire les fichiers. Ajoutez les ressources annexes nécessaires. Il n’existe pas de dossier universel reconnu par tous les outils.

4. Faire un premier essai

Utilisez une entrée courte et fictive : un endpoint d’API, un petit document ou un brief d’interface. Dans une nouvelle conversation, joignez le fichier ou donnez son chemin à l’agent, puis adaptez cette demande :

Lis .skill-downloads/gemini-api-caching-best-practices-msl9cevl/SKILL.md et applique ses instructions à cet exemple : [décrire une entrée de test]. Indique les fichiers, dépendances ou accès qui manquent. Produis le résultat demandé par la skill sans inventer de données ni exécuter de script non examiné.

Résultat attendu : une sortie correspondant aux instructions de la skill, ou une liste précise des prérequis manquants. Une simple confirmation de lecture ne valide pas le premier usage. Si une ressource externe est indisponible, ce parcours reste à tester.

Skills similaires