Skip to main content

Concept: rag-connectors

The framework's connector layer is the boundary between the pipeline and the outside world: embedding providers, vector stores, LLM APIs, document loaders. Every connector implements a plugin contract defined as a JSON schema in contracts/.

What's in rag-connectors​

Embedders​

ConnectorNotes
OpenAIConnectorembed() / embedQuery() via OpenAI embeddings (embeddingModel, default text-embedding-3-small). Reads OPENAI_API_KEY.
CohereConnectorembed() / embedQuery() via Cohere embed; also rerank(). Reads COHERE_API_KEY.
OllamaConnectorembed() / embedQuery() against a local Ollama server.
LocalEmbedderPure-JS TF-IDF for development, tests and small corpora. No network. Fit it with train(documents); getState() / setState() persist the vocabulary.
Custom (your code)Implement the embedder contract: embed(text, { signal }) returning number[] (optionally embedQuery() for queries).

Retrievers / Vector stores​

ConnectorNotes
MemoryRetrieverIn-process cosine-similarity store. Needs a queryVector (pass an embedder to the pipeline). Enforces maxDocuments (default 100000; eviction: 'fifo' drops the oldest) and rejects mismatched vector dimensions.
FileVectorStoreJSON-file vector index with atomic writes, embedder/dimension tracking and per-source re-ingestion. Used by the CLI (file-store, .rag/index.json).
HybridRetrieverCombines several retrievers (e.g. vector + BM25Search) with Reciprocal Rank Fusion.
GraphRetrieverKnowledge-graph retrieval over extracted entities.
Pinecone, Weaviate, Qdrant, pgvectorBuild your own retriever using the documented contract — examples in Examples.

LLMs​

ConnectorNotes
OpenAIConnectorOpenAI Chat Completions (default model gpt-4o-mini) + streaming via generateStream().
AnthropicConnectorAnthropic Messages API + streaming. Reads ANTHROPIC_API_KEY.
OllamaConnectorLocal Ollama server for offline development and self-hosted production.
CustomImplement the llm contract: generate(query, docs, { signal, ...options }) returning a string, and optionally generateStream(...).

All built-in connectors retry only transient failures (network errors, 408/409/425/429/5xx) with exponential backoff, jitter and Retry-After, fail fast with MISSING_API_KEY when no key is configured, honour the run's AbortSignal, and pass retrieved context to the model as delimited, untrusted reference data in the user message.

OpenAI-compatible providers (baseURL)​

OpenAIConnector works with any server that implements the OpenAI API (Groq, Together, the Hugging Face router, vLLM, LM Studio, Ollama's /v1 endpoint) when you pass baseURL and the provider's model names.

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

// A hosted provider: pass its key explicitly.
const groq = new OpenAIConnector({
baseURL: "https://api.groq.com/openai/v1",
apiKey: process.env.GROQ_API_KEY,
model: "llama-3.1-8b-instant",
});

// A local server that needs no key.
const local = new OpenAIConnector({
baseURL: "http://localhost:1234/v1",
model: "qwen2.5-7b-instruct",
embeddingModel: "nomic-embed-text",
});

With a custom baseURL the connector never reads OPENAI_API_KEY, so your OpenAI key is not sent to another provider. Pass apiKey for hosted providers, or leave it out for local servers that need none.

Loaders​

ConnectorNotes
Built-in document reader (auto loader in the CLI)Markdown, HTML, CSV and plain text files, or a directory of them.
CustomImplement the loader contract: load().

Rerankers​

ConnectorNotes
ScoringRerankerLexical (BM25-style) scoring on top of vector retrieval.
EmbeddingRerankerRe-scores with an embedder; LRU cache of document embeddings (cacheSize), concurrency (default 4).
CascadeRerankerChains rerankers (cheap first, expensive last) for cost-effective reranking.
CohereConnectorrerank() via Cohere's rerank API.

Why a connector layer​

Three reasons:

  1. Vendor independence. You can swap OpenAI for Anthropic without touching pipeline code. The pipeline doesn't know which LLM it's calling.
  2. Contract enforcement. Every connector must satisfy a JSON schema in contracts/. Plugins that don't register fail loudly, not silently.
  3. Isolated security review. When you add a new provider, the review surface is one file implementing one contract — not a pipeline-wide refactor.

Adding a connector​

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

const myEmbedder = {
metadata: { name: "vendor-x-embedder", version: "1.0.0", type: "embedder" },
async embed(text, { signal } = {}) {
/* call vendor X, passing signal to fetch */
return vector; // number[]
},
};

await pluginRegistry.register("embedder", "vendor-x-embedder", myEmbedder);

// Now usable by name
const pipeline = createRagPipeline({
embedder: "vendor-x-embedder",
retriever,
llm,
});

The registry checks the plugin's metadata (name, version, type) and validates it against contracts/embedder-contract.json on registration; registration throws if either check fails. See Plugins for the full guide.

Stability​

Connector classes shipped in the package are part of the public API surface and follow the SEMVER policy.

Connector contracts in contracts/ are also stable. Adding new optional fields is non-breaking; removing or renaming required fields is breaking and ships only in major versions.

  • Plugins — full plugin development guide
  • Architecture — internal plugin registry design
  • Examples — recipe for a custom Pinecone retriever, custom embedder, etc.