TL;DR: For image caption search over a changing folder of e-commerce PDFs, index one image-centered record per figure, keep nearby product text as bounded context, and treat the PDF version as part of the record identity. Use text embeddings to retrieve captions, but evaluate exact product, attribute, and revision matches before choosing an embedding model or API. Caption quality, chunk boundaries, and stale records usually deserve attention before model selection.

This is a retrieval problem first. The original RAG formulation combines a model's parametric memory with retrieved non-parametric memory, but the useful unit here is not an arbitrary page slice. It is the relationship among an image, its caption, the product identifiers around it, and the document revision that made it current. A gorgeous nearest-neighbor result from last quarter's catalog is still wrong.

The tempting first pass is simple: extract all text from every PDF, split it every fixed number of characters, embed those chunks, and search them with a caption-like query. It is also easy to evaluate badly. Page text extraction can separate a figure from its caption, repeated headers can dominate a short chunk, and a revised PDF can leave an older vector searchable unless ingestion has an explicit replacement rule.

How should text embeddings power retrieval for image caption search?

Use the image as the retrieval boundary and attach only evidence that helps identify it. A practical record has a stable document key, a document revision, a page number, an image key, the extracted caption, nearby text, and filterable commerce fields such as SKU or locale when those fields are actually present in the source. Keep the raw PDF location as provenance, not as prose fed blindly into the embedding.

The caption should lead the embedded text because the user is searching for an image description. Nearby text can disambiguate captions such as "rear view" or "available colors," but unbounded page text dilutes that signal. Tables, legal footers, navigation labels, and repeating catalog headers belong in separate structural handling. The chunk is small by design.

Start there.

Here is a focused Python representation. The values are illustrative schema data, not a claim about any embedding service:

from dataclasses import dataclass @dataclass(frozen=True) class ImageChunk: document_id: str revision: str page: int image_id: str caption: str nearby_text: str sku: str | None = None locale: str | None = None @property def record_id(self) -> str: return f"{self.document_id}:{self.revision}:{self.image_id}" def embedding_text(self) -> str: fields = [self.caption.strip(), self.nearby_text.strip()] return "\n".join(field for field in fields if field) 

That record_id makes the revision visible, but it is not the whole freshness strategy. The active index also needs a document-level pointer to the current revision, or an equivalent metadata filter, so an old revision cannot compete with a new one. Retaining historical records for audit is reasonable; returning them in normal search is not.

Chunking is a retrieval hypothesis

There is no universally correct caption chunk size. The correct boundary depends on what shoppers ask and how the PDFs encode product relationships. A furniture catalog may place one hero image beside a concise caption and a dense specification table. A parts catalog may label a diagram with callouts whose meanings live in a legend elsewhere on the page. Those cases should not share a chunking rule merely because both arrived as PDFs.

I would test at least three policies in the evaluation harness: caption only; caption plus the nearest bounded text region; and caption plus explicitly linked structures such as a figure legend or SKU row. The comparison should hold the query set, embedding method, filters, and ranking depth constant. Otherwise a chunking experiment quietly turns into several experiments at once.

One trap is allowing the extraction library's output order to define semantic proximity. PDF is a presentation format, and logical reading order may need to be inferred from structure and geometry. The PDF specification describes page contents and logical structure, while PDF/UA focuses on accessible, semantically meaningful PDF content. When tags are present, use them as evidence. When they are absent, record the geometric rule used to associate text with an image and put ambiguous pages into a review set.

This matters for captions generated from the images too. Generated captions should be marked with their generator version and kept distinct from source-authored captions. If a source caption says "Model A17 in graphite" while a generated caption says "dark office chair," the former carries catalog identity and the latter may improve visual recall. Concatenating them without labels hides which signal produced the match and makes regressions harder to diagnose.

Short chunks are not automatically cheap, either. More chunks mean more records to embed, store, refresh, and score. Longer chunks reduce record count but may spend the embedding input on irrelevant text. Choose the boundary with retrieval measurements, then inspect its indexing and query cost. Cost follows the design; it should not select the design by itself.

This approach has real limitations. Text embeddings over captions are a poor fit when the decisive evidence never appears in language: an unlabeled texture, a tiny connector shape, or a visual defect may require image embeddings or a combined text-and-image retrieval path. Caption-only records also lose relationships that span several figures or pages, while larger context windows recover some relationships at the cost of noisier matches and more embedded input. The trade-off is explicit: use image-centered text records for explainable catalog language and identifiers, then test a multimodal path when visual-only queries form a meaningful slice of the evaluation set. Do not add it on architectural instinct.

