本地嵌入需先自行编译 libllama_go 原生库并放到动态库搜索路径,dist 里的预编译二进制早于 llama.cpp v0.4.1 的固定版本;需用 git lfs pull 拉取 MiniLM 模型和测试向量,否则集成测试跑不起来;Add 和 Search 会原地归一化并保留传入切片,之后不能再修改该切片。

git submodule update --init --recursive
git lfs pull
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --config Release --target llama_go --parallel本地嵌入默认 0 层 GPU 即用 CPU 推理;GPU 需在编译 llama.cpp 时加对应 CMake 开关(如 Vulkan),README 未给出具体显存或型号要求。核心检索包无原生依赖,可纯 CPU 运行。
Go 语言实现的精确余弦相似度向量检索库,自带本地和云端文本嵌入
用 Go 写的嵌入式向量检索库,底层调 llama.cpp 做语义向量和相似度搜索,适合直接在 Go 服务里加语义搜索能力,不用另起向量数据库。
核心能力
- 用精确余弦相似度做全量扫描检索,适合中小数据集
- 核心包纯 Go 实现,不依赖任何原生库
- 通过 llama.cpp 和 purego 在本地跑 GGUF 模型生成嵌入
- 支持 OpenAI 兼容 API 及 OpenRouter 云端嵌入
- 索引支持 ReadFile/WriteFile 等格式持久化
容易踩的坑
- v0.5.0最新正式版2026-09-19 · 2026-09-19 08:35 UTC
What's Changed
- Split embedded llama support into a dedicated module by @kelindar in https://github.com/kelindar/search/pull/11
Full Changelog: https://github.com/kelindar/search/compare/v0.4.1...v0.5.0
- v0.4.12026-03-06 · 2026-03-06 18:57 UTC
查看更新说明
What's Changed
- Regenerate build with omitted frame pointer by @kelindar in https://github.com/kelindar/search/pull/9
Full Changelog: https://github.com/kelindar/search/compare/v0.4.0...v0.4.1
- v0.4.02025-03-07 · 2025-03-07 19:34 UTC
查看更新说明
What's Changed
- Update llama.cpp to tag b4689 by @samyfodil in https://github.com/kelindar/search/pull/4
New Contributors
- @samyfodil made their first contribution in https://github.com/kelindar/search/pull/4
Full Changelog: https://github.com/kelindar/search/compare/v0.3.0...v0.4.0
- v0.3.02024-10-28 · 2024-10-28 19:15 UTC
查看更新说明
What's Changed
- Support save and restore of index by @kelindar in https://github.com/kelindar/search/pull/2
Full Changelog: https://github.com/kelindar/search/compare/v0.2.0...v0.3.0
- v0.2.02024-10-27 · 2024-10-27 18:54 UTC
查看更新说明
What's Changed
- Normalize to speed up distance calculation by @kelindar in https://github.com/kelindar/search/pull/1
New Contributors
- @kelindar made their first contribution in https://github.com/kelindar/search/pull/1
Full Changelog: https://github.com/kelindar/search/compare/v0.1.0...v0.2.0
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
Vector search and embeddings
An exact cosine similarity index for small and medium datasets, with optional local and cloud embedding providers. Requires Go 1.27 or newer.
| Package | Purpose |
|---|---|
github.com/kelindar/search | Vector indexing, search, and persistence. No native library required. |
github.com/kelindar/search/llama | Local GGUF embeddings through llama.cpp and purego. |
github.com/kelindar/search/openai | Text embeddings through OpenAI-compatible APIs, including OpenRouter. |
Each library has its own go.mod and go.sum. Core search has no dependency on either embedding module or purego. The openai module uses only the standard library at runtime; llama owns the native inference dependency. Testify and its YAML dependency are used only by tests. Import paths and APIs are unchanged.
The interactive example has a separate development module with local replacements for search and llama. Native quality evaluation lives under llama/internal/eval, so neither introduces provider dependencies into core search.
Search with your own vectors
index := search.NewIndex[string]()
index.Add([]float32{1, 0}, "cat")
index.Add([]float32{0, 1}, "dog")
results := index.Search([]float32{1, 0}, 1)
fmt.Println(results[0].Value) // cat
Add normalizes the vector in place and retains its backing array. Do not modify it afterward. Search normalizes the query in place. Results contain cosine similarity in descending order, so larger Relevance values are better. Use nonzero, finite vectors from the same model with the same dimensions for all documents and queries. Changing models requires re-embedding the dataset, even if dimensions match.
Existing ReadFile, WriteFile, ReadFrom, and WriteTo formats remain unchanged. Search scans every vector; large datasets may need a different indexing algorithm. Concurrent searches require separate query slices and no concurrent index writes.
Local embeddings
Import github.com/kelindar/search/llama and install the native library as described below.
model, err := llama.New("dist/MiniLM-L6-v2.Q8_0.gguf", 0)
if err != nil {
return err
}
defer model.Close()
vector, err := model.EmbedText(ctx, "Your text here")
Zero GPU layers uses the CPU. The library initializes on the first valid constructor call, never on import; initialization failures are returned as errors and cached for the process lifetime. Configure library paths before constructing a model.
Embedding calls on a model may run concurrently. Finish all calls and close any explicitly created model.Context(size) values before closing the model. Individual contexts must not be shared concurrently. Contexts retain Tokens() accounting. Cancellation is checked around native inference and between batch items; it cannot interrupt native inference already in progress.
Cloud embeddings
Import github.com/kelindar/search/openai. Supply credentials and a model explicitly.
client, err := openai.New(os.Getenv("OPENAI_API_KEY"), "text-embedding-3-small")
if err != nil {
return err
}
vector, err := client.EmbedText(ctx, "Your text here")
vectors, err := client.EmbedBatch(ctx, []string{"first document", "second document"})
For OpenRouter, use its base URL and model identifier:
client, err := openai.New(os.Getenv("OPENROUTER_API_KEY"), "openai/text-embedding-3-small",
openai.BaseURL("https://openrouter.ai/api/v1"),
)
Optional configuration uses Dimensions(n), Headers(http.Header), and HTTPClient(*http.Client). Defaults are the OpenAI /v1 endpoint, provider-default dimensions, no extra headers, and a 60-second HTTP timeout. A supplied HTTP client controls its own timeout. Headers are copied and cannot override authorization or content type. Clients may be shared concurrently; do not mutate a supplied HTTP client during use.
Batches use one HTTP request and return vectors in input order. Returned vectors belong to the caller. Empty batches do no work; failures return no partial results. There are no automatic retries or batch splitting. Local EmbedBatch uses sequential inference with the same result contract. Cloud support covers text, not multimodal inputs or provider-specific routing.
Custom providers
Any function returning []float32 can supply vectors to the index, without importing either provider package. Applications that swap providers can define their own small interface:
type Embedder interface {
EmbedText(context.Context, string) ([]float32, error)
}
Both built-in providers satisfy this interface. See the custom-provider example.
Migration and tests
Replace search.NewVectorizer(path, layers) with llama.New(path, layers), search.Vectorizer with llama.Vectorizer, and search.Context with llama.Context. Pass a context.Context as the first argument to EmbedText, including calls on explicit local contexts. Index APIs and saved files require no migration.
Run go test ./... separately from the repository root, llama, openai, and example. Root ./... does not cross module boundaries. Native model and quality tests are opt-in via go test -tags integration ./... from llama; they require the native library on its platform search path and the repository's MiniLM model and evaluation fixtures. The native source is pinned to llama.cpp v0.4.1. The binaries in dist predate that pin; build the wrapper from source for the updated version. Build instructions below apply only to local embeddings.
Nested modules are released with their own tags: llama/vX.Y.Z and openai/vX.Y.Z. Root releases continue to use vX.Y.Z. Tests and module maintenance run with GOWORK=off in CI to verify isolation.
🛠 Compile library
First, clone the repository and its submodules with the following commands. This checks out the pinned llama.cpp source and retrieves the model and vector fixtures.
git submodule update --init --recursive
git lfs pull
Compile on Linux
Make sure you have a C/C++ compiler and CMake installed. For Ubuntu, you can install them with the following commands:
sudo apt-get update
sudo apt-get install build-essential cmake
Then you can compile the library with the following commands:
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_COMPILER=gcc ..
cmake --build . --config Release --target llama_go --parallel
This should generate libllama_go.so that statically links everything necessary. You can also install the library by coping it into /usr/lib.
Compile on macOS
Make sure you have Xcode Command Line Tools and CMake installed:
xcode-select --install
brew install cmake
Then compile the library:
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --config Release --target llama_go --parallel
This generates libllama_go.dylib in build/lib. If you run the Go tests or example from the repository root, point the dynamic loader to that directory:
cd llama
DYLD_LIBRARY_PATH="$(pwd)/../build/lib" go test -tags integration ./...
Compile on Windows
Make sure you have a C/C++ compiler and CMake installed. For Windows, a simple option is to use Build Tools for Visual Studio (make sure CLI tools are included) and CMake.
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --config Release --target llama_go --parallel
If you are using Visual Studio, solution files are generated. You can open the solution file with Visual Studio and build the project from there. The bin/Release directory contains llama_go.dll. Add that directory to PATH before running local embeddings or integration tests.
GPU and other options
To enable GPU support (e.g. Vulkan), you'll need to add an appropriate flag to the CMake command, please refer to refer to the llama.cpp build documentation for more details. For example, to compile with Vulkan support on Windows make sure Vulkan SDK is installed and then run the following commands:
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release -DGGML_VULKAN=ON ..
cmake --build . --config Release --target llama_go --parallel