docs: define and validate KV-affine Responses routing#65
docs: define and validate KV-affine Responses routing#65franciscojavierarceo wants to merge 1 commit into
Conversation
6f7afdd to
315b730
Compare
e2483a1 to
02ce0eb
Compare
|
@franciscojavierarceo thank you for the comprehensive ADR. I wanted to clarify my understanding of the overall follow proposed. Turn 1: no cache yet full path
Turn 2: cache path
currently we cannot interface this design we would need your feature branch from vllm fork to land into vllm upstream. are you planning to open PR soon on vllm? I was also wondering the benchmarking figure mentioned in this ADR how is it generated? like prototyping with |
|
@maralbahari the overall shape is close, with two important corrections. first, i would not want production turn 2 to do a fresh full render on every request. that is useful for prototype validation, CI, canary sampling, and fallback/reseed, but if it happens on every hot-path request we give back much of the render/tokenize win. the production path should validate the stored prefix metadata/handle, then render only the marginal suffix through a renderer-owned incremental path or a stored safe-boundary segment. second, for agentic-api storage, the hot path should store compact prefix metadata: prefix hash, token count, model/tokenizer/renderer/template fingerprints, safe-boundary proof, and eventually router-visible block hashes for llm-d. raw token ids are useful as an optional cold-path diagnostic/reseed artifact, but i do not think we should require reading/writing full token arrays synchronously every turn. same for marginal input ids: they are execution material for vLLM, but not something the DB hot path should need to persist as raw ids unless we explicitly choose to keep a debug/checkpoint span. on vLLM: yes, this design depends on a vLLM primitive that is not upstream today. the benchmark used my fork/branch with the on the figure: it was generated by a standalone benchmark harness against the forked vLLM server on the DGX with GPT-OSS-20B and APC enabled. it was not llm-d, not OGX rehydration, and not simply upstream prefix caching on/off. the key comparison was full-history streaming request versus minimal prompt-cache-ref replay. the important result was that APC was already hitting, so the measured win was mostly reduced prompt reconstruction / render-tokenize / request-size overhead, not recovering a missed KV prefill cache. i updated the ADR to make that provenance and storage split clearer. |
|
Something important to point out here is that in vLLM, subsequent turns of a conversation are not a strict append-only situation by adding new token ids at the end of an existing list of token ids. Reasoning handling is a good example, where depending on where we are in the turns we conditionally drop some older reasoning that would distract the model from its current task at hand. Other examples are things like handling of multiple system messages for specific models, where some models can handle system messages that arrive in later turns and some can not. Or toggling thinking on or off in subsequent turns, changing reasoning effort between turns, etc. This is not an exhaustive list, and these are model-specific things that may or may not invalidate our prefix caching for any given request. The point is, vLLM is the thing that knows how to properly turn a request into token ids and has model-dependent logic to do that. In many happy path cases that can look append-only, but in the real world it often is not with backtracking across at least one turn boundary for many popular models for every user turn due to how reasoning trimming is done. Basically, the full vLLM render pipeline has to run for a given request to get the correct token ids for that turn's input to the model. There may be some things that could be cached internally, in vLLM, for happy path situations specific to each model that are append-only for subsequent turns. But, any logic to do that would need to live in vLLM itself right next to all the logic that decides which inputs to keep, drop, munge, or otherwise change as it's constructing the next set of input tokens. |
b4649cc to
0395031
Compare
Signed-off-by: Francisco Javier Arceo <farceo@redhat.com>
f5a7e20 to
fd8876c
Compare
Summary
agentic-apirehydration and llm-d placement through vLLM APC lookup, generation, and KV-event publication.cache_saltcontract and the isolation failure found during live validation. The implementation fix is intentionally split into fix: preserve Responses cache salt #96.Tracking
Request lifecycle
The vLLM-placement router must run after agentic-api rehydration. A router placed only before agentic-api cannot see the model-visible history represented by
previous_response_id.Measured result
The accepted benchmark used two GPT-OSS-20B vLLM replicas with APC enabled, 64-token blocks, distinct KV-event publishers, and 12 sequential two-turn pairs per routing profile. Every pair used a new unpredictable
cache_salt; its continuation used onlyprevious_response_id, forcing agentic-api to rehydrate 6,653 input tokens before llm-d placement.The routing profiles differ only in how llm-d selects the continuation replica:
/tokenizefor the exact model-visible tokens, converts them to llm-d canonical block keys, and selects the replica with the longest known matching prefix in the KV-event index.Precise routing improved over load-only by 49.54 cache-hit percentage points and reduced mean continuation latency by 494.5 ms (60.97%).
The 99.08% hit rate means vLLM reused 6,592 of 6,653 continuation input tokens; APC matches complete blocks and still recomputes the unmatched or required tail. Load-only has a wide latency interval because its six warm returns took approximately 0.30-0.42 seconds while its six wrong-replica continuations took approximately 1.27-1.31 seconds. Both cache-aware profiles returned all 12 continuations to the warm replica, producing narrow intervals near 0.31 seconds.
Approximate and precise routing are effectively tied in this idle deterministic workload. The result proves that exact Responses identity reaches the maximum observed KV reuse without pseudo-token estimates; it does not yet prove an advantage over approximate routing under template changes, tools, concurrency, event lag, branching histories, or cache pressure.
Raw evidence is committed under
docs/adr/results/adr-04/2026-07-13-n12.Cache-salt isolation gate
Before accepting the routing comparison, the same 12,944-token prompt was sent to one fixed replica using salt A, salt B, and salt B again:
This confirms that agentic-api forwards the salt, different salts are isolated, and identical salts can reuse the matching vLLM blocks.
Required upstream work
cache_salt; point the execution LLM URL at llm-d after rehydration/tokenizeand delegate to the same Responses renderer used for inference/tokenize, preserve salt, reject incomplete identities, and propagate file-discoveryrankIndexfor same-host replicasScope boundaries
This PR is documentation and benchmark evidence only. It completes the single-client Stage 1 proof; production acceptance still requires concurrent agent/tool traffic, cache pressure and eviction, event lag, branching conversations, replica restart, and active-active EPP testing.
Portable token artifacts remain useful after routing is correct: they can avoid repeatedly transferring, reconstructing, rendering, and tokenizing long logical histories. They must preserve the Stage 1 cache-hit ratio and cannot replace llm-d's fleet-level placement decision with an endpoint-local handle.
Test Plan
uvx pre-commit run --all-filesuv run --with-requirements docs/requirements.txt mkdocs build --strictxmllint --noout docs/adr/results/adr-04/2026-07-13-n12/routing-comparison.svg/tokenizeparity across both replicas