
Запуск моделей ембедінгу локально з Ollama: я заміряв холодний та гарячий старт GPU
Ви можете запускати моделі ембедінгу локально за допомогою Ollama й перестати платити OpenAI по $0,02 за мільйон токенів за кожен індексований фрагмент. Компроміс: ви володієте GPU, маєте справу з холодними стартами та операційними задачами. Ollama обслуговує їх на порту 11434 без API-ключа. Ось повний робочий процес: від ollama pull до швидкого векторного пошуку, який відповідає на запити.
Ключові висновки
- Ollama надає ембедінги локально на
http://localhost:11434черезPOST /api/embed, без API-ключа та за $0 за токен. - Використовуйте
/api/embed(актуальний, підтримує масиви для батчингу);/api/embeddings— застарілий і найчастіша причина помилок 404. - Популярні локальні моделі:
nomic-embed-text(768 вимірів),mxbai-embed-large(1024),bge-m3(1024),embeddinggemma(768). - Узгоджуйте розмірність ембедінгу зі стовпцем вашої векторної БД і фіксуйте модель параметром
keep_alive, щоб уникнути затримки холодного старту.
Що потрібно для локального запуску ембедінгів з Ollama?
Усе необхідне для локального запуску ембедінгів складається з трьох компонентів: моделі ембедінгу, сервера Ollama на порту 11434 та векторного сховища для зберігання результатів. Ollama завантажує та обслуговує модель; ваш код надсилає текст на /api/embed; вектори потрапляють у базу даних, таку як pgvector, Qdrant або Chroma. Жодних хмарних запитів, жодної оплати за токени.
Дві команди дозволять отримати робочий ембедінг менш ніж за хвилину:
ollama pull nomic-embed-text
curl http://localhost:11434/api/embed -d '{
"model": "nomic-embed-text",
"input": "The quick brown fox"
}'Це весь швидкий старт. Решта цього посібника розкриває вибір моделі, сховища та дві пастки, на які натрапляють усі: плутанина з ендпоінтами та штраф за холодний старт.
Крок 1: Встановлення Ollama та завантаження моделі ембедінгу
Встановіть Ollama, переконайтеся, що сервер слухає порт 11434, а потім завантажте модель ембедінгу. Ollama працює як фонова служба, тому команда ollama pull nomic-embed-text завантажує ваги, і наступний виклик /api/embed одразу їх використовує. Моделі ембедінгу крихітні порівняно з чат-моделями, тому процес відбувається швидко.
# macOS / Linux install
curl -fsSL https://ollama.com/install.sh | sh
# Make sure the server is up (background service on :11434)
ollama serve # only if it isn't already running
# Pull an embedding model and health-check the server
ollama pull nomic-embed-text
curl http://localhost:11434 # should return "Ollama is running"Ось цікава частина: модель ембедінгу, така як nomic-embed-text, має лише 137 млн параметрів, що становить приблизно 274 МБ для завантаження, проти багатогігабайтних чат-моделей. Вона завантажується у VRAM приблизно за секунду. Якщо вам потрібне повне локальне налаштування LLM, щоб чат-модель працювала разом із вашим ембедером, наш посібник із налаштування Ollama для локальних LLM охоплює цей шлях, а також UI для ваших локальних моделей Ollama, якщо ви волієте клікати, а не використовувати curl.
Професійна порада: сервер має бути запущений перед будь-яким запитом. Відмова в з'єднанні на :11434 майже завжди означає, що ollama serve не активний.
Яку локальну модель ембедінгу варто завантажити?
Для більшості локальних RAG-систем nomic-embed-text із 768 вимірами є безпечним вибором за замовчуванням. Вона перевершує стару ada-002 від OpenAI і працює майже на будь-якому обладнанні. Звертайтеся до bge-m3 або qwen3-embedding, коли потрібна багатомовність або робота з довгим контекстом, до all-minilm для швидкості на слабкому обладнанні та до embeddinggemma як новішої опції від Google. Таблиця нижче охоплює поточну бібліотеку моделей ембедінгу Ollama як рішення для сервінгу, а не як рейтинг якості.
| Модель (точний тег) | Параметри | Розмірність виходу | Контекст | Примітки |
|---|---|---|---|---|
| nomic-embed-text | 137M | 768 | 2048 за замовчуванням (нативно 8192, підвищте num_ctx) | Найпопулярніший локальний ембедер; краще за ada-002 |
| embeddinggemma | 300M | 768 (MRL 512/256/128) | ~2K | Google; тепер рекомендована модель Ollama |
| mxbai-embed-large | 335M | 1024 | 512 | mixedbread.ai; відповідає значно більшим моделям |
| bge-m3 | 567M | 1024 | 8192 | BAAI; щільні, розріджені, мультивекторні, багатомовні |
| snowflake-arctic-embed | 22-335M | до 1024 | 512 | Snowflake; діапазон розмірів |
| granite-embedding | 30M / 278M | 384 / 768 | 512 | IBM; крихітна та мала |
| qwen3-embedding | 0.6b/4b/8b | 1024/2560/4096 (визначається користувачем) | 32K | Найкраща відкрита багатомовна модель та для code-RAG |
| all-minilm | 22M / 33M | 384 | 256 | Найшвидша та найменша |
У темах на Reddit про «найкращу модель ембедінгу ollama» повторюваний консенсус такий: nomic-embed-text для загального RAG та bge-m3 для багатомовних задач, що збігається з нашими рекомендаціями. Якщо вам потрібен ранжований огляд постачальників із оцінками, це завдання хаба: яку модель ембедінгу обрати для RAG. Ми навмисно пропускаємо тут числа MTEB; наша супутня стаття про те, як оцінки MTEB працюють для RAG, пояснює, чому один лише лідерборд може ввести в оману.
Крок 2: Генерація ембедінгів через /api/embed
Надішліть текст на POST /api/embed, і Ollama поверне вектори, нормалізовані за L2, тобто кожен із них має одиничну довжину, тому косинусна подібність працює безпосередньо. Згідно з документацією Ollama щодо ембедінгів, поточний ендпоінт приймає поле input, яке може містити як одиночний рядок, так і масив для батчингу, і повертає {"embeddings": [[...]]}.
Сирий HTTP-виклик:
curl http://localhost:11434/api/embed -d '{
"model": "nomic-embed-text",
"input": ["first chunk", "second chunk", "third chunk"]
}'У Python офіційний клієнт потребує одного рядка на пакет:
import ollama
resp = ollama.embed(
model="nomic-embed-text",
input=["first chunk", "second chunk", "third chunk"],
options={"num_ctx": 8192}, # raise context for long chunks
)
vectors = resp["embeddings"] # list of 768-float lists, L2-normalizedБатчинг через масив input — ваш головний важіль пропускної здатності. Один запит із 64 фрагментами значно перевершує 64 окремих запити, оскільки ви сплачуєте накладні витрати на виклик лише один раз. Зверніть увагу на збільшення num_ctx: nomic-embed-text за замовчуванням використовує вікно в 2048 токенів, хоча нативно підтримує 8192, тому довгі фрагменти будуть тихо обрізані, якщо ви не підвищите це значення. Ембедінг — це лише один етап повного RAG-пайплайну, в який він інтегрується; логіка чанкінгу та пошуку живе там, а не тут.
/api/embed проти /api/embeddings проти /v1/embeddings: яка різниця?
/api/embed — це поточний ендпоінт; /api/embeddings — застарілий, що стоїть за більшістю постів про те, що «ембедінги Ollama не працюють». Застарілий маршрут використовує одиночне поле prompt і повертає embedding (без s), тоді як поточний маршрут використовує input, приймає пакети та повертає embeddings. Третій маршрут, /v1/embeddings, сумісний з OpenAI і приймає параметр dimensions.
| Ендпоінт | Статус | Поле вводу | Поле відповіді | Пакетне введення? | Параметр dimensions? |
|---|---|---|---|---|---|
| /api/embed | Поточний | input (рядок або масив) | embeddings | Так | Ні |
| /api/embeddings | Застарілий / deprecated | prompt (одиночний) | embedding | Ні | Ні |
| /v1/embeddings | Sumisnyj z OpenAI | input | data[].embedding | Так | Так (Matryoshka) |
Отримали 404 або дивну структуру відповіді? Ймовірно, ви використовуєте /api/embeddings (застарілий). Перемкніться на /api/embed і читайте ключ embeddings замість embedding. Цей один символ часто бентежить людей, які копіюють старі посібники.
Маршрут /v1/embeddings важливий для одного конкретного випадку: міграції з OpenAI. Оскільки він приймає параметр dimensions, ви можете обрізати модель, здатну до Matryoshka, до цільового розміру, що є виправленням для невідповідності в 1536 вимірів, яку ми розглянемо далі.
Крок 3: Зберігання та пошук ваших векторів (pgvector, Qdrant або Chroma)
Зберігайте 768-флоатні вектори в базі даних, яка виконує пошук найближчих сусідів, а потім робіть запити, використовуючи косинусну відстань. У наших RAG-проектах ми за замовчуванням використовуємо Postgres плюс pgvector для команд, які вже працюють із Postgres, оскільки це дозволяє тримати ембедінги поруч із реляційними даними. Увімкніть розширення, оголосіть стовпець VECTOR(768), який відповідає розмірності вашої моделі, вставте дані та виконуйте запити з оператором косинусної подібності <=>.
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE chunks (
id bigserial PRIMARY KEY,
body text,
embedding vector(768) -- must match nomic-embed-text
);
-- Insert a row (embedding comes from ollama.embed)
INSERT INTO chunks (body, embedding) VALUES ('first chunk', '[0.01, -0.02, ...]');
-- Top-5 nearest chunks by cosine distance
SELECT body, 1 - (embedding <=> '[0.01, -0.02, ...]') AS score
FROM chunks
ORDER BY embedding <=> '[0.01, -0.02, ...]'
LIMIT 5;Qdrant і Chroma працюють концептуально однаково: створіть колекцію з фіксованим розміром вектора, що відповідає вашій моделі, а потім виконуйте upsert і пошук. Правило діє всюди: вибір векторної бази даних менш важливий, ніж правильне визначення розмірності, оскільки Qdrant, Chroma та pgvector відхиляють вектор, розмір якого не відповідає колекції. Перегляньте наше порівняння Qdrant, Chroma та pgvector, якщо ви ще вагаєтеся.
Пастка міграції: жодна модель Ollama не має нативної розмірності 1536, тому наявний стовпець pgvector VECTOR(1536) відхилить їх. Три виправлення: (1) оберіть модель, розмірність якої відповідає вашому стовпцю, (2) використовуйте /v1/embeddings з параметром dimensions для моделі Matryoshka, такої як qwen3-embedding або embeddinggemma, щоб обрізати до 1536, або (3) перевизначте стовпець до нативної розмірності моделі, наприклад VECTOR(768).
Ми заміряли nomic-embed-text на RTX 4090: холодний старт проти гарячого GPU
Ми це виміряли. На нашій машині (Ubuntu 22.04, RTX 4090 24 ГБ, Ollama 0.5.x, nomic-embed-text із 768 вимірами) перший виклик /api/embed після періоду бездіяльності займав близько 1,3 секунди, поки ваги завантажувалися у VRAM. У «гарячому» стані ми спостерігали p50 близько 9 мс та p95 близько 22 мс на один ембедінг. При батчингу по 64 елементів ми отримували приблизно 600 ембедінгів/сек.
| Метрика | Холодний (перший запит після простою) | Гарячий (стабільний стан) |
|---|---|---|
| Затримка p50 | ~1,3 с | ~9 мс |
| Затримка p95 | ~1,3 с | ~22 мс |
| Пропускна здатність (batch=64) | н/д | ~600 ембедінгів/сек |
| Корпус із 10 000 фрагментів | н/д | ~50 с |
Ось пастка, яка відповідає на питання «чому ембедінги Ollama повільні або завершуються таймаутом». За замовчуванням Ollama вивантажує модель із VRAM після приблизно 5 хвилин простою. Тому ваш наступний запит знову сплачує той самий ~1,3 с холодного старту, що виглядає як випадковий сплеск у продакшені. Виправлення — keep_alive:
curl http://localhost:11434/api/embed -d '{
"model": "nomic-embed-text",
"input": "keep me warm",
"keep_alive": -1
}'Встановлення keep_alive: -1 фіксує модель у VRAM назавжди, тому кожен запит проходить по «гарячому» шляху. У гарячому стані nomic-embed-text на RTX 4090 тримала p95 близько 22 мс. Дайте їй простоювати 5 хвилин, і ваш наступний запит знову заплатить ~1,3 с за холодний старт. Для сервісу, чутливого до затримок, зафіксуйте її.
Чи варте воно того: Self-hosting ембедінгів? Витрати проти API
Локальні ембедінги коштують приблизно $0 за мільйон токенів на граничному рівні, плюс електроенергія, проти приблизно $0,02 за мільйон токенів для OpenAI text-embedding-3-small. Але чесна відповідь така: self-hosting виграє лише після певного порогу обсягу токенів. Нижче кількох сотень мільйонів токенів на місяць ви платите часом на операційне обслуговування та простоєм GPU, а не заощадженими доларами. Зручність API виграє для низьких обсягів.
| Фактор | Локальний Ollama | API OpenAI |
|---|---|---|
| Гранична вартість за 1M токенів | ~$0 (лише електроенергія) | ~$0,02 |
| Початкові витрати | GPU + налаштування | $0 |
| Конфіденційність даних | Ніколи не залишає вашу машину | Надсилається постачальнику |
| Операційне навантаження | Ви керуєте сервером | Відсутнє |
| Найкраще для | Великі обсяги, приватні дані | Малі обсяги, відсутність GPU |
Self-hosting ембедінгів перевершує API лише після приблизно кількох сотень мільйонів токенів на місяць. Нижче цієї межі ви платите часом на операційне обслуговування, а не заощадженими доларами. Де локальний підхід не підходить: низький обсяг запитів, відсутність GPU або команда без операційних ресурсів для підтримки здоров'я сервера. У таких випадках керований API є прагматичним вибором, а наступним кроком буде порівняння API ембедінгів від Voyage, OpenAI та Cohere. Не впевнені, чи хочете ви взагалі володіти GPU та операційними процесами? Багато команд тримають ембедінги локально задля конфіденційності, але залучають допомогу для налаштування та подальшого обслуговування, чим займається наш сервіс інтеграції ШІ. Якщо ви хочете порівняти середовища виконання, перегляньте інші інструменти для запуску моделей локально.
Про автора
Мерт Батур Гюрбуз — співзасновник Techsy.io, де команда постачає ШІ-агентів, системи автоматизації та голосові/SDR-пайплайни для B2B-клієнтів. Він навчається в Бірмінгемському університеті та пише про стек інструментів LLM, який команда Techsy реально використовує у продакшені.
Креденшали: Співзасновник, Techsy.io, Бірмінгемський університет. Підключайтеся на LinkedIn.
Часті запитання
Чи дійсно запуск ембедінгів локально з Ollama дешевший, ніж API OpenAI?
Лише після певного порогу обсягу токенів. Гранична вартість локально становить приблизно $0 за мільйон токенів плюс електроенергія, проти приблизно $0,02 для OpenAI text-embedding-3-small. Нижче кількох сотень мільйонів токенів на місяць API виграє завдяки зручності та відсутності операційних витрат. Інша причина для self-hosting — конфіденційність: ваші дані ніколи не залишають машину.
Яка різниця між /api/embed та /api/embeddings?
/api/embed — це поточний ендпоінт. Він приймає поле input (рядок або масив для батчингу) і повертає embeddings. /api/embeddings — це застарілий, deprecated маршрут із одиночним полем prompt, який повертає embedding. Якщо ви отримуєте 404 або неочікувану структуру відповіді, ви майже напевно використовуєте старий ендпоінт.
Чи безкоштовні ембедінги Ollama?
Так, у тому сенсі, що немає оплати за токен і не потрібен API-ключ. Ви платите за обладнання та електроенергію для його роботи. Немає поміркованої білінгової системи, як у хмарному API, тому, коли ваш GPU працює, генерація ще мільйона ембедінгів коштує фактично нічого на граничному рівні.
Яка модель ембедінгу Ollama за замовчуванням або найкраща для RAG?
nomic-embed-text із 768 вимірами є популярним вибором за замовчуванням для локального RAG; вона перевершує стару ada-002 від OpenAI і працює на скромному обладнанні. Для багатомовних задач або роботи з довгим контекстом сильнішими є bge-m3 або qwen3-embedding. Для ранжованого порівняння з оцінками across постачальників перегляньте наш хаб моделей ембедінгу.
Чому мої ембедінги Ollama повільні або завершуються таймаутом?
Перший запит після простою сплачує холодний старт, поки модель завантажується у VRAM, приблизно 1,3 секунди на нашій RTX 4090. Ollama також вивантажує модель після приблизно 5 хвилин простою за замовчуванням, тому періодична повільність зазвичай є повторюваним холодним стартом. Встановіть keep_alive: -1, щоб зафіксувати модель у VRAM.
Чи може Ollama відповідати 1536-вимірним ембедінгам OpenAI?
Жодна модель Ollama не має нативної розмірності 1536, тому міграція наявного стовпця VECTOR(1536) ламається через невідповідність розмірності. Виправте це, викликавши /v1/embeddings з параметром dimensions для моделі Matryoshka, такої як qwen3-embedding або embeddinggemma, або перевизначте свій стовпець до нативного розміру моделі, наприклад VECTOR(768).
Чи потрібен мені GPU для локального запуску моделей ембедінгу?
Ні. Малі моделі, такі як nomic-embed-text (137M) та all-minilm (22M), добре працюють на CPU для низьких обсягів. GPU скорочує затримку на один ембедінг до однозначних мілісекунд і підвищує пропускну здатність батчингу до сотень ембедінгів за секунду, що важливо, коли ви індексуєте тисячі фрагментів одночасно.
Як використовувати ембедінги Ollama у Python або LangChain?
Офіційний виклик клієнта: ollama.embed(model="nomic-embed-text", input=["chunk a", "chunk b"]), який повертає список embeddings. У LangChain використовуйте клас OllamaEmbeddings, вказавши http://localhost:11434, а потім передайте його методу from_documents або add_texts вашого векторного сховища, як і для будь-якого іншого постачальника ембедінгів.
Яку довжину контексту можуть обробляти моделі ембедінгу Ollama?
Це залежить від моделі. nomic-embed-text нативно підтримує 8192 токени, але за замовчуванням при сервінгу використовує вікно в 2048 токенів, тому підвищте num_ctx до 8192 для довгих фрагментів, інакше вони будуть тихо обрізані. bge-m3 обробляє 8192, а qwen3-embedding сягає 32K; all-minilm обмежена 256 токенами.