Гайд · TNWS AI

Как получить batch embeddings для массива текстов в Ollama API

WebLinuxmacOSWindows#Ollama#API#JavaScript
7 мин

Передаём массив строк в /api/embed, проверяем число и размерность векторов и сохраняем соответствие индексов исходным документам.

Задача и применимость

Цель этого руководства — векторизовать пакет документов одним запросом и не перепутать соответствие исходных строк и embeddings. Используется точный интерфейс: POST /api/embed: input[]. Материал подходит для локального сервиса, тестового контура или внутреннего API, где Ollama доступна по доверенному адресу. Не публикуйте порт 11434 напрямую в интернет и не подставляйте в примеры реальные клиентские данные.

В отличие от общего обзора здесь есть проверяемый контракт: запрос, структура ответа, позитивные assertions и негативный сценарий. Название модели в коде — пример; выберите установленную модель, которая поддерживает нужную capability, и зафиксируйте её имя в конфигурации проекта.

Проверенные факты и первоисточники

Сведения проверены 13 сентября 2026 года по официальной документации Ollama. input принимает строку или массив строк, а embeddings возвращается как массив числовых векторов. Дополнительно структура базовых ответов сверена с Generate API, Chat API и Embed API.

Цены и тарифы не приводятся. Доступность конкретной модели, качество ответа и аппаратная производительность зависят от локальной установки, поэтому они не выдаются за универсальный факт. Метрики берутся только из фактического JSON-ответа вашего запуска.

Подготовка безопасного тестового стенда

  1. Убедитесь, что Ollama запущена локально и endpoint доступен приложению.
  2. Получите список установленных моделей через официальный endpoint tags и выберите модель, подходящую capability.
  3. Не зашивайте имя модели в десятки файлов: храните его в переменной окружения или одном конфигурационном модуле.
  4. Используйте искусственные значения DEMO, тестовые SKU и вымышленные тексты.
  5. Задайте timeout и проверяйте HTTP status до разбора JSON.
  6. Сохраняйте исходный request без секретов, версию приложения и имя модели для воспроизводимости.
  7. Разделяйте сетевую ошибку, ошибку JSON, нарушение схемы и неверный бизнес-результат.

Ollama генерирует вероятностный результат. Даже при стабильном запросе текст может отличаться, поэтому тестируйте инварианты: наличие поля, роль сообщения, допустимое имя tool, формат аргумента, число векторов или ожидаемое вычисление. Не сравнивайте длинный ответ целиком со snapshot без необходимости.

Пошаговая реализация

  1. Сформируйте payload только из документированных полей.
  2. Укажите model и обязательный prompt, messages либо input.
  3. Для примеров, которым нужен один JSON, явно задайте stream:false.
  4. Отправьте POST с Content-Type: application/json.
  5. При status вне диапазона 200–299 прочитайте текст ошибки и остановите обработку.
  6. Разберите JSON и проверьте типы нужных полей до использования.
  7. Проверьте связь ответа с входом: роли, индексы, tool_name или сохранённые фрагменты.
  8. Не исполняйте tool по имени напрямую через eval или динамический import; используйте allowlist dispatcher.
  9. Ограничьте число шагов agent loop и общий timeout.
  10. Запишите технические счётчики отдельно от пользовательского результата.
  11. Выполните негативный тест и убедитесь, что он действительно отклоняется.
  12. Только после этого переносите код в основной сервис.

Готовый пример

const input=["Доставка по Москве за один день","Самовывоз доступен до 20:00","Возврат оформляется через поддержку"];
const r=await fetch("http://localhost:11434/api/embed",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({model:"embeddinggemma",input})});
if(!r.ok)throw Error(await r.text());
const d=await r.json();
if(d.embeddings.length!==input.length)throw Error("нарушено соответствие");
const dims=new Set(d.embeddings.map(v=>v.length));
if(dims.size!==1||[...dims][0]===0)throw Error("неверная размерность");
const rows=input.map((text,i)=>({id:i,text,embedding:d.embeddings[i]}));
console.log(rows.map(x=>({id:x.id,dimensions:x.embedding.length})));

Код рассчитан на Node.js с глобальным fetch. Его можно адаптировать к Python, сохранив ту же JSON-схему и последовательность проверок. Перед production добавьте AbortController, структурированный журнал без содержимого пользовательского prompt и retry только для безопасных транспортных сбоев.

Не повторяйте автоматически запрос, который уже мог вызвать внешний tool с побочным эффектом. Для инструментов записи используйте idempotency key на стороне приложения и сохраняйте состояние выполненного вызова. Модель предлагает аргументы, но доверять им без валидации нельзя.

Пример входа и ожидаемого результата

Вход: Три коротких искусственных документа о доставке, самовывозе и возврате.

Ожидаемый результат: API возвращает три непустых вектора одинаковой размерности; индекс каждого вектора совпадает с индексом исходного текста.

Фактическая формулировка модели может отличаться. Критерием служат явно перечисленные свойства. Если критерий зависит от знания модели, используйте небольшой набор тест-кейсов и ручную выборочную проверку, но не выдумывайте процент точности без измерения.

Негативный тест

Удалите пустую строку из input после ответа, но до сопоставления. Проверка длины должна предотвратить сдвиг индексов и запись неверного embedding.

Негативный тест запускайте автоматически рядом с позитивным. Он должен завершаться конкретной ошибкой и не оставлять частично записанное состояние. Для 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: POST /api/embed: input[]
Задача: векторизовать пакет документов одним запросом и не перепутать соответствие исходных строк и embeddings
Модель и capability проверены: <да/нет>
Искусственный вход: <значение>
Обязательные поля request: <список>
Обязательные поля response: <список>
Позитивный invariant: <условие>
Негативный сценарий: <условие>
Timeout: <значение проекта>
Max turns для цикла: <значение>
Allowlist tools: <имена>
PII и секреты отсутствуют: <да>
Источник: https://docs.ollama.com/api/embed
Дата проверки: 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 результат.

Читайте также

Комментарии

Пока тихо. Скажите первое слово