Skip to content

RAG (Retrieval-Augmented Generation) ​

Meloqui provides components for building RAG pipelines that enhance LLM responses with relevant context.

Overview ​

RAG works by:

  1. Chunking documents into smaller pieces
  2. Converting chunks to vector embeddings
  3. Storing embeddings for similarity search
  4. Retrieving relevant chunks based on user queries
  5. Injecting context into the LLM prompt

IDocumentStore ​

Interface for document storage and retrieval.

typescript
interface IDocumentStore {
  /** Add documents (automatically chunked and embedded) */
  addDocuments(docs: Document[]): Promise<void>;

  /** Search for relevant chunks */
  search(query: string, topK?: number): Promise<SearchResult[]>;

  /** Delete chunks from a source */
  delete(source: string): Promise<void>;

  /** Clear all documents */
  clear(): Promise<void>;
}

Document ​

A document to add to the store.

typescript
interface Document {
  /** The text content */
  content: string;
  /** Source identifier (e.g., filename) */
  source: string;
  /** Optional metadata */
  metadata?: Record<string, unknown>;
}

DocumentChunk ​

A chunk with its embedding.

typescript
interface DocumentChunk {
  /** Unique chunk ID */
  id: string;
  /** Chunk text content */
  content: string;
  /** Vector embedding */
  embedding: number[];
  /** Chunk metadata */
  metadata: {
    source: string;
    chunkIndex: number;
    [key: string]: unknown;
  };
}

SearchResult ​

Search result with similarity score.

typescript
interface SearchResult extends DocumentChunk {
  /** Similarity score (-1 to 1, higher is more similar) */
  score: number;
}

InMemoryDocumentStore ​

In-memory document store for development and small datasets.

typescript
import { InMemoryDocumentStore, OpenAIEmbeddings } from 'meloqui';

const embeddings = new OpenAIEmbeddings({
  apiKey: process.env.OPENAI_API_KEY
});

const store = new InMemoryDocumentStore({ embeddingProvider: embeddings });

await store.addDocuments([
  { content: 'Meloqui is an LLM SDK', source: 'docs/intro.md' }
]);

const results = await store.search('What is Meloqui?', 3);

InMemoryDocumentStoreConfig ​

typescript
interface InMemoryDocumentStoreConfig {
  /** Embedding provider for generating vectors */
  embeddingProvider: IEmbeddingProvider;
  /** Maximum chunk size in characters (default: 1000) */
  chunkSize?: number;
  /** Overlap between chunks in characters (default: 200) */
  chunkOverlap?: number;
  /** Optional logger for warnings */
  logger?: ILogger;
  /** Warning threshold (default: 10000) */
  warnThreshold?: number;
  /** Maximum chunks to store (default: 100000, set to 0 to disable) */
  maxChunks?: number;
}

Constants ​

typescript
const DEFAULT_MAX_CHUNKS = 100000;
const DEFAULT_WARN_THRESHOLD = 10000;

FileDocumentStore ​

File-based persistence for document stores.

typescript
import { FileDocumentStore, OpenAIEmbeddings } from 'meloqui';

const store = new FileDocumentStore({
  embeddingProvider: new OpenAIEmbeddings({ apiKey }),
  directory: './rag-data'
});

FileDocumentStoreConfig ​

typescript
interface FileDocumentStoreConfig {
  /** Embedding provider for generating vectors */
  embeddingProvider: IEmbeddingProvider;
  /** Directory to store chunk data */
  directory: string;
  /** Maximum chunk size in characters (default: 1000) */
  chunkSize?: number;
  /** Overlap between chunks in characters (default: 200) */
  chunkOverlap?: number;
}

IEmbeddingProvider ​

Interface for embedding providers.

typescript
interface IEmbeddingProvider {
  /** Embed single text */
  embed(text: string): Promise<number[]>;

  /** Embed multiple texts (batch) */
  embedBatch(texts: string[]): Promise<number[][]>;

  /** Embedding dimensions */
  readonly dimensions: number;
}

OpenAIEmbeddings ​

OpenAI embedding provider using text-embedding-3-small.

typescript
import { OpenAIEmbeddings } from 'meloqui';

const embeddings = new OpenAIEmbeddings({
  apiKey: process.env.OPENAI_API_KEY,
  model: 'text-embedding-3-small' // default
});

const vector = await embeddings.embed('Hello world');
console.log(`Dimensions: ${embeddings.dimensions}`); // 1536

OpenAIEmbeddingsConfig ​

typescript
interface OpenAIEmbeddingsConfig {
  /** API key (defaults to OPENAI_API_KEY env var) */
  apiKey?: string;
  /** Model name (default: 'text-embedding-3-small') */
  model?: string;
  /** Custom base URL for API-compatible endpoints */
  baseUrl?: string;
  /** Maximum texts per API request (default: 2048) */
  batchSize?: number;
  /** Override dimensions for custom/unknown models */
  dimensions?: number;
}

Text Chunking ​

chunkText ​

Split text into overlapping chunks for embedding.

typescript
import { chunkText } from 'meloqui';

const chunks = chunkText(longDocument, {
  chunkSize: 1000,    // max chars per chunk
  chunkOverlap: 200,  // overlap between chunks
  splitOn: 'sentence' // boundary type
});

ChunkOptions ​

typescript
interface ChunkOptions {
  /** Maximum chunk size in characters (default: 1000) */
  chunkSize?: number;
  /** Overlap between chunks (default: 200) */
  chunkOverlap?: number;
  /** Split boundary type (default: 'character') */
  splitOn?: SplitBoundary;
}

SplitBoundary ​

typescript
type SplitBoundary = 'character' | 'sentence' | 'paragraph';
BoundaryDescription
characterSplit at exact positions (may split mid-word)
sentenceSplit at sentence boundaries (., ?, !)
paragraphSplit at double newlines

Similarity ​

cosineSimilarity ​

Calculate cosine similarity between two vectors.

typescript
import { cosineSimilarity } from 'meloqui';

const similarity = cosineSimilarity(vectorA, vectorB);
// Returns -1 to 1 (higher = more similar)

Using RAG with ChatClient ​

typescript
import { ChatClient, InMemoryDocumentStore, OpenAIEmbeddings } from 'meloqui';

const store = new InMemoryDocumentStore({
  embeddingProvider: new OpenAIEmbeddings({ apiKey })
});

await store.addDocuments([
  { content: 'Product docs...', source: 'product.md' },
  { content: 'API reference...', source: 'api.md' }
]);

const client = new ChatClient({
  provider: 'openai',
  model: 'gpt-4o',
  documentStore: store,
  ragOptions: {
    topK: 3,
    minScore: 0.5
  }
});

// Context is automatically retrieved and injected
const response = await client.chat('How do I use the API?');

RAGOptions ​

typescript
interface RAGOptions {
  /** Number of chunks to retrieve (default: 3) */
  topK?: number;
  /** Minimum similarity threshold (default: 0) */
  minScore?: number;
  /** Custom context injection template */
  contextTemplate?: string;
  /** Throw on RAG failure (default: false) */
  failOnError?: boolean;
  /** Error callback */
  onError?: (error: Error) => void | Promise<void>;
}

Released under the MIT License.