Когда Kimi K2.5 молчит вместо ответа
Вы развернули Kimi K2.5 на кластере из 8x H200, запустили vLLM или SGLang, отправили запрос и получили в ответ... пустоту. Или странный XML-мусор вроде <thinking> или <function_calls>, который должен был остаться внутри модели. Знакомо? Это не баг вашей настройки - это особенность архитектуры K2.5, которую нужно правильно обойти.
На 28.01.2026 Kimi K2.5 остается одной из самых капризных моделей для развертывания. Ее гибридная архитектура (MoE + reasoning) требует специфичных настроек, которых нет в документации vLLM.
Почему это происходит? Разбираем механизм ошибки
Kimi K2.5 использует внутренние теги для структурирования reasoning и tool calls. В обычном режиме эти теги удаляются перед выводом. Но когда вы запускаете модель через vLLM или SGLang, система постобработки не знает, как работать с кастомными тегами Kimi.
| Проблема | Причина | Когда проявляется |
|---|---|---|
| (no content) в ответе | Модель генерирует только внутренние теги, которые удаляются постпроцессором | При использовании tool-call-parser без правильных стоп-токенов |
| Утечка XML-тегов | Постпроцессор не распознает теги Kimi как служебные | Когда skip_special_tokens=True не работает с кастомными тегами |
| Бесконечная генерация | Отсутствие стоп-последовательностей для tool calls | В SGLang без настройки stop_tokens |
Проблема усугубляется тем, что Kimi K2.5 на 28.01.2026 использует собственную систему tool calling, несовместимую со стандартным OpenAI-форматом. Если вы пытались запустить ее как обычную модель - вот почему получали мусор.
Решение для vLLM: правильная настройка tool-call-parser
Основная ошибка - запуск vLLM с флагом --tool-call-parser, но без указания кастомных тегов Kimi. vLLM по умолчанию ожидает OpenAI-формат, а K2.5 говорит на своем диалекте.
1 Создаем кастомный парсер для Kimi
Вам нужен Python-скрипт, который понимает теги Kimi. Не используйте стандартный tool-call-parser - он сломается.
# kimi_parser.py
import json
import re
from typing import List, Dict, Any
from vllm.transformers_utils.tokenizer import get_tokenizer
class KimiToolCallParser:
def __init__(self, tokenizer):
self.tokenizer = tokenizer
# Теги, специфичные для Kimi K2.5 (актуально на 28.01.2026)
self.kimi_tags = [
"",
" ",
"",
" ",
"",
" ",
"",
" ",
"",
" ",
]
def parse_tool_calls(self, text: str) -> List[Dict[str, Any]]:
"""Извлекает tool calls из текста Kimi K2.5"""
if "" not in text:
return []
tool_calls = []
# Ищем все вызовы инструментов
pattern = r'.*? '
matches = re.findall(pattern, text, re.DOTALL)
for match in matches:
# Извлекаем название инструмента
tool_name_match = re.search(r'(.*?) ', match)
# Извлекаем параметры
params_match = re.search(r'(.*?) ', match, re.DOTALL)
if tool_name_match and params_match:
try:
params = json.loads(params_match.group(1).strip())
tool_calls.append({
"type": "function",
"function": {
"name": tool_name_match.group(1).strip(),
"arguments": json.dumps(params, ensure_ascii=False)
}
})
except json.JSONDecodeError:
# Если JSON невалидный, пытаемся починить
continue
return tool_calls
def clean_text(self, text: str) -> str:
"""Удаляет теги Kimi из финального ответа"""
for tag in self.kimi_tags:
text = text.replace(tag, "")
# Удаляем множественные пробелы
text = re.sub(r'\s+', ' ', text).strip()
return text
2 Запускаем vLLM с правильными параметрами
Теперь запускаем vLLM с нашим парсером и критически важными стоп-токенами:
# Запуск на 8x H200 с правильными настройками
python -m vllm.entrypoints.openai.api_server \
--model moe-community/Kimi-K2.5-8x7B \
--tensor-parallel-size 8 \
--gpu-memory-utilization 0.95 \
--max-model-len 32768 \
--served-model-name kimi-k2.5 \
--trust-remote-code \
--disable-custom-all-reduce \
--enforce-eager \
--stop "" --stop "" --stop "" \
--stop-token-ids 2 # EOS token для Kimi
# Важно: НЕ используйте --tool-call-parser без кастомной реализации!
--enforce-eager критически важен для H200 с Kimi K2.5. Графовый режим vLLM иногда конфликтует с архитектурой MoE модели, вызывая артефакты генерации.3 Интегрируем парсер в клиентский код
При запросах к API используйте наш парсер для постобработки:
import openai
from kimi_parser import KimiToolCallParser
# Инициализируем парсер с токенизатором Kimi
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(
"moe-community/Kimi-K2.5-8x7B",
trust_remote_code=True
)
parser = KimiToolCallParser(tokenizer)
# Запрос к vLLM API
client = openai.OpenAI(
base_url="http://localhost:8000/v1",
api_key="token-abc123"
)
response = client.chat.completions.create(
model="kimi-k2.5",
messages=[{"role": "user", "content": "Какая погода в Москве?"}],
temperature=0.7,
max_tokens=1024
)
# Постобработка ответа
raw_text = response.choices[0].message.content
# Извлекаем tool calls
tool_calls = parser.parse_tool_calls(raw_text)
# Очищаем текст от тегов
clean_text = parser.clean_text(raw_text)
print(f"Tool calls: {tool_calls}")
print(f"Clean response: {clean_text}")
Решение для SGLang: настройка stop_tokens и template
SGLang более гибок, но требует точной настройки шаблона. Основная проблема - SGLang по умолчанию не знает про теги Kimi.
1 Создаем кастомный шаблон для Kimi K2.5
# kimi_sglang.py
from sglang import function, system, user, assistant, gen, set_default_backend
from sglang.backend.runtime_endpoint import RuntimeEndpoint
import re
# Кастомный шаблон для Kimi K2.5
KIMI_TEMPLATE = """{{#system}}Вы - полезный ассистент Kimi.{{/system}}
{{#user}}
{{content}}
{{/user}}
{{#assistant}}
{{gen 'response' stop=['', '', '', '\n\n']}}
{{/assistant}}"""
@function
def kimi_chat(s, question):
s += system("Вы - полезный ассистент Kimi.")
s += user(question)
# Критически важно: указываем stop-токены для Kimi
s += assistant(gen(
"response",
max_tokens=1024,
stop=["", "", "", "\n\n"],
temperature=0.7
))
# Постобработка для удаления тегов
raw_response = s["response"]
# Удаляем теги Kimi
kimi_tags = [
"", " ",
"", " ",
"", " ",
"", " ",
"", " ",
]
for tag in kimi_tags:
raw_response = raw_response.replace(tag, "")
# Удаляем множественные пробелы и пустые строки
raw_response = re.sub(r'\s+', ' ', raw_response).strip()
return raw_response
# Инициализация бэкенда для H200
backend = RuntimeEndpoint(
"http://localhost:30000",
tokenizer_path="moe-community/Kimi-K2.5-8x7B"
)
set_default_backend(backend)
# Использование
state = kimi_chat.run("Какая погода в Москве?")
print(f"Response: {state['response']}")
2 Запускаем SGLang сервер с правильными параметрами
# Запуск SGLang сервера для Kimi K2.5 на H200
python -m sglang.launch_server \
--model-path moe-community/Kimi-K2.5-8x7B \
--port 30000 \
--tp-size 8 \
--trust-remote-code \
--max-total-tokens 32768 \
--chat-template ./kimi_template.jinja # Используем кастомный шаблон
# В kimi_template.jinja:
# {{#system}}Вы - ассистент Kimi.{{/system}}
# {{#user}}{{content}}{{/user}}
# {{#assistant}}{{gen stop=['','']}}{{/assistant}}
Типичные ошибки и как их избежать
Ошибка 1: Использование skip_special_tokens=True с токенизатором по умолчанию. Токенизатор Kimi не знает про ее внутренние теги как "специальные".
Неправильно:
# Так НЕ работает с Kimi K2.5
text = tokenizer.decode(output_ids, skip_special_tokens=True)
# Все равно получите теги в выводе
Правильно:
# Сначала декодируем, потом удаляем теги
raw_text = tokenizer.decode(output_ids)
# Кастомная очистка тегов Kimi
clean_text = re.sub(r'<[^>]+>', '', raw_text)
Ошибка 2: Не указаны stop-токены для tool calls. Модель будет генерировать бесконечно, ожидая закрывающих тегов.
Если вы видите бесконечную генерацию или обрыв ответа - проверьте стоп-токены. Kimi K2.5 требует явного указания , и .
Оптимизация для H200: что еще нужно знать
На кластере 8x H200 Kimi K2.5 показывает странное поведение, если не настроить коммуникацию между GPU. Добавьте эти параметры:
# Для vLLM на H200
export NCCL_IB_HCA=mlx5_0,mlx5_1,mlx5_2,mlx5_3
export NCCL_IB_GID_INDEX=3
export NCCL_IB_TC=136
export NCCL_IB_QPS_PER_CONNECTION=8
export NCCL_SOCKET_IFNAME=eth0
# Запуск с оптимизациями для H200
python -m vllm.entrypoints.openai.api_server \
--model moe-community/Kimi-K2.5-8x7B \
--tensor-parallel-size 8 \
--gpu-memory-utilization 0.92 \ # Не 0.95! H200 нужен запас
--max-parallel-loading-workers 4 \
--disable-custom-all-reduce \
--enforce-eager \
--pipeline-parallel-size 1 # Для MoE моделей всегда 1
Почему --gpu-memory-utilization 0.92, а не 0.95? H200 с Kimi K2.5 иногда страдает от фрагментации памяти при высокой утилизации. 0.92 дает буфер для маневров.
Проверка решения: тестовые запросы
После настройки проверьте систему этими запросами:
- Базовый запрос: "Привет, как дела?" - должен вернуть нормальный ответ без тегов
- Запрос с reasoning: "Реши задачу: у Васи 5 яблок, у Пети на 3 больше. Сколько всего?" - может содержать
<thinking>, но в очищенном выводе его не должно быть - Tool call запрос: "Какая погода в Лондоне?" - может вызвать tool call, который должен быть извлечен парсером
- Длинный контекст: Запрос на 20к токенов - проверка стабильности генерации
Если все работает - вы победили капризную архитектуру Kimi K2.5. Если нет - проверьте версию vLLM/SGLang. На 28.01.2026 нужны vLLM >= 0.4.3 и SGLang >= 0.3.0 с поддержкой MoE-моделей.
А что если проблема не в настройках?
Бывает, что проблема глубже. Если после всех настроек Kimi K2.5 все равно выдает (no content):
- Проверьте загрузку весов: иногда часть экспертов MoE не загружается
- Убедитесь, что используете актуальную версию модели (на 28.01.2026 это Kimi-K2.5-8x7B, а не более ранние версии)
- Проверьте совместимость CUDA версий: H200 требует CUDA 12.4+
- Посмотрите логи vLLM на предмет ошибок инициализации экспертов
Если модель загружена частично (не все эксперты), она может генерировать мусор или молчать. В логах ищите Loaded expert - должно быть 56 экспертов для 8x7B конфигурации.
Похожие проблемы бывают и с другими сложными моделями. Если вы сталкивались с прерыванием генерации в Claude Code или бесконечным reasoning в GLM 4.7, принцип решения тот же: понять внутреннюю структуру модели и настроить стоп-токены под нее.
Архитектура MoE, которую использует Kimi K2.5, вообще создает много уникальных проблем. Если хотите глубже разобраться в экономии памяти на таких моделях, посмотрите как MoE меняет подход к VRAM.
И последнее: не верьте, что однажды настроив Kimi K2.5, вы решили проблему навсегда. Модели обновляются, vLLM и SGLang выпускают новые версии. То, что работает сегодня, может сломаться завтра после обновления. Держите под рукой логи, мониторьте вывод и будьте готовы к тому, что через месяц придется настраивать все заново. Такая цена работы с cutting-edge моделями на 28.01.2026.