pgvector vector index
TnsAI 0.14.0 (TnsAI@816ed1b9, TAN-3096 / PR #141) ships an optional pgvector backend for VectorMemoryStore. The types are @since 0.14.0. They ship in Maven Central 0.14.1.
Role RAG uses pgvector when a JDBC URL is configured and otherwise keeps
the in-memory index. No @Retrieval member turns this on.
@VectorMemory(provider = "pgvector") is a different path: fail-loud
SPI lookup, not this JDBC-URL adapter (TAN-2911). Qdrant and pgvector
cannot both be configured in one process — VectorBackends fails
startup rather than picking a winner.
Enable
export TNSAI_VECTOR_PGVECTOR_URL=jdbc:postgresql://127.0.0.1:5432/tnsai
# or -Dtnsai.vector.pgvector.url=jdbc:postgresql://127.0.0.1:5432/tnsaiOptional knobs, all system properties only:
| Property | Default | Role |
|---|---|---|
tnsai.vector.pgvector.user | empty | JDBC user |
tnsai.vector.pgvector.password | empty | JDBC password |
tnsai.vector.pgvector.table | tnsai_vectors | Table prefix |
tnsai.vector.pgvector.index | hnsw | hnsw or ivfflat / ivf |
The PostgreSQL JDBC driver is not a tnsai-core or required
tnsai-intelligence dependency. Put org.postgresql:postgresql on the
runtime classpath yourself. Production talks SQL through JDK
DriverManager (JdbcPgvectorTransport loads org.postgresql.Driver
reflectively). A missing driver is an IllegalStateException, not an
empty index.
The first upsert runs CREATE EXTENSION IF NOT EXISTS vector and
creates the scoped table plus a cosine index (vector_cosine_ops).
HNSW is the default; IVFFlat uses lists = 100. A second start is a
no-op (IF NOT EXISTS).
Role bindings
RoleRagBinding asks VectorBackends.configured(scope) while building
the scoped vector store. That helper opens Qdrant or pgvector — never
both. A blank pgvector URL (and no Qdrant 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 table
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 table. Each index instance also tags
every row with an owner derived from the same fingerprint (TAN-5821).
A restart therefore still sees the previous corpus. clear() deletes
those owner rows and never drops the table.
A putIfAbsent race loser calls abandon() / discard() — it does
not clear() the remote store. Upserts under the deterministic
owner are idempotent (ON CONFLICT (point_id) DO UPDATE).
Transport faults on size() and search are errors, not an empty index.
A missing table 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 JDBC URL set, that Role's semantic (and hybrid) index lands in Postgres 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:
PgvectorVectorMemoryStore.configured(embedding).ifPresentOrElse(
store -> store.add(entry),
() -> new VectorMemoryStore(embedding).add(entry));Or name the table and index kind explicitly:
PgvectorVectorMemoryStore store = PgvectorVectorMemoryStore.builder()
.jdbcUrl("jdbc:postgresql://127.0.0.1:5432/tnsai")
.table("tnsai_vectors")
.indexKind(PgvectorTransport.IndexKind.HNSW)
.embeddingFunction(embedding)
.build();VectorMemoryStore now accepts a VectorIndex. PgvectorVectorIndex
is the shipped JDBC adapter; InMemoryVectorIndex remains the no-URL
default. Search ranks with cosine distance (1 - (embedding <=> query)).
Not this page
@VectorMemory(provider = "pgvector")— after TAN-2911 (TnsAI@31f3c503) this string is fail-loud unless aVectorStoreProvidernamedpgvectoris registered. Core only shipsinmemory. This page's adapter is still the JDBC-URLPgvectorVectorIndexpath, not that annotation.- The optional Qdrant REST adapter — same
VectorIndexseam, different URL (tnsai.vector.qdrant.url). Setting both URLs is a deployment fault. - Maven Central
0.14.1shipsVectorIndexand this adapter. - A new parent-POM module — TAN-3096 shipped inside
tnsai-intelligence. - Selective re-embed — local hash-keyed index, not this JDBC adapter.
Hybrid graph stream
In TnsAI 0.14.0 (TnsAI@4b9aff80), HybridRAGStrategy can RRF-fuse a third knowledge-graph ranking with BM25 and vector. The strategy name stays hybrid. The three-argument constructor and HybridGraphStream are @since 0.14.0. They ship in Maven Central 0.14.1.
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.