OrkaJS
Orka.JS

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

Accuracy

Vitesse Éclair

Architecture événementielle pour un contrôle fin

Performance

Efficience Temporelle

Suivi du Time to First Token (TTFT)

Reliability

Connectivité Native

Support de tous les fournisseurs LLM (OpenAI, Anthropic, Mistral, Ollama)

Ecosystem
  • 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 callback
const 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 control
for 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 VieDescription FonctionnelleIdentifiant

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 definitions
type 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 structure
interface TokenEvent {
type: 'token';
token: string; // The token text
index: number; // Token position
timestamp: number; // Event timestamp
}
 
// Done event structure
interface 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 usage
const 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 directly
console.log('Supports streaming:', llm.supportsStreaming); // true

Annulation

Utilisez AbortController pour annuler un stream :

import { OpenAIAdapter } from '@orka-js/openai';
 
const llm = new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY! });
 
// Create abort controller
const controller = new AbortController();
 
// Cancel after 5 seconds
setTimeout(() => 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 ServiceCapacités FondamentalesIdentifiant
OpenAI

Stack

GPT-4o / GPT-4 Turbo

Streaming complet avec stats d'utilisation

OpenAI
Anthropic

Stack

Claude 3.5 Sonnet / Opus

Streaming avec support de la réflexion étendue

Anthropic
Mistral

Stack

Mistral Large / Codestral

Streaming compatible OpenAI

Mistral
Ollama

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 base
await orka.knowledge.create({
name: 'docs',
source: ['OrkaJS is a TypeScript framework for LLM systems.'],
});
 
// Retrieve context first
const context = await orka.knowledge.search('docs', 'What is OrkaJS?', { topK: 3 });
 
// Then stream the response with context
if (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.

streaming-tool-agent.ts
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 time
for 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 result
const result = await agent.run('What is the weather in Lyon?');
console.log(result.output); // Final answer
console.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.