Skip to content

Embeddings are truncated at 512 tokens while chunks are allowed to be ~6-7K tokens and the model supports 8192 #67

Description

@citron07r

Three numbers in the local embedding path disagree with each other:

setting value source
max_chunk_bytes 24576 config.rs, commented "~6K-7K tokens, safe for any embedding model"
EMBEDDING_MAX_LENGTH 512 local_models/mod.rs
model max sequence length 8192 jina-embeddings-v5-text-nano-retrieval model card

load_tokenizer applies the middle one as a hard truncation:

tokenizer.with_truncation(Some(tokenizers::TruncationParams {
    max_length,                       // 512
    strategy: tokenizers::TruncationStrategy::LongestFirst,
    ..Default::default()
}))

So the chunker is allowed to emit chunks of ~6-7K tokens, the model can encode 8192, and everything
past token 512 is discarded before embedding. The comment on max_chunk_bytes says the size is
chosen to be safe for the embedding model, but the embedding model never sees most of it.

Measured impact

Indexed two repositories from the eval corpus at their pinned commits and measured chunk sizes
against a ~2KB proxy for 512 tokens (code runs roughly 3-4 characters per token):

repo chunks over ~512 tokens largest chunk content past the window
ripgrep 5495 505 (9.2%) 24558 B 1.5 MB
fastify 8986 185 (2.1%) 24554 B 529 KB

A minority of chunks by count, but they are the largest ones — whole functions and tier-0 line
chunks — and 1.5 MB of ripgrep's indexed content contributes nothing to its own embedding. The
tail of a long function is unreachable by vector search, though BM25 still matches it, which is
probably why this has not been obvious.

Notes

  • The 2KB proxy is rough. The precise figure needs tokenizing the corpus, but the direction does
    not depend on the constant: the largest chunk is 12x the window whatever the exact ratio.
  • Raising EMBEDDING_MAX_LENGTH is not free. Attention cost grows with sequence length and the
    local backend is already the slow path, so the sensible fix might instead be lowering
    max_chunk_bytes to match the window, or splitting large chunks for embedding and keeping them
    whole for display.
  • Whichever way it goes, the two constants should be derived from one another rather than set
    independently, so they cannot drift apart again.

Raising this as an issue rather than a PR because the resolution is a quality-versus-latency call
that wants benchmark evidence, and this touches the indexing path for every local-backend user.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions