# llama.cpp Embeddings API: локальные векторы для поиска

Источник: https://modelium.tech/zhurnal/llama-cpp-embeddings-api/

llama.cpp выдаёт векторы через локальный `/v1/embeddings`, если запустить `llama-server` с выделенной embedding-моделью и `--embedding`. Индексируйте фрагменты и вопросы одной моделью, соблюдая её префиксы; сравнение векторов даёт ближайший фрагмент, но ещё не ответ RAG. Показанная Nomic v1.5 помечена автором как англоязычная: результат на русских документах нужно оценить отдельно.

**Проверка документации: 29 сентября 2026 года.** Инструкция привязана к тегу llama.cpp v0.5.0 (коммит `7fe450e`) и двум закреплённым ревизиям карточек Nomic. Ни модель, ни GPU, ни сервер Modelium не запускал; приведённые команды — план воспроизведения на вашем устройстве, не наш результат. [s1](#src-s1) [s5](#src-s5)

## Что делает llama.cpp Embeddings API?

`llama-server` умеет возвращать числовой вектор для строки или массива строк по OpenAI-совместимому маршруту `POST /v1/embeddings`. Для этого в версии v0.5.0 включают `--embedding` и берут **выделенную embedding-модель**, а не произвольную разговорную GGUF. Маршрут `/embedding` отличается форматом запроса и не является OpenAI-совместимым; есть также отдельный `/embeddings` с иным форматом ответа [s1](#src-s1). В исходном обработчике вызов без `--embedding` получает ошибку, а `/v1/embeddings` не принимает pooling `none` [s4](#src-s4).

Это **не** готовый чат с документом: индекс хранит пару «фрагмент — вектор», запрос получает вектор той же моделью, а сравнение помогает найти кандидата. Проверять полезность нужно на вопросах с заранее известными релевантными фрагментами; генератор ответа и проверка цитат — следующий, отдельный этап [оценки RAG](/zhurnal/ocenka-kachestva-rag/). Не смешивайте в одном индексе векторы из разных моделей или конфигураций: совпадение длины массива не доказывает сопоставимость семантики.

## Что подготовить перед запуском?

Нужны `git`, CMake, компилятор C/C++ и диск для исходников и конкретного файла GGUF; пример ниже — CPU-путь сборки по официальной инструкции. Для GPU в исходной документации есть другие параметры сборки, но ускорение и память зависят от вашей системы [s3](#src-s3). На ревизии `0188c9bf` авторский репозиторий Nomic Embed Text v1.5 GGUF содержит `nomic-embed-text-v1.5.f16.gguf` и квант `Q4_K_M`; здесь для прозрачности указан файл F16. Размер файла **не** означает минимальную RAM/VRAM, а лицензию и происхождение выбранного файла проверяйте для своего применения [s5](#src-s5)[s7](#src-s7).

Карточка Nomic помечает язык `en` и лицензию `apache-2.0`; это сведения карточки, а не независимая оценка или юридическое заключение. В демонстрации ниже короткие **английские** тексты; для русского корпоративного архива нужен отдельный набор вопросов и подходящая проверенная модель [s5](#src-s5). Nomic требует `search_document: `перед текстом фрагмента и `search_query: `перед вопросом. Пропуск префиксов меняет вход модели и обесценивает сопоставление с инструкцией автора [s5](#src-s5)[s6](#src-s6).

Карточка GGUF предупреждает о контексте по умолчанию 2048 токенов в llama.cpp и описывает отдельный способ расширения до 8192. Для первого теста используйте короткие фрагменты и не переносите автоматически чужой рецепт длинного контекста на сервер; после смены версии заново проверьте поведение [s5](#src-s5).

## Как поднять локальный embedding-сервер?

Закрепите исходники на коммите тега и соберите CPU-версию. Официальная сборка использует `cmake -B build` и `cmake --build build --config Release`; расположение бинарника для вашей платформы проверьте в полученной директории [s3](#src-s3). Здесь пути Linux/macOS, на Windows путь и окружение будут другими.

git clone https://github.com/ggml-org/llama.cpp.gitcd llama.cppgit checkout 7fe450e19305b828c199d602c23a8337aaa1f03bcmake -B buildcmake --build build --config Release# Скачивание выполняет читатель в свой каталог, Modelium не скачивал веса.mkdir -p modelscurl -fL --retry 3 -o models/nomic-embed-text-v1.5.f16.gguf \  https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF/resolve/0188c9bf409793f810680a5a431e7b899c46104c/nomic-embed-text-v1.5.f16.gguf./build/bin/llama-server -m models/nomic-embed-text-v1.5.f16.gguf \  --embedding --host 127.0.0.1 --port 8080

Выбрана ревизия файла, а не плавающее `main`: состав файлов в ней подтверждён API репозитория [s7](#src-s7). В примере нет GPU-флага и обещания минимальной памяти. Скачивание может потребовать свободного места и сети; если файл не загружен целиком, сервер не запустится. Ключевой маркер готовности в **другом** терминале — `GET /health` с HTTP 200 и `{"status":"ok"}`; во время загрузки возможен HTTP 503 [s1](#src-s1). Не публикуйте локальный порт в корпоративную сеть: `127.0.0.1` только ограничивает слушающий интерфейс и не заменяет политику доступа между процессами [s1](#src-s1).

## Как получить и проверить форму векторов?

Сначала запросите один вектор. Префиксы взяты из карточки модели, а поле `encoding_format: float` документировано в API llama.cpp [s1](#src-s1)[s6](#src-s6). `-f` у `curl` завершит команду с ошибкой при HTTP 4xx/5xx.

curl -fsS http://127.0.0.1:8080/v1/embeddings \  -H 'Content-Type: application/json' \  -d '{"input":"search_document: The invoice contains a due date.","encoding_format":"float"}' \  | python3 -c 'import json,sys; x=json.load(sys.stdin)["data"][0]["embedding"]; print("dimension:",len(x),"first_values:",x[:3])'

Ожидается **форма**: положительная длина числового массива, не конкретные значения. API нормализует pooled embeddings по евклидовой норме, а `--pooling none` несовместим с этим маршрутом [s1](#src-s1). Это ещё не измерение точности или корректной загрузки всех фрагментов. CLI `llama-embedding` — другой путь получения векторов без HTTP-сервера; не смешивайте его формат вывода с JSON `/v1/embeddings` [s2](#src-s2).

## Как найти ближайший фрагмент без дополнительной базы?

Следующий пример использует стандартную библиотеку Python и **только ваш запущенный локальный сервер**. Он отправляет три вымышленных фрагмента и один вопрос в одном запросе, проверяет число и размерность векторов и выводит ранжирование. Формула косинуса: сумма попарных произведений координат, делённая на произведение евклидовых норм. Это локальный протокол, а не проверенное Modelium качество модели.

import jsonimport mathfrom urllib.request import Request, urlopenchunks = [    "The invoice is due on Friday.",    "The package ships on Tuesday.",    "The agreement ends in December.",]question = "When must the invoice be paid?"texts = ["search_document: " + x for x in chunks]texts.append("search_query: " + question)request = Request(    "http://127.0.0.1:8080/v1/embeddings",    data=json.dumps({"input": texts, "encoding_format": "float"}).encode(),    headers={"Content-Type": "application/json"},)with urlopen(request, timeout=90) as response:    rows = json.load(response)["data"]assert len(rows) == len(texts), "неполный ответ: проверьте запрос и сервер"rows.sort(key=lambda row: row["index"])vectors = [row["embedding"] for row in rows]dim = len(vectors[0])assert dim > 0 and all(len(v) == dim for v in vectors), "несовпадение размерностей"assert all(math.isfinite(x) for v in vectors for x in v), "неконечные числа"def cosine(a, b):    dot = sum(x * y for x, y in zip(a, b))    na = math.sqrt(sum(x * x for x in a))    nb = math.sqrt(sum(y * y for y in b))    if not na or not nb:        raise ValueError("нулевая норма вектора")    return dot / (na * nb)for i in sorted(range(len(chunks)), key=lambda i: cosine(vectors[i], vectors[-1]), reverse=True):    print(f"{cosine(vectors[i], vectors[-1]):.4f} | {chunks[i]}")

Индекс ответа нужен для восстановления исходного порядка при массиве входов [s1](#src-s1). Даже если счёт выше у строки про invoice, это один искусственный пример; если выше иная строка, зафиксируйте ошибку, а не переписывайте ожидаемый ответ. Для реального корпуса храните идентификатор и исходный фрагмент вместе с вектором, не помещайте чувствительный текст в публичный индекс. Перед сравнением на русском определите список проверочных вопросов, релевантные фрагменты и критерий успеха по [протоколу оценки RAG](/zhurnal/ocenka-kachestva-rag/).

## Какие ошибки и ограничения учитывать?

- `503` от `/health` означает, что модель ещё загружается; дождитесь готовности. Отсутствие `--embedding` приводит к отказу API, а pooling `none` не поддерживается на совместимом маршруте [s1](#src-s1)[s4](#src-s4).

- Несовпадающие длины векторов, нулевая норма или неверный `index` — повод остановить построение индекса, проверить файл, версию сервера и входы. Не дополняйте массив нулями и не выдавайте синтетический ответ за результат модели.

- Пример Nomic ориентирован на английский по карточке. Для русского поиска сравните несколько embedding-моделей на своём размеченном наборе; здесь не заявлена ни одна измеренная точность, задержка, минимальная память или совместимость произвольного GPU [s5](#src-s5).

- Поиск в небольшом массиве выше выполняет Python в памяти процесса. Для постоянной коллекции используйте подходящее хранилище, например [локальный Qdrant](/zhurnal/qdrant-lokalno/), но не путайте приведённый вручную вектор из того гайда с качеством реальной embedding-модели.

Для отката остановите запущенный тестовый процесс `llama-server` в его терминале; оставшийся файл GGUF удаляйте только если он больше не нужен. Эта инструкция не меняет ваши другие модели или внешнюю базу. **Основной следующий шаг** — [разметить вопросы и оценить retrieval](/zhurnal/ocenka-kachestva-rag/) на собственных документах, затем уже выбирать постоянный индекс и отдельный генератор ответа.

## Источники

1. [llama.cpp v0.5.0 — server README и Embeddings API](https://raw.githubusercontent.com/ggml-org/llama.cpp/7fe450e19305b828c199d602c23a8337aaa1f03b/tools/server/README.md) — получено 2026-09-29
2. [llama.cpp v0.5.0 — пример вычисления embedding](https://raw.githubusercontent.com/ggml-org/llama.cpp/7fe450e19305b828c199d602c23a8337aaa1f03b/examples/embedding/README.md) — получено 2026-09-29
3. [llama.cpp v0.5.0 — сборка на CPU](https://raw.githubusercontent.com/ggml-org/llama.cpp/7fe450e19305b828c199d602c23a8337aaa1f03b/docs/build.md) — получено 2026-09-29
4. [llama.cpp v0.5.0 — обработчик Embeddings API](https://raw.githubusercontent.com/ggml-org/llama.cpp/7fe450e19305b828c199d602c23a8337aaa1f03b/tools/server/server-context.cpp) — получено 2026-09-29
5. [Nomic Embed Text v1.5 GGUF — карточка автора](https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF/blob/0188c9bf409793f810680a5a431e7b899c46104c/README.md) — получено 2026-09-29
6. [Nomic Embed Text v1.5 — исходная карточка и префиксы](https://huggingface.co/nomic-ai/nomic-embed-text-v1.5/blob/e9b6763023c676ca8431644204f50c2b100d9aab/README.md) — получено 2026-09-29
7. [Nomic Embed Text v1.5 GGUF — состав файлов на закреплённой ревизии](https://huggingface.co/api/models/nomic-ai/nomic-embed-text-v1.5-GGUF/revision/0188c9bf409793f810680a5a431e7b899c46104c) — получено 2026-09-29
