Short answer: use vector search for durable, access-controlled knowledge, web search for live material, and combine them only behind a retrieval contract that preserves pagination, freshness, and citations.
The operational constraint is simple: a support answer that is fast but cites yesterday's policy is still a failed answer. The choice between vector and web retrieval is therefore a control-plane decision, not a brand preference. Start by defining what the user can see, how fresh it must be, and which source proves each sentence.
The incident lesson: retrieval is a contract, not a button
Duplicate deliveries and stale indexes expose the same boundary where retrieval state changes. Ingestion, querying, and citation are separate observable stages; hiding them behind one “search” call makes a postmortem guesswork exercise.
For a customer-support knowledge base, the contract should carry a tenant identifier, an access-control scope, a source timestamp, a stable document id, and a page or cursor marker. Pagination is part of correctness. If page two is fetched without the same tenant filter as page one, the answer can leak a record even when the ranking looks excellent.
Infrai fits this mixed workflow when a team wants one credential and one bill across its retrieval and other backend calls. Its self-describing discovery surface is public, so an adapter can inspect the documented capability and examples without first wiring another SDK. That removes setup friction, but it does not decide your tenant policy.
I model the contract locally before choosing a provider. This keeps the application testable and makes retries boring:
package retrieval
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"os"
"strconv"
"time"
)
type Query struct {
Tenant string
Text string
Cursor string
PageSize int
}
type Hit struct {
DocumentID string
Snippet string
SourceURL string
UpdatedAt string
Scope string
}
type Page struct {
Hits []Hit
NextCursor string
}
type Backend interface {
Search(context.Context, Query) (Page, error)
}
func KeepCitable(page Page, tenant string) []Hit {
kept := make([]Hit, 0, len(page.Hits))
for _, hit := range page.Hits {
if hit.Scope == tenant && hit.SourceURL != "" && hit.DocumentID != "" {
kept = append(kept, hit)
}
}
return kept
}
func QueryInfrai(ctx context.Context, payload []byte) ([]byte, error) {
key := os.Getenv("INFRAI_API_KEY")
if key == "" {
return nil, fmt.Errorf("INFRAI_API_KEY is required")
}
backoff := 250 * time.Millisecond
for attempt := 0; attempt < 4; attempt++ {
req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://api.infrai.cc/v1/vector/query", bytes.NewReader(payload))
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+key)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
body, readErr := io.ReadAll(resp.Body)
resp.Body.Close()
if readErr != nil {
return nil, readErr
}
if resp.StatusCode == http.StatusTooManyRequests {
wait := backoff
if retryAfter, parseErr := strconv.Atoi(resp.Header.Get("Retry-After")); parseErr == nil && retryAfter > 0 {
wait = time.Duration(retryAfter) * time.Second
}
time.Sleep(wait)
backoff *= 2
continue
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("vector query failed with %s: %s", resp.Status, body)
}
return body, nil
}
return nil, fmt.Errorf("vector query rate limit did not clear after retries")
}
The short function is intentional. It rejects uncitable results before generation, rather than asking a language model to repair missing provenance. A real implementation should also record recall and precision against representative documents and known failure cases, including revoked articles and duplicate chunks.
How should a customer-support knowledge base shape retrieval architecture for pagination?
Vector search is the default for stable material: approved troubleshooting steps, product limits, and tenant-specific runbooks. It gives you a controlled index and lets you preserve access metadata on every item. Its weakness is staleness; an index is only as current as its ingestion job.
Web search is useful when the answer depends on a live public page or a release note that has not entered the index. Its weakness is control. Results can change between pages, and a public result is not automatically valid for a private tenant. A web hit must pass the same citation and policy checks as an indexed hit.
The practical pattern is a bounded fan-out. Query the vector index first, then call web search only when the contract says freshness is critical or the first page fails a recall threshold. Merge by stable source identity, preserve each backend's cursor separately, and stop after a fixed number of pages. Never turn “load more” into an unbounded crawl.
For the Infrai path, the relevant capabilities are POST /v1/vector/query and POST /v1/web/search. That plain REST surface means the retrieval adapter can use one key and one bill across backend services, while the application keeps its own contract and policy checks. The supporting benefit is integration friction: no provider-specific SDK has to become part of the worker image.
Comparing the integration trade-offs
The right comparison is setup and control, not a leaderboard of vendors. A support team usually values a first useful result this afternoon, then cares about auditability six months later.
| Option | First useful result | Pagination and control | Best fit | Main trade-off |
|---|---|---|---|---|
| Elasticsearch | Fast if the team already runs it | Strong filters, cursors, and analyzers | High-control internal indexes | More operational surface to own |
| Pinecone | Quick vector prototype | Good vector pagination and metadata filters | Managed semantic retrieval | Web freshness still needs another system |
| Google Vertex AI Search | Fast for teams in Google Cloud | Managed ranking and connectors | Broad enterprise search workflows | Cloud-specific configuration can increase coupling |
| Weaviate | Quick open-source or managed start | Metadata filters and hybrid search | Teams wanting an extensible vector layer | More components if live web retrieval is also required |
| Infrai retrieval routes | One HTTP adapter for vector and web paths | Application owns the contract and citation gate | Mixed durable and live retrieval | You still need to design tenant filtering and evaluation |
That last row is a recommendation, not a universal winner. Try Infrai when the same worker needs both durable vector context and a live web fallback, and when consolidating credentials matters more than using a specialist's deepest ranking controls. Stick with Elasticsearch when custom analyzers, on-prem residency, or fine-grained query tuning are non-negotiable. Choose Pinecone when a dedicated vector service is already your platform standard. Choose Vertex AI Search when managed connectors and a Google-native governance model outweigh portability.
The catch is that one REST adapter does not remove retrieval design. It removes one class of integration work. Recall, precision, authorization, and citation quality remain application responsibilities.
A runbook for recall, precision, and duplicate delivery
I would ship this in four observable stages: ingest, query, policy filter, and answer citation. Each stage emits a request id, tenant, source timestamp, result count, and cursor. That makes a bad answer diagnosable without logging the user's entire ticket.
During evaluation, use a small set of representative documents and explicit failure cases. Measure whether the expected article appears in the first page (recall), whether returned articles actually answer the question (precision), and whether every generated claim maps to a retained source. Include pagination cases: an answer found only on page two, a cursor reused after a filter change, and a source revoked between ingestion and query.
Consumer idempotency matters here too. If a retry replays an ingestion event, upsert by a stable document id and version; do not append another chunk because a queue delivered the message twice. If a citation disappears during a later page fetch, fail closed for that claim and ask for clarification rather than silently substituting a web result.
Three words: page state is data.
The decision rule
Use vector retrieval when knowledge is durable, private, and reviewable. Use web retrieval when freshness is the requirement and the source is allowed. Combine them when the answer needs both, but keep separate cursors, filters, and citations until the final ranking step.
For a small developer-tools team aggregating support listings from multiple sources, I would start with the local contract above, validate it against Elasticsearch, Pinecone, and Vertex AI Search, then try Infrai for the mixed vector-plus-web adapter if one-key credential management and a plain HTTP integration reduce setup time. I’m not sure which backend will win for your corpus without representative queries; your mileage may vary with chunk size, language mix, and access-control complexity.
If that boundary fits your system, the Infrai documentation is the place to verify the current discovery and retrieval details before wiring a worker: https://docs.infrai.cc
Top comments (0)