ai-machine-learning

Kör embeddingmodeller lokalt med Ollama: jag tidtog kall vs varm GPU

Skriven av Mert Batur
Jul 13, 2026
10 läsning
Kör embeddingmodeller lokalt med Ollama: jag tidtog kall vs varm GPU

Kör embeddingmodeller lokalt med Ollama: jag tidtog kall vs varm GPU

Du kan köra embeddingmodeller lokalt med Ollama och sluta betala OpenAI $0.02 per miljon tokens för varje textbit du indexerar. Bytet: du äger GPU:n, kallstarterna och driften själv. Ollama serverar dem på port 11434 utan API-nyckel. Här är hela arbetsflödet, från ollama pull till en varm vektorsökning som besvarar frågor.

Det viktigaste i korthet

  • Ollama serverar embeddings lokalt på http://localhost:11434 via POST /api/embed, utan API-nyckel och till $0 per token.
  • Använd /api/embed (aktuell, tar en batch-array); /api/embeddings är föråldrad och den vanligaste 404-källan.
  • Populära lokala modeller: nomic-embed-text (768-dim), mxbai-embed-large (1024), bge-m3 (1024), embeddinggemma (768).
  • Matcha din embedding-dimension mot kolumnen i vektordatabasen, och pinna modellen med keep_alive för att slippa kallstartslatens.

Vad behöver du för att köra embeddings lokalt med Ollama?

Allt du behöver för att köra embeddings lokalt är tre delar: en embeddingmodell, Ollama-servern på port 11434, och ett vektorlager som tar hand om resultatet. Ollama laddar ner och serverar modellen; din kod postar text till /api/embed; vektorerna hamnar i en databas som pgvector, Qdrant eller Chroma. Ingen molnrundtur, ingen per-token-faktura.

Två kommandon räcker för en fungerande embedding på under en minut:

bash
ollama pull nomic-embed-text
curl http://localhost:11434/api/embed -d '{
  "model": "nomic-embed-text",
  "input": "The quick brown fox"
}'

Det är hela snabbstarten. Resten av den här guiden går igenom modellvalet, lagringen och de två fallgroparna som biter alla: endpoint-förvirringen och kallstartsstraffet.

Steg 1: Installera Ollama och hämta en embeddingmodell

Installera Ollama, kontrollera att servern lyssnar på port 11434, och hämta sedan en embeddingmodell. Ollama körs som en bakgrundstjänst, så ollama pull nomic-embed-text laddar ner vikterna och nästa /api/embed-anrop serverar dem direkt. Embeddingmodeller är små jämfört med chattmodeller, så det här går snabbt.

bash
# macOS / Linux-installation
curl -fsSL https://ollama.com/install.sh | sh

# Se till att servern är igång (bakgrundstjänst på :11434)
ollama serve            # endast om den inte redan körs

# Hämta en embeddingmodell och kontrollera serverns hälsa
ollama pull nomic-embed-text
curl http://localhost:11434            # ska returnera "Ollama is running"

Här kommer den roliga detaljen: en embeddingmodell som nomic-embed-text väger bara 137M parametrar, ungefär 274 MB att ladda ner, jämfört med chattmodeller på flera gigabyte. Den laddas in i VRAM på ungefär en sekund. Om du vill sätta upp en fullständig lokal LLM-installation med en chattmodell bredvid din embedder går vår guide om att sätta upp Ollama för lokala LLM:er igenom det spåret, och ett grafiskt gränssnitt för dina lokala Ollama-modeller om du hellre klickar än kör curl.

Proffstips: servern måste vara igång innan du gör några anrop. En nekad anslutning på :11434 betyder nästan alltid att ollama serve inte körs.

Vilken lokal embeddingmodell bör du hämta?

För de flesta lokala RAG-lösningar är nomic-embed-text på 768 dimensioner det säkra standardvalet. Den slår OpenAIs gamla ada-002 och körs på nästan vad som helst. Ta bge-m3 eller qwen3-embedding när du behöver flerspråkig eller långkontext-hämtning, all-minilm för snabbhet på liten hårdvara, och embeddinggemma som Googles nyare alternativ. Tabellen nedan täcker Ollamas embeddingmodellbibliotek som ett serveringsbeslut, inte en kvalitetsrankning.

