Ingest embeds four batches at a time, and both ingests share the loop - #539
Merged
Merged
Conversation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #513.
What changed
The ingest pipeline embedded one batch of 16 chunks, waited for it, then sent the next. Nothing in the loop depended on the batch before it: vectors are paired by position within a batch and independent across them. The same loop sat verbatim in
memory_ingest. The fix the issue points at was already inontology_index.rs, with the incident that shaped its ceiling written above it.embed_pending, for both call sites. It fetches the chunks still without a vector, batches them, and runs the batches throughbuffer_unordered(EMBED_JOBS). Each batch holds one permit on the shared embedding gate only for its own request and write, as before.EMBED_JOBS = 4, the same as the ontology backfill, and the reasoning is above the constant: the gate (model_concurrency, default 10) is shared by the backfill, type resolution and every question's query embedding. Ingest is foreground and has the better claim, but it is also the caller that can arrive with a thousand chunks; unbounded, it starves everything else, which is the recorded incident. Two callers at 4 sum to 8 and leave 2 for the rest.EMBED_BATCHstays at 16. The ontology side warns that batch size has to be measured on real text; chunk text is much longer than a class label and 16 may well be right for a different reason. Concurrency and batch size are two knobs, and turning both in one change makes the result unreadable.process_documentmarks the documentfailedwith the reason instead of leaving it inembedding. Vectors already written stay; a rerun only embeds what is still missing.Tests
pipeline_tests.rs, database-backed, with wiremock standing in for the embedding endpoint. The fake derives each vector from the text it was given, so pairing is checked by reading the rows back, and it records every request's arrival time and size.every_chunk_gets_the_vector_of_its_own_text: 40 chunks, three batches, four in flight, completing out of order; every stored vector matches its own text. Request sizes are 16, 16 and 8, so the remainder is sent; an empty document makes no request.a_batch_that_answers_with_the_wrong_count_is_abandoned_whole: 15 vectors for 16 texts, nothing written.the_embedding_gate_is_never_held_beyond_its_ceiling: twelve batches with a 150 ms response delay; the peak number of requests in flight, computed from arrival times, never exceedsEMBED_JOBS, batches do overlap, and the whole run takes less than half of serial.a_failed_batch_does_not_strand_the_document: the realprocess_documentpath with a 20-paragraph blob; the second request returns 500; the document lands infailedwith the reason.a_document_is_fully_embedded_before_it_is_ready: the real path succeeds; status isready, chunk count matches, no chunk is left without a vector.a_memory_episode_embeds_by_the_same_path_as_a_document:memory_ingestembeds its chunks with the same pairing.All ran green with
UTOPIA_TEST_REQUIRE_DB=1against a database at dev's migrations. As with the other server-side database tests, CI's backend job has no database and skips them; they run locally.Acceptance
Not done here; it needs a real embedding endpoint and a document of several hundred chunks. Time the
embeddingstage before and after, and run an ontology backfill at the same time to confirm neither starves; that second one is the recorded incident and is the one worth doing carefully.🤖 Generated with Claude Code