人工智能大模型模型推理服务AscendCANN【免费下载链接】vllm-ascendCommunity maintained hardware plugin for vLLM on Huawei Ascend项目地址https://gitcode.com/gh_mirrors/vl/vllm-ascend点击查看免费下载Disaggregated Encoder解耦编码器是 vllm-ascend 面向多模态大模型推理的一种架构方案它将视觉编码器Vision Encoder阶段从语言模型的 Prefill/Decode 流程中拆出运行在独立的 vLLM 进程中通过专用的 ECEncoder-Cache传输连接器把编码结果传递给语言模型侧。本文以仓库中的官方文档docs/source/user_guide/feature_guide/epd_disaggregation.md为主体结合可运行的部署脚本、EPD 负载均衡代理和 EC 传输连接器的源码实现系统讲解其设计动机、架构抽象、端到端部署步骤与关键限制帮助读者在昇腾 NPU 上落地 Encoder-Prefill-DecodeEPD解耦推理。一、什么是 Disaggregated Encoder在 vLLM 的传统部署形态中多模态请求的视觉编码、Prompt Prefill计算 KV Cache和自回归 Decode 都在同一个 vLLM 进程中顺序完成。Disaggregated Encoder 则把这三者拆开Encoder 实例独立 vLLM 实例仅负责视觉多模态编码产出 Encoder CacheEC嵌入Prefill/DecodePD实例独立 vLLM 实例负责语言模型的 Prefill 与 Decode既可以是单个同时承载 EPD 的常规实例也可以在继续解耦后形成 EPD 三个独立实例。与之对应Disaggregated Prefill把 Prompt 处理KV Cache 计算与自回归 Token 生成Decode 阶段隔离到不同的 vLLM 实例中。这种分离使得每个阶段都可以针对自身的硬件与资源特征做独立调优从而在Time-to-First-TokenTTFT与Inter-Token LatencyITL之间精确权衡在高负载服务下提升整体吞吐与资源利用率。从架构上看Prefill-DecodePD解耦是整个机制的顶层骨架专门的 Prefill 实例计算 KV Cache再通过 MooncakeLayerwise 等专用连接器将 KV Cache 逐层推送到 Decode 实例完成 Token 生成。在 vLLM包括昇腾硬件插件 vllm-ascend中PD 解耦通常与多模态模型的 EPD 架构结合并支持多节点配置与分布式负载均衡。编码与 Prefill 阶段是计算密集型、突发性负载Decode 阶段则是访存密集型、持续性负载两种截然不同的计算特征正是 EPD 架构能够最大化推理效率的根本原因。二、为什么需要解耦编码器将多模态 LLM 的视觉编码器阶段部署在与 Prefill/Decoder 独立的 vLLM 实例中带来三个实际收益独立、细粒度的弹性伸缩视觉编码器体量轻量语言模型则大数个数量级语言模型可以独立并行化扩展而不受编码器集群牵制编码器节点可以随时独立增删按需扩缩容。更低的 TTFT纯文本请求完全绕过视觉编码器直接进入语言模型编码器输出仅在需要的 Attention 层注入缩短了 Prefill 关键路径。跨进程复用与缓存编码器输出进程内编码器In-process Encoder只能把复用范围限制在单个 Worker 内远程共享缓存让任意 Worker 都能直接取回已存在的嵌入消除冗余的视觉计算。注原文档中附有外部设计文档链接Google Docs本仓库代码即为其实现载体读者可直接以本仓库源码为准。三、架构总览与核心抽象下图是 vllm-ascend 官方文档中 EPD 解耦的整体架构示意图片来源docs/source/user_guide/feature_guide/images/epd_disaggregation.jpg整个 Disaggregated Encoder 机制由两部分协同实现Encoder 实例一个执行视觉编码的 vLLM 实例Prefill/DecodePD实例执行语言 Prefill 与 Decode。PD 既可以是单个常规实例EPD也可以是解耦实例EPD。两者之间由Connector负责把 Encoder-CacheEC嵌入从 Encoder 实例传输到 PD 实例。相关代码全部位于 vllm_ascend/distributed/ec_transfer 目录下。3.1 ECConnector编码缓存检索接口ECConnector 是获取 Encoder 实例产出 EC 缓存的接口在调度与执行两个角色上分工明确Scheduler 角色检查缓存是否存在、调度加载对应ensure_cache_available、has_cache_item等逻辑Worker 角色把嵌入实际加载进内存对应start_load_caches、save_caches等逻辑。在 vllm_ascend/distributed/ec_transfer/ec_memcache_connector.py 中可以看到这一接口的完整实现Scheduler 侧是 memcache 的元数据客户端MemcacheBackend.create_scheduler_client负责按mm_hash查询缓存存在性并统计命中率Worker 侧是数据面客户端负责读写嵌入张量。代码中的缓存命中规则与MultiLevelEncoderCacheManager一致——以request.mm_features[i].identifier即 mm_hash作为缓存键命中则跳过 ViT 计算未命中才执行 ViT 并将结果按 mm_hash 写入共享存储。3.2 EPD Load Balancing Proxy多路径调度与实例级负载均衡EPD 负载均衡代理承担请求路由职责Multi-Path Scheduling Strategy多路径调度策略动态地把多模态请求或文本请求分流到对应的推理路径Encoder → PD或直接 → PDInstance-Level Dynamic Load Balancing实例级动态负载均衡基于最小负载策略least-loaded分派多模态请求使用优先级队列在各实例间均衡活跃 Token 负载。仓库中的参考实现为 examples/disaggregated_encoder/disagg_epd_proxy.py详见第五节。3.3 MooncakeLayerwiseConnectorP/D 间 KV 传输PD 解耦部分使用MooncakeLayerwiseConnector完成 Prefill 与 Decode 之间的 KV 传输其实现位于 vllm_ascend/distributed/kv_transfer/kv_p2p/mooncake_layerwise_connector.py部署参考 examples/disaggregated_prefill_v1/load_balance_proxy_layerwise_server_example.py。在该连接器下PD 解耦的请求流程为请求先进入Decoder 实例Decoder 通过Metaserver反向触发远程 Prefill 任务Prefill 节点执行推理并把 KV Cache逐层推送给 Decoder实现计算与传输重叠传输完成后Decoder 无缝继续后续 Token 生成。该流程的设计思路可参见 docs/source/developer_guide/Design_Documents/disaggregated_prefill.md。四、端到端部署实战1 Encoder 1 PD 实例当前参考实现路径为ExampleConnector。仓库提供了可直接运行的脚本两种拓扑1 Encoder 实例 1 PD 实例EPDexamples/disaggregated_encoder/disagg_1e1pd_example.sh1 Encoder 1 Prefill 1 Decode 实例EPD对应disagg_1e1p1d拓扑可结合 EPD Proxy 的--prefill-servers-urls参数与 PD 解耦部署实现。下面以disagg_1e1pd_example.sh为例逐步拆解完整流程。4.1 配置项与环境变量脚本顶部通过环境变量提供全部可调配置均有默认值运行前可覆盖环境变量默认值说明MODELQwen/Qwen2.5-VL-7B-Instruct推理模型LOG_PATH./logs各实例日志目录ENCODE_PORT19534Encoder 实例端口PREFILL_DECODE_PORT19535PD 实例端口PROXY_PORT10001EPD 代理端口CARD_E0Encoder 使用的昇腾设备卡号ASCEND_RT_VISIBLE_DEVICESCARD_PD1PD 使用的昇腾设备卡号EC_SHARED_STORAGE_PATH/tmp/ec_cacheEC 缓存共享存储路径Encoder 与 PD 共用TIMEOUT_SECONDS12000服务就绪等待超时NUM_PROMPTS100benchmark 发送的 prompt 数量脚本先清理并重建EC_SHARED_STORAGE_PATH确保跨进程缓存目录干净随后按顺序拉起 Encoder、PD 与 Proxy 三个进程并通过wait_for_server轮询curl localhost:port/v1/chat/completions等待服务就绪。4.2 启动 Encoder 实例ec_producerASCEND_RT_VISIBLE_DEVICES$CARD_E vllm serve $MODEL \ --gpu-memory-utilization 0.01 \ --port $ENCODE_PORT \ --enforce-eager \ --enable-request-id-headers \ --no-enable-prefix-caching \ --max-num-batched-tokens 114688 \ --max-num-seqs 128 \ --ec-transfer-config { ec_connector: ECExampleConnector, ec_role: ec_producer, ec_connector_extra_config: { shared_storage_path: $EC_SHARED_STORAGE_PATH } }关键点--ec-transfer-config是 vllm-ascend 对接上游 EC 传输框架的入口配置以 JSON 形式传入ec_connector选择连接器实现此处为上游的ECExampleConnector基于共享文件系统路径ec_roleec_producer表示该实例只产出 EC 缓存ec_connector_extra_config连接器专属参数shared_storage_path指定共享存储目录Encoder 实例只做视觉编码--gpu-memory-utilization 0.01即可满足其轻量需求使用--enable-request-id-headers以便 Proxy 通过x-request-id关联编码与解码请求。4.3 启动 PD 实例ec_consumerASCEND_RT_VISIBLE_DEVICES$CARD_PD vllm serve $MODEL \ --gpu-memory-utilization 0.9 \ --port $PREFILL_DECODE_PORT \ --enforce-eager \ --enable-request-id-headers \ --max-num-seqs 128 \ --ec-transfer-config { ec_connector: ECExampleConnector, ec_role: ec_consumer, ec_connector_extra_config: { shared_storage_path: $EC_SHARED_STORAGE_PATH } }PD 实例与 Encoder 使用相同的共享存储路径但角色相反ec_role: ec_consumer即从共享存储加载已编码的嵌入。语言模型体量大因此--gpu-memory-utilization 0.9为其预留绝大部分显存。需要说明的是示例脚本基于 ECExampleConnector 的shared_storage_path文件系统共享方案同一--ec-transfer-config框架也支持ECMemcacheConnectorec_role: ec_both单实例同时产出与消费与AscendECCPUConnector基于 pinned 共享 mmap CANN 批量 DMA 的 CPU 卸载方案等实现详见 vllm_ascend/distributed/ec_transfer。4.4 启动 EPD 代理并验证请求python ./disagg_epd_proxy.py \ --host 0.0.0.0 \ --port $PROXY_PORT \ --encode-servers-urls http://localhost:$ENCODE_PORT \ --prefill-servers-urls disable \ --decode-servers-urls http://localhost:$PREFILL_DECODE_PORT--encode-servers-urlsEncoder 集群地址逗号分隔支持多实例--prefill-servers-urlsPrefill 集群地址设为disable或none表示运行EPD拓扑跳过独立 Prefill 阶段若传入真实地址则启用EPD拓扑--decode-servers-urlsDecoder 集群地址。服务全部就绪后脚本先构造一个含本地图片base64 内联的image_url请求通过 Proxy 的/v1/chat/completions发起单请求验证随后使用vllm bench serve以random-mm数据集、openai-chat后端发起$NUM_PROMPTS个多模态请求的压力测试最后统一清理进程。五、EPD Proxy 源码剖析请求如何被分流examples/disaggregated_encoder/disagg_epd_proxy.py 是一个基于 FastAPI aiohttp 的 OpenAI 兼容代理其核心路由逻辑在forward_non_stream/forward_stream中按三步处理请求Encoder 阶段若请求含多模态输入image_url/audio_url/input_audio先发送给 Encoder 集群。fanout_encoder_primer依据--encoder-dispatch-mode选择两种分派模式single整体请求直接发给随机选中的 Encoderfanout用extract_mm_items拆出每一个多模态条目去掉全部文本后逐条并发发送每条max_tokens: 1仅触发编码路径并等待全部成功。Prefill 阶段maybe_prefill检查p_url是否存在——存在则先走 Prefill并从响应中取回kv_transfer_params用于 nixl 等连接器的 KV 传输不存在则跳过EPD 模式。Decode 阶段把可能已携带 KV 传输参数的请求转发给 Decoder 集群非流式返回 JSON流式返回 SSE 分块。代理还实现了stream_retry_wrap/non_stream_retry_wrap默认最多重试 3 次指数退避首块已发送后不再重试以及/health聚合检查 encode/prefill/decode 三集群健康状态、/start_profile、/stop_profile等辅助端点。--prefill-servers-urls的disable/none判断逻辑位于__main__参数解析处是切换 EPD 与 EPD 拓扑的关键开关。六、EC 传输连接器昇腾侧源码级实现vllm-ascend 在 vllm_ascend/distributed/ec_transfer 目录下为上游 EC 传输框架提供了昇腾适配实现主要包括三块6.1 ECMemcacheConnectormemcache 后端vllm_ascend/distributed/ec_transfer/ec_memcache_connector.py 以 memcache 为共享后端通过--ec-transfer-config即可接入无需改动 vLLM{ ec_connector: ECMemcacheConnector, ec_connector_module_path: vllm_ascend.distributed.ec_transfer.ec_memcache_connector, ec_role: ec_both, ec_connector_extra_config: { recv_buffer_tokens: 8192 } }实现要点从源码可以确认Scheduler 侧ensure_cache_available批量检查mm_hash是否已存在于 memcache命中计入_mm_hash_hits并暴露hit_rate统计update_state_after_alloc决定本次需要 load 还是 save 的 hash 集合build_connector_meta把这些元数据打包传给 Worker 侧Worker 侧start_load_caches按元数据批量拉取嵌入到 NPU 显存save_caches只由 rank 0 的保存进程_save_rank异步写入 memcache单线程ThreadPoolExecutor接收缓冲管理recv_buffer_tokens是持久 NPU 接收缓冲的 Token 容量合法取值范围为[2048, scheduler_config.max_num_batched_tokens]超出该容量的超大嵌入会走临时缓冲二次批处理_load_oversized_requests并立即同步 copy-out 事件缓存命中语义以mm_hash为键命中跳过 ViT未命中才执行编码并写回memcache 负责淘汰策略连接器本身不实现淘汰。6.2 AscendECCPUConnectorCPU 卸载适配vllm_ascend/distributed/ec_transfer/ec_connector/cpu/connector.pyAscendECCPUConnector继承上游ECCPUConnector仅替换 Worker 实现vllm_ascend/distributed/ec_transfer/ec_connector/cpu/worker.pyAscendECCPUWorker使用 pinned 共享 mmap 与 CANN 批量 DMAaclrtMemcpyBatchAsyncaclrtHostRegisterV2(ACL_HOST_REG_PINNED)传输编码缓存通过torch.ops._C_ascend.swap_blocks_batch提交 H2D/D2H 批量拷贝注册逻辑位于 vllm_ascend/distributed/ec_transfer/init.pyregister_connector仅在检测到上游 CPU 连接器存在时把ECConnectorFactory注册表中的ECCPUConnector替换为昇腾适配类。6.3 EC 消费者侧的 TP 设备修正补丁vllm_ascend/patch/platform/patch_example_connector.py 记录了上游ECExampleConnector.start_load_caches在昇腾上的一个关键问题上游仅在is_cuda_alike()返回 True 时才会为 safetensors 加载指定设备索引而昇腾 NPU 返回 False导致 TP1 时每个 rank 都加载到默认设备npu:0rank 1 访问跨设备张量会触发 NPU AI Coreerrcode95MTE DDR 地址越界。该补丁仅对EC 消费者生效将设备限定扩展为device npu时也使用npu:当前设备索引Producer 与非 EC 部署保持上游原行为。七、PD 解耦部分MooncakeLayerwiseConnector 工作流在 EPD 拓扑中Prefill 与 Decode 之间使用 MooncakeLayerwiseConnector 传输 KV Cache源码见 vllm_ascend/distributed/kv_transfer/kv_p2p/mooncake_layerwise_connector.py。按 docs/source/developer_guide/Design_Documents/disaggregated_prefill.md 的描述其工作流为请求先发送到 Proxy 的_handle_completions端点Proxy 调用select_decoder选择 D 节点并转发请求同时配置kv_transfer_paramsdo_remote_prefillTrue并设置metaserver端点D 节点调度器依据kv_transfer_params将请求标记为RequestStatus.WAITING_FOR_REMOTE_KVS预分配 KV Cache再调用kv_connector_no_forward向 metaserver 发起请求并等待 KV 传输完成Proxy 的metaserver端点收到请求后调用select_prefiller选择 P 节点以do_remote_decodeTrue、max_completion_tokens1、min_tokens1转发P 节点调度器逐层推送 KV Cache全部层推送完成后释放请求并通知 D 节点开始解码D 节点执行解码并返回结果。该流程的代理侧实现即 examples/disaggregated_prefill_v1/load_balance_proxy_layerwise_server_example.py通过select_prefiller/select_decoder的最小负载优先级队列Prefill 侧还叠加active_kv_cache权重 0.3选择后端实例并提供/v1/metaserver端点协调 P/D 之间的 KV 元数据交换。该代理对--host有限制Wildcard 地址0.0.0.0、::等被禁止因为 Decoder 节点需要反向访问 Proxy 的 metaserver 端点必须使用实际可达的地址。八、注意事项与已知限制跨进程缓存若要在 PD 实例上使用跨进程的 EC 缓存复用需要禁用--mm-processor-cache-gb即设置--mm-processor-cache-gb 0否则进程内处理器缓存会掩盖远程缓存的效果PD 解耦限制PD 解耦部分遵循 PD 分解PD disaggregation自身的限制——异构 P/D 节点不被支持例如 P 节点在 A2、D 节点在 A3 的组合不可行在非对称 TP 配置下仅支持 P 节点 TP 度大于 D 节点且 P 的 TP 数为 D 的整数倍P_tp D_tp且P_tp % D_tp 0的情形TP1 场景使用 ECExampleConnector 作为消费者时须确保部署版本包含 patch_example_connector.py 的设备索引补丁避免跨设备张量访问导致的errcode95错误连接器选择ECExampleConnector共享文件路径适合单机演示与验证生产多节点场景可评估ECMemcacheConnectormemcache 后端自带淘汰策略或AscendECCPUConnectorpinned mmap CANN DMA 的 CPU 卸载路径三者共用同一--ec-transfer-config配置框架。结语Disaggregated Encoder 通过把多模态编码、Prefill 与 Decode 拆入独立 vLLM 实例配合 ECConnector 缓存传输与 EPD 负载均衡代理实现了针对编码/预填充计算密集、突发与解码访存密集、持续两类负载的独立资源调优。本文给出的disagg_1e1pd_example.sh一键脚本覆盖了从实例启动、代理路由到多模态 benchmark 的完整闭环结合 EC 连接器源码中的调度/Worker 双角色设计、接收缓冲管理与 TP 补丁读者可以在此基础上按需扩展为 EPD 多节点拓扑或切换不同的 EC 后端连接器以满足生产环境的跨进程缓存与扩展性要求。赞分享人工智能大模型模型推理服务AscendCANN【免费下载链接】vllm-ascendCommunity maintained hardware plugin for vLLM on Huawei Ascend项目地址https://gitcode.com/gh_mirrors/vl/vllm-ascend点击查看免费下载相关推荐vLLM Ascend 预填充-解码分离Disaggregated Prefill架构解析与 Mooncake 连接器实战vLLM Ascend 预填充 解码分离Disaggregated Prefill架构解析与 Mooncake 连接器实战 Disaggregated Pr人工智能大模型模型推理服务AscendCANN告别黑苹果配置噩梦OpenCore Configurator如何重新定义引导设置流程告别黑苹果配置噩梦OpenCore Configurator如何重新定义引导设置流程 OpenCore Configurator是一款针对OpenCore引导人工智能大模型模型推理服务推理引擎本地部署vllm-ascend 分层与稀疏 KV Cache 卸载指南Prefill/Decode 解耦部署实战vllm ascend 分层与稀疏 KV Cache 卸载指南Prefill/Decode 解耦部署实战 本篇指南面向在昇腾AscendNPU 上使用 v人工智能大模型模型推理服务AscendCANN创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考