Modell (exakt tagg)ParametrarUtdata-dimKontextAnteckningar
nomic-embed-text137M7682048 standard (nativt 8192, höj num_ctx)Mest populära lokala embeddern; slår ada-002
embeddinggemma300M768 (MRL 512/256/128)~2KGoogle; numera en Ollama-rekommenderad modell
mxbai-embed-large335M1024512mixedbread.ai; matchar mycket större modeller
bge-m3567M10248192BAAI; tät, gles, multivektor, flerspråkig
snowflake-arctic-embed22-335Mupp till 1024512Snowflake; storleksspann
granite-embedding30M / 278M384 / 768512IBM; mikroliten och liten
qwen3-embedding0.6b/4b/8b1024/2560/4096 (användardefinierbar)32KBästa öppna flerspråkiga och kod-RAG-modellen
all-minilm22M / 33M384256Snabbast och minst

I trådarna om "best ollama embedding model reddit" är det återkommande konsensuset nomic-embed-text för generell RAG och bge-m3 när du går flerspråkigt, vilket stämmer med vad vi själva kör. Om du vill ha den rankade jämförelsen mellan alla leverantörer med poäng är det jobbet för navet: vilken embeddingmodell du ska välja för RAG. Vi hoppar medvetet över MTEB-poäng här; vår kompletterande artikel om hur MTEB-poäng fungerar för RAG förklarar varför rankningslistan ensam kan lura dig.

Steg 2: Generera embeddings via /api/embed

Skicka text till POST /api/embed så returnerar Ollama L2-normaliserade vektorer, vilket betyder att varje vektor har enhetslängd så att cosinuslikhet fungerar direkt. Enligt Ollamas embeddings-dokumentation tar den aktuella endpointen ett input-fält som accepterar antingen en enskild sträng eller en array för batchning, och returnerar {"embeddings": [[...]]}.

Det råa HTTP-anropet:

bash
curl http://localhost:11434/api/embed -d '{
  "model": "nomic-embed-text",
  "input": ["first chunk", "second chunk", "third chunk"]
}'

I Python är det officiella klientanropet en rad per batch:

python
import ollama

resp = ollama.embed(
    model="nomic-embed-text",
    input=["first chunk", "second chunk", "third chunk"],
    options={"num_ctx": 8192},  # höj kontextfönstret för långa textbitar
)
vectors = resp["embeddings"]   # lista med 768-flottal, L2-normaliserad

Batchning via input-arrayen är din främsta hävstång för genomströmning. En förfrågan med 64 textbitar slår 64 enskilda förfrågningar med bred marginal, eftersom du bara betalar overheaden per anrop en gång. Lägg märke till num_ctx-höjningen: nomic-embed-text använder som standard ett fönster på 2048 tokens trots att den nativt stödjer 8192, så långa textbitar trunkeras tyst om du inte höjer det. Embedding är ett steg i hela RAG-pipelinen som detta matar in i; chunking och hämtningslogik hör hemma där, inte här.

/api/embed vs /api/embeddings vs /v1/embeddings: vad är skillnaden?

/api/embed är den aktuella endpointen; /api/embeddings är den föråldrade som ligger bakom de flesta "Ollama embeddings not working"-inläggen. Den gamla routen använder ett enskilt prompt-fält och returnerar embedding (utan s), medan den aktuella routen använder input, accepterar batchar och returnerar embeddings. En tredje route, /v1/embeddings, är OpenAI-kompatibel och accepterar en dimensions-parameter.

EndpointStatusInputfältSvarsfältBatch-input?dimensions-parameter?
/api/embedAktuellinput (sträng eller array)embeddingsJaNej
/api/embeddingsFöråldrad/utfasadprompt (enskild)embeddingNejNej
/v1/embeddingsOpenAI-kompatibelinputdata[].embeddingJaJa (Matryoshka)

Får du en 404 eller ett konstigt svarsformat? Du använder förmodligen /api/embeddings (den gamla). Byt till /api/embed och läs embeddings-nyckeln istället för embedding. Just den enda bokstaven ställer till det för många som kopierar gamla guider.

Routen /v1/embeddings spelar roll i ett specifikt fall: att migrera bort från OpenAI. Eftersom den accepterar en dimensions-parameter kan du trunkera en Matryoshka-kapabel modell ner till en målstorlek, vilket är lösningen på 1536-dimensionsmissmatchen vi går igenom härnäst.

Steg 3: Lagra och sök dina vektorer (pgvector, Qdrant eller Chroma)

Lagra de 768-flottalsvektorerna i en databas som klarar närmaste-granne-sökning, och sök sedan med cosinusavstånd. I våra RAG-bygg väljer vi som standard Postgres plus pgvector för team som redan kör Postgres, eftersom det håller dina embeddings nära din relationsdata. Aktivera tillägget, deklarera en VECTOR(768)-kolumn som matchar din modells dimension, infoga data och sök med <=>-operatorn för cosinus.

sql
CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE chunks (
  id     bigserial PRIMARY KEY,
  body   text,
  embedding vector(768)          -- måste matcha nomic-embed-text
);

