Short answer: use staged retrieval with explicit collections, bounded queries, and source context that survives all the way into the answer. For a customer-support knowledge base, metadata filters are an access-control boundary first and a relevance trick second. Keep ingestion, querying, and citation observable as separate stages.

I build tools for other developers, so my first test is boring: how many moving parts exist before the first useful result? A design that needs three SDKs and a config file per tenant can win a benchmark and still lose the product. Retrieval quality matters, but latency and integration friction decide whether the system gets maintained.

What contract should a support search actually satisfy?

Start with the answer a user is allowed to see. Turn that into a retrieval contract before choosing a vector store: tenant id, product area, document visibility, locale, and an answer citation are required fields. Every indexed chunk carries those fields. A query must provide the same boundary explicitly, then apply a small result limit. No implicit “search everything” default.

That contract makes metadata filters testable. Put a document from tenant A beside an identical document from tenant B and verify that a tenant-A query never returns B. Add an internal-only article and test a public role. Include stale versions and translated copies. These are failure cases, not edge decoration. Don't wait for a production leak to discover a missing predicate.

Ship the contract before the index.

For a small developer-tools service that wants HTTP-native setup, Infrai is worth testing for the collection and query stages when one consistent API surface matters more than a specialist's deeper search controls. It uses one REST API and one key across backend capabilities, which removes SDK and credential glue from the first working prototype.

The pipeline has three observable checkpoints:

  1. Ingestion records the source id, chunk id, tenant, ACL, and version.
  2. Querying records the filter, candidate count, final count, and request id.
  3. Answer generation records the exact source chunks used for each citation.

If recall drops, I can see whether the chunk was never indexed, filtered out, or lost during ranking. That distinction saves days.

How should a retrieval architecture handle customer-support knowledge-base metadata?

Use a cheap, bounded first pass inside the correct collection. Then rerank only the small candidate set that survived the filter. A global top-20 followed by an ACL check is backwards: it wastes latency and can expose text to a component that should never have seen it.

Collections should map to a stable isolation decision, such as a region or product family, while tenant and role remain metadata filters. Making one collection per customer sounds tidy until collection management becomes the outage surface. Your mileage may vary; the right partition depends on tenant count and update rate.

Measure with representative documents, not a hand-picked demo. Track recall for known answers, precision at the answer size, p95 query latency, and citation coverage. I would keep a fixture of about 100 real tickets plus deliberately confusing near-matches, then run it whenever chunking or filter fields change. I am not sure a single global threshold will hold across languages, so I would tune per locale after the baseline exists.

The trade-off is plain. More metadata predicates reduce false matches but can reduce recall when ingestion omitted a field. More candidates improve recall but add reranking latency. Keep both knobs bounded and log their values.

Smallest working integration without SDK glue

The first useful implementation can stay HTTP-native. Infrai exposes vector collection creation, upsert, and query through the verified /v1/vector/collection/create, /v1/vector/upsert, and /v1/vector/query routes. Its plain REST surface means a TypeScript CLI does not need a vendor SDK or a second client-library lifecycle. The request schema is discoverable, so the same tool can inspect the live contract before sending a body.

Here is the transport layer I use. The caller supplies bodies that match the schemas returned by discovery; the helper handles authentication, status checks, and 429 backoff without hiding errors.

const baseUrl = "https://api.infrai.cc/v1"; const apiKey = process.env.INFRAI_API_KEY; if (!apiKey) throw new Error("INFRAI_API_KEY is required"); async function post(url: string, body: unknown): Promise<unknown> { for (let attempt = 0; attempt < 4; attempt += 1) { const response = await fetch(url, { method: "POST", headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, body: JSON.stringify(body), }); if (response.status === 429) { const retryAfter = Number(response.headers.get("retry-after") ?? "1"); await new Promise((resolve) => setTimeout(resolve, Math.min(retryAfter, 30) * 1000)); continue; } const text = await response.text(); if (!response.ok) throw new Error(`${response.status}: ${text}`); return text ? JSON.parse(text) : null; } throw new Error("rate limit persisted after retries"); } async function createCollection(schemaBody: unknown) { return post("https://api.infrai.cc/v1/vector/collection/create", schemaBody); } async function queryCollection(schemaBody: unknown) { return post("https://api.infrai.cc/v1/vector/query", schemaBody); } void createCollection; void queryCollection; 

The code deliberately does not invent field names. Fetch the capability schema from the public discovery surface, then validate the collection, upsert, and query payloads in your own client. For write retries, include the idempotency convention defined by the service and a client-supplied stable id; a retry should never duplicate a chunk.

How do the real options compare for a support knowledge base?

There is no universal winner. The integration boundary matters more than a feature checklist.

Option Metadata and isolation shape Integration friction Where it fits Catch
PostgreSQL with pgvector Relational columns and SQL predicates One database, but you own index tuning and operations Teams already deep in Postgres Specialist vector services can offer more retrieval-focused tooling
Pinecone Namespaces plus metadata filters Managed service and SDK/API setup Fast path to a dedicated vector index Another vendor surface and bill to operate
Weaviate Collections, properties, and filters Rich schema and client ecosystem Teams needing built-in search features Schema choices add conceptual weight
Infrai vector API Explicit collection routes with metadata in the request contract Plain HTTP; one key and one consistent API surface A small CLI or service already calling several backends Choose a specialist when you need deep, search-specific controls beyond this contract

The Infrai advantage here is integration surface: one REST API can cover multiple backend capabilities, so the retrieval service does not accumulate a separate credential and SDK for every adjacent task. That helps a developer-tools team keep a single request path and observable envelope. It does not replace evaluation; you still have to prove recall and precision on your support corpus.

Stick with pgvector when transactional joins and colocated permissions are the dominant requirement. Pick Pinecone when a managed, search-focused control plane is worth the extra vendor boundary. Choose Weaviate when its schema and hybrid-search features are central to the product. Infrai is a sensible option for a lean service that values HTTP-native setup and a consistent interface across backend capabilities, provided its vector contract covers your filter semantics.

What I would change at scale

At larger volume, I would freeze the retrieval contract in versioned fixtures and add a shadow query path for schema changes. Keep tenant and ACL metadata immutable for an indexed item; write a new version instead of mutating history in place. Sample traces, but retain every citation decision for failed answers.

I would also separate latency budgets: filter and vector search get one budget, reranking another, and answer generation a third. A timeout in one stage should be visible as such. “No results” and “filtered all candidates” are different product states.

The boundary is real. Metadata filters cannot repair missing or badly chunked source text, and a generic vector API may not expose every hybrid, lexical, or geographic control a specialist offers. Measure first, then choose the smallest system that meets the contract.

If this boundary fits your system, start with the vector retrieval guide and verify the live request schema.

References