# One vector blurs a document about many topics

One vector for a document about many topics matches each topic weakly. Several vectors win most of it back. Most of the gain comes from having more pieces, not smarter pieces.

Author: Murali Sid (https://linkedin.com/in/muralisid)
Source: https://www.agenticarchitectureskills.com/patterns/aspect-dilution
Published: 2026-08-23
Updated: 2026-10-15
Licence: CC BY-SA 4.0, https://creativecommons.org/licenses/by-sa/4.0/
Cite as: Murali Sid. One vector blurs a document about many topics. Agentic Architecture Skills. https://www.agenticarchitectureskills.com/patterns/aspect-dilution

---


Search for agents usually turns each document into one vector, a list of numbers that stands for its meaning. Think of a library that gives every book one index card. If a book covers ten topics, its card mixes all ten. A question about one chapter then only half matches. We asked how much is lost, and whether several cards per document win it back. They do. Most of the gain comes from simply having more pieces to search. Pieces shaped around one topic add a smaller extra, and only when questions target one topic.

This is the evidence for the first of the [context patterns](/patterns). It shapes how agents find what they know, the subject of [knowledge and memory](/memory). The work belongs to the [agent data engineering layer (R14)](/layers/r14-agent-data-engineering). It sits at the chunk and embed stages of the [data-to-memory pipeline](/architecture/data-to-memory). The research name for this loss is aspect dilution. An <Term k="aspect">aspect</Term> is one topic a document covers.

## The test: three setups with one encoder [#the-test-three-setups-with-one-encoder]

A purpose card is one searchable piece per topic in a document, with its own vector. Giving a document several cards means giving it several vectors. Cutting the same document into fixed windows also gives several vectors. So if cards beat one <Term k="pooled embedding">pooled vector</Term>, that proves nothing about topics. Plain chunks might beat it too. Every test therefore compares three setups.

| Setup          | What it is                                                                                                               | What it shows                                                 |
| -------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------- |
| Pooled         | One vector for the whole document.                                                                                       | The usual baseline.                                           |
| Matched chunks | The same text cut into fixed word windows. The window size is set so each document gets as many chunks as it gets cards. | What more pieces buy on their own, with no regard to meaning. |
| Purpose cards  | The same text split by topic. Each card gets its own vector. A document scores by its best card.                         | More pieces, plus pieces shaped around one topic.             |

Every setup uses the same encoder, all-MiniLM-L6-v2. An encoder is the model that turns text into vectors. This one is small and general-purpose. Everything is scored per document. The <Term k="matched control">control is matched</Term>: it gets the same number of pieces per document as the cards.

## Step 1: the loss grows with every topic [#step-1-the-loss-grows-with-every-topic]

We built a synthetic collection where we control the number of topics per document. Each document joins k passages from k of ten unrelated topic pools. The pools are legal, logistics, finance, engineering, personnel, marketing, facilities, research, security and procurement. Each passage states one fact. Each query asks about one fact, in wording that shares no template with the passages. Every document holding that fact counts as relevant. So relevance comes from how the data was built, not from a guess. Relevant documents per query grow from 3.7 at k=1 to 33 at k=10. Each setting has five hundred documents and two hundred queries.

Cards are built around anchors. An anchor is a short description of a topic. The card builder uses it to decide which passages go on which card. We tried two kinds. Template anchors are taken from the generator's own sentence templates. Hand-written anchors are short topic descriptions a person wrote, with none of the generator's wording.

The score is <Term k="ndcg">nDCG\@10</Term>, a 0 to 1 measure of how good the top ten results are.

<ResultChart
  kind="lines"
  title="Retrieval as the number of topics per document grows"
  subtitle="nDCG@10 on the synthetic collection. 200 queries per setting, seed 13. At k=1 every setup holds the same document, and the scores confirm it."
  categories="['1', '2', '3', '4', '5', '7', '10']"
  xValues="[1, 2, 3, 4, 5, 7, 10]"
  xLabel="Topics per document (k)"
  yLabel="nDCG@10"
  min="0.2"
  max="0.9"
  series="[
  { name: 'Pooled, one vector', color: 'slate', values: [0.815, 0.485, 0.394, 0.355, 0.377, 0.356, 0.294] },
  { name: 'Matched blind chunks', color: 'gray', values: [0.832, 0.738, 0.677, 0.657, 0.638, 0.676, 0.633] },
  { name: 'Purpose cards, template anchors', color: 'aqua', values: [0.799, 0.734, 0.684, 0.678, 0.702, 0.731, 0.742] },
  { name: 'Purpose cards, hand-written anchors', color: 'ember', values: [null, null, 0.694, null, 0.742, 0.774, 0.803] },
]"
  caption="The one-vector index collapses and does not recover. Splitting the document, by any method, holds retrieval up. Purpose cards pull away from matched chunks from k=5 onward. Hand-written anchors do better than anchors taken from the generator's own templates."
  source="Author-reported experiment, August 2026. The comparison and limitations are described on this page."
