DS DevShelfHub Projects · AI tools
Tutorials / LangChain / Embedding Models
LangChain Intermediate · 9 min read Page 9 of 20

Embeddings in LangChain: How Vector Search Powers RAG

By DevShelfHub

Convert text into dense float vectors. Understand the 20+ embedding providers, core methods, caching strategies, and how to pick the right model for your RAG pipeline.

Series progress9 / 20
Embeddings in LangChain — text embedded into dense vectors and matched by vector search to power RAG retrieval

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
OpenAIEmbeddingslangchain-openaiAPI
AzureOpenAIEmbeddingslangchain-openaiAPI
BedrockEmbeddingslangchain-awsAPI
CohereEmbeddingslangchain-cohereAPI
GoogleGenerativeAIEmbeddingslangchain-google-genaiAPI
OllamaEmbeddingslangchain-ollamaLocal
HuggingFaceEmbeddingslangchain-huggingfaceLocal
NomicEmbeddingslangchain-nomicAPI / Local
MistralAIEmbeddingslangchain-mistralaiAPI
VoyageAIEmbeddingslangchain-voyageaiAPI
FakeEmbeddingslangchain-coreIn-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.

python
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")
python
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.

python
# 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.

python
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.

python
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-smallFast$$ (cheapest)GoodDevelopment, prototyping
text-embedding-3-largeMedium$$$BestProduction RAG, high accuracy needed
nomic-embed-text (Ollama)SlowFreeGoodPrivate data, offline, local dev
CohereEmbeddingsMedium$$Very GoodMultilingual, 100+ languages
MistralAIEmbeddingsFast$GoodCost-effective production
FakeEmbeddingsInstantFreeN/AUnit tests, debugging (not production)

Cost & Performance Reference

OpenAI Pricing (per 1M tokens)

text-embedding-3-small: $0.02
text-embedding-3-large: $0.13

Dimension reduction (e.g., 1536→512) saves ~25% cost with minimal accuracy loss.

Performance Estimates

text-embedding-3-small: ~50ms per query
text-embedding-3-large: ~100ms per query
OllamaEmbeddings (local): ~500ms per query

Choosing the Right Model - Decision Tree

Use this decision tree to pick the right embedding model:

Do you need to keep data private/offline?
├─ Yes → Use OllamaEmbeddings (local, free, private)
└─ No: Do you need production accuracy?
├─ Yes → Use text-embedding-3-large (best, but $$)
└─ No: Are you developing/prototyping?
├─ Yes → Use text-embedding-3-small (fast, cheap, good)
└─ No: Do you need multilingual support?
└─ Yes → Use CohereEmbeddings (100+ languages)
For unit tests only: Use FakeEmbeddings (no API calls)
Scenario Recommended Reason
Prototyping / devtext-embedding-3-smallFast, cheap, good enough
Production accuracytext-embedding-3-largeBest retrieval accuracy
Privacy / offlinenomic-embed-text (Ollama)No data leaves your machine
Multilingual docsCohereEmbeddings100+ language support
Unit testsFakeEmbeddingsNo 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.

Quick jump: API Reference