Skip to content
tnsaijava agent framework

Qdrant vector index

TnsAI 0.14.0 (TnsAI@01fba8ef, TAN-3101 / PR #131) ships an optional Qdrant backend for VectorMemoryStore. The types are @since 0.14.0. They ship in Maven Central 0.14.1.

Role RAG uses Qdrant when a URL is configured and otherwise keeps the in-memory index. No @Retrieval member turns this on. @VectorMemory(provider = "qdrant") is a different path: fail-loud SPI lookup, not this env-URL adapter (TAN-2911).

Enable

export TNSAI_VECTOR_QDRANT_URL=http://localhost:6333
# or -Dtnsai.vector.qdrant.url=http://localhost:6333

Optional knobs, both system properties only:

PropertyDefaultRole
tnsai.vector.qdrant.collectiontnsaiCollection prefix
tnsai.vector.qdrant.apiKeyemptySent as the api-key header

The official Qdrant Java client is not a tnsai-core or required tnsai-intelligence dependency. Production talks REST through JDK HttpClient (HttpQdrantTransport: 5 s connect, 15 s request).

Role bindings

RoleRagBinding asks QdrantVectorIndex.configured(scope) while building the scoped vector store. A blank URL returns empty and the binding constructs new VectorMemoryStore(embedding) as before.

The scope is the Role class plus the selected source-name set. The collection becomes prefix + _ + the first sixteen hex digits of the SHA-256 of that scope (fingerprint walks eight bytes and writes two hex chars each), so two Roles never share a collection. Each index instance also tags every point with an instanceId owner derived from the same fingerprint (ownerFor(scope); a blank scope uses SHARED_OWNER) — TAN-5821. A restart therefore still sees the previous corpus. clear() deletes those owner points and never drops the collection.

A putIfAbsent race loser calls abandon() / discard() — it does not clear() the remote store. Upserts under the deterministic owner are idempotent.

Transport faults on size() and search are errors, not an empty index. A missing collection (404) is the one quiet case: size is 0 and search is empty.

@KnowledgeSource(name = "handbook", path = "knowledge/handbook")
@Retrieval(strategy = Retrieval.Strategy.SEMANTIC)
public final class HandbookRole extends Role {
}

With the URL set, that Role's semantic (and hybrid) index lands in Qdrant and survives a process restart. Without the URL, the same declaration stays in-process.

Standalone store

Programmatic callers can open the same adapter without a Role:

QdrantVectorMemoryStore.configured(embedding).ifPresentOrElse(
        store -> store.add(entry),
        () -> new VectorMemoryStore(embedding).add(entry));

Or name the collection explicitly:

QdrantVectorMemoryStore store = QdrantVectorMemoryStore.builder()
        .url("http://localhost:6333")
        .collection("tnsai")
        .embeddingFunction(embedding)
        .build();

VectorMemoryStore now accepts a VectorIndex. QdrantVectorIndex is the shipped adapter; InMemoryVectorIndex remains the no-URL default.

Not this page

  • @VectorMemory(provider = "qdrant") — after TAN-2911 (TnsAI@31f3c503) this string is fail-loud unless a VectorStoreProvider named qdrant is registered. Core only ships inmemory. This page's adapter is still the env-URL QdrantVectorIndex path, not that annotation.
  • tnsai-tools QdrantTools — a separate agent-tool surface for collections and upserts, not the RAG VectorIndex.
  • Maven Central 0.14.1 ships VectorIndex and this adapter.
  • Selective re-embed — local hash-keyed index, not this REST adapter.