Skip to content

Semantic index cold builds are serial and lossy: no concurrent embedding, no mid-build persistence #280

Description

@trim21

Problem

Cold semantic index builds for remote embedding backends are far too slow for medium/large repos, and an interrupted build loses all progress.

1. Embedding batches are strictly serial

build_from_chunks (crates/aft/src/semantic_index.rs:2555-2572) calls the sync embed_fn(batch_texts) one batch at a time — no in-flight concurrency, and the FnMut signature rules out pipelining without a change.

Measured in the wild (OpenRouter, qwen/qwen3-embedding-8b, batch=64): ~5 chunks/s over a 34,736-chunk repo (543 batches), i.e. a ~2 hour cold build. At this batch size the bottleneck is per-request RTT, not server compute — exactly what concurrency would absorb.

There is also no config knob: the semantic config surface is only backend / model / base_url / timeout_ms / query_timeout_ms / max_batch_size / max_files (crates/aft/src/config.rs:134-158). When the upstream provider caps batch size (e.g. DashScope-backed routes reject input arrays > 20), max_batch_size: 20 multiplies the request count ~3x and makes the serial latency problem worse.

2. No mid-build persistence

semantic.bin is written only when the build completes. A cold build killed halfway (user closes the harness, machine restarts) restarts from zero — the 2-hour build has no checkpoint.

Proposal

  1. Add semantic.max_concurrent_requests (default 1 = current behavior) and pipeline N batches in flight through the embed engine.
  2. Periodically persist partial build progress (per-batch checkpoint keyed by the existing fingerprint), so an interrupted cold build resumes from the last flush instead of restarting.
  3. Optionally: a small request coalescer/buffer so a batch-size clamp from provider errors doesn't inflate request count.

Happy to take a stab at a PR if the overall approach sounds right.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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