SSD Nodes Learn 🎉 VPS от $5.50/мес
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-08-21

Настройка reasoning effort для локальных LLM

Узнайте, как параметр reasoning effort влияет на скорость генерации и расход ресурсов GPU. Разбираем, почему высокие значения увеличивают время отклика до нескольких минут.

Как меняется вычислительная нагрузка на локальных LLM

Параметр reasoning effort определяет, сколько времени модель будет «размышлять» перед ответом. Он влияет исключительно на объем сегмента рассуждений. Веса на диске, квантование и сам процесс прямого прохода (forward pass) остаются неизменными. Меняется только количество токенов, которые модель предварительно записывает в свой «черновик».

Это различие важно из-за того, где именно расходуются токены. При использовании API сторонних сервисов токены рассуждений отражаются в счете. На собственном VPS вы оплачиваете их временем генерации на своем CPU или GPU, а также местом в контекстном окне. Если оставить модель на максимальном уровне усилий, она может потратить большую часть вывода на рассуждения, прежде чем появится первое слово ответа. На собственном оборудовании это превращает двухсекундный отклик в двухминутный.

Где задается уровень: шаблон чата, а не веса

Модель с поддержкой рассуждений обучена выводить сегмент размышлений, обычно заключенный в теги <think> и </think>, перед выдачей итогового ответа. Уровень усилий — это инструкция, которую шаблон чата модели записывает в промпт. Этот шаблон представляет собой файл Jinja, поставляемый вместе с моделью. Он считывает переменную, такую как reasoning_effort, и формирует соответствующую строку системного уровня для каждого значения; модель обучена сокращать или удлинять свой черновик в ответ на эту строку.

Из этого следует два вывода. Названия уровней принадлежат модели, а не вашей среде выполнения, поэтому имя из карточки одной модели может ничего не значить для другой. Если какой-либо элемент цепочки заменяет шаблон чата модели на универсальный, переменная не рендерится, и настройка без предупреждения перестает работать.

По состоянию на 2026-08-20 в карточке модели Qwen3.8-27B задокументированы три уровня усилий: low, medium и xhigh, где xhigh является значением по умолчанию. Уровня high не существует. Процесс рассуждения включается параметром enable_thinking, который активен по умолчанию; также в карточке указан параметр preserve_thinking, который по умолчанию включен и сохраняет рассуждения из предыдущих этапов диалога. В gpt-oss вместо этого используются low, medium и high. Многие другие семейства моделей принимают только логическое значение и ничего более. Изучите карточку для конкретной версии, которую вы загрузили, так как эти названия не являются стандартом. Запуск модели 27B на VPS выполняется в первую очередь. Эта страница посвящена тому, что настроить после того, как модель начнет отвечать.

Почему высокая вычислительная нагрузка обходится дороже на VPS

Выходные токены. Токены рассуждений — это сгенерированные токены. Они проходят через тот же цикл декодирования, что и ответ, с той же скоростью генерации, которую позволяет ваше оборудование. Допустим, задача генерирует 200 токенов ответа и 4 000 токенов рассуждений. Вы сгенерировали 4 200 токенов, а пользователь увидел только 200 из них. Скорость декодирования определяется пропускной способностью памяти и выбранной вами квантованием, поэтому единственный рычаг управления — это само количество токенов.

Реальное время ожидания. Пользователь ждет появления первого токена ответа, так как всё, что было до этого, — это пустой экран или индикатор загрузки. Рассуждения выводятся первыми, поэтому время ожидания примерно равно количеству токенов рассуждений, деленному на скорость декодирования, плюс время обработки промпта. Увеличение длины рассуждений вдвое удваивает время ожидания.

Контекст. Токены рассуждений занимают контекстное окно, как и любые другие токены. При включенном preserve_thinking «черновик» из первого шага остается в промпте на пятом шаге, поэтому обработка промпта замедляется с каждым шагом, пока окно заполняется с обеих сторон. Увеличение num_ctx для его размещения требует памяти под KV-кэш, которая на VPS без GPU является системной оперативной памятью, которой у вас может не быть в избытке.

Когда повышать уровень, а когда оставлять его низким

