Late-interaction first-stage retriever (ColBERT / MaxSim) for BrainAPI POST /retrieve/search. It keeps its own token-embedding index (plugin-local, in memory) and registers channel plugin:colbert. It does not run on /retrieve/context. Core hybrid works if this plugin is absent.
Unknown or missing plugin:colbert is 400, never treated as a ranking miss.
| Registry name | search-colbert |
| Version | 0.1.0 |
| BrainAPI | >=2.17.0 |
| Channel | plugin:colbert |
| Default model | colbert-ir/colbertv2.0 |
| Index | POST /search-colbert/index |
| Health | GET /search-colbert/health |
git clone https://github.com/Lumen-Labs/brainapi-plugin-search-colbert.git plugins/search-colbertOr:
./bin/brainapi install search-colbertRestart the API. Encoding needs torch and transformers. Optional numpy speeds up MaxSim (a pure-Python fallback exists). The checkpoint is lazy-loaded on first encode. Device order: MPS → CUDA → CPU.
curl -X POST "$BRAINAPI_URL/search-colbert/index" \
-H "Content-Type: application/json" \
-H "BrainPAT: $BRAINPAT_TOKEN" \
-d '{"brain_id": "searchbenchsmoke", "limit": 1000}'
curl -X POST "$BRAINAPI_URL/retrieve/search" \
-H "Content-Type: application/json" \
-H "BrainPAT: $BRAINPAT_TOKEN" \
-H "X-Brain-ID: searchbenchsmoke" \
-d '{
"query": "navy wool coat",
"k": 50,
"channels": ["plugin:colbert"]
}'You can fuse with core passages (channels: ["passages", "plugin:colbert"]). Frozen-head merge of plugin lists into the default passages head is a core /retrieve/search behavior — it is not the omitted-channels default (["passages"] only).
Benchmark harness: --channels plugin:colbert after indexing.
POST /search-colbert/indexpages text chunks (up tolimit, max 20 000) and encodes each doc to a list of token vectors (CLS/SEP stripped when possible). Max sequence length 180.- A query is encoded the same way.
- Score is MaxSim: for each query token, take max cosine similarity over document tokens, then sum.
- Top
kchunk ids go back to/retrieve/search.
The index lives in process. Restarting the API clears it. index_chunks(..., replace=True) (the HTTP route) resets that brain first.
This is a first-stage plugin, not PLAID-scale serving. Expect it to be slower than BM25/dense on large catalogs.
| Env | Default |
|---|---|
SEARCH_COLBERT_MODEL |
colbert-ir/colbertv2.0 |
Tests can inject set_encoder(fn).
{
"plugin": "search-colbert",
"channel": "plugin:colbert",
"model": "colbert-ir/colbertv2.0",
"loaded": false,
"error": null,
"index": { "brain_id": "searchbenchsmoke", "n_docs": 2043 }
}index is included only when brain_id is passed.
{ "brain_id": "searchbenchsmoke", "limit": 1000 }limit is 1…20000 (default 1000). Returns { brain_id, n_docs }.
search-colbert/
plugin.yaml
main.py # register_search_retriever("colbert", …)
encode.py # ColBERT token encoder
index.py # MaxSim index + retrieve
routes.py # health + index
Pushes to main publish to the BrainAPI registry via GitHub Actions.
Apache License, Version 2.0. See LICENSE.
- search-splade
- search-rerank
- BrainAPI
docs/research/18-search-eval-protocol.mdon brainapi2