Embeddable vector database for Go with Chroma-like interface and zero third-party dependencies. In-memory with optional persistence.
Because chromem-go
is embeddable it enables you to add retrieval augmented generation (RAG) and similar embeddings-based features into your Go app without having to run a separate database. Like when using SQLite instead of PostgreSQL/MySQL/etc.
It's not a library to connect to Chroma and also not a reimplementation of it in Go. It's a database on its own.
The focus is not scale (millions of documents) or number of features, but simplicity and performance for the most common use cases. On a mid-range 2020 Intel laptop CPU you can query 1,000 documents in 0.3 ms and 100,000 documents in 40 ms, with very few and small memory allocations. See Benchmarks for details.
⚠️ The project is in beta, under heavy construction, and may introduce breaking changes in releases before
v1.0.0
. All changes are documented in theCHANGELOG
.
With a vector database you can do various things:
Let's look at the RAG use case in more detail:
The knowledge of large language models (LLMs) - even the ones with 30 billion, 70 billion parameters and more - is limited. They don't know anything about what happened after their training ended, they don't know anything about data they were not trained with (like your company's intranet, Jira / bug tracker, wiki or other kinds of knowledge bases), and even the data they do know they often can't reproduce it exactly, but start to hallucinate instead.
Fine-tuning an LLM can help a bit, but it's more meant to improve the LLMs reasoning about specific topics, or reproduce the style of written text or code. Fine-tuning does not add knowledge 1:1 into the model. Details are lost or mixed up. And knowledge cutoff (about anything that happened after the fine-tuning) isn't solved either.
=> A vector database can act as the up-to-date, precise knowledge for LLMs:
text-embedding-3-small
.
chromem-go
can do this for you and supports multiple embedding providers and models out-of-the-box.Check out the example code to see it in action!
Our original inspiration was the Chroma interface, whose core API is the following (taken from their README):
Our Go library exposes the same interface:
Initially chromem-go
started with just the four core methods, but we added more over time. We intentionally don't want to cover 100% of Chroma's API surface though.
We're providing some alternative methods that are more Go-idiomatic instead.
For the full interface see the Godoc: https://pkg.go.dev/github.com/philippgille/chromem-go
chromem.EmbeddingFunc
)chromem-go
create them$contains
, $not_contains
io.Writer
/io.Reader
so you can plug S3 buckets and other blob storage, see examples/s3-export-import for example codeEmbeddingFunc
that downloads and shells out to llamafile$and
, $or
etc.)go get github.com/philippgille/chromem-go@latest
See the Godoc for a reference: https://pkg.go.dev/github.com/philippgille/chromem-go
For full, working examples, using the vector database for retrieval augmented generation (RAG) and semantic search and using either OpenAI or locally running the embeddings model and LLM (in Ollama), see the example code.
This is taken from the "minimal" example:
package main
import (
"context"
"fmt"
"runtime"
"github.com/philippgille/chromem-go"
)
func main() {
ctx := context.Background()
db := chromem.NewDB()
c, err := db.CreateCollection("knowledge-base", nil, nil)
if err != nil {
panic(err)
}
err = c.AddDocuments(ctx, []chromem.Document{
{
ID: "1",
Content: "The sky is blue because of Rayleigh scattering.",
},
{
ID: "2",
Content: "Leaves are green because chlorophyll absorbs red and blue light.",
},
}, runtime.NumCPU())
if err != nil {
panic(err)
}
res, err := c.Query(ctx, "Why is the sky blue?", 1, nil, nil)
if err != nil {
panic(err)
}
fmt.Printf("ID: %v\nSimilarity: %v\nContent: %v\n", res[0].ID, res[0].Similarity, res[0].Content)
}
Output:
ID: 1
Similarity: 0.6833369
Content: The sky is blue because of Rayleigh scattering.
Benchmarked on 2024-03-17 with:
$ go test -benchmem -run=^$ -bench .
goos: linux
goarch: amd64
pkg: github.com/philippgille/chromem-go
cpu: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
BenchmarkCollection_Query_NoContent_100-8 13164 90276 ns/op 5176 B/op 95 allocs/op
BenchmarkCollection_Query_NoContent_1000-8 2142 520261 ns/op 13558 B/op 141 allocs/op
BenchmarkCollection_Query_NoContent_5000-8 561 2150354 ns/op 47096 B/op 173 allocs/op
BenchmarkCollection_Query_NoContent_25000-8 120 9890177 ns/op 211783 B/op 208 allocs/op
BenchmarkCollection_Query_NoContent_100000-8 30 39574238 ns/op 810370 B/op 232 allocs/op
BenchmarkCollection_Query_100-8 13225 91058 ns/op 5177 B/op 95 allocs/op
BenchmarkCollection_Query_1000-8 2226 519693 ns/op 13552 B/op 140 allocs/op
BenchmarkCollection_Query_5000-8 550 2128121 ns/op 47108 B/op 173 allocs/op
BenchmarkCollection_Query_25000-8 100 10063260 ns/op 211705 B/op 205 allocs/op
BenchmarkCollection_Query_100000-8 30 39404005 ns/op 810295 B/op 229 allocs/op
PASS
ok github.com/philippgille/chromem-go 28.402s
go build ./...
go test -v -race -count 1 ./...
go test -benchmem -run=^$ -bench .
(add > bench.out
or similar to write to a file)go test -benchmem -run ^$ -cpuprofile cpu.out -bench .
-cpuprofile
, -memprofile
, -blockprofile
, -mutexprofile
)benchstat
: go install golang.org/x/perf/cmd/benchstat@latest
benchstat before.out after.out
In December 2023, when I wanted to play around with retrieval augmented generation (RAG) in a Go program, I looked for a vector database that could be embedded in the Go program, just like you would embed SQLite in order to not require any separate DB setup and maintenance. I was surprised when I didn't find any, given the abundance of embedded key-value stores in the Go ecosystem.
At the time most of the popular vector databases like Pinecone, Qdrant, Milvus, Chroma, Weaviate and others were not embeddable at all or only in Python or JavaScript/TypeScript.
Then I found @eliben's blog post and example code which showed that with very little Go code you could create a very basic PoC of a vector database.
That's when I decided to build my own vector database, embeddable in Go, inspired by the ChromaDB interface. ChromaDB stood out for being embeddable (in Python), and by showing its core API in 4 commands on their README and on the landing page of their website.