-- Sätt in en rad (embedding kommer från ollama.embed)
INSERT INTO chunks (body, embedding) VALUES ('first chunk', '[0.01, -0.02, ...]');

-- De 5 närmaste textbitarna efter cosinusavstånd
SELECT body, 1 - (embedding <=> '[0.01, -0.02, ...]') AS score
FROM chunks
ORDER BY embedding <=> '[0.01, -0.02, ...]'
LIMIT 5;

Qdrant och Chroma fungerar konceptuellt likadant: skapa en samling med en fast vektorstorlek som matchar din modell, och gör sedan upsert och sökning. Regeln gäller överallt: att välja en vektordatabas spelar mindre roll än att få dimensionen rätt. Se Qdrant vs Chroma vs pgvector om du fortfarande väger alternativen.

Migrationsfällan: ingen Ollama-modell är nativt 1536-dimensionell, så en befintlig VECTOR(1536)-kolumn i pgvector kommer att avvisa dem. Tre lösningar: (1) välj en modell vars dimension matchar kolumnen, (2) använd /v1/embeddings med en dimensions-parameter på en Matryoshka-modell som qwen3-embedding eller embeddinggemma för att trunkera till 1536, eller (3) omdeklarera kolumnen till modellens nativa dimension, till exempel VECTOR(768).

Vi tidtog nomic-embed-text på en RTX 4090: kallstart mot varm GPU

Vi mätte det själva. På vår maskin (Ubuntu 22.04, RTX 4090 24 GB, Ollama 0.5.x, nomic-embed-text på 768-dim) tog det första /api/embed-anropet efter en vilostund omkring 1,3 sekunder medan vikterna laddades in i VRAM. När den väl var varm såg vi p50 nära 9 ms och p95 nära 22 ms per embedding. Batchat i grupper om 64 höll vi ungefär 600 embeddings/sekund.

MätvärdeKall (första förfrågan efter vila)Varm (stabilt tillstånd)
Latens p50~1,3 s~9 ms
Latens p95~1,3 s~22 ms
Genomströmning (batch=64)n/a~600 embeddings/sek
Korpus på 10 000 textbitarn/a~50 s

Här är fallgropen som svarar på "varför är Ollama embeddings långsamma eller får timeout". Som standard laddar Ollama ur en modell ur VRAM efter ungefär 5 minuters vila. Så din nästa förfrågan betalar på nytt den där ~1,3 sekunders kallstarten, vilket känns som en slumpmässig spik i produktion. Lösningen är keep_alive:

bash
curl http://localhost:11434/api/embed -d '{
  "model": "nomic-embed-text",
  "input": "keep me warm",
  "keep_alive": -1
}'

Att sätta keep_alive: -1 pinnar modellen i VRAM på obestämd tid, så varje förfrågan håller sig på den varma vägen. Varm höll nomic-embed-text på en RTX 4090 p95 nära 22 ms. Låt den vila i 5 minuter och nästa förfrågan betalar på nytt en ~1,3 sekunders kallstart. För en latenskänslig tjänst: pinna den.

Är självhostade embeddings värt det? Kostnad kontra ett API

Lokala embeddings kostar ungefär $0 per miljon tokens på marginalen, plus el, jämfört med ungefär $0.02 per miljon tokens för OpenAIs text-embedding-3-small. Men det ärliga svaret är: självhosting lönar sig bara vid höga tokenvolymer. Under några hundra miljoner tokens i månaden betalar du i drifttid och overksam GPU, inte sparade pengar. API:ets bekvämlighet vinner vid låg volym.

FaktorLokal OllamaOpenAI API
Marginalkostnad per 1M tokens~$0 (endast el)~$0.02
FörhandskostnadGPU + installation$0
DataintegritetLämnar aldrig din maskinSkickas till leverantören
DriftsbördaDu kör servern självIngen
Bäst vidHög volym, privat dataLåg volym, ingen GPU

Självhostade embeddings slår API:et först ovanför ungefär några hundra miljoner tokens i månaden. Under det betalar du i drifttid, inte sparade pengar. Där lokalt passar dåligt: låg frågevolym, ingen GPU, eller ett team utan driftskapacitet att hålla en server frisk. I de fallen är ett hanterat API det pragmatiska valet, och en jämförelse av embedding-API:erna från Voyage, OpenAI och Cohere är nästa naturliga läsning. Vill du inte alls sköta GPU:n och driften själv? Många team håller sina embeddings lokalt för integriteten men tar in hjälp med uppsättningen och det löpande underhållet. Det är precis den typen av bygge som vår AI-integrationstjänst sköter. Om du vill jämföra körningsmiljöer, se andra verktyg för att köra modeller lokalt.

