TellWorldAI 世界档案
问档案English

首页›实践›实践

实践

Kimi K2.5 用 vLLM 部署

在 8 卡环境上用 vLLM 部署 Kimi K2.5:思考模式官方参数、kimi_k2 推理与工具解析器、模型名即路径的细节,以及针对推理模型易错题的工具调用实测。

Kimi K2.5 是月之暗面的旗舰级开源模型,部署它的第一道门槛不是安装而是硬件:参考配置横跨 8 张显卡。这篇用 vLLM 走完全流程——离线推理、带推理解析器的 API 服务,以及一道针对推理模型易错点的工具调用实测。

八卡不是随口一说的数字:千亿参数级的权重本身就要占用数百 GB 显存,再叠加 KV 缓存、激活值和运行时开销,单卡甚至双卡都放不下。张量并行的代价也要计入——卡与卡之间的通信带宽直接影响解码速度,卡数越多,每生成一个 token 的同步成本越高。规划资源时除了看权重大小,还要给上下文长度留出 KV 缓存的空间:max_model_len 设到 8192,并发一多,缓存增长会非常快。

环境和模型

vLLM 提供这套部署依赖的全部机械:PagedAttention 管理 KV 缓存、连续批处理提升吞吐、OpenAI 协议服务器、跨卡张量并行 [1]。参考环境:Ubuntu 22.04、Python 3.12、CUDA 12.8、PyTorch 2.8.0 [1]。依赖只有 modelscope 和 vllm,走清华镜像源 [1]:

python -m pip install --upgrade pip
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

pip install modelscope
pip install vllm

下载环节也有讲究:旗舰模型体积大,走 ModelScope 的国内源比从 HuggingFace 拉取快得多,cache_dir 指定的目录要预留足够的磁盘空间;revision 固定在 master 分支,复现时注意模型仓库可能更新,必要时锁定具体的版本号。如果磁盘空间紧张,把缓存目录放到挂载的大容量盘上是常见的做法。

模型从 ModelScope 下载 [1]:

from modelscope import snapshot_download

model_dir = snapshot_download('moonshotai/Kimi-K2.5', cache_dir='/root/autodl-tmp', revision='master')

离线推理

脚本沿用标准 vLLM 写法,关键数字是 tensor_parallel_size=8——旗舰规模的权重需要 8 卡并行才装得下 [1]:

from vllm import LLM, SamplingParams
from transformers import AutoTokenizer
import os
import json

# 自动下载模型时,指定使用modelscope; 否则,会从HuggingFace下载
os.environ['VLLM_USE_MODELSCOPE']='True'

def get_completion(prompts, model, tokenizer=None, temperature=0.6, top_p=0.95, top_k=20, min_p=0, max_tokens=4096, max_model_len=8192):
    stop_token_ids = [151645, 151643]
    # 创建采样参数。temperature 控制生成文本的多样性,top_p 控制核心采样的概率,top_k 通过限制候选词的数量来控制生成文本的质量和多样性, min_p 通过设置概率阈值来筛选候选词,从而在保证文本质量的同时增加多样性
    sampling_params = SamplingParams(temperature=temperature, top_p=top_p, top_k=top_k, min_p=min_p, max_tokens=max_tokens, stop_token_ids=stop_token_ids)  # max_tokens 用于限制模型在推理过程中生成的最大输出长度
    # 初始化 vLLM 推理引擎
    llm = LLM(model=model, tokenizer=tokenizer, max_model_len=max_model_len,trust_remote_code=True, tensor_parallel_size=8)  # max_model_len 用于限制模型在推理过程中可以处理的最大输入和输出长度之和。
    outputs = llm.generate(prompts, sampling_params)
    return outputs

提示词经聊天模板格式化,思考模式的开关就在这次调用里 [1]:

if __name__ == "__main__":
    # 初始化 vLLM 推理引擎
    model='/root/autodl-fs/moonshotai/Kimi-K2.5' # 指定模型路径
    tokenizer = AutoTokenizer.from_pretrained(model) # 加载分词器

    prompt = "给我一个关于大模型的简短介绍。"
    messages = [
        {"role": "user", "content": prompt}
    ]
    text = tokenizer.apply_chat_template(
        messages,
        tokenize=False,
        add_generation_prompt=True,
        enable_thinking=True  # 是否开启思考模式,默认为 True
    )

    outputs = get_completion(text, model, tokenizer=None, temperature=0.6, top_p = 0.95, top_k=20, min_p=0)  # 对于思考模式,官方建议使用以下参数:temperature = 0.6,TopP = 0.95,TopK = 20,MinP = 0。

思考模式的官方推荐参数:temperature 0.6、TopP 0.95、TopK 20、MinP 0 [1]。输出循环打印原始生成结果 [1]:

    # 输出是一个包含 prompt、生成文本和其他信息的 RequestOutput 对象列表。
    # 打印输出。
    for output in outputs:
        prompt = output.prompt
        generated_text = output.outputs[0].text
        print(f"Prompt: {prompt!r}, \nResponse: {generated_text!r}")

这组参数不是随手填的:推理模型在思考阶段需要一定的随机性来探索解题路径,temperature 0.6 和 TopP 0.95 是在推理任务上验证过的平衡点;TopK 20 收紧候选词分布,MinP 0 则表示不做额外的概率阈值过滤。换成普通对话场景,参数可以适当放松,但要复现标准效果时照抄这组数字最稳妥。

响应分两部分:<think> 和 </think> 之间是思考过程,之后是最终答案 [1]。

