Chaînes
Chaînes pré-construites pour les patterns LLM courants : question-réponse sur documents, récupération conversationnelle avec mémoire, et résumé multi-stratégie. Chaque chaîne orchestre la récupération, la construction de contexte et la génération en un seul appel.
Pourquoi des Chaînes ?
Construire un pipeline RAG from scratch nécessite plusieurs étapes : récupérer les documents, construire le contexte, formater les prompts, appeler le LLM et gérer les erreurs. Les chaînes encapsulent ces patterns dans des composants réutilisables et testés avec une observabilité intégrée via les étapes intermédiaires.
RetrievalQA
Q&R simple sur documents
Conversational
Chat avec mémoire + récupération
Summarization
Stuff, map-reduce, refine
QA Chain
QA avancé avec stratégies
# RetrievalQAChain
La chaîne la plus simple pour le question-réponse sur documents. Elle récupère les documents pertinents, construit une fenêtre de contexte et génère une réponse en un seul appel. Parfaite pour les requêtes simples sur une base de connaissances.
import { RetrievalQAChain } from 'orkajs/chains/retrieval-qa';import { VectorRetriever } from 'orkajs/retrievers/vector';import { OpenAIAdapter } from 'orkajs/adapters/openai'; const llm = new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY! }); const retriever = new VectorRetriever({ llm, vectorDB: myVectorDB, topK: 5}); const chain = new RetrievalQAChain({ llm, retriever, collection: 'documentation', returnSources: true, // Include source documents in result maxSourceTokens: 3000, // Max tokens for context window systemPrompt: 'You are a helpful assistant. Answer based ONLY on the provided context.'}); const result = await chain.call('How do I configure authentication?'); console.log(result.answer);// "To configure authentication, you need to..." console.log(result.sources);// [{ id: 'doc-1', score: 0.92, content: '...' }, ...] console.log(result.intermediateSteps);// [// { name: 'retrieve', input: '...', output: 'Found 5 relevant documents', latencyMs: 120 },// { name: 'generate', input: '...', output: '...', latencyMs: 850 }// ] console.log(result.usage);// { promptTokens: 1200, completionTokens: 350, totalTokens: 1550 }📊 Étapes Intermédiaires
Chaque chaîne retourne intermediateSteps avec le nom, l'entrée, la sortie et la latence de chaque étape. Cela vous donne une observabilité complète de l'exécution de la chaîne — utile pour le débogage, le monitoring et l'optimisation.
# ConversationalRetrievalChain
Étend RetrievalQA avec la mémoire conversationnelle. Elle condense automatiquement les questions de suivi en utilisant l'historique du chat, pour que le retriever reçoive une requête autonome même quand l'utilisateur demande "Et le deuxième ?" ou "Peux-tu expliquer plus ?". La chaîne maintient son propre historique de chat en interne.
import { ConversationalRetrievalChain } from 'orkajs/chains/conversational-retrieval'; const chain = new ConversationalRetrievalChain({ llm, retriever, collection: 'documentation', returnSources: true, maxHistoryLength: 10, // Keep last 10 messages in context // Optional: customize how follow-up questions are condensed condenseQuestionPrompt: `Given the following conversation and a follow-up question,rephrase the follow-up as a standalone question. Chat History:{{history}} Follow-up: {{question}} Standalone Question:`}); // First question — normal retrievalconst result1 = await chain.call('What authentication methods are supported?');console.log(result1.answer);// "Orka AI supports JWT, OAuth2, and API key authentication..." // Follow-up — automatically condensed with historyconst result2 = await chain.call('How do I configure the second one?');// Internally condensed to: "How do I configure OAuth2 authentication?"console.log(result2.answer);// "To configure OAuth2, you need to set up..." // Another follow-upconst result3 = await chain.call('What are the required scopes?');// Condensed to: "What are the required OAuth2 scopes?"console.log(result3.answer); // Check intermediate steps to see the condensed questionconsole.log(result2.intermediateSteps);// [// { name: 'condense_question', input: 'How do I configure the second one?',// output: 'How do I configure OAuth2 authentication?' },// { name: 'retrieve', ... },// { name: 'generate', ... }// ] // Manage historyconsole.log(chain.getChatHistory());// [{ role: 'user', content: '...' }, { role: 'assistant', content: '...' }, ...] chain.clearHistory(); // Reset conversation🔄 Flux de Condensation de Question
- L'utilisateur demande: "Comment configurer le deuxième ?"
- Le LLM condense: Utilise l'historique pour produire "Comment configurer OAuth2 ?"
- Le retriever cherche: Avec la question autonome
- Le LLM répond: En utilisant le contexte récupéré + l'historique complet
# SummarizationChain
Résume un ou plusieurs documents en utilisant trois stratégies différentes, chacune avec des compromis différents pour la qualité, la vitesse et le coût.
📦 Stuff
Concatène tous les documents en un seul prompt. Le plus rapide, le moins cher, mais limité par la fenêtre de contexte.
Idéal pour : docs courts🗺️ Map-Reduce
Résume chaque chunk indépendamment (map), puis combine tous les résumés (reduce). Gère une taille de document illimitée.
Idéal pour : gros docs🔄 Refine
Commence avec le premier chunk, puis affine itérativement le résumé avec chaque chunk suivant. Meilleure qualité mais séquentiel.
Idéal pour : qualité- Stratégie Stuff
import { SummarizationChain } from 'orkajs/chains/summarization'; // Stuff: all documents in one promptconst stuffChain = new SummarizationChain({ llm, strategy: 'stuff', systemPrompt: 'Provide a clear and concise summary.'}); const result = await stuffChain.call([ 'Document 1 content here...', 'Document 2 content here...', 'Document 3 content here...']); console.log(result.answer); // Combined summaryconsole.log(result.usage); // Token usage (1 LLM call)- Stratégie Map-Reduce
// Map-Reduce: summarize chunks independently, then combineconst mapReduceChain = new SummarizationChain({ llm, strategy: 'map-reduce', maxChunkSize: 3000, // Split large docs into 3000-char chunks combinePrompt: 'Combine the following summaries into a single coherent summary:\n\n{{summaries}}\n\nCombined Summary:'}); const result = await mapReduceChain.call([ veryLongDocument1, // 50,000 chars veryLongDocument2 // 30,000 chars]); console.log(result.answer);console.log(result.intermediateSteps);// [// { name: 'map_chunk_0', ... }, // Summary of chunk 1// { name: 'map_chunk_1', ... }, // Summary of chunk 2// ...// { name: 'reduce_combine', ... } // Final combined summary// ]- Stratégie Refine
// Refine: iteratively improve summary with each chunkconst refineChain = new SummarizationChain({ llm, strategy: 'refine', maxChunkSize: 3000, refinePrompt: `Here is an existing summary:{{existingSummary}} Refine this summary with the following additional context:{{context}} Refined Summary:`}); const result = await refineChain.call([longDocument]); console.log(result.answer);console.log(result.intermediateSteps);// [// { name: 'initial_summary', ... }, // First chunk summary// { name: 'refine_1', ... }, // Refined with chunk 2// { name: 'refine_2', ... }, // Refined with chunk 3// ...// ]# QAChain — Question-Réponse Avancé
QAChain combine la récupération avec le question-réponse multi-stratégie. Contrairement à RetrievalQAChain qui utilise toujours l'approche "stuff", QAChain supporte les stratégies stuff, map-reduce et refine pour répondre aux questions sur de grands ensembles de documents.
import { QAChain } from 'orkajs/chains/qa'; // Stuff strategy (default) — fast, for small document setsconst stuffQA = new QAChain({ llm, retriever, collection: 'docs', strategy: 'stuff', returnSources: true}); const result1 = await stuffQA.call('What is the rate limit?'); // Map-Reduce strategy — for many retrieved documentsconst mapReduceQA = new QAChain({ llm, retriever, collection: 'docs', strategy: 'map-reduce', returnSources: true, systemPrompt: 'Answer precisely based on the documents. Cite sources when possible.'}); const result2 = await mapReduceQA.call('Compare all authentication methods');// Map: extracts relevant info from each document// Reduce: combines into a comprehensive answer // Refine strategy — best quality for complex questionsconst refineQA = new QAChain({ llm, retriever, collection: 'docs', strategy: 'refine', returnSources: true}); const result3 = await refineQA.call('Explain the complete deployment process step by step');// Starts with answer from first doc, refines with each additional docExemple Complet — Pipeline RAG Production
import { createOrka } from 'orkajs/core';import { OpenAIAdapter } from 'orkajs/adapters/openai';import { EnsembleRetriever, VectorRetriever, BM25Retriever } from 'orkajs/retrievers';import { ConversationalRetrievalChain, SummarizationChain } from 'orkajs/chains';import { MemoryCache } from 'orkajs/cache/memory';import { CachedLLM } from 'orkajs/cache/llm'; // Setup with cachingconst baseLLM = new OpenAIAdapter({ apiKey: process.env.OPENAI_API_KEY! });const llm = new CachedLLM(baseLLM, new MemoryCache({ maxSize: 500 })); const orka = createOrka({ llm, vectorDB: myVectorDB }); // Hybrid retriever (BM25 + Vector)const hybrid = new EnsembleRetriever({ retrievers: [ new BM25Retriever({ documents: myDocs, topK: 10 }), new VectorRetriever({ llm, vectorDB: myVectorDB, topK: 10 }) ], weights: [0.3, 0.7], topK: 5}); // Conversational chain with hybrid retrievalconst chatChain = new ConversationalRetrievalChain({ llm, retriever: hybrid, collection: 'documentation', returnSources: true, maxHistoryLength: 10}); // Handle user conversationasync function handleMessage(userMessage: string) { const result = await chatChain.call(userMessage); return { answer: result.answer, sources: result.sources?.map(s => ({ id: s.id, score: s.score, preview: s.content?.slice(0, 100) })), steps: result.intermediateSteps };} // Summarize long documentsconst summarizer = new SummarizationChain({ llm, strategy: 'map-reduce', maxChunkSize: 3000}); async function summarizeDocuments(texts: string[]) { const result = await summarizer.call(texts); return result.answer;}Comparaison
| Chaîne | Cas d'Usage | Mémoire | Stratégies |
|---|---|---|---|
| RetrievalQA | Q&R simple sur docs | ❌ | stuff |
| Conversational | Chat avec suivi | ✅ | stuff |
| Summarization | Résumé de documents | ❌ | stuff, map-reduce, refine |
| QAChain | Q&R avancé avec stratégies | ❌ | stuff, map-reduce, refine |
Comparaison des Stratégies de Résumé
| Stratégie | Appels LLM | Qualité | Taille Max Doc |
|---|---|---|---|
| stuff | 1 | ⭐⭐⭐ | Limite fenêtre contexte |
| map-reduce | N + 1 | ⭐⭐ | Illimité |
| refine | N | ⭐⭐⭐⭐ | Illimité |
💡 Bonnes Pratiques
1. Commencez avec RetrievalQA
Pour la plupart des cas d'usage, RetrievalQAChain suffit. Passez à ConversationalRetrievalChain uniquement quand vous avez besoin de conversations multi-tours.
2. Utilisez la Récupération Hybride
Combinez BM25 + VectorRetriever dans un EnsembleRetriever pour les meilleurs résultats. La correspondance de mots-clés capture les termes exacts que la recherche sémantique pourrait manquer.
3. Surveillez les Étapes Intermédiaires
Utilisez intermediateSteps pour déboguer la qualité de récupération, identifier les étapes lentes et optimiser votre pipeline.
4. Choisissez la Bonne Stratégie de Résumé
Utilisez 'stuff' pour les documents courts (<4K tokens), 'map-reduce' pour le traitement parallèle de gros docs, et 'refine' quand la qualité du résumé est critique.
Imports Tree-shakeable
// ✅ Import only what you needimport { RetrievalQAChain } from 'orkajs/chains/retrieval-qa';import { ConversationalRetrievalChain } from 'orkajs/chains/conversational-retrieval';import { SummarizationChain } from 'orkajs/chains/summarization';import { QAChain } from 'orkajs/chains/qa'; // ✅ Or import from indeximport { RetrievalQAChain, ConversationalRetrievalChain, SummarizationChain, QAChain } from 'orkajs/chains';