Interfaces
Interfaces define the contracts between components in the Ragfish Framework.
They allow the core framework to work with different implementations without becoming tightly coupled to a specific AI provider, vector database, or connector.
This is an important part of Ragfish's modular architecture.
For example, @ragfish/core can define how an LLM or retriever should behave, while packages such as @ragfish/openai and @ragfish/qdrant provide concrete implementations.
Why Interfaces?
Consider a Ragfish application that uses OpenAI and Qdrant.
@ragfish/core
│
├── LLM Contract
├── Embedding Contract
├── Retriever Contract
└── Vector Store Contract
│
┌─────┴─────┐
▼ ▼
@ragfish/openai @ragfish/qdrant
│ │
▼ ▼
OpenAILLM QdrantRetriever
OpenAI QdrantVectorStore
Embedding
The core framework does not need to know the internal implementation details of each provider.
It only needs the component to satisfy the expected interface.
Interface vs Implementation
An interface defines what a component must provide.
An implementation defines how that component works.
Conceptually:
Interface │ │ defines contract ▼ Implementation │ │ provides behavior ▼ Runtime
For example:
LLM Interface
│
├── OpenAILLM
├── AnthropicLLM
├── GeminiLLM
└── OllamaLLM
The same principle can be applied to other framework components.
Interfaces in Ragfish
Ragfish's modular architecture can be organized around contracts for components such as:
Language Models
Embedding Models
Retrievers
Vector Stores
Connectors
Documents
Chat responses
The exact interface names and method signatures are defined by the version of the Ragfish core package you are using.
LLM Abstraction
The language model is an important example of interface-based design.
The core framework can work with an LLM abstraction without depending directly on OpenAI.
LLM Interface
│
├───────────────┬───────────────┐
▼ ▼ ▼
OpenAILLM GeminiLLM OllamaLLM
The OpenAI implementation belongs to the provider package rather than the core framework.
The current Ragfish architecture demonstrates this separation through:
import { Settings } from "@ragfish/core";
import { OpenAILLM } from "@ragfish/openai";
Settings.llm = new OpenAILLM({
apiKey: process.env.OPENAI_API_KEY
});
Here, Settings comes from the core package while OpenAILLM comes from the OpenAI provider package.
Embedding Abstraction
The same architecture applies to embedding models.
Embedding Interface
│
┌─────────────┼─────────────┐
│ │ │
▼ ▼ ▼
OpenAIEmbedding OtherProvider CustomEmbedding
The core framework can use the embedding abstraction while the provider package handles the actual implementation.
For example:
Settings.embedModel = new OpenAIEmbedding({
apiKey: process.env.OPENAI_API_KEY
});
This keeps embedding-provider details outside the core framework.
Retriever Abstraction
A retriever provides the mechanism for finding relevant knowledge.
Conceptually:
Retriever Interface
│
┌─────────────┼─────────────┐
│ │ │
▼ ▼ ▼
QdrantRetriever CustomRetriever OtherRetriever
The Chat component can work with a retriever without needing to know the internal search implementation.
For example:
const chat = new Chat({
retriever
});
This is what allows the chat layer to remain independent of the vector database being used.
Vector Store Abstraction
A vector store is responsible for storing and searching vector representations.
Conceptually:
Vector Store Interface
│
┌─────────────┼─────────────┐
▼ ▼ ▼
QdrantVectorStore ChromaStore CustomStore
The current Ragfish package architecture includes QdrantVectorStore as the Qdrant implementation.
const store = new QdrantVectorStore({
// configuration
});
The retriever can then use the vector store:
const retriever = new QdrantRetriever({
vectorStore: store,
collectionName: "knowledge"
});
This separation allows the retrieval layer to remain independent from the underlying vector database.
Connector Abstraction
Connectors provide another natural extension point.
A connector is responsible for accessing a particular knowledge source.
Conceptually:
Connector Interface
│
┌─────────────┼─────────────┐
▼ ▼ ▼
Spreadsheet PDF Database
Connector Connector Connector
The connector-specific implementation can change without changing the rest of the knowledge pipeline.
Connector
│
▼
Ingestion
│
▼
Chunking
│
▼
Embeddings
│
▼
Vector Store
Dependency Direction
A key principle of the architecture is that the core framework should not depend on individual provider implementations.
The preferred dependency direction is:
Application
│
▼
@ragfish/core
▲ ▲
│ │
│ │
@ragfish/openai @ragfish/qdrant
The provider packages extend the framework rather than forcing the core framework to depend on them.
This keeps the architecture modular.
Replacing an Implementation
Because components communicate through interfaces, an implementation can be replaced without redesigning the entire application.
For example:
Current Chat │ ▼ Retriever │ ▼ QdrantVectorStore A future application could use: Chat │ ▼ Retriever │ ▼ AnotherVectorStore
The higher-level application architecture remains the same.
Custom Implementations
The interface-based architecture also allows developers to create their own implementations.
Potential custom components include:
Custom LLM providers
Custom embedding providers
Custom vector stores
Custom retrievers
Custom connectors
A custom implementation should follow the corresponding Ragfish interface defined by the core framework.
This allows the custom component to participate in the same framework pipeline as the built-in integrations.
Interfaces and TypeScript
Interfaces are particularly important in a TypeScript-first framework.
They provide:
Compile-time contracts
Type safety
Better IDE support
Easier testing
Clear extension points
More maintainable integrations
A simplified TypeScript contract might look like:
interface Component {
// Framework-defined contract
}
The actual interfaces exposed by Ragfish should be used when implementing framework extensions.
Refer to the Types and API Reference sections for the exact interfaces and definitions available in your installed version.
Interface-Based Architecture
The overall design can be summarized as:
Ragfish Core
│
┌───────────────┼───────────────┐
▼ ▼ ▼
LLM Interface Retriever Interface Connector Interface
│ │ │
▼ ▼ ▼
OpenAI / Qdrant / Spreadsheet /
Other LLMs Other Stores Other Sources
This approach allows the framework to grow without introducing unnecessary coupling between components.
Best Practices
When working with Ragfish interfaces:
Depend on framework abstractions rather than provider-specific implementations where possible.
Keep custom implementations isolated from application business logic.
Use the interfaces exposed by @ragfish/core.
Avoid modifying core framework contracts for application-specific requirements.
Keep provider-specific functionality inside provider packages.
Follow TypeScript typing conventions when creating extensions.
What's Next?
Interfaces define the contracts between Ragfish components. The next page focuses on the Types used throughout the framework.
Continue to Types to understand the shared TypeScript models, configuration types, data structures, and other type definitions used by Ragfish applications and integrations.