3.2 KiB
Stream SDK
Stateful, single-request orchestration over the KV Cache SDK.
Goal
lmcache.sdk.kvcache is stateless — it moves KV by token ids and forgets. A
token dropping request spans several passes (prefill, modify the cached KV,
decode), which are encoded as different requests. LMCacheStream binds all
request belonging to a request as a stream instead of leaving the management
to the user.
import lmcache.sdk.kvcache as lmc_sdk
import lmcache.sdk.stream as lmc_stream
ctx = lmc_sdk.connect(url=..., http_url=..., model_name="Qwen/Qwen3-8B")
stream = lmc_stream.create_request(
ctx, post_completion, prompt_token_ids=source_tokens
)
stream.generate({"max_tokens": 1}) # prefill -> offload the prompt KV
stream.modify_kv(drop_tokens) # drop_tokens: retrieve -> edit -> store
stream.generate({"max_tokens": 256}) # replay the uncached tail + decode
post_completion(prompt_token_ids, sampling_params, cache_salt) calls the
engine (e.g. vLLM /v1/completions, streaming) and yields one
TokenEvent(token_id, text) per token. See the
token-dropping example.
Stream is not used on its own. LMCacheBatchedStream wraps it for submitting
batched requests. See batch.md.
State model
The full logical sequence is tokens + _suffix_tokens. The token-bearing
fields mean different things:
tokens— sequence backing the stored KV; sent as the next prompt. Replaced when the KV is modified viaupdate_kv._suffix_tokens— tokens not in the stored KV: the non-chunk-aligned tail left aftermodify_kv. Managed by the nextgenerate._decoded/_text_parts— cumulative generated count / text across allgenerates (decoded_tokens(),output_text()); unaffected by compaction.done— True once agenerateyields< max_tokens(EOS). Reset whenupdate_kvis called.
Suffix contract
retrieve_kv returns only a chunk-aligned prefix, so after modify_kv
edits it the remainder (sub-chunk tail + not-yet-offloaded tokens) has no
stored KV. The stream carries it across the edit:
modify_kvrecords the uncached tailtokens[cached_len:]after KV modification (e.g. compaction).generateprepends_suffix_tokens(plus any callersuffix_tokens) totokensfor request submission, then clears it.
Public API
LMCacheStream(ctx, post_completion, prompt_token_ids, cache_salt="")or thecreate_request().generate(sampling_params, suffix_tokens=())returnsStreamPerfMetricsthe performance metrics of one requestmodify_kv(fn): callsretrieve_kv, passing the KV and tokens so far to the functionfn(kv[2,L,T,D], tokens[:cached_len])which returns the new pair of(new_kv, new_tokens), then replaces the original KV byupdate_kv.retrieve_kv(timeout=30, poll_interval=0.2)andupdate_kv(kv, tokens): wrapslmc_sdk.retrieve()andlmc_sdk.store()- Accessors:
stream_id(),suffix_tokens(),decoded_tokens(),output_text(),output_tokens(),is_done(). StreamPerfMetrics(per call metric, times in seconds).TokenEvent(token_id, text),PostCompletion(Protocol),LMCacheStreamError.