Turbo论文解析:LLM推理优化的系统级突破 这次是这套论文记录的第 25 篇看的是 SIGCOMM 26 的 Turbo。主题一句话就能讲清楚LLM 模型推理优化。但和之前几篇只谈单卡显存、模型权重的笔记不太一样这篇的落点更偏系统层关心的是请求调度、批量处理、跨节点传输和显存协同这类服务端问题。换句话说它想解决的不是“模型能不能跑”而是“模型跑起来之后别人几十个并发打过来链路还扛不扛得住”。先给结论性信息这篇论文的关键词是 LLM、模型推理、优化、Turbo、SIGCOMM。按 SIGCOMM 的主流研究口味推断Turbo 大概率围绕在线推理场景的吞吐与时延做文章核心对象可能在请求调度、连续批处理、KV Cache 缓存管理、跨节点通信或精度感知优化这几块。文章后面会给出完整论文笔记拆解思路以及一套不依赖论文代码也能验证的评测流程。这样写的好处是即使原文公式还没完全啃完你也能先形成自己的判断框架这个优化到底动了哪儿、值不值得复现、在自己的推理服务里能省多少钱。先说清楚这篇笔记的边界本文不会假装读过原文细节后替你复述每个模块的数学推导而是告诉你从系统角度看这类 SIGCOMM 论文应该拆哪些层、验证哪些指标、最容易在哪翻车。如果你想照着论文复现实验后文的环境准备和评测方法可以直接平滑迁移到 vLLM、SGLang、TensorRT-LLM 这类主流推理框架上。1. 核心能力速览在动手之前先把论文的信息钉在表格里。论文笔记不是翻译机先判断值不值得读这张表就是判断依据。项目说明论文名称TurboSIGCOMM 26研究主题LLM 模型推理优化研究层面系统 / 网络 / 服务端调度核心目标提升在线推理吞吐、降低端到端时延可能涉及的优化点请求调度、连续批处理、KV Cache 管理、Prell/Decode 分离、跨节点传输、精度与编译优化适合读者大模型推理工程师、分布式系统研究者、SRE、算法工程师单机单卡能否复现可以验证部分思想完整验证需要多卡或多机代码与实验细节以论文原文为准再补充一句阅读顺序上的建议。拿到这类论文后不要先钻进公式里花 10 分钟看三块第一Related Work 里它承认了哪些前人没解决的问题第二Figure 里的系统架构图这决定了它的优化发生在哪一层第三实验部分的负载设置也就是它拿什么请求分布来证明自己方法有效。看完这三块你对 Turbo 的实用价值就已经有大致的判断了。2. 论文定位LLM 推理优化到底在优化什么很多刚入门的朋友会觉得 LLM 推理慢是“显卡不够好”或者“模型太大”实际上到了在线服务阶段瓶颈是复合的。第一个瓶颈是自回归生成方式。LLM 是逐 token 生成的每生成一个 token 都要把所有已生成内容重新走一遍注意力计算计算量随序列长度线性上涨。第二个瓶颈是显存带宽。推理时模型权重和 KV Cache 都要从显存反复读取真正花在算力上的时间反而不是大头大量时间花在“把数据搬进计算单元”的过程。第三个瓶颈是 KV Cache 膨胀。每个请求都会占用一定长度的 KV Cache并发越高、上下文越长显存消耗越快请求稍微一多就 OOM。第四个瓶颈是批处理策略。不同请求的输入输出长度不一样短的 Token 已经生成完长的还在跑怎么把空闲的计算资源塞给新请求这就是连续批处理解决的问题。第五个瓶颈是跨节点网络。单机显存放不下模型或并发太高时请求要走多机协同网络延迟和带宽立刻成为新瓶颈。Turbo 放在 SIGCOMM 这个会议上最有价值的信息其实在这里它的优化视角大概率不是“单卡显存怎么塞更大模型”而是数据中心里网络和服务端怎么配合才能让 LLM 推理链路整体更快。这类型的系统论文一般会叠加多种优化手段比如把 Prefill 阶段和 Decode 阶段分离到不同资源池、在网络感知的条件下做请求路由、用前缀缓存复用公共提示词、甚至把量化精度和显存带宽需求放在一起考虑。你不需要一开始就完全看懂模型内部的注意力机制但你需要知道这类优化本质上是在和显存容量、带宽、网络时延这三样东西做交换。3. 论文方法拆解值得重点验证的四个机制由于目前公开信息里暂未看到 Turbo 论文的完整技术细节这里给出的是 SIGCOMM 系 LLM 推理优化论文通用的方法拆解框架供你对照原文阅读时使用。等原文公开后可以直接拿这个框架去勾选它实际用了几条。值得重点检查的四个机制如下。3.1 是否把 Prefill 和 Decode 拆成两段Prefill 阶段计算量大、并行度高但每个请求只跑一次Decode 阶段是逐个 token 生成并行度低但时间长。两者混在一起跑时调度器很难兼顾两类请求的不同特性。很多系统优化论文会把这两个阶段拆开放到不同的 GPU 池甚至选不同的批量大小策略。对应到你的场景里如果 Turbo 做了这一步复现时就要看两个池子的资源比例怎么调节。3.2 是否做网络感知的请求调度SIGCOMM 论文的经典做法是把网络拓扑和通信开销纳入调度决策。举例来说多机部署时某台机器内存里有大量已缓存的公共前缀新请求如果路由到这台机器能省去大量重复计算但代价是这台机器可能网络负载已经很高。如果 Turbo 引入了类似的调度策略你需要关注的指标就是路由决策延迟和请求命中率之间的权衡。3.3 是否做 KV Cache 复用或前缀缓存很多在线服务的请求是有公共前缀的比如系统提示词、角色设定、Few-shot 示例。Turbo 如果做 KV Cache 复用核心价值是让这些公共部分只计算一次后续请求直接复用。这个优化对显存和时延的改善非常直观但也要求系统能快速匹配前缀并管理缓存淘汰验证时可以专门构造一批共享前缀的请求来测试命中率。3.4 是否做精度感知或量化感知的调度LLM 推理中的精度选择直接影响两个东西模型大小和 KV Cache 占用的显存。fp16、bf16、fp32 混用或者更激进的 int8/fp8 量化会改变模型体积和带宽需求。如果 Turbo 在调度层面对不同精度做感知那么它的显存分配策略和批处理策略可能和传统框架完全不同。验证时可以分别用 fp16 和量化版本跑同样负载看吞吐提升来源到底是带宽下降还是调度优化。用这套框架去读论文能避免被“Turbo 更高效”这种结论带跑。你需要搞清楚的是它把性能收益建立在哪几个假设上而这些假设在你的业务请求分布里是否存在。4. 适用场景与使用边界这类论文适合的场景和它的优化对象高度一致。先说适合的场景。第一并发访问量高的在线推理服务。比如几十路 Agent 同时调用模型、在线客服、写作助手这类场景请求密度高对调度和批处理优化最敏感。第二请求长度分布非常不均匀的场景。有的请求只有 20 个 token有的要写 2000 字长度差异越大连续批处理和缓存复用带来的收益越明显。第三有多机推理条件的团队。如果单卡放不下模型或者并发已经撑爆单机SIGCOMM 这类系统论文的参考价值会立刻变大。第四按 tokens 计费或按 GPU 成本核算的服务。吞吐优化直接对应成本下降论文里的优化思路能帮你找到现有系统里“白花钱”的部分。再说使用边界。第一单卡、单机、小并发场景不要盲目套用系统级优化方案很多机制在请求量很小时反而增加调度开销。第二论文里的优化通常建立在特定硬件假设上比如多机 RDMA 网络、高端 GPU 或特定型号的显存规划你的环境如果没有这些硬件复现结果会打折。第三论文实验设置和线上真实流量差异巨大比如论文可能用固定输出长度测试而线上请求长度是长尾分布收益会有偏差。第四工程落地成本需要单独评估很多论文优化需要侵入推理框架底层如果框架不支持改造代价比想象中高得多。这里还要专门提醒一下合规边界。部署 LLM 推理服务时不管用什么优化方案都必须保证模型输入输出不涉及侵犯他人版权、隐私或违法内容涉及用户真实文本、图片、语音时要确保数据脱敏和授权合规多机部署时模型权重文件应来自合法渠道遵循对应开源或商用许可。Turbo 这类系统论文本身是研究资料但应用到生产环境时责任在部署方。5. 环境准备与前置条件如果你只是想读懂论文那么准备 PDF 阅读器、笔记工具、一台能上网的电脑就够。如果想复现并验证论文里的优化思想按现代 LLM 推理框架的通用要求推荐准备以下环境。操作系统Linux 优先Ubuntu 20.04 或 22.04 比较省心Windows 可用 WSL2 过渡但多机通信测试建议直接上 Linux。GPUNVIDIA 显卡显存越大越好单卡至少 8GB 以上才有意义如果计划测试多机协同准备两台同配置机器。CUDA 与驱动CUDA 版本与 PyTorch 版本匹配即可不需要最新稳定优先。Python3.10 或 3.11 版本兼容性最好。推理框架vLLM、SGLang 或 TensorRT-LLM三者都是当前主流vLLM 对连续批处理和 PagedAttention 支持好适合做基线SGLang 对前缀缓存调度更激进适合对比测试。网络环境多机测试需要高速网卡普通千兆网卡会限制跨节点性能RDMA / InfiniBand 更贴近 SIGCOMM 论文假设但实际验证时可以先在千兆网卡上跑通流程再评估通信开销。先做一遍环境自检避免后面把时间浪费在依赖上。# 检查显卡和驱动 nvidia-smi # 检查 CUDA 编译版本 nvcc --version # 检查 PyTorch 是否检测到 GPU python -c import torch; print(torch.__version__, torch.cuda.is_available())更稳妥的做法是创建一个干净的虚拟环境把依赖固定住。后面跑对比实验时不同框架、不同 CUDA 版本相互污染是很常见的坑。python -m venv llm-opt source llm-opt/bin/activate pip install --upgrade pip # 根据实际框架文档安装依赖以下仅为示例 # pip install vllm torch openai requests磁盘空间也要提前估算。一个 7B 模型 fp16 权重大约 14GB13B 大约 26GB再算上 Python 环境和框架缓存预留至少 100GB 比较稳。如果你测试的是更大模型空间要按倍数放大。6. 复现与验证思路论文方法怎么落到框架里论文里提出的系统级优化真正从头复现成本很高。更实用的路径是先用现有推理框架搭出基线再针对论文里最核心的那一两个机制做对照组实验看收益是否成立。这套方法不需要改框架源码也能得到有价值的验证结果。6.1 第一步跑通基线服务以 vLLM 为例先启动一个最基础的 OpenAI 兼容接口服务。注意下面的命令是通用模板实际模型名、路径、端口要按你的环境和模型文件调整。python -m vllm.entrypoints.openai.api_server \ --model /path/to/your-model \ --served-model-name turbo-opt \ --tensor-parallel-size 1 \ --max-model-len 4096 \ --host 127.0.0.1 \ --port 8000启动后先做一个简单请求确认服务能跑通记录这时候的显存占用和响应时间。curl http://127.0.0.1:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: turbo-opt, messages: [{role: user, content: 你好请用一句话介绍你自己。}], max_tokens: 128 }这一步的意义是确认环境没问题。如果这个请求都失败后面所有压测数据都不可信。6.2 第二步构造可控的测试请求集论文验证最怕“随手发几个请求就下结论”。请求的输入长度、输出长度、并发数每一项都会直接影响指标。建议构造三类请求短请求输入 100 token输出 50 token模拟轻量问答。中等请求输入 500 token输出 256 token模拟文档摘要。长请求输入 1200 token输出 512 token模拟长文生成。每类请求准备 30 到 50 条内容可以复用同一批文本但为了避免缓存命中带来的假优化正式测试时最好打乱顺序并做前缀扰动。6.3 第三步写一个简单的压测脚本下面是一个通用的 Python 压测模板使用openai库并发发请求统计平均时延和吞吐。脚本本身不包含任何论文特有逻辑适用于所有兼容 OpenAI 接口的推理服务。import asyncio import time from openai import AsyncOpenAI API_BASE http://127.0.0.1:8000/v1 API_KEY EMPTY MODEL_NAME turbo-opt CONCURRENCY 8 TOTAL_REQUESTS 40 MAX_TOKENS 128 PROMPT 请写一段关于人工智能发展的简短介绍。 client AsyncOpenAI(base_urlAPI_BASE, api_keyAPI_KEY) async def send_one(semaphore, idx): async with semaphore: start time.perf_counter() resp await client.chat.completions.create( modelMODEL_NAME, messages[{role: user, content: PROMPT}], max_tokensMAX_TOKENS, ) elapsed time.perf_counter() - start output_text resp.choices[0].message.content or return elapsed, len(output_text) async def main(): sem asyncio.Semaphore(CONCURRENCY) tasks [send_one(sem, i) for i in range(TOTAL_REQUESTS)] results await asyncio.gather(*tasks) latencies [r[0] for r in results] total_tokens sum(r[1] for r in results) total_time sum(latencies) / len(latencies) print(f平均时延: {sum(latencies) / len(latencies):.3f}s) print(f总输出 tokens: {total_tokens}) print(f平均生成速率: {total_tokens / sum(latencies):.3f} tokens/s) if __name__ __main__: asyncio.run(main())这个脚本统计的是端到端响应时间也就是用户真实感受。论文里可能会区分 Prefill 时间和 Decode 时间但你自己验证时先看端到端指标是最不容易骗自己的。6.4 第四步做对照实验对照组的设计要围绕论文的核心假设。假设 Turbo 的主要收益来自连续批处理那么对照组就是“关闭批处理”和“开启批处理”的同一模型假设收益来自 KV Cache 复用那么对照组就是“相同前缀”和“完全随机前缀”的请求集假设收益来自精度优化那么对照组就是 fp16 和 int8 两个精度版本的同一负载。每改一个变量固定其他条件跑三轮取平均。下面给出一份实验记录模板组别并发数请求数平均时延(s)总输出 tokenstokens/s显存占用(GB)基线-fp16-并发8840待测待测待测待测优化A-并发8840待测待测待测待测优化B-并发8840待测待测待测待测得出数据后不要只盯着平均时延。平均时延下降但 P95 时延恶化对生产服务未必是好事tokens/s 上升但显存占用翻倍也要继续观察性价比。7. 模型推理评测指标与实验设计理解指标比理解论文公式更快。LLM 推理优化论文里出现频率最高的指标有以下几类。指标全称/含义关注价值TTFTTime To First Token首 token 延迟用户第一次看到输出的等待时间TPOTTime Per Output Token每个输出 token 的平均生成时间决定生成速度的核心指标ITLInter-Token Latency相邻 token 生成间隔流式输出的主观流畅度吞吐量单位时间生成的 token 总数衡量系统整体处理能力显存占用推理过程模型权重 KV Cache 激活值判断能否扩展并发批处理成功率在压力下没有失败、没有超时的请求比例生产环境稳定性实验设计要覆盖三个维度。第一是并发梯度建议从 1、4、8、16、32 递增观察吞吐的变化是线性增长还是提前饱和。第二是请求长度混合不要只测固定长度要模拟线上请求长短混合的分布。第三是输出长度限制设置 max_tokens 为 64、128、256、512 四档观察生成变长时 TTFT 和 TPOT 如何变化。跑实验前记住三点固定模型版本、固定随机种子、固定推理参数。三个条件只要换一个对比数据的可信度就会大打折扣。8. 接口 API 与批量任务落地系统级推理优化论文的价值最终要通过接口体现出来。不管 Turbo 内部怎么优化对外暴露的通常还是 OpenAI 兼容接口。8.1 接口调用示例启动服务后用 Pythonrequests或者openai库都能直接调用。下面的示例以requests为主方便看清请求结构。import requests import json url http://127.0.0.1:8000/v1/chat/completions payload { model: turbo-opt, messages: [ {role: system, content: 你是一个严谨的技术助手。}, {role: user, content: 解释一下 LLM 推理优化的核心瓶颈。} ], max_tokens: 512, temperature: 0.2, stream: False } headers {Content-Type: application/json} resp requests.post(url, headersheaders, datajson.dumps(payload), timeout120) print(resp.status_code) print(resp.json()[choices][0][message][content])注意模型名、端口、请求格式需要以实际部署框架为准。如果自己搭的推理服务没有 HTTP 接口直接用框架内置的 Python 生成接口也可以但生产环境还是建议走标准 API方便后续接网关、日志和监控。8.2 批量任务设计很多工具有批量推理需求比如批量润色文档、批量生成摘要、批量审核文本。批量任务和在线单请求不同它更关心吞吐而非单请求时延。建议按队列模型设计{ task_id: batch-001, model: turbo-opt, input_file: ./inputs/batch_input.jsonl, output_file: ./outputs/batch_output.jsonl, max_tokens: 256, concurrency: 8, retry_times: 3 }批量执行时先做小规模试跑比如 10 条数据确认输出格式稳定后再全量跑。任务脚本里要加日志记录每条请求的耗时、是否重试、失败原因。如果发到一半服务崩了最少能从日志恢复结果。8.3 LLM Gateway 的作用热词里出现过的 LLM gateway 和这里高度相关。当推理服务面向多个业务线时建议在模型服务前面加一层网关统一做鉴权、限流、路由、缓存和成本统计。Turbo 这类系统优化解决的是模型服务本身的效率网关解决的是访问治理和稳定性。两者是互补关系不是替代关系。9. 资源占用与性能观察验证系统论文时不能只看日志里的时间数字还要观察资源占用否则你无法判断性能提升来自算法还是来自硬件差异。显存是第一观察项。推理过程中显存会逐步增长原因是 KV Cache 会随着生成 token 数量增加而膨胀。用watch -n 1 nvidia-smi可以实时看显存变化重点关注显存利用率是否平稳、是否出现碎片化导致的峰值升高。如果并发上去后显存直接打满说明 KV Cache 管理策略还需要调整。GPU 利用率也要看。LLM 推理通常不会像训练那样把 GPU 算力拉满因为瓶颈可能在显存带宽。如果利用率低但显存吞吐很高说明瓶颈在数据搬运如果利用率高但时延也高说明计算调度有问题。观察时结合nvidia-smi里显示的内存带宽利用率和温度能初步判断是计算受限还是带宽受限。跨节点测试还要关注网络。普通千兆网卡下模型分到两台机器后通信时延会显著上升。观察工具可以用iperf3或者直接看推理日志里的等待时间。如果发现跨节点吞吐还不如单卡先排查网络再排查调度策略。精度也是一个变量。fp16 和 bf16 在数值范围上不同fp32 占显存更大但精度更高量化到 int8 或 fp8 后模型体积更小、传输更快但生成质量可能下降。Turbo 这类论文如果包含精度感知调度你就要多测一组“不同精度下吞吐与时延”的对比数据判断收益来源是否真的是精度压缩而不是别的机制。功耗和温度同样值得记一笔。连续压测会让 GPU 温度升高导致降频进而让推理变慢。如果你做对比实验时两组数据不是在同一温度区间测的结果可能失真。建议每组实验前休息两分钟让 GPU 温度回落后再跑下一轮。10. 论文里的关键权衡与工程坑系统论文往往会把单个优化点的收益放大落到工程上时一个优化点常常会挤压另一个维度的空间。下面这几组权衡在阅读和验证时需要特别注意。第一组是延迟与吞吐的权衡。连续批处理能显著提升吞吐但单个请求的等待时间可能变长多机并行能降低单请求时延但网络通信会抵消一部分吞吐收益。Turbo 如果声称二者兼得你要看它用在哪个阶段哪个用户群体受益。第二组是精度与速度的权衡。量化让模型更快但输出质量可能下降。对需要精确生成代码、数学推导、长文档的场景int8 的坏例子可能比想象中多。验证时不要只看 BLEU 或人工打分要看具体业务字段是否出错。第三组是调度开销与收益的权衡。任何调度器都有决策成本。请求量小时调度决策本身可能比优化收益还贵。所以论文实验里的并发规模非常重要如果并发只有 16 路你就别指望调度优化能带来数量级提升。第四组是网络传输与计算的重叠情况。跨节点推理里最理想的状态是计算和传输并行即数据在路上时 GPU 还在算其他请求。如果你的框架不支持这类重叠那么多机方案会很难看。工程上常见的问题还包括显存碎片。长期运行的推理服务里KV Cache 不断分配和释放显存碎片会越来越严重最后明明显存总量够却申请不到连续块。这类问题在短时间压测里不容易暴露需要长时间稳定性测试才能发现。长尾请求也会打乱优化节奏。有些请求生成特别长占住了批量窗口里的资源导致其他短请求全部排队。好的调度器会做抢占或超时处理但很多论文实验不会专门测试这个场景。你自己验证时专门往请求集里塞几个超长输出请求看系统是否还能保持稳定。11. 常见问题与排查方法这里整理一份通用排查表覆盖从装环境到压测结果的常见问题。问题现象可能原因排查方式解决方案启动服务报 CUDA 不可用PyTorch 与 CUDA 版本不匹配运行python -c import torch; print(torch.cuda.is_available())重装匹配的 PyTorch/CUDA模型加载后显存不足模型权重 KV Cache 超过显存容量nvidia-smi确认显存占用减小max-model-len限制并发或加载量化版本压测后吞吐没有变化优化点本身占比小或请求集不合适对比不同并发、不同请求长度下的数据调整请求集确认瓶颈在 GPU 还是网络输出质量明显变差精度设置过低对比 fp16 与 int8 的输出结果换用更高精度或做针对性质量测试跨节点速度反而下降网络带宽不足或调度未感知拓扑用 iperf3 测试机器间带宽调整网络环境或减小张量并行规模并发上升后大面积超时队列积压或批处理窗口过长查看服务日志里的 pending 时间限制最大并发开启请求超时和抢占显存碎片导致 OOM长期运行释放不充分观察服务运行较久后的显存碎片率定时重启服务或启用显存整理机制批量任务中途失败单条请求超时或服务重启查看任务日志中的失败记录加入重试机制失败请求单独重跑12. 最佳实践与使用建议读这类论文和做实际推理优化侧重点不一样。论文更看重机制的创新性和实验结论工程则更看重可维护性与长期稳定性。把两者结合建议按下面的思路走。第一第一次接触论文时先做小参数验证。不要一上来就用几十路并发跑长文本先用单请求验证环境再逐步加压。环境都不稳时任何压测数据都没有说服力。第二保留一套最小可运行配置。把启动命令、模型路径、端口、依赖版本写进 README每个参数写清楚含义。团队协作时这套配置能节省大量沟通成本。第三模型文件、输入素材、输出结果分目录管理。推理优化项目会反复跑实验如果所有数据都堆在一个目录最后连自己都分不清哪一组是基准线。第四批量任务要加日志和失败重试。任务队列里的每条请求都要有唯一 ID记录开始时间、结束时间、失败原因。重试时要做好幂等设计避免同一个请求生成两次结果造成重复计费。第五接口服务要限制访问范围。如果只是内部验证绑定127.0.0.1或内网 IP不要直接暴露公网。对外开放时务必加鉴权、限流和内容安全策略。第六涉及人脸、声音、版权素材时必须确认授权。Turbo 是推理优化论文本身不涉及生成内容但如果你在部署的模型服务中加入了图像、语音或文本生成能力生成结果可能涉及版权和肖像权问题责任在部署方。第七发布或商用前要做效果复核。系统优化论文里的收益是在特定负载下测出来的你的业务负载不同收益会缩水甚至为负。上线前至少跑一周影子流量对比新旧方案的延迟、错误率和成本。第八多关注编译层优化给自己带来的额外收益。热词列表里反复出现编译器优化、精度问题等话题这些和 Turbo 并不冲突。推理框架内部的 torch.compile、算子融合、CUDA Graph 等技术可以作为 Turbo 这类调度优化的叠加项而不是二选一。13. 总结与下一步Turbo 这篇论文最值得关注的点是它把 LLM 推理优化放到了系统层来看用调度、缓存、网络协同的方式解决在线推理吞吐和时延问题。这种视角对单卡玩家可能没那么直观但对已经在跑多卡服务或者准备上生产环境的团队来说方向非常对口。如果你打算跟进最先应该验证的是吞吐量和 TTFT 两项指标。建议先把 vLLM 基线跑通再用第 6 节和第 7 节的测试方法测一组并发梯度数据打好基线后等原文公开再对照复现。最容易踩的坑是把论文里的单点优化当成生产系统全量方案实际上任何优化都要在自己的请求分布、硬件环境和稳定性要求下重新验证。后续可以继续扩展的方向也很多一是关注 PD 分离思路在推理框架里的落地进展二是尝试前缀缓存/共享前缀机制在 Agent 类应用里的收益三是把精度量化与调度优化结合在成本敏感场景里找到更优的平衡点。建议收藏备用等论文原文、代码或评测数据公开后按这套验证流程过一次就能很快判断 Turbo 到底适不适合自己的推理服务。