| layout | default |
|---|---|
| title | Embeddings & Vector Stores |
| parent | Core Development |
{: .no_toc }
Embeddings modules turn source documents into vectors and register the retrieval/indexing dependency that the core backend needs at runtime. Vector store modules persist those vectors and execute similarity search. In AI Crew Suite, pgvector also persists agent runtime state, so this layer supports both RAG context and durable agent execution history.
The shared VectorStore contract is intentionally small:
interface VectorStore {
connectEmbeddings(embeddings: Embeddings): void;
addDocuments(docs: EmbeddingDoc[]): Promise<void>;
deleteDocuments(params: {
ids?: string[];
filter?: EmbeddingDocMetadata;
}): Promise<void>;
similaritySearch(
query: string,
filter?: EmbeddingDocMetadata,
amount?: number,
): Promise<EmbeddingDoc[]>;
}Indexers connect the embedding model before writing documents. Retrievers use similaritySearch with optional metadata filters. The current default vector retriever filters by { source } for source-specific queries and omits the filter for the special all source.
@ai-crew-suite/agent-alert-tuner-backend-module-storage-pgvector provides the createPgVectorStore factory, which applies migrations, reads vector-store config, and returns a VectorStore implementation. Agent runtime persistence is provided separately by @ai-crew-suite/agent-alert-tuner-backend-module-runtime-store.
The module uses the Backstage database service and Knex. PostgreSQL must support the vector extension for embedding similarity search. The historical uuid-ossp requirement may still matter for existing deployments or migrations; verify the active migration before changing database extension assumptions.
Example vector storage config:
ai:
storage:
pgVector:
chunkSize: 500
amount: 10chunkSize controls batched inserts. amount controls the default number of similar documents returned when a caller does not provide an explicit retrieval amount.
Agent runtime persistence is owned by @ai-crew-suite/agent-alert-tuner-backend-module-runtime-store, which registers stores with the core backend plugin through the runtimeStoreExtensionPoint. Its SQL implementation, SqlAgentRuntimeStore, runs on any database supplied by the Backstage database service (PostgreSQL, MySQL, or SQLite) and implements:
SessionStorefor conversation messages.CheckpointStorefor resumable orchestration state.RunStorefor run records, event logs, statuses, idempotency keys, and approvals.ArtifactSinkfor generated artifact references.AuditLogSinkfor approval and write-action audit records.
Sessions and checkpoints can optionally be redirected to a dedicated Redis connection through ai.runtime.stores configuration; run, approval, artifact, and audit records always use the SQL store.
Message listing returns recent messages in chronological order after applying the limit. JSON payloads are parsed defensively so callers receive structured payloads even when database drivers return serialized JSON strings.
@ai-crew-suite/agent-alert-tuner-backend-module-storage-qdrant provides createQdrantVectorStore, an alternate VectorStore implementation backed by a Qdrant server instead of PostgreSQL. It covers vector storage and similarity search only; agent runtime persistence (sessions, checkpoints, runs, artifacts, approvals, and audit logs) remains owned by the pgvector storage module.
The store lazily creates the configured collection on first use, deriving the vector size from the first embedded batch and using cosine distance. Metadata filters translate to Qdrant must match clauses on metadata.* payload keys, and documents are stored as point payloads with content and metadata fields.
Example vector storage config:
ai:
storage:
qdrant:
url: http://localhost:6333
apiKey: ${QDRANT_API_KEY}
collectionName: embeddings
chunkSize: 500
amount: 10url falls back to the QDRANT_URL environment variable and then http://localhost:6333; apiKey falls back to QDRANT_API_KEY. collectionName defaults to embeddings. chunkSize controls batched upserts and amount controls the default number of similar documents returned, matching their pgvector counterparts.
Point IDs are generated UUIDs, so deletion by explicit ID only accepts Qdrant point IDs. Metadata-filter deletion and similarity search behave the same as the pgvector store from the caller's perspective.
Embeddings providers register tools through toolExtensionPoint. Each tool exposes both an augmentationIndexer and a retrievalPipeline, which lets plugin-ai-core-backend create the generic knowledge.retrieve tool.
@ai-crew-suite/agent-alert-tuner-backend-module-llm-aws creates a pgvector store, constructs BedrockAugmenter, creates the default retrieval pipeline, and registers aws.bedrock.retrieval.
Provider config lives at ai.embeddings.bedrock:
ai:
embeddings:
chunkSize: 1000
chunkOverlap: 200
concurrencyLimit: 10
bedrock:
modelName: amazon.titan-embed-text-v1
region: us-east-1
maxRetries: 3
maxConcurrency: 100modelName is required and must not be blank. Region falls back to AWS_REGION, then AWS_DEFAULT_REGION, then us-east-1. Cohere Bedrock models use the Cohere-specific embedding wrapper; model detection is case-insensitive.
@ai-crew-suite/agent-alert-tuner-backend-module-llm-openai creates a pgvector store, constructs OpenAiAugmenter, creates the default retrieval pipeline, and registers openai.embeddings.retrieval.
Provider config lives at ai.embeddings.openai:
ai:
embeddings:
chunkSize: 1000
chunkOverlap: 200
concurrencyLimit: 10
openai:
openAiApiKey: ${OPENAI_API_KEY}
openAiBaseUrl: https://api.openai.com
modelName: text-embedding-3-large
batchSize: 512
embeddingsDimensions: 3072batchSize and embeddingsDimensions must be positive when supplied. If openAiApiKey is omitted, the OpenAI SDK follows its environment-variable behavior.
Several config keys sound similar but tune different layers of the pipeline. Keep these meanings separate when reviewing changes or debugging retrieval quality.
| Key | Layer | What it measures | Change risk |
|---|---|---|---|
ai.embeddings.chunkSize |
Ingestion | Approximate text length per chunk before embedding. | Safe to tune, but requires re-indexing to affect existing documents. |
ai.embeddings.chunkOverlap |
Ingestion | Text carried across adjacent chunks to preserve boundary context. | Safe to tune, but requires re-indexing to affect existing documents. |
ai.embeddings.concurrencyLimit |
Ingestion | Number of concurrent source document processing tasks. | Safe to tune for throughput and provider pressure. |
ai.embeddings.openai.batchSize |
Provider API | Number of chunks sent in one embedding request batch. | Safe to tune within provider limits. |
ai.embeddings.openai.embeddingsDimensions |
Embedding model | Numeric vector length produced per text chunk. | Destructive unless the vector table is rebuilt or isolated by dimension. |
ai.storage.pgVector.chunkSize |
Database writes | Rows per bulk insert batch into PostgreSQL. | Safe to tune for database memory and write throughput. |
ai.storage.pgVector.amount |
Retrieval | Default number of nearest documents returned by similarity search. | Safe to tune, but it changes prompt size and retrieval diversity. |
chunkSize is about source text. embeddingsDimensions is about vector shape. A 1,000-character text chunk can produce a 1,536-dimension vector, a 3,072-dimension vector, or another length depending on the embedding model. Those two values should not be compared or tuned as if they are the same unit.
storage.pgVector.chunkSize is also unrelated to text chunking. It is a database flush size: how many vector rows to insert per batch after the embedding provider has already returned vectors.
Chunk size controls the tradeoff between retrieval precision, context completeness, and downstream prompt cost.
| Content type | Suggested starting range | Why |
|---|---|---|
| Catalog entities, YAML, JSON, OpenAPI fragments | 250-500 characters | Highly structured content often contains many unrelated fields; smaller chunks avoid mixing distinct endpoints or ownership metadata. |
| TechDocs how-to guides and README-style docs | 800-1,200 characters | Keeps a conceptual paragraph and nearby command or code block together without bloating the prompt. |
| ADRs, RFCs, and long-form architecture notes | 1,500-2,000 characters | Preserves rationale and surrounding context that may be needed to answer design questions. |
For the default catalog and TechDocs ingestion path, start with:
ai:
embeddings:
chunkSize: 1000
chunkOverlap: 200That gives roughly a 20% overlap buffer. Increase chunkSize when retrieved snippets contain the answer but cut off the explanation or code example. Decrease it when retrieval pulls in long, only loosely related sections that crowd out more precise context.
Overlap reduces boundary loss. Without overlap, a sentence, list item, or code example that straddles two chunks can lose meaning in both vectors. With chunkSize: 1000 and chunkOverlap: 200, the splitter advances by about 800 characters per chunk:
Chunk 1: characters 0-1000
Chunk 2: characters 800-1800
Chunk 3: characters 1600-2600
Use overlap when source documents are prose-heavy or contain explanatory code blocks. Keep it modest; very high overlap increases duplicate vectors, indexing cost, and the chance that near-identical chunks dominate the top retrieval results.
Provider batchSize and ingestion concurrencyLimit affect indexing throughput, not retrieval semantics.
batchSize groups multiple text chunks into one provider request. Larger batches reduce HTTP overhead but can hit provider payload limits, rate limits, or memory pressure. concurrencyLimit controls how many indexing tasks run at once, which is especially important when loading many TechDocs search indexes.
When tuning throughput:
- Increase
batchSizeuntil provider latency improves or provider limits become visible. - Increase
concurrencyLimitonly when the provider and Backstage services can absorb the parallelism. - Watch indexing logs for partial TechDocs failures, provider throttling, and vector-count mismatches.
- Keep database
storage.pgVector.chunkSizeseparate; tune it based on PostgreSQL insert performance.
Embedding dimensions are part of the storage contract even when they are not represented as a separate config field in the vector store. Changing embedding models, dimensions, or provider-specific dimension options can make old vectors incompatible with new query vectors.
When changing dimensions:
- Confirm the new model's vector length.
- Plan whether to truncate, migrate, or rebuild existing rows.
- Clear or rebuild affected source embeddings.
- Re-index every source that will be queried with the new model.
- Run retrieval tests against representative catalog and TechDocs content.
Do not mix vectors from different dimensions in the same pgvector table unless the table schema and query code explicitly support that layout.
DefaultVectorAugmentationIndexer.createEmbeddings deletes existing documents for the requested supported source/filter before writing new documents. deleteEmbeddings resolves matching catalog entities and deletes the vector documents for their metadata.
PgVectorStore.deleteDocuments supports deleting by explicit IDs or by metadata filter. Avoid passing both unless the implementation has been intentionally updated and tested for that combination.
When changing embeddings or vector storage behavior:
- Add tests around vector count validation, deletion filters, similarity filters, and provider config validation.
- Re-index affected sources after changing chunking, metadata fields, embedding model, or dimensions.
- Keep
EmbeddingDoc.metadata.sourcepopulated; retrieval routing depends on it. - Validate provider errors at module startup where possible instead of during the first indexing run.
- Update Ingestion Pipelines if indexing source behavior changes.
- Update LLM Providers only when a module also registers executable generation models.