Повышайте уровень для задач, где неверный промежуточный шаг портит результат: многоэтапные вычисления и конвертация единиц измерения, планирование правок в нескольких файлах, написание кода, который должен компилироваться, и задачи с ограничениями, где один ответ должен удовлетворять нескольким условиям одновременно. В таких случаях черновик выполняет реальную работу, и его увеличенный объем — это недорогой способ обнаружить ошибку, которую модель в противном случае допустила бы.

Оставляйте уровень низким, если ответ уже содержится во входных данных и задача состоит в его переносе. Сюда относятся извлечение, классификация, тегирование, перевод, переписывание, суммаризация и форматирование. Сегмент рассуждений в таких случаях в основном повторяет задачу, давая модели возможность отказаться от верного первого решения в пользу ошибочного.

Также оставляйте уровень низким для любых интерактивных задач. В чате или редакторе вы находитесь в цикле взаимодействия, поэтому быстрый ответ, который вы можете исправить, лучше медленного, который приходится ждать. В этом заключается реальный компромисс при настройке агента для написания кода на локальную модель: агент делает множество мелких вызовов, и на каждом из них взимается «налог» на рассуждения.

Как задать уровень в llama.cpp

llama.cpp записывает переменную непосредственно в шаблон, что делает его средой выполнения, где можно быть уверенным в получении уровня. Укажите -m на имеющийся у вас файл GGUF.

llama-server -m ./qwen3.8-27b-Q4_K_M.gguf \
  --jinja \
  --reasoning-effort medium \
  --reasoning-format deepseek \
  -c 32768 \
  --host 127.0.0.1 --port 8080

--jinja использует собственный чат-шаблон модели и включен по умолчанию в текущих сборках. --reasoning-effort принимает default, minimal, low, medium, high, xhigh или max, где default означает использование значения по умолчанию, заданного в самом шаблоне. Этот список является словарем llama.cpp, а не модели, поэтому передавайте только те имена, которые перечислены в карточке: уровень, не определенный в шаблоне, может вызвать ошибку шаблона во время запроса. --reasoning-format deepseek переносит процесс рассуждения из message.content в message.reasoning_content, что делает разделение измеримым в следующем разделе.

Чтобы отключить процесс мышления, а не просто сократить его, задайте переменную шаблона самостоятельно:

llama-server -m ./qwen3.8-27b-Q4_K_M.gguf --jinja \
  --chat-template-kwargs '{"enable_thinking": false}'

--reasoning-budget — это другой механизм. Он ограничивает сегмент рассуждений по количеству токенов, при этом 0 немедленно завершает его, а -1 оставляет его без ограничений, вместо того чтобы запрашивать у модели более короткий план. Оба флага действуют на уровне всего сервера. llama-server не принимает reasoning_effort как поле для каждого отдельного запроса, поэтому для обслуживания двух уровней усилий одновременно требуется запуск двух процессов на двух разных портах.

vLLM предоставляет ту же переменную для каждого запроса внутри тела запроса, совместимого с OpenAI:

{"model": "Qwen/Qwen3.8-27B",
 "messages": [{"role": "user", "content": "Summarise this changelog in two lines."}],
 "chat_template_kwargs": {"reasoning_effort": "medium"}}

Настройка уровня в Ollama

Ollama использует собственное поле think в /api/chat и /api/generate. Оно принимает значения true, false или одно из low, medium, high и max, где max запрашивает максимальный уровень, поддерживаемый моделью. Функция мышления (thinking) включена по умолчанию для моделей, которые её поддерживают.

ollama run qwen3.8:27b --think=low "Draft a one line commit message for a README typo fix"
{"model": "qwen3.8:27b",
 "messages": [{"role": "user", "content": "Which HTTP status code means the request body was too large?"}],
 "think": "low",
 "stream": false}

Рассуждения возвращаются в message.thinking, а ответ — в message.content; они уже разделены для вас. Внутри интерактивной сессии ollama run команды /set think и /set nothink позволяют переключать этот режим без перезапуска.

Обратите внимание на возможное несоответствие. Словари Ollama включают уровни low, medium, high и max. Шаблон Qwen3.8 определяет low, medium и xhigh. Необходима привязка одного набора к другому. Поскольку модель Ollama содержит шаблон, упакованный внутри её тега, а не Jinja-файл из исходного репозитория, то, будет ли ваш уровень распознан моделью, зависит от этого упакованного шаблона. Не полагайтесь на то, что это сработает автоматически. Проверка занимает около минуты.

