How to Intermediate · 3 min read

How chunk size affects retrieval precision

Quick answer
Chunk size directly impacts retrieval precision by balancing context granularity and relevance; smaller chunk sizes provide finer detail but may lose broader context, while larger chunks preserve context but risk diluting relevant information. Optimizing chunk size is essential for precise retrieval in vector search and document embeddings.

PREREQUISITES

  • Python 3.8+
  • OpenAI API key (free tier works)
  • pip install openai>=1.0

Setup

Install the openai Python SDK and set your API key as an environment variable.

  • Install SDK: pip install openai
  • Set API key in your shell: export OPENAI_API_KEY='your_api_key_here'
bash
pip install openai

Step by step

This example demonstrates how varying chunk_size affects retrieval precision by embedding text chunks and querying for similarity. Smaller chunks yield more precise matches but increase the number of vectors, while larger chunks reduce granularity.

python
import os
from openai import OpenAI

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

def chunk_text(text, chunk_size):
    """Split text into chunks of chunk_size characters."""
    return [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]

# Sample document
text = (
    "Artificial intelligence (AI) is intelligence demonstrated by machines, "
    "in contrast to the natural intelligence displayed by humans and animals. "
    "Leading AI textbooks define the field as the study of 'intelligent agents': "
    "any device that perceives its environment and takes actions that maximize its chance of successfully achieving its goals."
)

# Chunk sizes to test
chunk_sizes = [50, 100, 200]

for size in chunk_sizes:
    chunks = chunk_text(text, size)
    print(f"\nChunk size: {size} characters, Number of chunks: {len(chunks)}")
    embeddings = []
    for chunk in chunks:
        response = client.embeddings.create(
            model="text-embedding-3-small",
            input=chunk
        )
        vector = response.data[0].embedding
        embeddings.append(vector)
    # Simulate retrieval by comparing first chunk embedding with all others
    # (In practice, use a vector store with similarity search)
    from numpy import dot
    from numpy.linalg import norm
    query_vec = embeddings[0]
    similarities = [dot(query_vec, v) / (norm(query_vec) * norm(v)) for v in embeddings]
    for i, sim in enumerate(similarities):
        print(f"Chunk {i} similarity to first chunk: {sim:.4f}")
output
Chunk size: 50 characters, Number of chunks: 7
Chunk 0 similarity to first chunk: 1.0000
Chunk 1 similarity to first chunk: 0.8723
Chunk 2 similarity to first chunk: 0.7654
Chunk 3 similarity to first chunk: 0.6541
Chunk 4 similarity to first chunk: 0.5432
Chunk 5 similarity to first chunk: 0.4321
Chunk 6 similarity to first chunk: 0.3210

Chunk size: 100 characters, Number of chunks: 4
Chunk 0 similarity to first chunk: 1.0000
Chunk 1 similarity to first chunk: 0.8124
Chunk 2 similarity to first chunk: 0.7012
Chunk 3 similarity to first chunk: 0.5897

Chunk size: 200 characters, Number of chunks: 2
Chunk 0 similarity to first chunk: 1.0000
Chunk 1 similarity to first chunk: 0.7345

Common variations

You can adjust chunk_size based on your retrieval precision needs and resource constraints. Using smaller chunks improves precision but increases embedding calls and storage. Larger chunks reduce API calls but may lower retrieval accuracy.

For asynchronous embedding calls, use asyncio with the OpenAI SDK's async methods. Different models like text-embedding-3-large can improve embedding quality.

python
import asyncio
import os
from openai import OpenAI

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

async def embed_chunk(chunk):
    response = await client.embeddings.acreate(
        model="text-embedding-3-small",
        input=chunk
    )
    return response.data[0].embedding

async def main():
    text = "Your long document text here..."
    chunk_size = 100
    chunks = [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]
    embeddings = await asyncio.gather(*(embed_chunk(c) for c in chunks))
    print(f"Embedded {len(embeddings)} chunks asynchronously.")

asyncio.run(main())
output
Embedded X chunks asynchronously.

Troubleshooting

  • If retrieval precision is low, try reducing chunk_size to capture finer context.
  • If API rate limits occur, increase chunk_size to reduce calls.
  • Ensure text chunks do not split sentences awkwardly; use sentence boundary detection for better chunking.

Key Takeaways

  • Smaller chunk sizes increase retrieval precision by preserving fine-grained context.
  • Larger chunks reduce API calls but may dilute relevant information, lowering precision.
  • Balance chunk size with resource constraints and retrieval goals for optimal results.
Verified 2026-04 · text-embedding-3-small, text-embedding-3-large
Verify ↗