/>

The pooled index falls from 0.815 at one topic to 0.294 at ten. Every split setup stays above 0.63.

Against matched chunks, cards built from hand-written anchors gain more as topics grow.

| Topics per document (k) | Cards minus matched chunks | Detail                                                                 |
| ----------------------- | -------------------------- | ---------------------------------------------------------------------- |
| 3                       | +0.023                     | p=0.12. Not significant.                                               |
| 5                       | +0.099                     |                                                                        |
| 7                       | +0.098                     |                                                                        |
| 10                      | +0.188                     | 95 percent interval +0.152 to +0.225. p=0.0001. 135 wins to 34 losses. |

At k=10 the cards use 9.8 pieces per document. The control uses 13.0. That is 25 percent fewer vectors. An earlier version of the same test used template anchors. It gave +0.109 at k=10. The cruder hand-written anchors do better for a simple reason. A topic description is a better stand-in for a topic than one sentence carrying one fact.

## Step 2: what the theory predicts [#step-2-what-the-theory-predicts]

The cause behaves roughly as theory says. We measured how close each query sits to its target document. Closeness here is cosine similarity, a measure of how alike two vectors are. Against the best card, it stays flat as topics grow: 0.476 at k=1 and 0.466 at k=10. Against the pooled vector, it falls steadily from 0.476 to 0.225.

Simple theory treats the pooled vector as the average of k unrelated topic vectors. That predicts closeness falls with one over the square root of k. The measured fall follows k to the power -0.32. It stays above the prediction at every k. Real topics are not fully unrelated. The passages share style and grammar, and encoders squeeze differences together. So the theory gives the worst case for dilution. It is not a forecast the data confirm.

| k  | Pooled similarity | Best-card similarity | Measured ratio | Predicted ratio |
| -- | ----------------- | -------------------- | -------------- | --------------- |
| 1  | 0.476             | 0.476                | 1.00           | 1.00            |
| 2  | 0.368             | 0.475                | 0.77           | 0.71            |
| 5  | 0.292             | 0.482                | 0.61           | 0.45            |
| 10 | 0.225             | 0.466                | 0.48           | 0.32            |

## Step 3: more pieces, or better pieces? The LIMIT test [#step-3-more-pieces-or-better-pieces-the-limit-test]

LIMIT is a public test set built to break one-vector search (Weller, Boratko, Naim, Lee, arXiv:2508.21038, Aug 2025). Its authors prove a limit. For a vector of fixed size, some groups of documents can never come back together in the top results. Leading embedding models hit that limit in practice. Each LIMIT document names a person and lists things they like. Each query asks who likes one specific thing. The small version has 46 documents, 44 attributes each, and 1,000 queries. The task looks trivial, yet it defeats meaning-based search. It also gives a perfect split for free: one card per attribute.

<ResultChart kind="bars" title="LIMIT-small: five systems, one encoder" subtitle="nDCG@10 over 1,000 queries. Every gap against the pooled vector is significant at p=0.0001, after Holm correction for many comparisons." categories="['BM25 keyword search', 'Meaning-based, pooled', 'Meaning-based, 30-word chunks (4 per document)', 'Meaning-based, per-attribute cards (44 per document)', 'Cards fused with BM25']" series="[{ name: 'nDCG@10', values: [0.997, 0.314, 0.390, 0.988, 0.997] }]" emphasis="['Meaning-based, per-attribute cards (44 per document)']" min="0" max="1" ticks="[0, 0.25, 0.5, 0.75, 1]" caption="Keyword search wins outright, because LIMIT queries name an exact attribute. The pooled vector fails. Per-attribute cards recover it. The hybrid matches BM25. The 30-word chunk setup is not a matched control here. It has 4 pieces per document against the cards' 44." source="Author-reported experiment, August 2026. The comparison and limitations are described on this page." />

