Debugging Vector Search Latency Spikes (Start With Top K and Payloads) A developer outlined a debugging approach for vector search latency spikes that starts with the request's top-k value and returned payload rather than the vector index itself. The method indexes only IDs and compact ranking metadata, resolves full article text from a separate content store, and records latency by query shape—requested k, whether full text was returned, metadata profile, collection and caller—so spikes can be traced to specific callers. The developer recommends a single controlled comparison varying k with IDs-only results to separate index slowdowns from payload serialization and parsing costs. Start with top k and returned metadata before blaming the vector index. In help-center search, the usual load-sensitive failure is straightforward: returning full chunk text for every match multiplies the response payload by k , and concurrent callers multiply it again. Make the cheap result small, then fetch the few details the UI will actually show. TL;DR: index IDs and compact ranking metadata, resolve article text from your own store, and record latency by query shape. A single aggregate latency chart cannot tell a k=5 ID-only lookup from a k=50 request carrying full PDF chunks. That distinction is the diagnosis. This matters for a game studio's help center. Patch notes and PDF manuals change, players arrive in bursts after a release, and stale chunks can be perfectly fast while giving the wrong answer. Latency and freshness need separate signals. Picture the request as three boxes in a line: embed the question, find neighbors, return results. Teams often stare at the middle box because it says "vector search." Yet the last box can dominate what users observe under load. Before: each hit contains an ID, score, title, locale, product version, source URL, and the entire chunk. Ask for 40 hits and the same request now carries 40 chunks through serialization, the network, JSON parsing, and application memory. Nothing about that pattern proves the index became slow. After: each hit contains an ID, score, and a few small fields needed to reject an obviously wrong version or locale. The application keeps perhaps five candidates, resolves those IDs from its own content store, and sends only the useful passages to the answer model. The vector query stays a ranking operation. Small first. Rich later. The key trade-off is an extra store lookup. I would accept it for a help center because it bounds the search response and keeps source-of-truth content outside the index. It also makes PDF replacement cleaner: update indexed IDs and compact metadata, while the content store owns the full text. The cost is more application orchestration and a consistency rule for deleted or superseded IDs. Freshness deserves its own clock. Record the PDF revision or ingestion generation beside each indexed ID, then compare it with the revision in the content store. Do not infer freshness from query latency. A fast result can still point at last season's game manual. You cannot answer that from a service-wide p95. Track a latency metric per query shape so a spike maps to a caller. At minimum, distinguish requested k , whether full text was requested, the metadata profile, collection, and caller. Keep the labels bounded; a raw query string or document ID creates dangerous cardinality. I use two timing boundaries in the application: vector request time, then detail-resolution time. Add response bytes and returned-hit count. Those four values produce a crisp before/after: if vector time is steady while bytes and parse time climb, index tuning is a distraction. If the small-payload query itself slows as concurrency rises, then index capacity, filtering, or provider limits move back onto the suspect list. Do one controlled comparison: k and IDs-only results. One axis. One answer. This test also catches a common caller mismatch. The interactive search box may need five visible answers, while an offline evaluation job legitimately asks for 50 candidates. Those workloads should not share an unlabeled latency series or the same alert threshold. The example below deliberately does not guess vendor request fields. It accepts two JSON request bodies that you have validated against the public discovery schemas: one for the vector query and one for creating the reindex schedule. The probe calls only two documented routes, uses the same base URL and key, handles 429 with Retry-After , and surfaces response bodies on errors. That choice trades a little setup for honesty: copying an attractive sample with invented request fields is worse than asking the reader to paste schema-valid JSON. The handoff is explicit in the local state: a successful query records the observed result size, then the scheduler request is created with the same authenticated client. Your supplied schedule body should describe the nightly crawl-and-reindex job. Crawling, embedding, and its schedule can therefore sit behind one credential rather than requiring credentials to be passed among separate services. js const baseUrl = process.env.INFRAI BASE URL; const apiKey = process.env.INFRAI API KEY; const vectorQuery = process.env.VECTOR QUERY JSON; const reindexSchedule = process.env.REINDEX SCHEDULE JSON; const idempotencyKey = process.env.REINDEX IDEMPOTENCY KEY; if baseUrl || apiKey || vectorQuery || reindexSchedule || idempotencyKey { throw new Error "Set INFRAI BASE URL, INFRAI API KEY, VECTOR QUERY JSON, " + "REINDEX SCHEDULE JSON, and REINDEX IDEMPOTENCY KEY" ; } type JsonValue = | null | boolean | number | string | JsonValue | { key: string : JsonValue }; type CallResult = { body: JsonValue; bytes: number; latencyMs: number; }; function retryDelayMs response: Response, attempt: number : number { const retryAfter = response.headers.get "retry-after" ; if retryAfter { const seconds = Number retryAfter ; if Number.isFinite seconds return seconds 1 000; const dateDelay = Date.parse retryAfter - Date.now ; if Number.isFinite dateDelay return Math.max 0, dateDelay ; } return 500 2 attempt; } async function send request: Request : Promise