Как измерить, действительно ли уровень был применен

Отправьте один и тот же запрос на нескольких уровнях с параметром temperature, установленным в 0, а затем сравните количество токенов. Здесь jq формирует тело запроса, поэтому вам не нужно вручную экранировать кавычки.

for level in low medium max; do
  body=$(jq -n --arg lvl "$level" '{
    model: "qwen3.8:27b",
    messages: [{role: "user", content: "A pump fills a 4500 litre tank in 25 minutes. A second pump is 40 percent slower. How long do both together take? Answer in minutes."}],
    think: $lvl,
    stream: false,
    options: {temperature: 0, num_ctx: 8192}
  }')
  echo "== $level"
  curl -s http://localhost:11434/api/chat -d "$body" | jq '{
    thinking_chars: (.message.thinking // "" | length),
    answer_chars: (.message.content | length),
    eval_count: .eval_count,
    seconds: (.total_duration / 1e9),
    tok_per_sec: (.eval_count / (.eval_duration / 1e9))
  }'
done

eval_count — это все сгенерированные токены, включая рассуждения, поэтому разница между двумя уровнями почти полностью состоит из рассуждений. thinking_chars предоставляет разделение напрямую. Должны выполняться два условия: числа меняются при смене уровней, а ответ остается верным на более низком уровне. Если eval_count находится в пределах погрешности во всех трех запусках, значит, уровень игнорируется, и решение заключается в использовании среды выполнения, которая передает его, а не в смене названия уровня.

Общее время — это лишь половина картины, поэтому измерьте задержку до первого токена ответа, используя потоковую передачу и остановку на первом непустом фрагменте content. Для этого потребуются jq и bc.

start=$(date +%s.%N)
curl -sN http://localhost:11434/api/chat -d '{
  "model": "qwen3.8:27b",
  "messages": [{"role": "user", "content": "Explain what a reverse proxy does, in three sentences."}],
  "think": "low",
  "stream": true
}' |
while IFS= read -r line; do
  if [ -n "$(printf '%s' "$line" | jq -r '.message.content // ""')" ]; then
    echo "first answer token after $(echo "$(date +%s.%N) - $start" | bc)s"
    break
  fi
done

Запустите это с low, а затем с max. Разница — это время ожидания, которое вы приобретаете. В llama.cpp те же числа возвращаются внутри ответа, поэтому арифметические операции в оболочке не требуются:

curl -s http://localhost:8080/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model": "local", "temperature": 0,
       "messages": [{"role": "user", "content": "A pump fills a 4500 litre tank in 25 minutes. A second pump is 40 percent slower. How long do both together take?"}]}' | jq '{
  reasoning_chars: (.choices[0].message.reasoning_content // "" | length),
  answer_chars: (.choices[0].message.content | length),
  predicted_n: .timings.predicted_n,
  tok_per_sec: .timings.predicted_per_second
}'

Выполните это на своей машине. Опубликованные сравнения производительности были измерены на оборудовании, которое вам не принадлежит, а ваша скорость декодирования — это тот показатель, который переводит количество токенов в секунды. Измерение количества токенов в секунду на собственном сервере дает вам этот показатель: количество токенов рассуждений, деленное на вашу скорость декодирования, равно времени ожидания, которое вы только что добавили.

Что может пойти не так

Ответ обрывается, или content пуст, а thinking заполнен. Лимит генерации был исчерпан на этапе рассуждений. Параметр num_predict в Ollama ограничивает весь объем генерации, включая рассуждения, а рассуждения идут первыми. Поэтому ограничение в 512 токенов при высоком уровне усилий может привести к завершению ответа до того, как начнется сам ответ. Ollama сообщает "done_reason": "length" для такого ответа. Увеличьте лимит или снизьте уровень усилий. В Как num_predict считает токены подробно описано это взаимодействие.

Уровень ничего не меняет. Количество токенов идентично на каждом уровне. Либо среда выполнения не передает переменную, либо шаблон её не считывает. Проверьте шаблон, который ваша среда выполнения использует на самом деле, а не тот, что указан в исходном репозитории. llama.cpp с --jinja и --chat-template-kwargs записывает переменную вручную, поэтому это хороший способ проверки: если уровень работает там, но не работает в другом месте, значит, с моделью всё в порядке, а другая среда выполнения отбрасывает этот параметр.

Имя уровня отклоняется. Ошибка шаблона во время запроса или сбой на первом сообщении при исправно работающем сервере обычно означают, что вы передали уровень, который не определен в шаблоне, например high для модели, в карточке которой указаны только low, medium и xhigh.

Диалоги из нескольких реплик замедляются с каждым шагом. Старые рассуждения сохраняются в истории. Установите preserve_thinking в значение false, если модель это поддерживает, или удалите поле thinking из сообщений, которые вы отправляете обратно. В противном случае время обработки промпта увеличивается с каждым шагом, хотя длина ответов остается прежней.

Качество падает при низком уровне усилий в задаче, которая казалась простой. Некоторые задачи по извлечению данных на самом деле таковыми не являются. Если для входных данных требуется преобразование единиц измерения или применение правил в определенном порядке, это задача на рассуждение с коротким выводом. Повысьте уровень для этого конкретного вызова, а не для всего сервера целиком.

Запуск двух уровней одновременно

llama.cpp фиксирует уровень при запуске, поэтому для сервера, который одновременно обслуживает редактор и ночное пакетное задание, требуется два процесса на разных портах, каждый со своим --reasoning-effort. Два процесса также означают две копии весов в оперативной памяти, если только вы не разнесете эти задачи по времени. На одном VPS более дешевым решением обычно является запуск сервера с низкими требованиями для задач, ожидаемых пользователем, и запланированный запуск с высокими требованиями для фоновой работы. Что происходит, когда несколько пользователей используют одну локальную модель также применимо здесь: токены рассуждения — это вычислительная нагрузка на декодирование, поэтому повышение уровня сложности снижает эффективную параллельность примерно на тот же коэффициент, на который увеличивается количество токенов.

FAQ

Какой уровень усилий для рассуждения следует использовать по умолчанию?

Начинайте с самого низкого уровня, предлагаемого моделью, и повышайте его только для задач, с которыми она не справилась. Многие модели с функцией рассуждения поставляются с высоким уровнем по умолчанию; так, Qwen3.8-27B по состоянию на август 2026 года использует xhigh — свой максимальный уровень. Это значение выбрано для достижения высоких показателей в бенчмарках, а бенчмарки не учитывают время выполнения. На собственном оборудовании вы платите временем, поэтому используйте более высокий уровень как опцию для конкретных задач, а не как настройку, наследуемую каждым запросом.

Учитываются ли токены рассуждения в контекстном окне?

Да. Это обычные токены в выводе, и они занимают место в контекстном окне наравне с остальными данными. Останутся ли они там на следующем шаге, зависит от среды выполнения и модели. В документации к Qwen3.8 указан параметр preserve_thinking, включенный по умолчанию: он сохраняет предыдущие рассуждения в истории, поэтому длинный диалог накапливает все созданные «черновики». Установите его в значение false или удалите поле thinking из сообщений, которые вы отправляете повторно, чтобы объем обрабатываемых данных перестал расти.

Почему изменение уровня рассуждения не влияет на количество токенов?

Настройка не доходит до шаблона чата. Уровень — это переменная шаблона, поэтому она работает только в том случае, если среда выполнения передает её, а упакованный шаблон считывает. Некоторые среды выполнения используют собственные шаблоны вместо файла Jinja из оригинального репозитория, из-за чего переменная отбрасывается без вывода каких-либо ошибок. Проверьте это, отправив один и тот же запрос на самом низком и самом высоком уровне с параметром temperature, равным 0, и сравнив eval_count. Если значения совпадают с учетом погрешности, значит, уровень игнорируется.

Снижает ли низкий уровень рассуждения точность модели?

Это зависит от задачи, и данный аспект стоит измерить, а не предполагать заранее. Если ответ уже содержится во входных данных (например, при извлечении или переписывании текста), короткий «черновик» обычно ничего не меняет. Если же для получения финального результата необходимо верно выполнить промежуточный шаг (например, в многоэтапных вычислениях или при написании кода, который должен компилироваться), точность при использовании короткого «черновика» действительно падает. Создайте набор из двадцати запросов из вашей реальной рабочей нагрузки, выполните их на двух уровнях с temperature, равным 0, и подсчитайте количество неверных ответов. Это число будет специфичным именно для вашей задачи, и ни одна опубликованная таблица не даст вам точного ответа.