思考过程本身也消耗 token 预算。开思考模式后,completion tokens 里很大一部分花在推理步骤上,真正输出答案的份额相应变少。max_tokens 设得太小时,模型可能还在思考就被截断,最终连答案都拿不到——这类问题的表象是响应突然以思考文本结尾,调整办法要么加大 max_tokens,要么在问题里要求模型精简推理。

起 API 服务:解析器与「模型名即路径」

Kimi-2.5 兼容 OpenAI 协议,vllm serve 在 http://localhost:8000 起服务,带模型列表、completions、chat completions 三类端点,一次托管一个模型 [1]。启动命令里有并行设置、上下文上限和两个解析器 [1]:

VLLM_USE_MODELSCOPE=true vllm serve /root/autodl-fs/moonshotai/Kimi-K2.5 -tp 8 --max_model_len 8192 --trust-remote-code --tool-call-parser kimi_k2 --reasoning-parser kimi_k2

开启 --enable-reasoning 时 --reasoning-parser 是必填项:模型会在输出里附带 reasoning_content 字段,装着导向结论的推理步骤,解析器负责提取和格式化 [1]。写客户端之前有个细节要先知道:这条命令没有设 --served-model-name,所以模型列表里返回的 id 就是完整的文件系统路径,所有请求都得拿这个路径当模型名 [1]:

curl http://localhost:8000/v1/models

completions 测试,注意 model 字段填的是路径,提示词带 <think>\n 后缀 [1]:

curl http://localhost:8000/v1/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "/root/autodl-fs/moonshotai/Kimi-K2.5",
        "prompt": "我想问你,什么是深度学习算法?<think>\n",
        "max_tokens": 1024,
        "temperature": 0
    }'

这次调用用了 9 个 prompt token、343 个 completion token [1]。Python 聊天客户端结构相同,model 字段还是路径 [1]:

from openai import OpenAI
openai_api_key = "sk-xxx" # 随便填写,只是为了通过接口参数校验
openai_api_base = "http://localhost:8000/v1"

client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)

chat_outputs = client.chat.completions.create(
    model="/root/autodl-fs/moonshotai/Kimi-K2.5",
    messages=[
        {"role": "user", "content": "什么是大模型?"},
    ]
)
print(chat_outputs)

配好解析器后,聊天响应分得很干净:最终答案在 content 字段,思考步骤单独放在 reasoning 字段里 [1]。示例这次调用用了 12 个 prompt token、847 个 completion token——推理模型的预算有多少花在思考上,这个比例一目了然 [1]。

路径当模型名这个细节最容易在客户端踩坑:写死的字符串里带着服务器的目录结构,换个部署位置就全部失效。工程上更稳的做法是启动时先请求一次模型列表,从返回的 id 动态读取模型名,再把它填进后续请求。另外,completions 接口的提示词末尾加 <think>\n 是在提示模型续写推理过程,走 chat completions 接口时由解析器自动处理,不需要手动加。

工具调用实测

示例定义了四个函数——加法、乘法、比较、数字母——每个都配带类型和必填字段的工具描述 [1]。客户端把问题和工具列表一起发出,读回模型的选择 [1]:

def function_call_playground(prompt):
    messages = [{'role': 'user', 'content': prompt}]
    response = client.chat.completions.create(
        model="/root/autodl-fs/moonshotai/Kimi-K2.5",
        messages = messages,
        temperature=0.01,
        top_p=0.95,
        stream=False,
        tools=tools)

    # print(response)
    func1_name = response.choices[0].message.tool_calls[0].function.name
    func1_args = response.choices[0].message.tool_calls[0].function.arguments
    func1_out = eval(f'{func1_name}(**{func1_args})')

temperature 压到 0.01——选工具要确定性 [1]。函数结果以 tool 消息的身份回到对话里,第二次调用生成自然语言回答 [1]:

    messages.append(response.choices[0].message)
    messages.append({
        'role': 'tool',
        'content': f'{func1_out}',
        'tool_call_id': response.choices[0].message.tool_calls[0].id
    })
    # print(messages)
    response = client.chat.completions.create(
        model="/root/autodl-fs/moonshotai/Kimi-K2.5",
        messages=messages,
        temperature=0.01,
        top_p=0.95,
        stream=False,
        tools=tools)
    return response.choices[0].message.content

两道测试题瞄准推理模型的经典盲区——数 strawberry 里的 r、比较 9.11 和 9.9——走工具链路全部答对:r 有 3 个,9.11 更小 [1]。请求处理全程 API 后端都会打印日志和统计信息,调用行为异常时先看那里 [1]。

跑工具调用循环时还有几件事值得注意:解析器必须正确配置,否则模型输出的工具意图会以普通文本形式出现,客户端拿不到结构化的 tool_calls;eval 直接执行模型给出的参数有安全隐患,生产环境应换成显式的函数映射表;工具描述写得越具体,模型选错函数的概率越低——参数类型、单位、边界条件都值得写进去。

整条链路回顾下来:装环境、下模型、离线验证、起服务、配解析器、跑工具调用,每一步都有明确的验证点。对推理模型来说,解析器和采样参数是两个最值得反复确认的环节——前者决定响应结构,后者决定生成质量。

本文改编自 Datawhale 开源教程《self-llm》的 KiMi-2.5 vLLM 部署一节[1],原文以 Apache-2.0 许可证发布。

来源

  1. 1
    02-KiMi-2.5 vLLM 部署调用 | self-llmDatawhale self-llm (Apache-2.0)

引用本页: Kimi K2.5 用 vLLM 部署. TellWorld, https://www.tellworld.net/zh/practice/practice-kimi-k2-5-vllm. 更新于 2026-11-14

相关动态