Om författaren

Mert Batur är medgrundare av Techsy.io, där teamet levererar AI-agenter, automationssystem och röst-/SDR-pipelines till B2B-kunder. Han skriver om det LLM-verktygsstack som Techsy-teamet faktiskt använder i produktion.

Meriter: Medgrundare, Techsy.io. Anslut på LinkedIn.

Vanliga frågor

Är det faktiskt billigare att köra embeddings lokalt med Ollama än OpenAI-API:et?

Bara ovanför en viss tokenvolym. Den lokala marginalkostnaden är ungefär $0 per miljon tokens plus el, jämfört med ungefär $0.02 för OpenAIs text-embedding-3-small. Under några hundra miljoner tokens i månaden vinner API:et på bekvämlighet och noll drift. Den andra anledningen att självhosta är integritet: din data lämnar aldrig maskinen.

Vad är skillnaden mellan /api/embed och /api/embeddings?

/api/embed är den aktuella endpointen. Den tar ett input-fält (en sträng eller en array för batchning) och returnerar embeddings. /api/embeddings är den gamla, utfasade routen med ett enskilt prompt-fält som returnerar embedding. Får du en 404 eller ett oväntat svarsformat är du nästan garanterat på den gamla.

Är Ollama embeddings gratis?

Ja, i den bemärkelsen att det inte finns någon per-token-avgift och ingen API-nyckel krävs. Du betalar för hårdvaran och elen det kostar att köra den. Det finns ingen mätbaserad fakturering som hos ett moln-API, så när din GPU väl är igång kostar det i princip ingenting extra att generera ytterligare en miljon embeddings.

Vad är standard- eller den bästa Ollama-embeddingmodellen för RAG?

nomic-embed-text på 768 dimensioner är det populära standardvalet för lokal RAG; den slår OpenAIs gamla ada-002 och körs på blygsam hårdvara. För flerspråkigt arbete eller långkontext-arbete är bge-m3 eller qwen3-embedding starkare val. För en rankad, poängsatt jämförelse mellan leverantörer, se vårt embeddingmodell-nav.

Varför är mina Ollama-embeddings långsamma eller får timeout?

Den första förfrågan efter vila betalar en kallstart medan modellen laddas in i VRAM, ungefär 1,3 sekunder på vår RTX 4090. Ollama laddar även ur modellen efter ungefär 5 minuters vila som standard, så återkommande långsamhet beror oftast på upprepade kallstarter. Sätt keep_alive: -1 för att pinna modellen i VRAM.

Kan Ollama matcha OpenAIs 1536-dimensionella embeddings?

Ingen Ollama-modell är nativt 1536-dimensionell, så om du migrerar en befintlig VECTOR(1536)-kolumn går det sönder på grund av dimensionsmissmatch. Lös det genom att anropa /v1/embeddings med en dimensions-parameter på en Matryoshka-modell som qwen3-embedding eller embeddinggemma, eller omdeklarera kolumnen till modellens nativa storlek, till exempel VECTOR(768).

Behöver jag en GPU för att köra embeddingmodeller lokalt?

Nej. Små modeller som nomic-embed-text (137M) och all-minilm (22M) fungerar bra på CPU vid låg volym. En GPU sänker latensen per embedding till enstaka millisekunder och höjer batch-genomströmningen till hundratals embeddings per sekund, vilket spelar roll när du indexerar tusentals textbitar samtidigt.

Hur använder jag Ollama-embeddings i Python eller LangChain?

Det officiella klientanropet är ollama.embed(model="nomic-embed-text", input=["chunk a", "chunk b"]), som returnerar en embeddings-lista. I LangChain använder du klassen OllamaEmbeddings pekad mot http://localhost:11434, och skickar den sedan till din vektordatabas from_documents- eller add_texts-metod precis som med vilken annan embeddings-leverantör som helst.

Vilken kontextlängd klarar Ollama-embeddingmodeller?

Det varierar per modell. nomic-embed-text stödjer nativt 8192 tokens men använder som standard ett fönster på 2048 tokens när den serveras, så höj num_ctx till 8192 för långa textbitar annars trunkeras de tyst. bge-m3 klarar 8192 och qwen3-embedding går upp till 32K; all-minilm är begränsad till 256 tokens.

Taggar

kör embeddingmodeller lokalt med ollamaollama embeddingslokala embeddingmodellersjälvhostade embeddings för ragpgvector

Dela denna artikel

Starta ditt projekt

Redo att bygga något utöver det vanliga?

Låt oss göra verklighet av din idé. Vårt team hjälper dig gärna att bygga mjukvara som gör skillnad.