多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

AI Infra与Agent技能全景:vLLM、SGLang、PyTorch实战避坑指南

AI Infra与Agent技能全景:vLLM、SGLang、PyTorch实战避坑指南 1. AI Infra 与 Agent 技能全景拆解这两年 AI 基础设施和 Agent 开发这两个方向几乎是从“小众硬核”一路卷成了“人人都在聊”。但真正落到工程实践里你会发现一个很尴尬的现实网上讲原理的多讲“到底该学什么、每个东西解决什么问题、它们之间怎么配合”的少。我自己从最早折腾单卡推理到后来搭多机多卡的服务化推理再到把 Agent 跑在自建推理后端上踩过的坑基本能写一本小册子。这篇就把 AI infra 和 Agent 相关的技能点做一次系统整理重点放在 vLLM、SGLang、PyTorch 这几个核心组件上顺带把 Agent 开发需要的能力串起来。先说清楚这篇适合谁看。如果你刚开始接触大模型部署想知道 vLLM 和 SGLang 到底选哪个、PyTorch 环境怎么配不翻车这篇能帮你少走弯路。如果你已经在做 Agent 开发但推理后端总是性能上不去、显存爆掉、并发一高就崩这篇里的调度逻辑和排查思路应该对你有用。如果你只是想搞清楚“AI infra 到底包含哪些技能”把它当成一张学习地图也完全没问题。核心关键词我先摆出来AI infra、Agent、vLLM、SGLang、PyTorch。这几个词基本构成了当前大模型工程化的主干。vLLM 和 SGLang 是推理引擎层的两大主力PyTorch 是它们共同的底层依赖Agent 则是跑在这些推理能力之上的应用形态。理解它们各自的位置和相互关系比单独学某一个工具重要得多。我个人的判断是AI infra 的技能树可以分成四层——硬件与驱动层、框架与算子层、推理服务层、应用编排层。PyTorch 主要落在框架层vLLM/SGLang 在推理服务层Agent 在应用编排层。很多人学的时候是跳着学的直接上手 vLLM 部署结果遇到 CUDA 版本不匹配、显存碎片、调度参数不理解就卡住了。所以下面我会按这个层次来拆但不会死板地一层层讲而是围绕实际会用到的技能点展开。2. PyTorch 环境搭建与避坑指南2.1 为什么 PyTorch 版本选择是第一道坎PyTorch 看起来只是pip install torch一行命令的事但实际项目里版本选错能让你排查一整天。核心矛盾在于PyTorch 版本、CUDA 版本、显卡驱动版本、Python 版本这四者必须互相兼容。任何一个对不上轻则报 warning重则直接CUDA unavailable。我见过最典型的报错就是热词里提到的那个torch/cuda/__init__.py:180: UserWarning。这个警告通常出现在 PyTorch 检测不到可用 CUDA 设备的时候原因无非几种装的是 CPU 版 torch、CUDA 版本和驱动不匹配、或者环境里混装了多个 torch。很多人第一反应是重装但如果不搞清楚根因重装十次还是同样的结果。正确的做法是先确认三件事。第一nvidia-smi看驱动支持的 CUDA 最高版本。第二确认你要装的 PyTorch 对应的 CUDA 版本。第三用 conda 或 venv 隔离环境避免和系统 Python 混在一起。这三步做完基本能规避 80% 的环境问题。2.2 安装命令背后的逻辑网上流传的安装命令很多比如pip3 install torch1.8.2 torchvision0.9.2 torchaudio0.8.2 --extra-index-url ...。这条命令的关键在于--extra-index-url它指向的是 PyTorch 官方的 wheel 索引因为默认的 PyPI 源里 torch 的 CUDA 版本往往不是你要的那个。如果你不加这个参数pip 可能给你装一个 CPU 版或者 CUDA 版本不对的包。我的建议是直接去 PyTorch 官网的安装选择器选好你的 OS、包管理工具、Python 版本、CUDA 版本它会给你一条精确的命令。不要凭记忆手写版本号因为 torch、torchvision、torchaudio 三者的版本是有对应关系的错一个就可能 import 失败。另外提醒一点现在很多新项目已经不再需要手动指定 torchvision 和 torchaudio 了除非你确实要做视觉或音频任务。纯推理场景下只装 torch 往往就够了少装一个包就少一个版本冲突的可能。2.3 验证环境是否真的可用装完之后别急着跑项目先做三步验证。第一步python -c import torch; print(torch.__version__)确认版本。第二步print(torch.cuda.is_available())确认 CUDA 可用。第三步print(torch.cuda.device_count())确认能看到所有卡。这三步都过了再去看torch.version.cuda确认 CUDA 版本。如果is_available()返回 False先别慌。检查是不是装了 CPU 版用torch.__version__看有没有cpu后缀。如果有说明装错了重新按官网命令装。如果没有cpu但还是 False那大概率是驱动或 CUDA 运行时的问题这时候再去看nvidia-smi和nvcc --version是否一致。提示conda 装的 PyTorch 和 pip 装的 PyTorch 在 CUDA 处理上略有差异。conda 版本通常会自带 CUDA runtimepip 版本则依赖系统的 CUDA。混用容易出问题建议一个环境里只用一种方式。3. vLLM 推理引擎核心机制与部署实战3.1 vLLM 到底解决了什么问题vLLM 之所以能成为推理引擎里的主流选择核心就一个词PagedAttention。传统推理框架在处理 KV Cache 的时候要么预分配一大块连续显存要么频繁申请释放前者浪费严重后者碎片化严重。PagedAttention 借鉴了操作系统虚拟内存分页的思路把 KV Cache 切成固定大小的 block按需分配不要求连续。这样一来显存利用率能提升好几倍吞吐量自然就上去了。除了 PagedAttentionvLLM 还有几个关键设计。Continuous Batching让不同请求可以在不同时间点加入同一个 batch不用等齐了再算这对在线服务特别重要。Scheduler负责决定每一轮哪些请求进入计算、哪些等待它和 EngineCore、Executor 之间的交互是整个推理流程的中枢。理解这条链路是排查性能问题的前提。3.2 EngineCore、Scheduler、Executor 的交互流程很多人用 vLLM 就是vllm serve一跑能用就行。但一旦遇到吞吐上不去、延迟抖动、显存 OOM就必须理解内部流程。我尽量用大白话讲清楚这条链路。请求进来之后先到EngineCore它是整个引擎的大脑负责管理请求的生命周期。EngineCore 会把新请求交给SchedulerScheduler 根据当前显存里 KV Cache 的占用情况、等待队列的长度、请求的优先级决定这一轮 step 要处理哪些请求。这个决策过程就是所谓的调度逻辑。决定好之后Scheduler 把这一批请求的元信息交给ExecutorExecutor 负责真正在 GPU 上执行前向计算。Executor 可能是单卡的也可能是分布式的比如 tensor parallel 场景下多个 worker。计算完的结果再回传给 EngineCore由它决定哪些请求已经生成结束、哪些需要继续下一轮。这条链路里Scheduler 是最容易成为瓶颈的地方。如果调度策略过于保守GPU 利用率上不去如果过于激进显存又容易爆。vLLM 提供了若干调度相关的参数比如max_num_seqs、max_num_batched_tokens、gpu_memory_utilization这些参数的调整直接影响吞吐和延迟的平衡。3.3 Docker 部署 vLLM 的完整流程用 Docker 部署 vLLM 是目前最省心的方式因为官方镜像已经把 CUDA、PyTorch、vLLM 都打包好了省去了环境配置的麻烦。但镜像选择有讲究。以vllm/vllm-openai:v0.27.1这类镜像为例它内置了 OpenAI 兼容的 API server启动后直接暴露/v1/chat/completions等接口。部署命令大致长这样docker run --gpus all \ -v /path/to/models:/models \ -p 8000:8000 \ --shm-size 16g \ vllm/vllm-openai:v0.27.1 \ --model /models/Qwen3-Embedding-0.6B \ --served-model-name qwen3-embedding \ --max-model-len 8192这里有几个参数值得展开说。--gpus all让容器能访问所有 GPU如果只想用特定几张卡可以用--gpus device0,1。--shm-size很多人会忽略但 vLLM 在多进程通信时依赖共享内存默认的 64MB 往往不够设成 16g 是比较稳妥的做法。--max-model-len控制最大上下文长度设得越大占的显存越多要根据实际需求来。关于“vllm docker 镜像中带模型吗”这个问题答案是不带。镜像里只有代码和依赖模型权重需要你通过 volume 挂载进去或者启动时从模型仓库下载。挂载本地模型是更推荐的方式因为下载慢且占容器空间。3.4 部署 DeepSeek、Qwen 等大模型的注意事项部署 DeepSeek 这类大模型时最容易遇到的问题就是显存不够。以 DeepSeek 的某个 7B 级别模型为例FP16 精度下光权重就要占约 14GB加上 KV Cache 和中间激活单卡 24GB 勉强够用但余量不多。如果上下文开得长很容易 OOM。这时候有几个应对策略。第一用--gpu-memory-utilization控制 vLLM 预分配的显存比例默认 0.9可以适当调低留出余量。第二用--tensor-parallel-size做张量并行把模型切到多张卡上。第三考虑量化版本比如 AWQ 或 GPTQ 量化后的权重显存占用能降到一半左右。部署 Qwen 系列时注意它的 tokenizer 和 chat template 配置。有些模型需要显式指定--chat-template否则对话格式会不对导致输出质量下降。这个坑我在早期部署时踩过模型明明能跑但回答总是答非所问排查半天才发现是模板没对上。3.5 vLLM 新版本性能下降的排查思路热词里提到“vllm 新版本性能下降”这个现象确实存在而且原因往往不止一个。我总结了几种常见情况。第一种是默认参数变了。新版本可能调整了max_num_batched_tokens的默认值或者改了调度策略导致在特定负载下吞吐不如旧版。这种情况可以通过显式指定参数来对比。第二种是依赖库版本变化。vLLM 依赖 PyTorch、CUDA、FlashAttention 等任何一个升级都可能带来性能波动。排查方法是固定其他依赖只换 vLLM 版本做 A/B 测试。第三种是模型本身的问题。有些新模型在旧版 vLLM 上跑得好新版反而因为算子实现变化而变慢。这时候要么等官方修复要么回退版本。我的经验是生产环境不要盲目追新版本。新版本出来先在测试环境跑一轮基准测试确认吞吐和延迟都符合预期再升级。升级前记录好当前版本的各项指标升级后对比有回退方案。4. SGLang 与 vLLM 的对比与选型4.1 SGLang 的核心优势在哪里SGLang 和 vLLM 经常被放在一起比较但它们的定位其实有差异。vLLM 更偏向通用的高吞吐推理引擎SGLang 则在结构化生成和复杂编排上做了很多优化。SGLang 最出名的特性是RadixAttention它用一个基数树来管理 KV Cache 的复用。在多轮对话、few-shot 提示、树状推理这些场景下不同请求之间往往有大量重复的前缀RadixAttention 能自动识别并复用这些前缀的 KV Cache省去重复计算。这在 Agent 场景里特别有用因为 Agent 的每一步往往都带着很长的历史上下文。另一个特性是结构化输出。SGLang 支持用正则表达式或语法约束来限制生成格式比如强制输出 JSON、强制符合某个 schema。这对需要程序化解析输出的 Agent 来说能省掉大量后处理逻辑。4.2 SGLang 和 vLLM 到底怎么选这个问题没有标准答案取决于你的场景。我列一个对比表方便对照。维度vLLMSGLang核心优势高吞吐、生态成熟前缀复用、结构化生成适用场景通用在线服务、批量推理多轮对话、Agent、树状推理调度机制PagedAttention Continuous BatchingRadixAttention 前缀缓存结构化输出支持但相对基础原生支持语法约束强社区与文档更成熟案例多增长快但资料相对少部署复杂度低Docker 镜像完善中等配置项较多我的实际选择逻辑是如果只是做一个标准的对话服务请求之间前缀重复不多vLLM 更省心。如果是做 Agent每一步都要带上很长的历史或者需要严格的结构化输出SGLang 的优势会很明显。当然两者并不是互斥的。有些团队会用 vLLM 做底层的通用推理用 SGLang 做 Agent 专用的推理服务各取所长。4.3 从 vLLM 迁移到 SGLang 的注意事项如果你已经在用 vLLM想试试 SGLang有几个地方需要调整。第一API 接口不完全一样虽然 SGLang 也提供了 OpenAI 兼容接口但一些高级参数的名字和语义有差异。第二模型加载方式不同SGLang 对某些模型的支持可能滞后于 vLLM。第三性能调优的参数体系不一样vLLM 的max_num_seqs在 SGLang 里对应的是别的参数。迁移前建议先做小规模验证用同一批请求分别打到两个引擎上对比吞吐、延迟、输出质量。确认没问题再逐步切流量。5. Agent 开发的核心技能与推理后端协同5.1 Agent 到底是什么和普通对话有什么区别Agent 这个词现在被用得很泛但核心特征其实就几条能调用工具、能多步推理、能根据中间结果调整策略。普通对话是一问一答Agent 是“想一步、做一步、看结果、再想下一步”的循环。这个循环对推理后端提出了完全不同的要求。普通对话的请求是独立的Agent 的每一步都依赖上一步的输出而且上下文会不断累积。这就导致两个问题一是上下文越来越长KV Cache 压力大二是每一步都要等上一步完成延迟敏感。所以做 Agent 开发光会写 prompt 是不够的必须理解推理后端的特性知道怎么利用前缀缓存、怎么控制上下文长度、怎么做并发编排。5.2 Agent 框架与编排的选型Agent 框架这两年冒出来很多从早期的 LangChain到后来的各种轻量级框架。选型的时候我建议关注几个点。第一是否支持流式输出。Agent 的中间步骤如果能流式返回用户体验会好很多。第二是否支持工具调用的标准化。不同模型对 function calling 的支持格式不一样框架能不能抹平这个差异很重要。第三是否支持记忆管理。Agent 需要记住历史交互记忆的存储、检索、压缩都是学问。第四是否容易和自建推理后端对接。很多框架默认调 OpenAI 的 API但你要接自己的 vLLM 或 SGLang 服务得确认接口兼容性。我个人的偏好是框架越轻越好。重型框架抽象层太多出问题不好排查而且性能开销大。核心的编排逻辑自己写反而更可控。5.3 Agent 记忆管理的工程实践Agent 记忆是个容易被低估的问题。短期记忆就是当前对话的上下文长期记忆则需要外部存储。上下文一长推理成本就上去了所以必须做压缩或检索。常见的做法是把历史对话做摘要只保留关键信息或者用向量检索每次只取最相关的几条历史。前者适合对话连贯性要求高的场景后者适合知识密集型的场景。这里有个坑摘要本身也要消耗推理资源如果摘要做得太频繁反而增加成本。我的做法是设置一个阈值上下文超过一定长度才触发摘要而且摘要用一个小模型来做不用主模型。5.4 Agent 安全与沙盒机制Agent 能调用工具就意味着它能执行实际操作这就带来了安全风险。比如 Agent 调用了一个删除文件的工具或者访问了不该访问的接口后果可能很严重。所以生产级的 Agent 必须有沙盒机制。工具的执行要在受控环境里权限要最小化敏感操作要有人工确认。热词里提到的“agent 沙盒”和“agent 安全”就是这个方向。我的建议是默认拒绝显式授权。每个工具都要明确声明它能做什么、不能做什么执行前做参数校验执行后做结果审计。6. 常见问题与排查技巧实录6.1 推理服务类问题速查问题现象可能原因排查方向CUDA unavailabletorch 装成 CPU 版 / 驱动不匹配检查 torch 版本后缀、nvidia-smi启动即 OOM模型太大 / max-model-len 过高降低 gpu-memory-utilization、用量化吞吐上不去调度参数保守 / batch 太小调 max_num_seqs、max_num_batched_tokens延迟抖动大请求长度差异大 / 抢占频繁开 chunked prefill、限制最大长度输出格式不对chat template 没配对显式指定 chat-template多卡通信慢NCCL 配置问题检查 NCCL 环境变量、网络带宽6.2 几个我踩过的坑第一个坑是共享内存不够。Docker 里跑 vLLM默认 shm 只有 64MB多进程通信直接卡死。这个问题的表现是服务启动后无响应日志里也没有明显报错特别难排查。后来加了--shm-size 16g就好了。第二个坑是模型路径权限。挂载本地模型目录时容器内的用户可能没有读权限导致加载失败。解决方法是确认目录权限或者用--user指定用户。第三个坑是版本锁定。有次升级 vLLM 后性能掉了 30%排查半天发现是新版本默认开了某个特性和我们的负载不匹配。后来在 requirements 里锁死了版本问题解决。所以生产环境一定要锁版本。第四个坑是Agent 死循环。Agent 调用工具后如果结果不符合预期可能会反复重试陷入死循环。热词里“agent execution terminated due to error”就是这类问题。解决方法是在编排层加最大步数限制和超时机制超过就强制终止。6.3 性能调优的实操心得调优这件事我的原则是先测量再优化。不要凭感觉调参数要用基准测试工具跑出数据。vLLM 自带的 benchmark 脚本就很好用可以测不同并发下的吞吐和延迟。调参的顺序建议是先定gpu_memory_utilization保证不 OOM再调max_num_batched_tokens平衡吞吐和延迟最后调max_num_seqs控制并发度。每次只调一个参数观察指标变化避免多个变量同时动导致无法归因。还有一个容易被忽略的点是输入长度分布。如果你的请求长度差异很大短请求会被长请求拖累。这时候可以开 chunked prefill让长请求分块处理短请求不用等太久。7. 学习路线与技能进阶建议7.1 从零到能上手的学习路径如果你现在还是零基础我建议按这个顺序来。第一步把 PyTorch 环境搭起来能跑通一个简单的模型推理。第二步用 vLLM 部署一个小模型理解 API 怎么调。第三步读一读 vLLM 的调度相关文档理解 EngineCore、Scheduler、Executor 的关系。第四步写一个最简单的 Agent能调用一两个工具。第五步把 Agent 接到自建的 vLLM 服务上跑通完整链路。这个路径看起来简单但每一步都有细节。不要跳步跳步的结果就是遇到问题不知道从哪查。7.2 进阶方向怎么选上手之后进阶方向大致有几个。一个是推理性能优化深入研究调度算法、量化、并行策略。一个是Agent 编排研究复杂工作流、多 Agent 协作、记忆管理。一个是工程化研究服务治理、监控、弹性伸缩。我的建议是先把一个方向做深再横向扩展。AI infra 这个领域广度很重要但深度才是你的核心竞争力。7.3 一些实用的学习资源方向官方文档永远是最好的起点vLLM 和 SGLang 的文档都写得不错。然后是多看源码尤其是调度相关的部分看懂了源码很多问题自然就明白了。再就是多动手自己搭环境、部署模型、压测、调优这些经验是看文档看不来的。社区里的讨论也值得关注很多坑别人已经踩过了搜一搜能省不少时间。但要注意甄别信息有些说法是特定版本特定场景下的不一定适用于你的情况。最后分享一个我自己的习惯每次部署或调优都记录下环境版本、参数配置、测试结果。时间长了这就是你自己的知识库比任何文档都管用。
返回列表