资讯详情

LMCache Lookup 实战:在 LMCacheEngine 外部精确查询请求的 KV Cache 命中情况

📅 2026/9/16 17:21:27 | 华诺云谱 👁 阅读
LMCache Lookup 实战:在 LMCacheEngine 外部精确查询请求的 KV Cache 命中情况
LMCache Lookup 实战在 LMCacheEngine 外部精确查询请求的 KV Cache 命中情况【免费下载链接】LMCacheLMCache: Supercharge Your LLM with the Fastest KV Cache Layer项目地址: https://gitcode.com/GitHub_Trending/lm/LMCacheLMCache 作为面向 LLM 的 KV Cache 加速层不仅能在推理引擎内部自动完成缓存复用还提供了一整套基于 Controller 的外部管理接口。本文以 examples/cache_controller/lookup/README.md 为主线完整演示如何在 vLLM 之外通过 HTTP 请求向 LMCache Controller 查询某条 prompt 的 KV Cache 是否存在、缓存在哪个实例的哪个位置、最长可匹配前缀有多长并深入对应源码讲清 Lookup 从 HTTP 入口到缓存注册表检索的完整调用链。读完本文你将掌握lmcache_controller的部署方式、/lookup接口的请求/响应格式以及查询结果中event_id与layout_info的准确含义。一、背景为什么要外部查询 KV Cache在默认工作流中LMCache 作为 vLLM 的 KV 传输连接器如LMCacheConnectorV1自动处理 KV Cache 的存取与复用推理引擎内部会自行完成前缀命中检查。但在以下场景中你需要在引擎之外主动查询缓存状态调度与路由决策在多个引擎实例之间做负载均衡时希望优先把请求路由到已缓存该 prompt 前缀的实例避免重复计算缓存预热验证部署完成后验证指定 prompt 是否已进入缓存、命中前缀长度是否符合预期缓存监控与运维查看缓存分布在哪个实例、哪个后端位置如LocalCPUBackend辅助容量规划与故障排查。examples/cache_controller/lookup/示例正是为这类外部查询场景提供的最小可运行方案。它展示了如何先向 vLLM 发送一次真实请求让 KV Cache 落盘再通过/tokenize拿到 token id最后用 token id 向 LMCache Controller 的/lookup接口确认缓存存在性。二、环境前提与端口规划在开始之前请确认GPU服务器上至少要有 1 块可用 GPU示例中用CUDA_VISIBLE_DEVICES0指定模型示例使用meta-llama/Llama-3.1-8B-Instruct你可替换为任意 vLLM 支持的模型端口规划务必避免冲突端口占用者8000vLLM 引擎8001LMCacheworker 端口配置于lmcache_worker_ports9000LMCache Controller 主端口9001LMCache Controller monitor 端口--monitor-port其中 vLLM 与 LMCache 使用 8000/8001Controller 占据 9000/9001示例配置中controller_pull_url: localhost:9001正是 worker 向 monitor 端口上报信息所用。三、配置文件解析example.yaml示例目录下的 example.yaml 是 vLLM 启动时通过LMCACHE_CONFIG_FILE注入的 LMCache 配置内容如下chunk_size: 256 local_cpu: True max_local_cpu_size: 5 # cache controller configurations enable_controller: True lmcache_instance_id: lmcache_default_instance controller_pull_url: localhost:9001 lmcache_worker_ports: 8001 # Peer identifiers p2p_host: localhost p2p_init_ports: 8200各配置项的作用如下chunk_size: 256KV Cache 分块大小token 数。LMCache 按 chunk 粒度切分、存储与索引 KV CacheLookup 的前缀匹配也以 chunk 为基本单位推进返回的匹配长度是按 chunk 对齐后的 token 数local_cpu: True与max_local_cpu_size: 5开启本地 CPU 后端LocalCPUBackend并将其容量上限设为 5单位由后端实现约定。这也是 Lookup 返回结果中出现LocalCPUBackend的原因——缓存被存储在该实例的 CPU 内存后端enable_controller: True启用 LMCache Controller 集成这是 worker 能向 Controller 注册、上报缓存索引的前提lmcache_instance_id: lmcache_default_instance本引擎实例在 Controller 侧注册的实例 IDLookup 响应中的 key 即来源于此controller_pull_url: localhost:9001worker 拉取/上报 Controller 信息的地址对应 Controller 的--monitor-port 9001lmcache_worker_ports: 8001本 worker 对外通信端口p2p_host: localhost与p2p_init_ports: 8200实例间 P2P点对点传输的地址与初始端口用于多实例场景下直接传输 KV Cache本示例单机单实例下不参与 Lookup 主流程。四、完整操作步骤1. 启动 vLLM 引擎端口 8000PYTHONHASHSEED123 CUDA_VISIBLE_DEVICES0 LMCACHE_CONFIG_FILEexample.yaml vllm serve meta-llama/Llama-3.1-8B-Instruct --gpu-memory-utilization 0.8 --port 8000 --kv-transfer-config {kv_connector:LMCacheConnectorV1, kv_role:kv_both}要点说明LMCACHE_CONFIG_FILEexample.yaml使 vLLM 进程加载第三节的 LMCache 配置--kv-transfer-config指定使用LMCacheConnectorV1作为 KV 传输连接器kv_role: kv_both表示该实例同时承担 KV 生产者与消费者角色即同时负责存储与读取 KV CachePYTHONHASHSEED123用于稳定哈希种子保证多进程/多次实验行为一致该引擎作为lmcache_default_instance实例向 Controller 注册。2. 启动 LMCache Controller端口 9000 / 9001PYTHONHASHSEED123 lmcache_controller --host localhost --port 9000 --monitor-port 9001--host localhost --port 9000指定 Controller 主服务监听地址HTTP 管理接口所在端口--monitor-port 9001指定 monitor 端口用于接收 worker 的注册、心跳与索引上报对应配置中的controller_pull_url。3. 向 vLLM 发送一次真实请求为了让 KV Cache 真正落盘先向 vLLM 的/v1/completions接口发送一条 promptcurl -X POST http://localhost:8000/v1/completions \ -H Content-Type: application/json \ -d { model: meta-llama/Llama-3.1-8B-Instruct, prompt: Explain the significance of KV cache in language models., max_tokens: 10 }该请求执行后LMCache 会将该 prompt 的 KV Cache 按chunk_size分块存储到LocalCPUBackend并把块级索引上报给 Controller。4. 通过 /tokenize 获取 prompt 的 token idLookup 接口接收的是 token id 列表而非原始文本因此先用 vLLM 的 tokenize 端点完成分词curl -X POST http://localhost:8000/tokenize \ -H Content-Type: application/json \ -d { model: meta-llama/Llama-3.1-8B-Instruct, prompt: Explain the significance of KV cache in language models. }预期返回Llama-3.1 分词结果共 12 个 token{count:12,tokens:[128000,849,21435,279,26431,315,85748,6636,304,4221,4211,13],token_strs:null}注意token 序列因模型分词器而异请以你实际环境的返回为准后续 Lookup 必须使用与落盘请求完全一致的 prompt 的 token id否则前缀匹配会失败。5. 向 Controller 发起 Lookup 查询将上一步得到的 token id 原样作为tokens字段发给 Controller 的/lookup接口curl -X POST http://localhost:9000/lookup \ -H Content-Type: application/json \ -d { tokens: [128000, 849, 21435, 279, 26431, 315, 85748, 6636, 304, 4221, 4211, 13] }预期返回{event_id: xxx, lmcache_default_instance: (LocalCPUBackend, 12)}6. 响应语义解读返回体是一个 JSON 对象包含两个字段event_id本次 Controller 操作的唯一标识符形如Lookupuuid用于日志追踪与异步场景下的请求关联在本功能中可忽略lmcache_default_instance即layout_info中的键值对以实例 ID → (location, matched_token_count)形式描述缓存布局。示例中(LocalCPUBackend, 12)表示在lmcache_default_instance实例的LocalCPUBackend位置存在与请求前缀完全匹配的 12 个 token 的缓存与 prompt 的 12 个 token 一一对应即完整命中。从源码结构看HTTP 响应体中的layout_info是一个字典键为实例 ID值为(location, token_count)二元组——LookupResponse 定义中注释明确说明其形态为Dict[str, Tuple[str, int]]即a list of (instance_id, location, token_count)与示例输出一一对应。五、源码级原理/lookup 的完整调用链了解接口行为后我们顺着调用链看清每次查询背后发生了什么。5.1 HTTP 入口FastAPI 端点Controller 主服务在 lmcache/v1/api_server/main.py 中定义了LookupRequest与LookupResponse并实现了/lookupPOST 端点class LookupRequest(BaseModel): tokens: List[int] class LookupResponse(BaseModel): event_id: str # a list of (instance_id, location, token_count) layout_info: Dict[str, Tuple[str, int]] app.post(/lookup, response_modelLookupResponse) async def lookup(req: LookupRequest): event_id Lookup str(uuid.uuid4()) msg LookupMsg(event_idevent_id, tokensreq.tokens) ret_msg await lmcache_controller_manager.handle_orchestration_message(msg) ... return LookupResponse(event_idret_msg.event_id, layout_inforet_msg.layout_info)可以看到端点将 HTTP 请求包装为LookupMsg编排消息LookupMsg 定义只含event_id与tokens: list[int]两个字段交给lmcache_controller_manager分发处理。5.2 消息分发Orchestration 消息路由handle_orchestration_message位于 controller_manager.py是 Controller 编排消息的统一入口if isinstance(msg, LookupMsg): return await self.kv_controller.lookup(msg) elif isinstance(msg, HealthMsg): ... elif isinstance(msg, QueryInstMsg): ...即 Lookup 请求最终被路由到KVController.lookup执行与之并列的还有HealthMsg健康检查、QueryInstMsg查询实例 ID、ClearMsg清除缓存、PinMsg固定缓存等说明/lookup是 Controller 提供的 KV Cache 管理操作族lookup/clear/pin/compress 等中的一员。5.3 核心实现KVController.lookup 与块级前缀匹配真正的查询逻辑在 kv_controller.pyasync def lookup(self, msg: LookupMsg) - LookupRetMsg: tokens msg.tokens layout_info {} for start, end, key in self.token_database.process_tokens( tokens, make_keyFalse ): result self.registry.find_kv(key) if result is None: break matched_instance result.instance_id matched_location result.location layout_info[matched_instance] (matched_location, end) return LookupRetMsg(layout_infolayout_info, event_idmsg.event_id)关键点token_database.process_tokens(tokens, make_keyFalse)按chunk_size将 token 序列切分为若干 (start, end, key) 三元组——key 是该块的哈希标识此处make_keyFalsekey 由注册表侧维护对每个 chunk调用registry.find_kv(key)在缓存注册表中查找该块是否存在于某个实例的某个位置一旦某个 chunk 未命中立即break因此返回的是从开头起连续匹配的最长前缀长度示例中的 12 即最后一个连续命中块的 end 值LookupRetMsg定义见 message.py携带layout_info: Dict[str, Tuple[str, int]]原样返回给 HTTP 层。源码注释也如实记录了当前实现的边界见 kv_controller.py 第 380-387 行未处理前缀 chunk 被逐出而后续 chunk 仍存活的情况依赖 LMCache 保证块间一致性不考虑 chunk 的具体存储位置只返回最长前缀对应的instance_id尚未彻底去掉哈希参与后续演进方向。5.4 返回消息LookupRetMsg最终返回LookupRetMsg字段与 HTTP 响应一致event_id与layout_info。其中layout_info的键为实例 ID示例中即配置的lmcache_default_instance值为(location, end)二元组end即匹配到的 token 数。5.5 与内部 worker 查询的对比Controller 对外提供的/lookup面向引擎外部调用者而引擎内部 worker 在推理时使用的是 worker.py 中的self.lmcache_engine.lookup(...)返回num_pinned_tokens用于处理 pin/预取等内部流程。两者面向不同调用方但都依赖 LMCache 引擎的块级前缀匹配能力。六、测试验证Lookup 的正确性由什么保证/lookup的行为在 tests/v1/cache_controller/test_kv_controller.py 中有完整覆盖可用作理解语义的权威参考test_lookup_hit注册表中有完整前缀块时返回对应instance_id → (location, end)end 等于完整匹配的 token 数test_lookup_miss首个 chunk 即未命中时layout_info为空字典对应无缓存场景test_lookup_partial_match只命中前若干 chunk 时返回的end停留在最后一个连续命中块的结束位置验证了最长连续前缀匹配 遇 miss 即停的语义。此外test_messages.py 与 test_messages.py 分别覆盖了LookupMsg、LookupRetMsg的序列化正确性保证 HTTP 层与消息层字段一致。七、进阶话题与注意事项7.1 多实例 / P2P 场景的批量查询当集群包含多个 LMCache 实例时/lookup之外的另一个相关能力是 worker 间使用的batched_p2p_lookup实现见 kv_controller.py 第 403-439 行。它一次携带多个块哈希命中后返回(instance_id, location, num_hit_chunks, peer_init_url)其中peer_init_url是对方实例的 P2P 通信地址——这正是找到缓存后如何把缓存拉过来的衔接点用于跨实例直接传输 KV Cache。注意该接口面向 worker 消息WorkerReqMsg与面向外部 HTTP 的/lookup属于不同通道。7.2 与其它 Controller 管理接口的配合从 controller_manager.py 可以看到与lookup并列的编排操作还有clear按实例位置清除缓存、pin固定缓存防逐出、compress/decompress压缩与解压、move迁移等。实践中查询命中 → 决策路由 → 必要时 pin 固定是一条完整的缓存管理流水线。7.3 常见问题排查建议Lookup 返回空layout_info先确认第 3 步的真实请求是否已成功完成KV Cache 是否已落盘上报再确认/tokenize与落盘请求使用的 prompt 完全一致标点、大小写、换行都会影响 token 序列返回的匹配长度不是完整 prompt 长度属于正常的最长连续前缀命中语义若最后一个 chunk 未被完整缓存例如max_local_cpu_size过小导致逐出end会停留在之前的 chunk 边界可适当调大chunk_size或max_local_cpu_size观察变化端口冲突严格按照第二节的端口规划启动Controller 的--monitor-port 9001必须与配置中controller_pull_url一致否则 worker 无法完成注册与索引上报。八、总结通过本示例可以确认LMCache 的 Controller 提供了完整的引擎外部缓存查询能力一条 prompt 的 KV Cache 是否存在、位于哪个实例instance_id、哪个后端位置如LocalCPUBackend、最长连续命中多少 token均可通过一次/lookupHTTP 请求获得。其背后是token_database分块 registry.find_kv注册表检索 遇 miss 即停的连续前缀匹配算法语义由 test_kv_controller.py 中的命中/未命中/部分命中三类测试明确界定。这一接口为缓存感知的调度、路由、预热验证与监控提供了可编程的入口是 LMCache 从推理引擎内部加速走向集群级缓存编排的关键基础设施之一。【免费下载链接】LMCacheLMCache: Supercharge Your LLM with the Fastest KV Cache Layer项目地址: https://gitcode.com/GitHub_Trending/lm/LMCache创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。