Cache
Optimisez vos performance en évitant les appels redondants grâce au cache intelligent. Réduisez coûts et latence via des stratégiesIn-Memory ou Redis.
Pourquoi le Cache ?
Les appels API LLM sont coûteux et lents. Lorsque le même prompt est envoyé plusieurs fois (ex : questions utilisateur répétées, traitement par lots ou itérations de développement), le cache évite les appels API redondants en retournant instantanément les résultats précédemment calculés.
Latence cache hit (vs 500-3000ms appel API)
Coût par réponse en cache
Résultats déterministes
# Architecture
Le système de cache d'Orka JS est composé de trois couches qui fonctionnent ensemble :
Infrastructure de Stockage
La colonne vertébrale du cache. MemoryCache pour la vitesse, RedisCache pour la distribution.
CacheStoreAccélération des Réponses
Enveloppe les adaptateurs pour servir des résultats instantanés, éliminant les coûts API.
CachedLLMPersistance Vectorielle
Évite les calculs de vecteurs redondants pour les chunks répétés dans les pipelines RAG.
CachedEmbeddings# MemoryCache (En Mémoire)
Le store de cache le plus simple. Les données sont stockées en processus via une Map. Aucune dépendance externe requise. Idéal pour le développement, les serveurs mono-instance et les processus de courte durée.
import { MemoryCache } from '@orka-js/cache'; const cache = new MemoryCache({ maxSize: 1000, // Maximum number of entries (default: 1000) ttlMs: 1000 * 60 * 30, // Time-to-live: 30 minutes (optional) namespace: 'my-app' // Key prefix for isolation (optional)}); // Basic operationsawait cache.set('key', { data: 'value' });const value = await cache.get('key'); // { data: 'value' }const exists = await cache.has('key'); // trueawait cache.delete('key');await cache.clear(); // Get cache statisticsconst stats = cache.getStats();console.log(stats);// { hits: 42, misses: 8, size: 150, hitRate: 0.84 }Simplicité Native
Zéro dépendance externe. Opère entièrement dans la mémoire du processus Node.js.
Expiration Temporelle (TTL)
Contrôle granulaire du Time-To-Live. Les données s'auto-détruisent après expiration.
Politique d'Éviction LRU
Plafonnement automatique. Supprime les entrées les plus anciennes pour éviter le débordement.
Isolation Logique
Partitionnement par namespace. Plusieurs caches indépendants dans une même instance.
Télémétrie Hit/Miss
Statistiques intégrées pour surveiller l'efficacité et optimiser le taux de succès.
# RedisCache (Distribué)
Pour les environnements de production avec plusieurs instances de serveur, Redis fournit un cache partagé et persistant. Les données survivent aux redémarrages du serveur et sont accessibles depuis n'importe quelle instance.
📦 Installation Requise
RedisCache nécessite le package redis :
npm install redisimport { RedisCache } from '@orka-js/cache'; const cache = new RedisCache({ url: 'redis://localhost:6379', // Redis connection URL keyPrefix: 'orka:', // Key prefix (default: 'orka:') ttlMs: 1000 * 60 * 60, // TTL: 1 hour (optional)}); // Connect to Redis (auto-connects on first operation)await cache.connect(); // Same API as MemoryCacheawait cache.set('key', { data: 'value' });const value = await cache.get('key'); // Disconnect when doneawait cache.disconnect();MemoryCacheSpeed OptimizedRedisCacheScale Optimized# CachedLLM — Cache de Réponses LLM
CachedLLM enveloppe n'importe quel LLMAdapter et met en cache les réponses de manière transparente. Il implémente l'interface LLMAdapter, vous pouvez donc l'utiliser comme remplacement direct partout où vous utilisez un LLM.
import { OpenAIAdapter } from '@orka-js/openai';import { MemoryCache } from '@orka-js/cache';import { CachedLLM } from '@orka-js/cache'; // 1. Create your LLM adapterconst llm = new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY!, model: 'gpt-4o-mini'}); // 2. Create a cache storeconst cache = new MemoryCache({ maxSize: 500, ttlMs: 1000 * 60 * 30 }); // 3. Wrap with CachedLLMconst cachedLLM = new CachedLLM(llm, cache, { ttlMs: 1000 * 60 * 60 // Override TTL: cache for 1 hour}); // First call — hits the API (~800ms)const result1 = await cachedLLM.generate('What is TypeScript?');console.log(result1.content); // "TypeScript is a typed superset..." // Second call — instant from cache (~0ms)const result2 = await cachedLLM.generate('What is TypeScript?');console.log(result2.content); // Same response, from cache // Use in Orka config — transparent replacementimport { createOrka } from 'orkajs'; const orka = createOrka({ llm: cachedLLM, // ← Drop-in replacement vectorDB: /* ... */}); // All orka.ask(), orka.generate(), etc. now use cachingconst answer = await orka.ask({ question: 'What is TypeScript?', knowledge: 'docs'});Hachage Déterministe
Combine le prompt brut avec tous les paramètres du modèle (température, maxTokens, etc.) pour garantir une correspondance exacte.
hash(prompt + options)Key IntegrityScénario Match Exact
Entrée Identique + Config Identique = 0ms de latence. Le moteur ignore l'inférence et sert le résultat stocké.
cache_hitEfficiencyVariance de Paramètres
Changer une seule option (comme la température) déclenche une nouvelle inférence pour respecter le comportement du modèle.
cache_missPrecision# CachedEmbeddings — Cache d'Embeddings
Embedder le même texte plusieurs fois est du gaspillage. CachedEmbeddings met en cache les vecteurs d'embedding par texte d'entrée et n'envoie à l'API que les textes non mis en cache.
import { OpenAIAdapter } from '@orka-js/openai';import { MemoryCache } from '@orka-js/cache';import { CachedEmbeddings } from '@orka-js/cache'; const llm = new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY! });const cache = new MemoryCache({ maxSize: 10000 }); const cachedEmbed = new CachedEmbeddings(llm, cache, { ttlMs: 1000 * 60 * 60 * 24 // Cache embeddings for 24 hours}); // First call — computes all 3 embeddings via APIconst embeddings1 = await cachedEmbed.embed([ 'Hello world', 'TypeScript is great', 'Orka AI framework']); // Second call — all 3 from cache (0 API calls)const embeddings2 = await cachedEmbed.embed([ 'Hello world', 'TypeScript is great', 'Orka AI framework']); // Mixed call — only "New text" hits the API, others from cacheconst embeddings3 = await cachedEmbed.embed([ 'Hello world', // ← from cache 'New text here', // ← API call 'Orka AI framework' // ← from cache]);⚡ Batching Intelligent
CachedEmbeddings vérifie le cache pour chaque texte individuellement, puis regroupe uniquement les textes non mis en cache en un seul appel API. Cela signifie que si vous embeddez 100 textes et 80 sont en cache, seuls 20 sont envoyés à l'API en un seul lot.
# Configuration Production avec Redis
En production, utilisez RedisCache pour partager le cache entre plusieurs instances de serveur et persister les données entre les redémarrages.
import { createOrka, OpenAIAdapter } from '@orka-js/core';import { RedisCache } from '@orka-js/cache';import { CachedLLM } from '@orka-js/cache';import { CachedEmbeddings } from '@orka-js/cache'; // Shared Redis cacheconst redisCache = new RedisCache({ url: process.env.REDIS_URL!, // e.g. 'redis://redis:6379' keyPrefix: 'orka:prod:', ttlMs: 1000 * 60 * 60 * 4 // 4 hours}); const llm = new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY!, model: 'gpt-4o-mini'}); // Cache both LLM responses and embeddingsconst cachedLLM = new CachedLLM(llm, redisCache);const cachedEmbed = new CachedEmbeddings(llm, redisCache); const orka = createOrka({ llm: cachedLLM, vectorDB: /* ... */}); // All operations now use Redis-backed cachingconst result = await orka.ask({ question: 'How do I deploy my app?', knowledge: 'documentation'}); // Monitor cache performanceconst stats = redisCache.getStats();console.log(`Cache hit rate: ${(stats.hitRate * 100).toFixed(1)}%`); // Cleanup on shutdownprocess.on('SIGTERM', async () => { await redisCache.disconnect();});# Cache Store Personnalisé
Implémentez l'interface CacheStore pour créer votre propre backend de cache (ex : DynamoDB, Memcached, SQLite).
import type { CacheStore } from '@orka-js/cache'; class DynamoDBCache implements CacheStore { readonly name = 'dynamodb-cache'; async get<T>(key: string): Promise<T | undefined> { // Your DynamoDB get logic } async set<T>(key: string, value: T, ttlMs?: number): Promise<void> { // Your DynamoDB put logic } async delete(key: string): Promise<boolean> { // Your DynamoDB delete logic } async clear(): Promise<void> { // Your DynamoDB scan + delete logic } async has(key: string): Promise<boolean> { // Your DynamoDB exists check }} // Use with CachedLLMconst cache = new DynamoDBCache();const cachedLLM = new CachedLLM(llm, cache);Bonnes Pratiques
1. Définissez des TTL Appropriés
TTL court (5-30 min) pour le contenu dynamique. TTL long (heures/jours) pour les bases de connaissances stables. Pas de TTL pour les données immuables comme les embeddings.
2. Surveillez les Taux de Hit
Utilisez getStats() pour surveiller l'efficacité du cache. Un taux de hit inférieur à 50% peut indiquer que le cache est trop petit ou le TTL trop court.
3. Ne Cachez Pas les Appels Non-Déterministes
Si vous utilisez une température élevée (>0.8) pour la génération créative, le cache peut retourner des sorties créatives obsolètes. Envisagez de désactiver le cache pour les tâches créatives.
4. Utilisez les Namespaces
Utilisez des namespaces ou préfixes de clé différents pour les différents environnements (dev, staging, prod) pour éviter la pollution du cache.
Imports Tree-shakeable
// ✅ Import only what you needimport { MemoryCache } from '@orka-js/cache';import { CachedLLM } from '@orka-js/cache'; // ✅ Or import from indeximport { MemoryCache, RedisCache, CachedLLM, CachedEmbeddings } from '@orka-js/cache';