Skip to main content

Concept: rag-core

The framework is internally organized around four conceptual modules. rag-core is the orchestrator and contract layer — the pieces every pipeline needs, regardless of which connectors, evaluators, or guardrails you bolt on top.

Why "concepts" and not separate packages? Today everything ships as one npm package. The conceptual modules describe what code is responsible for what so you can reason about blast radius, security review scope, and dependency footprint without us splitting the codebase. A real monorepo split is on the roadmap.

What's in rag-core​

SurfacePurpose
createRagPipeline({ loader, embedder, retriever, llm, reranker, registry })The factory. Wires the components into a runnable pipeline and returns { run, cleanup }.
run({ query, queryVector, options })The main execution entry point. Resolves { success, query, results, answer, citations?, evaluation? }; failures, timeouts and aborts resolve { success: false, error }.
pluginRegistryHolds registered loader, embedder, retriever, reranker and LLM plugins by name. Validates them against the contract schemas in contracts/.
Plugin contractsJSON files in contracts/ that define the required methods for each plugin type.
CancellationEach run creates an AbortController; its signal reaches every component call. options.signal lets callers cancel and options.timeout aborts the run.
retry / withRetryRetry helpers with backoff for your own components (the built-in connectors already retry transient failures).
loggerpino-based structured logger.

Minimum viable pipeline​

import {
createRagPipeline,
MemoryRetriever,
OpenAIConnector,
} from "@devilsdev/rag-pipeline-utils";

const openai = new OpenAIConnector({ apiKey: process.env.OPENAI_API_KEY });

const pipeline = createRagPipeline({
embedder: openai, // embeds the query for vector search
retriever: new MemoryRetriever(), // populate with retriever.store([...])
llm: openai,
});

const result = await pipeline.run({ query: "What does X do?" });

That's it. No evaluation, no guardrails, no GraphRAG — just retrieval and generation. Add layers as needed.

When to extend rag-core​

You're operating in rag-core territory when you:

  • Build a custom plugin (loader, embedder, retriever, reranker, LLM)
  • Configure run behaviour (topK, timeout, cancellation via signal, streaming, the filterResults hook)
  • Tune logging, observability, correlation tracking
  • Need to compose multiple pipelines (e.g. a planner + executor pattern)

When to leave rag-core alone​

You don't need to touch rag-core internals when you:

Stability​

Everything documented in the API reference under "Core" is stable per the SEMVER policy.

Internal modules (plugin registry private methods, CLI internals, etc.) may change in patch releases. Experimental modules (see Experimental) are not covered by SEMVER.

  • Architecture — the deeper reference on how these pieces fit together
  • Plugins — building custom plugins against the contracts
  • API reference — full export list