Files
2026-07-13 12:24:33 +08:00

143 lines
4.8 KiB
ReStructuredText

KV Cache SDK
====================
The LMCache **SDK** lets you retrieve a request's KV cache from a LMCache
server, transform it on the CPU, and store it back. This can be used for KV
cache transformations, such as token dropping. In the example: we prefill a
batch of long prompts, drop half of each request's KV chunks, and show the
decode-throughput gain. The full runnable notebook lives at
`examples/token_dropping/token_dropping.ipynb
<https://github.com/LMCache/LMCache/tree/dev/examples/token_dropping>`_.
.. contents::
:local:
:depth: 2
Why KV Cache SDK
----------------
- **Improving Decode Throughput** when shrinking KV cache using token dropping.
Token dropping reduces the KV cache size, allowing more requests to fit in a
batch, improving decode throughput.
The SDK gives you the hooks to retrieve a request's KV, supply your own
function to edit the KV, and store the edited KV back. The SDK also provides a
batched-stream API to prefill, modify, and store the cache back before
decoding continues.
How it works
------------
A request flows through three phases on the batched-stream API:
- **prefill** — run each prompt through vLLM once (``max_tokens=1``); vLLM
computes the KV cache and stores it in LMCache.
- **modify** — the SDK retrieves the cached KV to CPU, hands it to your edit
function, and stores the result back.
- **decode** — continue generation against the smaller, edited cache.
The SDK runs on **CPU** and hands you KV tensors in ``HND`` order with shape
``[2, L, T, D]`` (K/V, layers, chunk-aligned tokens, ``num_kv_heads * head_dim``).
Configuration
-------------
To start the LMCache server with shared-memory transfer enabled, pass
``--shm-name`` and disable lazy L1 allocation with ``--no-l1-use-lazy``. If
shared memory is unavailable and these flags are not specified, the SDK falls
back to pickle.
.. code-block:: bash
lmcache server \
--l1-size-gb 150 \
--eviction-policy LRU \
--chunk-size 256 \
--port 6555 \
--http-port 8080 \
--shm-name lmcache_kvcache_sdk \
--no-l1-use-lazy
Then start vLLM with the LMCache MP connector.
.. code-block:: bash
vllm serve Qwen/Qwen3-8B \
--port 8000 \
--enforce-eager \
--gpu-memory-utilization 0.65 \
--kv-transfer-config '{
"kv_connector":"LMCacheMPConnector",
"kv_role":"kv_both",
"kv_connector_extra_config":{"lmcache.mp.port":6555}
}' \
--trust-remote-code \
--return-tokens-as-token-ids
The SDK keys the KV cache by token ids: ``create_request`` takes the prompt as
token ids, and every ``post_completion`` must report a ``token_id`` for each
generated token. The example gets these ids straight from vLLM by passing
``--return-tokens-as-token-ids``. Otherwise, if vLLM returns only text, the
``post_completion`` must tokenize each generated token back into a token id.
.. code-block:: python
import lmcache.sdk.kvcache as lmc_sdk
ctx = lmc_sdk.connect(
url="tcp://localhost:6555", # must match --port
http_url="http://localhost:8080", # must match --http-port
model_name="Qwen/Qwen3-8B",
timeout=60,
)
...
lmc_sdk.close(ctx)
Writing a custom edit function
------------------------------
An edit function takes the retrieved KV tensor and its token ids and returns the
edited ``(kv, tokens)``. ``batch.modify(fn)`` applies it to every stream.
``modify`` operates only on the **chunk-aligned** prefix. A trailing partial
chunk is tracked by the SDK and re-sent on the next ``decode``, so
``tokens`` arrives already truncated to the cached length.
API reference
-------------
.. list-table::
:header-rows: 1
:widths: 45 55
* - Function / method
- Description
* - ``lmc_sdk.connect(url, http_url, model_name, timeout=60.0)``
- Create an SDK context and register the transfer context, pass it to
every other call.
* - ``lmc_sdk.close(ctx)``
- Close the context and release resources. Called when done with the SDK.
* - ``lmc_stream.create_request(ctx, post_completion,
prompt_token_ids, cache_salt="")``
- Create one request stream to add to a batch.
* - ``lmc_batch.LMCacheBatchedStream()``
- Create an empty batch.
* - ``batch.add(stream)``
- Register a stream to the batch.
* - ``batch.prefill(sampling_params)``
- Prefill every stream once (``max_tokens`` forced to 1). Returns a
``Metrics`` report.
* - ``batch.modify(fn)``
- Apply the edit function ``fn`` to every stream's cached KV. Returns a
``Metrics`` report.
* - ``batch.decode(sampling_params)``
- Decode every stream. Returns a ``Metrics`` report.
```Metrics`` returns ``input_tokens``, ``input_tput`` for prefill, ``duration``
for modify, and ``output_tokens``, ``output_tput`` for decode.