Гайд · TNWS AI
Как измерить скорость генерации по полям Ollama API
Разбираем total_duration, load_duration, prompt_eval_count и eval_count и считаем наблюдаемую скорость без выдуманных метрик.
Задача и применимость
Цель этого руководства — отделить загрузку модели, обработку prompt и генерацию ответа в локальном benchmark. Используется точный интерфейс: response metrics /api/generate. Материал подходит для локального сервиса, тестового контура или внутреннего API, где Ollama доступна по доверенному адресу. Не публикуйте порт 11434 напрямую в интернет и не подставляйте в примеры реальные клиентские данные.
В отличие от общего обзора здесь есть проверяемый контракт: запрос, структура ответа, позитивные assertions и негативный сценарий. Название модели в коде — пример; выберите установленную модель, которая поддерживает нужную capability, и зафиксируйте её имя в конфигурации проекта.
Проверенные факты и первоисточники
Сведения проверены 13 сентября 2026 года по официальной документации Ollama. Ответ содержит длительности в наносекундах и счётчики входных, кэшированных и выходных токенов. Дополнительно структура базовых ответов сверена с Generate API, Chat API и Embed API.
Цены и тарифы не приводятся. Доступность конкретной модели, качество ответа и аппаратная производительность зависят от локальной установки, поэтому они не выдаются за универсальный факт. Метрики берутся только из фактического JSON-ответа вашего запуска.
Подготовка безопасного тестового стенда
- Убедитесь, что Ollama запущена локально и endpoint доступен приложению.
- Получите список установленных моделей через официальный endpoint tags и выберите модель, подходящую capability.
- Не зашивайте имя модели в десятки файлов: храните его в переменной окружения или одном конфигурационном модуле.
- Используйте искусственные значения DEMO, тестовые SKU и вымышленные тексты.
- Задайте timeout и проверяйте HTTP status до разбора JSON.
- Сохраняйте исходный request без секретов, версию приложения и имя модели для воспроизводимости.
- Разделяйте сетевую ошибку, ошибку JSON, нарушение схемы и неверный бизнес-результат.
Ollama генерирует вероятностный результат. Даже при стабильном запросе текст может отличаться, поэтому тестируйте инварианты: наличие поля, роль сообщения, допустимое имя tool, формат аргумента, число векторов или ожидаемое вычисление. Не сравнивайте длинный ответ целиком со snapshot без необходимости.
Пошаговая реализация
- Сформируйте payload только из документированных полей.
- Укажите model и обязательный prompt, messages либо input.
- Для примеров, которым нужен один JSON, явно задайте stream:false.
- Отправьте POST с Content-Type: application/json.
- При status вне диапазона 200–299 прочитайте текст ошибки и остановите обработку.
- Разберите JSON и проверьте типы нужных полей до использования.
- Проверьте связь ответа с входом: роли, индексы, tool_name или сохранённые фрагменты.
- Не исполняйте tool по имени напрямую через eval или динамический import; используйте allowlist dispatcher.
- Ограничьте число шагов agent loop и общий timeout.
- Запишите технические счётчики отдельно от пользовательского результата.
- Выполните негативный тест и убедитесь, что он действительно отклоняется.
- Только после этого переносите код в основной сервис.
Готовый пример
const r=await fetch("http://localhost:11434/api/generate",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({model:"gemma4",prompt:"Дай три названия для кофейни",stream:false})});
const d=await r.json();
for(const k of ["total_duration","load_duration","prompt_eval_count","eval_count","eval_duration"]){if(!Number.isFinite(d[k]))throw Error("нет поля "+k);}
const seconds=d.eval_duration/1e9;
const tokensPerSecond=seconds>0?d.eval_count/seconds:null;
console.log({load_ms:d.load_duration/1e6,total_ms:d.total_duration/1e6,tokens_per_second:tokensPerSecond});
Код рассчитан на Node.js с глобальным fetch. Его можно адаптировать к Python, сохранив ту же JSON-схему и последовательность проверок. Перед production добавьте AbortController, структурированный журнал без содержимого пользовательского prompt и retry только для безопасных транспортных сбоев.
Не повторяйте автоматически запрос, который уже мог вызвать внешний tool с побочным эффектом. Для инструментов записи используйте idempotency key на стороне приложения и сохраняйте состояние выполненного вызова. Модель предлагает аргументы, но доверять им без валидации нельзя.
Пример входа и ожидаемого результата
Вход: Один прогретый и один холодный запрос с одинаковыми model, prompt и stream:false.
Ожидаемый результат: Отчёт отдельно показывает load_ms, total_ms и вычисленную скорость output tokens/s; исходные поля сохраняются для аудита.
Фактическая формулировка модели может отличаться. Критерием служат явно перечисленные свойства. Если критерий зависит от знания модели, используйте небольшой набор тест-кейсов и ручную выборочную проверку, но не выдумывайте процент точности без измерения.
Негативный тест
Не сравнивайте модели по одному холодному запуску. Тестовый сценарий должен пометить первый запрос отдельно и не смешивать load_duration с eval_duration.
Негативный тест запускайте автоматически рядом с позитивным. Он должен завершаться конкретной ошибкой и не оставлять частично записанное состояние. Для tools проверьте неизвестное имя, лишние аргументы, пропущенное обязательное поле и неверный тип. Для embeddings проверяйте количество, размерность и конечность каждого числа.
Production-обёртка
Создайте одну функцию client.request, которая добавляет endpoint, timeout, заголовок и обработку статусов. Поверх неё сделайте отдельные функции generate, chat и embed с собственными схемами валидации. Так изменение одного endpoint не разнесётся по всему приложению.
В журнал пишите request_id, model, endpoint, status, done_reason и длительности, но не полный prompt, системную инструкцию, tool output или embedding. Вектор сам по себе не следует считать анонимным: применяйте к хранилищу те же правила доступа и срока хранения, что и к исходному документу.
Для agent loop храните messages в рамках одного задания, ограничивайте их размер и число ходов. Assistant message с tool_calls нужно добавить в историю до сообщений role=tool. Все результаты независимых параллельных вызовов добавьте до следующего обращения к модели.
Копируемый шаблон проверки
Endpoint: response metrics /api/generate
Задача: отделить загрузку модели, обработку prompt и генерацию ответа в локальном benchmark
Модель и capability проверены: <да/нет>
Искусственный вход: <значение>
Обязательные поля request: <список>
Обязательные поля response: <список>
Позитивный invariant: <условие>
Негативный сценарий: <условие>
Timeout: <значение проекта>
Max turns для цикла: <значение>
Allowlist tools: <имена>
PII и секреты отсутствуют: <да>
Источник: https://docs.ollama.com/api/generate
Дата проверки: 13 сентября 2026 года
Финальная проверка результата
Выполните тест дважды: после холодного старта и при загруженной модели. Не смешивайте эти измерения. Для времени переводите наносекунды явно и сохраняйте исходные значения. Для text generation проверяйте done и done_reason, если они участвуют в логике. Для chat проверяйте role и непустой content либо валидные tool_calls.
После обновления Ollama или модели снова прогоните контрактные тесты. Имя поля из документации важнее визуального сходства ответа. Если capability не подтверждена для выбранной модели, не маскируйте это повторными запросами: выберите совместимую модель или измените UX.
Чек-лист
- Slug и title уникальны.
- Endpoint и поля сверены 13 сентября 2026 года.
- Модель поддерживает нужную capability.
- Вход содержит только искусственные данные.
- Установлен timeout.
- HTTP status проверяется до JSON.
- Типы ключевых полей проверяются.
- Никакие tool calls не исполняются через eval.
- Аргументы tools проходят схему и allowlist.
- Agent loop имеет max turns.
- Индексы embeddings не смещаются.
- Метрики считаются из реальных полей ответа.
- Негативный тест завершается ожидаемо.
- Логи не содержат prompt, PII и секреты.
FAQ
Почему в примерах указан stream:false?
Так проще получить один JSON и проверить итоговые служебные поля. Для потокового UX нужен отдельный NDJSON-парсер, аккумуляция чанков и обработка финального done.
Можно ли считать ответ модели детерминированным?
Нет. Проверяйте структуру и бизнес-инварианты. Если нужна воспроизводимость, фиксируйте поддерживаемые параметры и модель, но всё равно оставляйте валидацию результата.
Нужно ли доверять аргументам tool_calls?
Нет. Это сгенерированный ввод. Проверяйте имя по allowlist, аргументы по JSON Schema и полномочия пользователя до выполнения функции.
Можно ли логировать весь payload для отладки?
Только на искусственном стенде. В production журнал ограничивают техническими идентификаторами, статусом и измерениями; чувствительное содержимое редактируют или исключают.
Что делать при несовместимой модели?
Остановить сценарий с понятной диагностикой и выбрать модель, для которой нужная capability подтверждена. Нельзя выдавать случайный текст за корректный structured/tool/FIM результат.
Читайте также
Как дополнить код через suffix в Ollama Generate API
Используем suffix для fill-in-the-middle: передаём код до и после пропуска, извлекаем вставку и проверяем итоговый файл.
Как получить batch embeddings для массива текстов в Ollama API
Передаём массив строк в /api/embed, проверяем число и размерность векторов и сохраняем соответствие индексов исходным документам.
Как получить logprobs и top_logprobs через Ollama Generate API
Включаем logprobs, задаём top_logprobs, разбираем токены и альтернативы и проверяем структуру без ложной интерпретации.
Комментарии
Пока тихо. Скажите первое слово