Перейти к содержанию
modelium.
Начать с задачи
←

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 s5

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

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

Это не готовый чат с документом: индекс хранит пару «фрагмент — вектор», запрос получает вектор той же моделью, а сравнение помогает найти кандидата. Проверять полезность нужно на вопросах с заранее известными релевантными фрагментами; генератор ответа и проверка цитат — следующий, отдельный этап оценки RAG. Не смешивайте в одном индексе векторы из разных моделей или конфигураций: совпадение длины массива не доказывает сопоставимость семантики.

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

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

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

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

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

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

git clone https://github.com/ggml-org/llama.cpp.git
cd llama.cpp
git checkout 7fe450e19305b828c199d602c23a8337aaa1f03b
cmake -B build
cmake --build build --config Release
# Скачивание выполняет читатель в свой каталог, Modelium не скачивал веса.
mkdir -p models
curl -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. В примере нет GPU-флага и обещания минимальной памяти. Скачивание может потребовать свободного места и сети; если файл не загружен целиком, сервер не запустится. Ключевой маркер готовности в другом терминале — GET /health с HTTP 200 и {"status":"ok"}; во время загрузки возможен HTTP 503 s1. Не публикуйте локальный порт в корпоративную сеть: 127.0.0.1 только ограничивает слушающий интерфейс и не заменяет политику доступа между процессами s1.

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

Сначала запросите один вектор. Префиксы взяты из карточки модели, а поле encoding_format: float документировано в API llama.cpp s1s6. -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. Это ещё не измерение точности или корректной загрузки всех фрагментов. CLI llama-embedding — другой путь получения векторов без HTTP-сервера; не смешивайте его формат вывода с JSON /v1/embeddings s2.

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

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

import json
import math
from urllib.request import Request, urlopen

chunks = [
"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. Даже если счёт выше у строки про invoice, это один искусственный пример; если выше иная строка, зафиксируйте ошибку, а не переписывайте ожидаемый ответ. Для реального корпуса храните идентификатор и исходный фрагмент вместе с вектором, не помещайте чувствительный текст в публичный индекс. Перед сравнением на русском определите список проверочных вопросов, релевантные фрагменты и критерий успеха по протоколу оценки RAG.

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

  • 503 от /health означает, что модель ещё загружается; дождитесь готовности. Отсутствие --embedding приводит к отказу API, а pooling none не поддерживается на совместимом маршруте s1s4.
  • Несовпадающие длины векторов, нулевая норма или неверный index — повод остановить построение индекса, проверить файл, версию сервера и входы. Не дополняйте массив нулями и не выдавайте синтетический ответ за результат модели.
  • Пример Nomic ориентирован на английский по карточке. Для русского поиска сравните несколько embedding-моделей на своём размеченном наборе; здесь не заявлена ни одна измеренная точность, задержка, минимальная память или совместимость произвольного GPU s5.
  • Поиск в небольшом массиве выше выполняет Python в памяти процесса. Для постоянной коллекции используйте подходящее хранилище, например локальный Qdrant, но не путайте приведённый вручную вектор из того гайда с качеством реальной embedding-модели.

Для отката остановите запущенный тестовый процесс llama-server в его терминале; оставшийся файл GGUF удаляйте только если он больше не нужен. Эта инструкция не меняет ваши другие модели или внешнюю базу. Основной следующий шаг — разметить вопросы и оценить retrieval на собственных документах, затем уже выбирать постоянный индекс и отдельный генератор ответа.

Источники

  1. llama.cpp v0.5.0 — server README и Embeddings API — revision 7fe450e19305b828c199d602c23a8337aaa1f03b. Получено 29.09.2026.
  2. llama.cpp v0.5.0 — пример вычисления embedding — revision 7fe450e19305b828c199d602c23a8337aaa1f03b. Получено 29.09.2026.
  3. llama.cpp v0.5.0 — сборка на CPU — revision 7fe450e19305b828c199d602c23a8337aaa1f03b. Получено 29.09.2026.
  4. llama.cpp v0.5.0 — обработчик Embeddings API — revision 7fe450e19305b828c199d602c23a8337aaa1f03b. Получено 29.09.2026.
  5. Nomic Embed Text v1.5 GGUF — карточка автора — revision 0188c9bf409793f810680a5a431e7b899c46104c. Получено 29.09.2026.
  6. Nomic Embed Text v1.5 — исходная карточка и префиксы — revision e9b6763023c676ca8431644204f50c2b100d9aab. Получено 29.09.2026.
  7. Nomic Embed Text v1.5 GGUF — состав файлов на закреплённой ревизии — revision 0188c9bf409793f810680a5a431e7b899c46104c. Получено 29.09.2026.