Streaming
Streaming de tokens en temps réel pour desapplications IA réactives.
OrkaJS supporte le streaming en temps réel des réponses LLM, vous permettant d'afficher les tokens au fur et à mesure de leur génération. Cela améliore considérablement l'expérience utilisateur en réduisant la latence perçue.
Fonctionnalités Clés
Haute Précision
Streaming token par token avec callbacks
Vitesse Éclair
Architecture événementielle pour un contrôle fin
Efficience Temporelle
Suivi du Time to First Token (TTFT)
Connectivité Native
Support de tous les fournisseurs LLM (OpenAI, Anthropic, Mistral, Ollama)
- Support d'annulation via AbortController
- Support de la réflexion étendue pour les modèles Claude
Démarrage Rapide
La façon la plus simple d'utiliser le streaming est avec le callback onToken :
import { OpenAIAdapter } from '@orka-js/openai'; const llm = new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY! }); // Stream with onToken callbackconst result = await llm.streamGenerate('Explain quantum computing', { onToken: (token, index) => { process.stdout.write(token); // Print each token as it arrives }, onEvent: (event) => { if (event.type === 'done') { console.log('\nStream complete!'); } },}); console.log('Total tokens:', result.usage.totalTokens);console.log('Time to first token:', result.ttft, 'ms');Utilisation de la Méthode stream()
Pour plus de contrôle, utilisez le pattern async iterator :
import { OpenAIAdapter } from '@orka-js/openai'; const llm = new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY! }); // Use async iterator for full controlfor await (const event of llm.stream('Write a poem about AI')) { switch (event.type) { case 'token': process.stdout.write(event.token); break; case 'thinking': console.log('[Thinking]:', event.delta); break; case 'usage': console.log('Usage:', event.usage); break; case 'done': console.log('\nFinished:', event.finishReason); break; case 'error': console.error('Error:', event.message); break; }}Types d'Événements
Le système de streaming émet différents types d'événements :
| Cycle de Vie | Description Fonctionnelle | Identifiant |
|---|---|---|
Token individuel reçu | token | |
Contenu accumulé avec delta | content | |
Raisonnement du modèle (réflexion étendue Claude) | thinking | |
Appel d'outil/fonction démarré | tool_call | |
Statistiques d'utilisation des tokens | usage | |
Stream terminé | done | |
Erreur survenue | error |
import type { LLMStreamEvent } from '@orka-js/core'; // Event type definitionstype StreamEventType = | 'token' // Individual token received | 'content' // Content chunk with accumulated text | 'tool_call' // Tool/function call started | 'thinking' // Model reasoning (Claude) | 'usage' // Token usage update | 'done' // Stream completed | 'error'; // Error occurred // Token event structureinterface TokenEvent { type: 'token'; token: string; // The token text index: number; // Token position timestamp: number; // Event timestamp} // Done event structureinterface DoneEvent { type: 'done'; content: string; // Full response content finishReason: 'stop' | 'length' | 'tool_calls' | 'error'; usage?: { promptTokens: number; completionTokens: number; totalTokens: number; };}Résultat du Stream
La méthode streamGenerate() retourne un StreamResult avec des métriques supplémentaires :
interface StreamResult { content: string; // Full response content usage: { promptTokens: number; completionTokens: number; totalTokens: number; }; model: string; // Model used finishReason: 'stop' | 'length' | 'tool_calls' | 'error'; ttft?: number; // Time to first token (ms) durationMs: number; // Total stream duration (ms)} // Example usageconst result = await llm.streamGenerate('Hello');console.log('TTFT:', result.ttft, 'ms');console.log('Duration:', result.durationMs, 'ms');console.log('Tokens/sec:', result.usage.completionTokens / (result.durationMs / 1000));Vérifier le Support du Streaming
Vous pouvez vérifier si un adaptateur supporte le streaming :
import { isStreamingAdapter } from '@orka-js/core';import { OpenAIAdapter } from '@orka-js/openai'; const llm = new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY! }); if (isStreamingAdapter(llm)) { // TypeScript knows llm has stream() and streamGenerate() const result = await llm.streamGenerate('Hello'); console.log(result.content);} else { // Fallback to regular generate const result = await llm.generate('Hello'); console.log(result.content);} // Check property directlyconsole.log('Supports streaming:', llm.supportsStreaming); // trueAnnulation
Utilisez AbortController pour annuler un stream :
import { OpenAIAdapter } from '@orka-js/openai'; const llm = new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY! }); // Create abort controllerconst controller = new AbortController(); // Cancel after 5 secondssetTimeout(() => controller.abort(), 5000); try { const result = await llm.streamGenerate('Write a very long essay...', { signal: controller.signal, onToken: (token) => process.stdout.write(token), });} catch (error) { if (error.name === 'AbortError') { console.log('Stream was cancelled'); }}Support des Fournisseurs
Tous les adaptateurs LLM supportent le streaming :
| Infrastructure Service | Capacités Fondamentales | Identifiant |
|---|---|---|
Stack GPT-4o / GPT-4 Turbo | Streaming complet avec stats d'utilisation | OpenAI |
Stack Claude 3.5 Sonnet / Opus | Streaming avec support de la réflexion étendue | Anthropic |
Stack Mistral Large / Codestral | Streaming compatible OpenAI | Mistral |
Stack Local Llama 3 / Mistral / Phi | Format de streaming NDJSON | Ollama |
Bonnes Pratiques
- Gérez toujours les erreurs dans votre callback onEvent
- Utilisez les métriques TTFT pour surveiller les performances
- Implémentez l'annulation pour les streams longs
- Bufferisez les tokens pour des mises à jour UI plus fluides
Intégration avec RAG
Le streaming fonctionne parfaitement avec les pipelines RAG :
import { createOrka, OpenAIAdapter, MemoryVectorAdapter } from 'orkajs';import { isStreamingAdapter } from '@orka-js/core'; const orka = createOrka({ llm: new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY! }), vectorDB: new MemoryVectorAdapter(),}); // Create knowledge baseawait orka.knowledge.create({ name: 'docs', source: ['OrkaJS is a TypeScript framework for LLM systems.'],}); // Retrieve context firstconst context = await orka.knowledge.search('docs', 'What is OrkaJS?', { topK: 3 }); // Then stream the response with contextif (isStreamingAdapter(orka.llm)) { const result = await orka.llm.streamGenerate( `Context: ${context.map(c => c.content).join('\n')}\n\nQuestion: What is OrkaJS?`, { systemPrompt: 'Answer based on the provided context.', onToken: (token) => process.stdout.write(token), } ); console.log('\nAnswer generated with', result.usage.totalTokens, 'tokens');}Appels d'Outils en Streaming
StreamingToolAgent stream les tokens en temps réel tout en exécutant les outils en parallèle. Les utilisateurs voient le modèle « réfléchir » pendant que les outils s'exécutent, des événements tool_result sont émis mi-stream, et la mémoire conversationnelle est préservée automatiquement entre les requêtes.
import { StreamingToolAgent } from '@orka-js/agent';import { OpenAIAdapter } from '@orka-js/openai'; const llm = new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY! }); const agent = new StreamingToolAgent({ goal: 'Answer questions using available tools', tools: [ { name: 'get_weather', description: 'Get current weather for a location', parameters: [{ name: 'location', type: 'string', description: 'City name', required: true }], execute: async ({ location }) => ({ output: `Weather in ${location}: Sunny, 22°C` }), }, ],}, llm); // Stream tokens + tool execution in real timefor await (const event of agent.runStream('What is the weather in Paris?')) { switch (event.type) { case 'token': process.stdout.write(event.token); // LLM "thinking" as tokens arrive break; case 'tool_result': console.log('\n[Tool result]:', event.result); // Tool output mid-stream break; case 'done': console.log('\n[Final answer]:', event.content); break; }} // Or use run() for a simple non-streaming resultconst result = await agent.run('What is the weather in Lyon?');console.log(result.output); // Final answerconsole.log(result.steps); // Tool execution steps with observations💡 Événements tool_result
Passez une instance Memory au constructeur pour maintenir le contexte conversationnel. L'historique est chargé avant chaque runStream() et sauvegardé après la complétion — l'agent ne perd jamais le contexte entre les tours.