Measure the miss first.

Freshness needs an explicit state transition

A file watcher is a trigger, not a freshness guarantee. A safe ingestion path computes a content digest, extracts image records into a staged revision, validates the staged set, activates that revision atomically at the document level, and only then retires the previous revision from normal retrieval. If extraction fails halfway through, the prior complete revision remains active.

The state transition can stay generic:

from collections.abc import Iterable from dataclasses import dataclass @dataclass(frozen=True) class IndexedRecord: record_id: str document_id: str revision: str vector: list[float] metadata: dict[str, str | int] def publish_revision(store, records: Iterable[IndexedRecord], document_id: str, revision: str) -> None: staged = list(records) if not staged: raise ValueError("A revision must contain at least one image record") store.stage(staged) store.activate(document_id=document_id, revision=revision) store.deactivate_other_revisions(document_id=document_id, keep_revision=revision) 

The store interface intentionally leaves transactions and index mechanics unspecified. Whatever implementation sits behind it must define what happens when activation succeeds but cleanup is delayed. Query-time filtering on the active revision prevents that delay from becoming stale search output. Idempotency matters as well: processing the same digest twice should not create a second logical revision.

Freshness is observable. Track the time from a source change to active indexing, the count of active revisions per document, extraction failures, records produced per page, and queries that return a non-current revision. The last metric should be zero under the normal search policy. Also log the retrieved record IDs and revision metadata with evaluation runs; otherwise a ranking change can be confused with a corpus change.

Version it.

Evaluate the failure you cannot accept

Start with queries derived from real catalog tasks, with sensitive or proprietary content removed as needed. Each query needs acceptable image IDs and the document revision against which it was judged. Include terse identifiers, descriptive requests, attribute combinations, and deliberately ambiguous phrases. For example, "A17 graphite rear view" tests identity and viewpoint; "chair with cable opening" tests descriptive recall; "current red packaging" tests a visual attribute and freshness together.

A compact scorecard separates retrieval quality from operations:

Measure What it catches Useful slice
Recall at k A relevant image never reaches the candidate set Query type, locale, caption source
Mean reciprocal rank The first acceptable image appears too low Exact identifier versus descriptive query
Stale-result rate A retired revision remains searchable Document and ingestion run
Caption coverage Images enter the index without useful text PDF template and extraction rule
Indexing lag Changed source content is not active yet File size and extraction stage
Embedded characters Chunking expands or contracts workload Chunk policy and caption source

Pick k from the consuming interface and evaluation goal, not from convention. If the UI displays 12 candidates, recall at 12 has direct product meaning; a reranker that only receives 20 candidates also gives recall at 20 a specific systems meaning. These are configuration examples, not universal thresholds.

The harness should pin the corpus revision and cache the query set. Run one controlled change at a time: chunk policy, caption composition, embedding method, or optional reranking. Report confidence intervals or the raw query-level differences when the set is small, because one average can hide a disastrous regression on exact SKU searches. Then inspect misses. Numbers point to the drawer; error analysis opens it.

A caption API belongs behind a narrow interface that accepts text and returns vectors plus model metadata. Batch requests where the selected service permits it, apply bounded retries only to retryable failures, and preserve an input hash so results can be reused safely. Do not silently mix vector spaces from different embedding model versions in one similarity index. A model migration is a versioned re-indexing event, followed by the same evaluation suite.

The decision rule before production

Choose a text-embedding approach only after it clears four gates: it retrieves the correct image-centered records on the frozen evaluation set; the chunk policy preserves identifiers and visual language; revision filtering prevents stale results; and indexing plus query telemetry fit the operating envelope. Latency and spend matter here, but compare them at the quality level the application requires. A faster or smaller index that misses current products is not equivalent.

Keep the first deployment legible. One caption record shape, one active-revision rule, one embedding version per index, and a small set of metrics make notebook results reproducible in production. Add hybrid lexical retrieval when exact tokens such as SKUs are underperforming, and add reranking only when candidate recall is healthy but ordering is weak. Each addition needs a measured failure to answer.

Before copying this design, measure caption coverage, retrieval quality by query class, stale-result rate, indexing lag, and embedded input volume on your own PDFs. The winning architecture is the smallest one that passes those checks on current catalog content.

Further reading