Гайд · TNWS AI
Как посчитать токены русского промпта через /tokenize в llama.cpp
Считаем токены конкретным токенизатором GGUF, проверяем структуру tokens и риск переполнения контекста.
Задача и применимость
Поисковый вопрос: «как посчитать токены русского текста llama.cpp tokenize with_pieces». Оценить размер промпта тем же токенизатором, который обслуживает локальную модель. llama.cpp server с загруженной GGUF-моделью и маршрутом POST /tokenize; описание маршрута сверено по официальной документации 20 сентября 2026 года. Длина токенизации зависит от файла модели и настроек add_special/parse_special.
Пример рассчитан на уже имеющийся файл модели, полученный законным способом по условиям его лицензии. Здесь не утверждается, что любая GGUF-модель одинаково понимает русский язык или имеет один и тот же чат-шаблон. Фактический номер сборки узнавайте локально через llama-server --version и повторяйте контрольный опыт после обновления бинарника.
Что подтверждено документацией
POST /tokenize принимает обязательное content и необязательные add_special, parse_special, with_pieces. В режиме with_pieces:false ответ содержит массив целочисленных ID tokens; в режиме true элементы представлены объектами id и piece. Некоторые piece могут быть массивом байтов, а не строкой Unicode. add_special по умолчанию false, parse_special по умолчанию true.
Порядок действий
- Сначала определите фактически загруженный GGUF и настроенный размер контекста.
- Подготовьте конечный текст, включая русские символы, числа и пунктуацию, без искусственных сокращений.
- Вызовите /tokenize с content и выведите длину массива tokens.
- Повторите с with_pieces:true, чтобы увидеть границы разбиения, но не показывайте пользователю секретные части текста.
- Добавьте бюджет для шаблона чата и ответа до сопоставления с контекстом модели.
Локальный запуск для описанного сценария (замените путь к файлу на ваш):
./build/bin/llama-server -m /models/your-chat-model.gguf --host 127.0.0.1 --port 8080
Готовый шаблон запроса и проверки
import json, urllib.request
url = "http://127.0.0.1:8080/tokenize"
text = "Заказ № 17: доставка завтра в Смоленск."
payload = {"content": text, "with_pieces": True, "add_special": False}
request = urllib.request.Request(
url, data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
headers={"Content-Type": "application/json"}, method="POST")
with urllib.request.urlopen(request, timeout=15) as reply:
result = json.load(reply)
tokens = result["tokens"]
assert all(isinstance(t.get("id"), int) for t in tokens)
print("Токенов:", len(tokens))
print("Фрагменты:", [t["piece"] for t in tokens[:8]])
Входные данные и ожидаемый результат
Вход: «Заказ № 17: доставка завтра в Смоленск.» Ожидаемый результат — положительное целое число и список объектов с id/piece, однако точное число намеренно не задано: оно меняется при смене токенизатора. Сравнивайте повторные вызовы на одном GGUF, а не числа из статей про чужую модель.
Почему важна именно эта проверка
Один символ, одно слово и один токен — разные вещи. Кириллица, знак номера и числительное могут разбиваться совсем не так, как английский текст. Это объясняет, почему правило «тысяча слов равна фиксированному числу токенов» плохо работает при расчёте локального контекста. Результат /tokenize привязан к модели на данном сервере; после смены GGUF измерьте промпты заново. Если with_pieces:true и отдельный piece представлен байтами, не пытайтесь насильно декодировать каждый фрагмент отдельно как завершённую UTF-8 строку: граница токена может проходить внутри символа.
Работа с реальными данными
Для чата важно учитывать не только текст пользователя. Системное сообщение, история и специальные маркеры шаблона тоже входят в общий контекст. Поэтому замер только строки content — нижняя оценка, а не расчёт всей переписки. Практический контроль: отдельно сформируйте полный шаблон через /apply-template и затем измерьте его, если используете этот формат, либо ориентируйтесь на серверный счётчик входных токенов при /v1/chat/completions/input_tokens. Не конвертируйте размер текстового файла в токены умножением байтов: размерности разные.
Проверка после изменения модели или нагрузки
Когда приложение отправляет материалы для RAG, сохраните несколько контрольных наборов: короткий вопрос, длинный русский документ, смешанный текст с артикулами и URL. Проверьте максимальную длину из реальных случаев и оставьте запас под ответ модели. Если сервер сообщает об усечении в /completion, считайте такой ответ невалидным для задач, где важен конец источника. Для воспроизводимости запишите хеш GGUF, параметры шаблона и add_special: без них два измерения легко окажутся несопоставимыми. Не используйте число токенов как оценку качества текста: оно характеризует способ кодирования.
Для точного учёта чат-ввода в README предусмотрен отдельный маршрут /v1/chat/completions/input_tokens, который принимает тело chat completions. Его удобнее использовать как дополнительный тест, если в цепочке присутствуют системная инструкция и много реплик. Сопоставление результата с простым /tokenize покажет накладные токены шаблона; не объявляйте разницу постоянным коэффициентом. При изменении chat template накладные расходы тоже меняются. Этот тест полезнее среднего коэффициента «токены на слово» именно для длинных русских бесед.
Критерии приёмки
- Каждый элемент tokens содержит числовой id.
- Повтор на той же модели и настройках даёт ту же длину.
- Промпт и резерв ответа вместе помещаются в выделенный контекст.
Частые ошибки и чего не делать
- Не считать слова или байты эквивалентом токенов.
- Не декодировать байтовый piece отдельно от остальных фрагментов.
- Не забывать служебные токены шаблона при оценке диалога.
Краткие ответы на вопросы
Одинаково ли считают токены разные модели?
Нет, используйте токенизатор загруженного GGUF.
Можно ли получить сами фрагменты?
Да, с параметром with_pieces:true.
Почему число не указано заранее?
Оно зависит от модели и параметров токенизации.
Официальные источники
Частые вопросы
Одинаково ли считают токены разные модели?
Нет, используйте токенизатор загруженного GGUF.
Можно ли получить сами фрагменты?
Да, с параметром with_pieces:true.
Почему число не указано заранее?
Оно зависит от модели и параметров токенизации.
Читайте также
Как ограничить генерацию llama.cpp через n_predict и проверить причину остановки
Используем native /completion и поля остановки, чтобы отличить заданный лимит от нормального конца ответа.
Как переранжировать найденные документы через llama.cpp /v1/rerank
Запускаем reranker GGUF, подаём список кандидатов и проверяем порядок и связь результата с исходными документами.
Как получить embeddings через llama.cpp /v1/embeddings и проверить pooling
Запускаем специализированную embedding-модель, кодируем две строки и проверяем размерность и числовой формат.
Комментарии
Пока тихо. Скажите первое слово