Skip to main content

Usage Guide

This guide covers how to use @devilsdev/rag-pipeline-utils programmatically via the JavaScript/TypeScript API and through the command-line interface.


Installation​

NPM Installation​

# Install as a project dependency
npm install @devilsdev/rag-pipeline-utils

# Or install globally for CLI usage
npm install -g @devilsdev/rag-pipeline-utils

# Using Yarn
yarn add @devilsdev/rag-pipeline-utils

# Using pnpm
pnpm add @devilsdev/rag-pipeline-utils

System Requirements​

  • Node.js: >= 18.0.0
  • Memory: depends on corpus size; the in-memory and file-based retrievers keep the index in memory while running
  • Storage: varies with the vector store and document size

Environment Setup​

The built-in connectors read their API key from the environment when they are constructed (or from an apiKey option). Calls without a key fail fast with MISSING_API_KEY.

# OpenAI (OpenAIConnector)
OPENAI_API_KEY=your_openai_api_key_here

# Anthropic (AnthropicConnector, optional)
ANTHROPIC_API_KEY=your_anthropic_api_key

# Cohere (CohereConnector, optional)
COHERE_API_KEY=your_cohere_api_key

OllamaConnector and LocalEmbedder need no API key.


Programmatic API Usage​

Basic Pipeline Setup​

createRagPipeline takes component instances (or names registered on pluginRegistry) for the stages loader, embedder, retriever, llm and reranker, plus an optional registry. It returns { run, cleanup }.

const {
createRagPipeline,
OpenAIConnector,
MemoryRetriever,
} = require("@devilsdev/rag-pipeline-utils");

const openai = new OpenAIConnector({
model: "gpt-4o-mini",
embeddingModel: "text-embedding-3-small",
temperature: 0.1,
});
const retriever = new MemoryRetriever();

// Index a few documents (vectors must come from the same embedder)
const docs = [
{
id: "1",
content: "Plugins implement one stage method, such as generate().",
},
{ id: "2", content: "Register plugins with pluginRegistry.register()." },
];
await retriever.store(
await Promise.all(
docs.map(async (d) => ({ ...d, vector: await openai.embed(d.content) })),
),
);

// The embedder turns each query into a queryVector for the retriever
const pipeline = createRagPipeline({
embedder: openai,
retriever,
llm: openai,
});

const response = await pipeline.run({
query: "How do I implement custom plugins in the RAG pipeline?",
});

if (response.success) {
console.log("Answer:", response.answer);
console.log("Sources:", response.results.length);
} else {
console.error("Pipeline error:", response.error);
}

run() resolves { success: false, error } instead of throwing when a stage fails, times out or is aborted.

Advanced Configuration Examples​

Multi-Provider Setup​

const {
createRagPipeline,
OpenAIConnector,
AnthropicConnector,
CohereConnector,
MemoryRetriever,
} = require("@devilsdev/rag-pipeline-utils");

const pipeline = createRagPipeline({
embedder: new OpenAIConnector({ embeddingModel: "text-embedding-3-large" }),
retriever: new MemoryRetriever(),
reranker: new CohereConnector({ rerankModel: "rerank-english-v3.0" }),
llm: new AnthropicConnector({ maxTokens: 4096 }),
});

Local-First Setup​

const {
createRagPipeline,
LocalEmbedder,
MemoryRetriever,
OllamaConnector,
} = require("@devilsdev/rag-pipeline-utils");

const embedder = new LocalEmbedder(); // TF-IDF, no network
embedder.train(corpus); // array of strings or { content } objects

const pipeline = createRagPipeline({
embedder,
retriever: new MemoryRetriever(),
llm: new OllamaConnector({
baseURL: "http://localhost:11434",
model: "llama3",
temperature: 0.2,
}),
});

For an index that persists to disk, use FileVectorStore as the retriever (see the API Reference).


Pipeline Methods & Operations​

Indexing Documents​

The pipeline object only exposes run() and cleanup(); there is no separate ingest method. Index documents by embedding them and calling your retriever's store() (as in the example above), or use the CLI's rag-pipeline ingest <path>, which loads, embeds and stores files into a local FileVectorStore index.

Querying & Response Generation​

// Basic query
const response = await pipeline.run({ query: "What is RAG?" });
console.log(response.answer);

// Query with options
const detailed = await pipeline.run({
query: "Explain the plugin architecture",
options: {
topK: 5,
timeout: 10000, // resolves { success: false, error: 'Execution timeout' }
citations: true,
evaluate: true,
},
});

console.log(detailed.answer, detailed.citations, detailed.evaluation);