We first credited the cards' 0.674 gain to their topic shape, because 30-word chunks gained only 0.076. That was wrong. A reviewer whose job was to break the result reran the test. It changed only the chunk size, as described in [how to test a context design](/patterns/how-to-test-a-context-design). The score rose smoothly with the number of pieces per document.

<ResultChart
  kind="lines"
  title="Blind windows against pieces per document"
  subtitle="The same text and encoder. Only the window width changes. Cards sit at 44 pieces per document."
  categories="['4.0', '10.8', '24.7', '36.8', '44']"
  xValues="[4, 10.8, 24.7, 36.8, 44]"
  xLabel="Pieces per document"
  yLabel="nDCG@10"
  min="0.3"
  max="1"
  series="[
  { name: 'Blind sliding windows', color: 'slate', values: [0.390, 0.611, 0.892, 0.924, null] },
  { name: 'Per-attribute cards', color: 'ember', values: [null, null, null, null, 0.988] },
]"
  caption="A three-word sliding window that ignores meaning recovers 0.610 of the 0.674 that cards gain. It uses no topics and no anchors. The cards' edge at the same number of pieces is +0.064. Using the bare attribute string instead of the card template adds a further +0.010 (p=0.0001)."
  source="Author-reported experiment, August 2026. The comparison and limitations are described on this page."
/>

Two things follow. First, more pieces are needed, and they explain most of the LIMIT result. The topic split must match the questions for the rest of the gain to appear. Second, LIMIT is a best case for cards. It hands over a perfect split, and its queries are exact-attribute lookups. That is why <Term k="bm25">BM25</Term> keyword search wins outright and the <Term k="hybrid retrieval">hybrid</Term> only matches it. Real documents arrive unsplit. Someone has to design the card types, and they may be wrong. So read the table as the most that topic-shaped cards can buy. Storage cost depends on the documents too. LIMIT needed 44 cards per document, far more than the small number the pattern assumes elsewhere.

## A worked example [#a-worked-example]

A utility's field work order often records a fault, the parts used and a safety note. One vector for the whole order blurs all three. A question about one safety issue then matches the order weakly. Plain chunks are the first fix. Topic cards are worth adding only if they beat those chunks on the questions engineers really ask. This example shows the shape of the problem. We did not test work orders.

## What we conclude [#what-we-conclude]

<PrincipleCard eyebrow="Verdict" title="Several vectors, yes. Topic-shaped cards, only sometimes." kind="evidence">
  Several vectors per document beat one on documents about many topics. Any way of splitting works. Topic-shaped cards add a measurable extra when questions target one topic and the anchors describe topics well. At ten topics the extra was +0.188, with fewer vectors. When those conditions fail, cards add nothing and can lose. That is the finding on [real prose](/patterns/real-prose). We withdraw the claim that topic shape, rather than the number of pieces, explains the gain.
</PrincipleCard>

## Evidence and limits [#evidence-and-limits]

<EvidenceBadge status="author-measured" /> The synthetic and LIMIT results reproduced exactly, or to floating-point precision, on two machines with two processor types. We ran both machines ourselves. Nobody else has repeated the tests yet.

The synthetic collection is built, not found. The one positive result for topic cards, +0.188, rests on it. The next test that matters is a real collection with single-topic questions judged by people.

## Next step [#next-step]

See where topic cards lose, on [real scientific text](/patterns/real-prose). Or go back to the [nine context patterns](/patterns).

<details>
  <summary>
    Explore this topic
  </summary>

  * Weller, Boratko, Naim, Lee, On the Theoretical Limitations of Embedding-Based Retrieval, arXiv:2508.21038, Aug 2025. [https://arxiv.org/abs/2508.21038](https://arxiv.org/abs/2508.21038)
  * [The papers behind the patterns](/patterns/reading-list), for the multi-vector work this sits in.
  * The experiments ran in August 2026, on public data and a synthetic collection.
</details>
