Когда модель шепчет на японском, а вы не понимаете ни слова
Однажды я запустил Qwen3 VL 8b на изображении с японским меню. Модель выдала "ラーメン" (рамен). Отлично! Но как она к этому пришла? Какие варианты рассматривала? "うどん" (удон) с вероятностью 30%? "そば" (соба) с 25%? Или вообще "パスタ" (паста) с 5%?
Без просмотра топ вероятностей токенов (logprobs) вы летите вслепую. Модель может быть уверена в ответе на 51% против 49% у альтернативы - и вы этого никогда не узнаете.
Самый частый косяк: люди думают, что модель "знает" ответ. На деле она просто выбирает наиболее вероятный токен из распределения. Разница между первым и вторым вариантом может быть микроскопической.
Зачем вам это вообще нужно?
Три реальных сценария:
- Отладка галлюцинаций: Модель пишет "кошка" вместо "собака". Смотрим logprobs - оказывается, "кошка" с вероятностью 52%, "собака" с 48%. Не галлюцинация, а статистическая погрешность.
- Анализ токенизации: Почему японский текст обрабатывается в 3 раза медленнее английского? Смотрим, как модель дробит иероглифы на суб-токены.
- Калибровка температуры: При temperature=0 модель всегда берет самый вероятный токен. При temperature=1.5 начинает "творить". Logprobs покажут, насколько сильно она отклоняется от оптимального пути.
1 Подготовка бэкенда: заставляем llama.cpp говорить правду
Все начинается с сервера. Если бэкенд не возвращает logprobs - фронтенды бессильны.
# Запуск llama.cpp с поддержкой logprobs
./server -m qwen2.5-7b-instruct-q4_K_M.gguf \
--port 8080 \
--n-predict 512 \
--logprobs 10 # <- вот это ключевое!
Флаг --logprobs 10 говорит серверу: "Верни топ-10 вероятностей для каждого токена". Можно поставить 5, 20, 50 - зависит от того, насколько глубоко хотите копать.
--mlock для загрузки модели в RAM (быстрее) и --ngl 20 для загрузки 20 слоев на GPU. Но для logprobs они не обязательны.Проверяем, что сервер отдает данные:
curl http://localhost:8080/completion \
-H "Content-Type: application/json" \
-d '{
"prompt": "Translate to Japanese: cat",
"n_predict": 10,
"logprobs": 5
}'
В ответе должны увидеть что-то вроде:
{
"content": "猫",
"generation_settings": {
"logprobs": 5
},
"tokens": [
{
"text": "猫",
"prob": 0.87,
"top_logprobs": [
{"token": "猫", "logprob": -0.13},
{"token": "ネコ", "logprob": -1.52},
{"token": "キャット", "logprob": -2.01}
]
}
]
}
2 OpenWebUI: самый простой способ (если знаете, где искать)
OpenWebUI по умолчанию скрывает logprobs. Разработчики считают, что это "техническая информация", которая пугает пользователей. (Спойлер: они не правы.)
Вот как включить отображение:
- Открываем настройки модели (шестеренка справа от выбора модели)
- Листаем вниз до "Advanced Parameters"
- Ставим галочку "Logprobs" и указываем количество (например, 5)
- Сохраняем
Теперь при каждом ответе модели в интерфейсе появится маленькая иконка 📊. Кликаем - и видим полное дерево вероятностей.
| Параметр | Значение | Что делает |
|---|---|---|
| Logprobs | 5 | Показывает топ-5 вероятностей для каждого токена |
| Temperature | 0.7 | Влияет на распределение вероятностей |
| Top-p | 0.9 | Ограничивает выбор токенов ядром распределения |
Но есть нюанс: OpenWebUI показывает вероятности только для сгенерированных токенов. Если хотите увидеть, что модель "думала" на каждом шаге - нужны расширения.
3 SillyTavern: для тех, кто любит копаться в JSON
SillyTavern изначально создавался для ролевых чатов, но его система расширений превратила его в швейцарский нож для отладки LLM.
Устанавливаем расширение "Token Probabilities":
# В папке SillyTavern/extensions
git clone https://github.com/SillyTavern/extensions.git
# Или через встроенный менеджер расширений
После установки в интерфейсе появляется новая вкладка "Tokens". Там можно увидеть:
- Вероятности для каждого токена в реальном времени
- Альтернативные варианты с их вероятностями
- Визуализацию в виде графика
- Экспорт в JSON для дальнейшего анализа
Главное преимущество SillyTavern - он не просто показывает цифры, а позволяет с ними взаимодействовать. Кликните на любой токен - увидите его числовой ID в словаре модели. Это полезно, когда пытаетесь понять, почему модель путает похожие слова.
Внимание: SillyTavern по умолчанию кэширует ответы. Если меняете параметры модели (temperature, top_p), очистите кэш или перезагрузите страницу. Иначе будете видеть старые вероятности.
4 LM Studio и другие: краткий обзор
LM Studio - самый популярный GUI для локальных LLM, но с logprobs у него проблемы. Версия 0.3.0 обещала поддержку, но в 0.3.4 ее все еще нет. Разработчики в Discord говорят "скоро". Уже полгода.
Что работает:
- text-generation-webui (oobabooga): Полная поддержка через API, но интерфейс выглядит так, будто его делал бэкенд-разработчик. (Потому что так и есть.)
- Faraday.dev: Показывает "confidence scores", но это не настоящие logprobs. Просто красивый процент уверенности.
- LocalAI: Если настроить как сервер для OpenWebUI - работает отлично. Но сам по себе интерфейс минималистичный.
Если хотите полный контроль - пишите свой скрипт. Это проще, чем кажется.
import requests
import json
# Запрос к llama.cpp серверу
def get_token_probs(prompt, top_k=5):
url = "http://localhost:8080/completion"
payload = {
"prompt": prompt,
"n_predict": 50,
"temperature": 0.7,
"top_k": 40,
"top_p": 0.9,
"logprobs": top_k,
"stream": False
}
response = requests.post(url, json=payload)
data = response.json()
# Парсим вероятности
for i, token in enumerate(data.get("tokens", [])):
print(f"Token {i}: {token['text']}")
for prob in token.get("top_logprobs", []):
# Преобразуем logprob в вероятность
probability = 100 * (2.71828 ** prob["logprob"])
print(f" {prob['token']}: {probability:.2f}%")
print("-" * 40)
# Пример с японским текстом
get_token_probs("画像には何が写っていますか?", top_k=3)
Реальный кейс: почему Qwen3 VL путает японские иероглифы
Вернемся к началу статьи. Я анализировал, как Qwen3 VL 8b обрабатывает японский текст с изображений. Вот что увидел в logprobs:
{
"tokens": [
{
"text": "ラ",
"prob": 0.91,
"top_logprobs": [
{"token": "ラ", "logprob": -0.09},
{"token": "ウ", "logprob": -2.30},
{"token": "リ", "logprob": -2.45}
]
},
{
"text": "ー",
"prob": 0.88,
"top_logprobs": [
{"token": "ー", "logprob": -0.12},
{"token": "-", "logprob": -2.08},
{"token": "〜", "logprob": -2.77}
]
}
]
}
Проблема в токенизации. Модель разбивает "ラーメン" на три токена: ["ラ", "ー", "メン"]. Для сравнения, английское "ramen" - один токен. Вот почему японский текст обрабатывается медленнее и иногда с ошибками.
Решение? Использовать модели с расширенным японским словарем или дообучать токенизатор. Но сначала нужно было это обнаружить - через анализ logprobs.
Частые ошибки и как их избежать
Ошибка 1: "Logprobs не работают!"
Проверьте цепочку: модель → бэкенд → фронтенд. Многие модели (особенно quantized версии) не поддерживают logprobs. Llama-2-7b-q4_K_M.gguf - поддерживает. Llama-2-7b-q4_0.gguf - может не поддерживать. Всегда проверяйте документацию к конкретному квантованию.
Ошибка 2: "Показывает только один токен"
Убедитесь, что в запросе указано logprobs: N где N > 1. Некоторые фронтенды по умолчанию ставят 0 или 1.
Ошибка 3: "Вероятности не суммируются до 100%"
Так и должно быть. Logprobs - это логарифмы вероятностей. Чтобы получить обычные вероятности, нужно вычислять exp(logprob). И даже тогда они могут не суммироваться до 100%, потому что модель рассматривает не все возможные токены, а только топ-N.
# Правильное преобразование logprob в вероятность
import math
logprob = -0.6931 # Пример
probability = math.exp(logprob) # ≈ 0.5 или 50%
print(f"Probability: {probability:.2%}")
Ошибка 4: "На разных запусках разные вероятности"
Temperature > 0 добавляет случайности. Для детерминированного поведения ставьте temperature=0 и seed=42. Но тогда модель всегда будет выдавать один и тот же ответ на один и тот же промпт.
Что делать с этими данными?
Logprobs - не просто любопытная статистика. Это инструмент для:
- Поиска слабых мест модели: Если на определенных типах запросов вероятность правильного ответа падает ниже 60% - модель нужно дообучать на таких примерах.
- Оптимизации промптов: Видите, что модель "колеблется" между двумя интерпретациями? Перефразируйте запрос, добавьте примеров, измените формат вывода.
- Сравнения моделей: Запустите один и тот же промпт на Llama 3.2, Qwen2.5 и Mistral. Сравните не только конечный ответ, но и уверенность модели на каждом шаге.
- Отладки агентов: Если ваш LLM-агент принимает странные решения, включите logprobs для каждого вызова модели. Увидите, в какой момент он "свернул не туда".
Кстати, о сравнении моделей. Если хотите автоматизировать процесс, посмотрите LLMPlot.com - там есть инструменты для визуализации таких метрик.
А что насчет облачных API?
OpenAI API возвращает logprobs с 2020 года. Anthropic Claude - тоже. Но есть два отличия:
- Облачные API обычно возвращают logprobs только для завершающих токенов, не для всего контекста
- Стоимость: каждый запрос с logprobs дороже на 10-20%
Главное преимущество локальных моделей - полный контроль. Хотите logprobs для каждого из 4096 токенов контекста? Пожалуйста. Хотите сохранить их в базу для анализа? Без проблем.
Важный момент: НЕ используйте logprobs в продакшене для критически важных решений. Это инструмент отладки, а не гарантия правильности. Модель может быть на 99% уверена в совершенно неверном ответе.
Что будет дальше?
Через год-два просмотр logprobs станет такой же стандартной функцией, как сегодня просмотр токенов. Фронтенды будут показывать не просто текст ответа, а "тепловую карту уверенности" модели - где она колеблется, где уверена, где гадает.
Уже сейчас появляются инструменты вроде TabBrain, которые используют уверенность модели для принятия решений. Если вероятность ниже порога - запрашивают уточнение у пользователя или переключаются на другую модель.
Мой прогноз: следующий шаг - автоматическая коррекция промптов на основе logprobs. Система увидит, что модель не уверена в ответе, и динамически переформулирует запрос, добавит контекста, изменит формат. Все это в реальном времени, без участия человека.
Пока этого нет - учитесь читать мысли нейросетей вручную. Начните с простого: запустите свою модель с флагом --logprobs 5 и спросите что-нибудь на японском. Удивитесь, как много вы узнаете о том, как она на самом деле "думает".