// Streaming responses (resolves to an async iterable when stream: true)
const stream = await pipeline.run({
query: "How do I optimize performance?",
options: { stream: true },
});

for await (const chunk of stream) {
if (!chunk.done) {
process.stdout.write(chunk.token);
}
}

With citations or evaluate in stream mode, the stream ends with one { token: '', done: true, citations, evaluation } chunk.

Without an llm, the pipeline runs retrieval only and returns answer: null.

Cancellation​

Pass an AbortSignal as options.signal. Every component receives the run's signal, and no later stage starts after an abort.

const controller = new AbortController();
setTimeout(() => controller.abort(), 2000);

const result = await pipeline.run({
query: "Summarise the release notes",
options: { signal: controller.signal },
});
// On abort: { success: false, error: 'Execution aborted' }

Pipeline Cleanup​

pipeline.cleanup();

Command Line Interface (CLI)​

npm install -g @devilsdev/rag-pipeline-utils

rag-pipeline init # writes .ragrc.json
rag-pipeline ingest ./docs # builds the local index
rag-pipeline query "What is the plugin architecture?"
rag-pipeline serve --port 3000 # local HTTP API (GET /health, POST /query)
rag-pipeline doctor # diagnose config, plugins and environment

See the CLI Reference for every command and option.


Configuration File (.ragrc.json)​

The CLI reads its pipeline from .ragrc.json. Each entry names a built-in component or a custom plugin, with optional constructor config:

{
"namespace": "default",
"pipeline": [
{ "stage": "loader", "name": "auto" },
{
"stage": "embedder",
"name": "openai",
"config": { "embeddingModel": "text-embedding-3-small" }
},
{
"stage": "retriever",
"name": "file-store",
"config": { "path": ".rag/index.json" }
},
{ "stage": "llm", "name": "my-llm", "config": { "temperature": 0.1 } }
],
"plugins": {
"llm": { "my-llm": "./plugins/my-llm.js" }
}
}

Run rag-pipeline info --plugins to list the built-in names, and rag-pipeline validate to check that every entry resolves.


Advanced Usage Patterns​

Error Handling & Resilience​

run() does not throw for stage failures: check success and error. For your own code, createError(code, context) and wrapError(error, code, context) create errors with a code from ERROR_CODES, a formatted message and suggestions.

const {
createError,
wrapError,
ERROR_CODES,
} = require("@devilsdev/rag-pipeline-utils");

const response = await pipeline.run({ query: "Complex query" });
if (!response.success) {
throw createError(ERROR_CODES.PIPELINE_EXECUTION_FAILED, {
reason: response.error,
});
}

try {
await loadMyDocuments();
} catch (err) {
throw wrapError(err, ERROR_CODES.PLUGIN_EXECUTION_FAILED, {
plugin: "my-loader",
});
}

Tracing Runs​

The pipeline object does not emit events. To record what each run did, wrap it with ExecutionTracer:

const { ExecutionTracer } = require("@devilsdev/rag-pipeline-utils");

const tracer = new ExecutionTracer();
const traced = tracer.trace(pipeline);

tracer.on("traced", (trace) => {
console.log(`Run ${trace.id} took ${trace.totalDurationMs}ms`);
});

const result = await traced.run({ query: "What is RAG?" });
console.log(result.trace.metadata.resultCount);

Wrapping a Pipeline​

There is no middleware API. Because a pipeline is just an object with run(), you can wrap it yourself; GuardrailsPipeline, CostTracker.wrap() and ExecutionTracer.trace() all work this way.

function withTiming(pipeline) {
return {
...pipeline,
async run(input) {
const start = Date.now();
const result = await pipeline.run(input);
console.log(`Query completed in ${Date.now() - start}ms`);
return result;
},
};
}

const timed = withTiming(pipeline);

Plugin Configuration​

You can register plugins by name on the exported pluginRegistry and then refer to them by name in createRagPipeline or .ragrc.json. register() is asynchronous. Each plugin needs a metadata object with name, version and type (the stage), plus the stage's methods (a retriever needs both store() and retrieve()).

const {
pluginRegistry,
createRagPipeline,
} = require("@devilsdev/rag-pipeline-utils");

class MyCustomLoader {
metadata = { name: "custom", version: "1.0.0", type: "loader" };
async load() {
/* ... */
}
}

await pluginRegistry.register("loader", "custom", new MyCustomLoader());
await pluginRegistry.register(
"retriever",
"opensearch",
new MyOpenSearchRetriever(), // metadata.type === "retriever"
);

const pipeline = createRagPipeline({
loader: "custom",
retriever: "opensearch",
embedder,
llm,
});

See Plugins for the stage contracts. For more use cases, see the Tutorials.


Next → CLI