What are Embeddings?
An embedding model converts text into a dense float vector — a list of numbers that captures the semantic meaning of the text. Similar text produces similar vectors, so you can measure meaning by computing vector distance.
Input
"What is LangChain?"
Embedding Model
1536 dimensions
Output
[0.021, -0.134, 0.872, ...]
In a RAG pipeline, you embed every document chunk when indexing, and embed the user's query at search time. The vector store then returns the closest matching chunks.
Two roles: .embed_query() for a single query string, and .embed_documents() for a batch of documents. Most providers use different encoding modes internally for each.
Provider Overview
LangChain has 20+ embedding integrations. Install the provider package, set your API key, and you are ready.
| Class | Package | Hosted |
|---|---|---|
| OpenAIEmbeddings | langchain-openai | API |
| AzureOpenAIEmbeddings | langchain-openai | API |
| BedrockEmbeddings | langchain-aws | API |
| CohereEmbeddings | langchain-cohere | API |
| GoogleGenerativeAIEmbeddings | langchain-google-genai | API |
| OllamaEmbeddings | langchain-ollama | Local |
| HuggingFaceEmbeddings | langchain-huggingface | Local |
| NomicEmbeddings | langchain-nomic | API / Local |
| MistralAIEmbeddings | langchain-mistralai | API |
| VoyageAIEmbeddings | langchain-voyageai | API |
| FakeEmbeddings | langchain-core | In-process (test) |
Core Methods
All embedding classes expose the same four methods regardless of provider — swap providers without changing any other code.
.embed_query(text: str) → list[float]
Embed a single query string. Use this at search time.
.embed_documents(texts: list[str]) → list[list[float]]
Embed a batch of documents. More efficient than looping.
await .aembed_query(text) → list[float]
Async version of embed_query. Use in async applications.
await .aembed_documents(texts) → list[list[float]]
Async batch embedding. Use in async web servers.
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# Single query
vector = embeddings.embed_query("What is LangChain?")
print(len(vector)) # 1536
# Batch documents
vectors = embeddings.embed_documents(["LangChain is a framework.", "LangGraph is for agents."])
print(len(vectors)) # 2
print(len(vectors[0])) # 1536
# Async
import asyncio
vector = asyncio.run(embeddings.aembed_query("async query"))
OpenAI Embeddings
The most widely used embedding provider. Two models with different dimension counts and cost profiles.
text-embedding-3-small
1536 dimensions · Cheapest · Best for most use cases
OpenAIEmbeddings(model="text-embedding-3-small")
text-embedding-3-large
3072 dimensions · Higher accuracy · Use for production RAG
OpenAIEmbeddings(model="text-embedding-3-large")
import os
from langchain_openai import OpenAIEmbeddings
os.environ["OPENAI_API_KEY"] = "sk-..."
embeddings = OpenAIEmbeddings(
model="text-embedding-3-small",
# Optional: reduce dimensions for storage savings
dimensions=512,
)
vector = embeddings.embed_query("LangChain tutorial")
Local Embeddings with Ollama
Run embedding models locally — no API key needed, fully private, works offline. Ideal for sensitive data.
# 1. Pull the embedding model
# ollama pull nomic-embed-text
from langchain_ollama import OllamaEmbeddings
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vector = embeddings.embed_query("private document content")
print(len(vector)) # 768 dimensions
Popular local embedding models: nomic-embed-text, mxbai-embed-large, all-minilm.
CacheBackedEmbeddings
Avoid re-embedding identical text on every run. Wrap any embedding model with CacheBackedEmbeddings to store results on disk.
from langchain.embeddings import CacheBackedEmbeddings
from langchain.storage import LocalFileStore
from langchain_openai import OpenAIEmbeddings
underlying = OpenAIEmbeddings(model="text-embedding-3-small")
store = LocalFileStore(".embedding_cache/")
cached_embeddings = CacheBackedEmbeddings.from_bytes_store(
underlying_embeddings=underlying,
document_embedding_cache=store,
namespace=underlying.model, # prevents cache collisions
)
# First call: hits the API
vectors = cached_embeddings.embed_documents(["Hello world"])
# Second call: reads from disk, no API cost
vectors = cached_embeddings.embed_documents(["Hello world"])
Production tip: Cache is keyed by the text content. Re-indexing the same documents costs nothing after the first run. Always set namespace to the model name so switching models invalidates the cache automatically.
Universal init_embeddings()
LangChain v1 provides init_embeddings() to initialize any embedding model from a single string — useful for configuration-driven code.
from langchain.embeddings import init_embeddings
# OpenAI
e = init_embeddings("openai:text-embedding-3-small")
# Ollama
e = init_embeddings("ollama:nomic-embed-text")
# Cohere
e = init_embeddings("cohere:embed-english-v3.0")
# Now embed — same interface for all
vector = e.embed_query("any text")
Common Mistakes & Solutions
❌ Mistake 1: Changing Models Mid-Project
Switching from OpenAI to Ollama embeddings breaks vector store compatibility — vectors are in different semantic spaces.
Solution: Choose your embedding model upfront. If you must switch, re-embed everything from scratch.
❌ Mistake 2: Forgetting to Set API Key
Using OpenAIEmbeddings without setting OPENAI_API_KEY environment variable causes auth errors.
AttributeError: OPENAI_API_KEY not found
Solution: Always set environment variable before creating embeddings: export OPENAI_API_KEY="sk-..."
❌ Mistake 3: Not Caching Embeddings
Re-indexing the same documents repeatedly wastes money (API calls) and time (computation).
Solution: Use CacheBackedEmbeddings to avoid duplicate API calls on identical text.
❌ Mistake 4: Choosing Wrong Model for Use Case
Using expensive large models for development, or cheap small models for production accuracy.
Solution: Use small models (faster, cheaper) for dev. Switch to large models only for production if accuracy is critical.
❌ Mistake 5: Looping Instead of Batch Embedding
Using embed_query() in a loop is slow — embed_documents() is optimized for batches.
for doc in docs: vectors.append(embeddings.embed_query(doc)) # Slow
Solution: Use batch method: vectors = embeddings.embed_documents(docs) # Fast
Embedding Models Comparison Matrix
Detailed comparison to help choose the right embedding model for your use case:
| Model | Speed | Cost | Accuracy | Best For |
|---|---|---|---|---|
| text-embedding-3-small | Fast | $$ (cheapest) | Good | Development, prototyping |
| text-embedding-3-large | Medium | $$$ | Best | Production RAG, high accuracy needed |
| nomic-embed-text (Ollama) | Slow | Free | Good | Private data, offline, local dev |
| CohereEmbeddings | Medium | $$ | Very Good | Multilingual, 100+ languages |
| MistralAIEmbeddings | Fast | $ | Good | Cost-effective production |
| FakeEmbeddings | Instant | Free | N/A | Unit tests, debugging (not production) |
Cost & Performance Reference
OpenAI Pricing (per 1M tokens)
Dimension reduction (e.g., 1536→512) saves ~25% cost with minimal accuracy loss.
Performance Estimates
Choosing the Right Model - Decision Tree
Use this decision tree to pick the right embedding model:
| Scenario | Recommended | Reason |
|---|---|---|
| Prototyping / dev | text-embedding-3-small | Fast, cheap, good enough |
| Production accuracy | text-embedding-3-large | Best retrieval accuracy |
| Privacy / offline | nomic-embed-text (Ollama) | No data leaves your machine |
| Multilingual docs | CohereEmbeddings | 100+ language support |
| Unit tests | FakeEmbeddings | No API calls needed |
LangChain Embeddings FAQ
What are embeddings in LangChain?
An embedding model converts text into a dense float vector — a list of numbers that captures the semantic meaning of the text. Similar text produces similar vectors, so you can measure meaning by computing the distance between vectors. In LangChain you embed every document chunk when indexing and embed the user query at search time, and the vector store returns the closest matching chunks.
How does vector search power RAG?
In a RAG pipeline you embed each document chunk once and store the vectors in a vector store. At query time you embed the user question with the same model, then run a nearest-neighbour search to find the chunks whose vectors are closest. Those top-k chunks are injected into the prompt, so the LLM answers from your data instead of hallucinating from training data.
Which embedding model should I use in LangChain?
For prototyping use text-embedding-3-small — it is fast, cheap, and good enough. For production accuracy use text-embedding-3-large. For private or offline data use a local model such as nomic-embed-text via Ollama or a HuggingFace model. Pick one model upfront, because switching later means re-embedding everything from scratch.
What is the difference between OpenAI and HuggingFace local embeddings?
OpenAIEmbeddings call a hosted API: no local GPU needed, high quality, but they cost money per token and send your text to OpenAI. HuggingFaceEmbeddings (and Ollama) run a model on your own machine: free per call, fully private and offline, but slower and dependent on your hardware. Use OpenAI for convenience and HuggingFace or Ollama when privacy, cost at scale, or offline use matter.
What are embedding dimensions and do they matter?
The dimension count is the length of each vector — for example 1536 for text-embedding-3-small and 3072 for text-embedding-3-large. More dimensions can capture more nuance but cost more storage and slower search. With OpenAI you can pass a dimensions parameter to shrink vectors (e.g. 1536 to 512) and save about 25 percent storage with minimal accuracy loss. All chunks and queries must use the same model and dimension count.
How do I cache embeddings in LangChain?
Wrap any embedding model with CacheBackedEmbeddings and a store such as LocalFileStore. The cache is keyed by the text content, so re-indexing the same documents costs nothing after the first run. Always set the namespace to the model name so that switching models invalidates the cache automatically and you never mix vectors from different models.