Skip to main content

Components

Introduction to the usage of components

Welcome to the Components section of the eLLMental library! eLLMental is like a master chef's kitchen, but instead of preparing food with ingredients, it helps you whip up AI applications with ease through the usage of well-defined components that work extremely well together.

In eLLMental, components are defined through interfaces. This means that you can easily swap out components for your own implementations, or even use multiple implementations of the same component in the same application. This allows you to easily experiment with different components and see which ones work best for your use case.

You write your functions and classes in terms of these components, and then you pass concrete implementations of the components when you call the functions or instantiate the classes.

import com.theagilemonkeys.ellmental.embeddingmodel.*

// Passing it as a parameter to the function
suspend fun doSomething(embeddingModel: EmbeddingModel<Any>): Embedding {
return embeddingModel.embed("Hello world!")
}

// Passing it as a parameter to the constructor
class MyService(val embeddingModel: EmbeddingModel<Any>) {
suspend fun doSomething(): Embedding {
return embeddingModel.embed("Hello world!")
}
}

Now you can pass your concrete implementations of the components when you call the functions or instantiate the classes:

fun main() = runBlocking {
// Instantiate the concrete implementation of the EmbeddingModel interface
val embeddingModel = OpenAIEmbeddingsModel("API KEY")

// Passing it as a parameter to the function
doSomething(embeddingModel)

// Passing it as a parameter to the constructor
val myService = MyService(embeddingModel)
myService.doSomething()
}

Available components

In this section you will find a list of all the available components in eLLMental, along with a brief description of what they do and how to use them.

If you want to go to the API documentation of a component, simply click on its name.

EmbeddingsModel

The embeddings model is the component that is responsible for generating embeddings from text.

An embedding is a semantic representation of a text in the "semantics space", an imaginary high-dimensional mathematical representation of all the possible semantics. In this space, each concept is associated with a specific point in a way that words or phrases that are similar from a meaning point of view are placed closer than those with different meanings. In short, an embedding is an array of numbers representing the text's meaning in the semantics space.

For example, If we were to represent the embeddings of the words swimming, swam, walking, walked in a very simplified visualization, we could see them like this:

Visualization of word embeddings

Embeddings are useful because they allow you to compare pieces of text by their meaning rather than by their characters or other properties. For example, the embeddings of the sentences "I like apples" and "I like oranges" will be very similar, because the vector representation of the sentences is similar.

The EmbeddingsModel interface is defined by the following interface:

interface EmbeddingsModel<Params> {
suspend fun embed(text: String, params: Params? = null): Embedding
}

As you may have noticed, the interface declares a generic parameter that represents possible configuration options for the concrete implementation of the EmbeddingsModel. If you're unsure about what to use, you can use Any as the generic parameter and then specify it later once you decide on a concrete implementation.

The EmbeddingsModel component declares a single embed method. This method receives a string that can be a single word, a sentence, a paragraph, or even a whole book, as long as the implementation of the EmbeddingsModel that you are using supports processing the length of text that you are passing.

import com.theagilemonkeys.ellmental.embeddingmodel.*

suspend fun doSomething(embeddingModel: EmbeddingModel<Any>) {
val swimmingEmbedding = embeddingModel.embed("swimming")
println(swimmingEmbedding)
}

VectorStore

The VectorStore component is responsible for storing the embeddings generated by the EmbeddingsModel and is defined by the following interface:

interface VectorStore {
suspend fun upsert(semanticEntry: SemanticEntry)
suspend fun query(semanticEntry: SemanticEntry, itemsLimit: Int): QueryOutput
}

It is important to note that the VectorStore component is not responsible for generating the embeddings. It only stores and retrieves them.

The VectorStore component declares two methods: upsert and query. The upsert method is used to store embeddings in the VectorStore, and the query method is used to retrieve semantically similar embeddings from the VectorStore.

import com.theagilemonkeys.ellmental.vectorstore.*

suspend fun doSomething(vectorStore: VectorStore<Any>) {
val embedding = // some embedding generated by an EmbeddingModel

vectorStore.upsert(embedding)
val similarEmbeddings = vectorStore.query(embedding, itemsLimit = 10)
println(similarEmbeddings)
}

SemanticSearch

The SemanticSearch component combines the functionality of the EmbeddingsModel and the VectorStore, abstracting the process of generating embeddings from text and storing them in a VectorStore to provide a higher-level interface for implementing semantic search use cases. It is defined by the SemanticSearch class, which has the following interface:

context(EmbeddingsModel<Any>, VectorStore)
class SemanticSearch {
suspend fun learn(input: LearnInput)
suspend fun search(text: String, itemsLimit: Int): SearchOutput
}

The SemanticSearch component declares two methods: learn and search. The learn method is used to store the semantic meaning of a piece of text, and the search method is used to retrieve semantically similar pieces of text.

import com.theagilemonkeys.ellmental.semanticsearch.*

suspend fun doSomething(semanticSearch: SemanticSearch<Any>) {
semanticSearch.learn("Hello world!")
val similarEmbeddings = semanticSearch.search("Hello world!", itemsLimit = 10)
println(similarEmbeddings)
}