Finding duplicates and checking citations need opposite kinds of search
· 4 min read
One night, four claims my agents made citing a source fell apart when the source was opened:
| The citation | What the source said |
|---|---|
| A paper on integral windup, cited for an agent’s control loop | The paper is about physical control loops. The claim came from a blog post about it |
| ”The reference says 50–100k” | The reference was quoting another document, which was not in the library |
| ”The ADR declares it done” | That ADR fixed the problem. The state cited was the one it repaired |
| ”It’s decided that way, see the ADR” | The ADR was written to reverse that decision |
TABLE 1 · An ADR (architecture decision record) is the short document where an architecture decision is written down with its reason.
The agents had two ways to search: exact, with grep or a full-text index that keeps identifiers as written, and semantic, with embeddings, which return whatever is closest in meaning. I used the semantic one to detect duplicate problem reports, and I wanted to know which is good for what.
Finding duplicates
The documented pattern for code is agentic search with grep over embeddings (Agentic Search Over Vector Embeddings); its own catalogue lists more tokens and limited semantic understanding as the cost. Code has exact identifiers. My case was prose: two reports from different roles about the same problem may not share a word.
| Engine | Duplicates found | Non-duplicates rejected | Total correct |
|---|---|---|---|
| Null (control, always “different”) | 0/6 | 8/8 | 8/14 |
| Token overlap | 0/6 | 8/8 | 8/14 |
| Exact full-text search | 1/6 | 8/8 | 9/14 |
| Embeddings, loose threshold | 6/6 | 0/8 | 6/14 |
| Embeddings, tuned threshold | not recorded | not recorded | 10/14 |
TABLE 2 · 14 labelled pairs: 6 duplicates and 8 different problems. For the tuned threshold only the total was recorded.
The same 14 pairs, by engine
Bars cross. What finds duplicates fails at rejecting non-duplicates, and the reverse.
FIG. 1 · Exact search rejects every non-duplicate and finds almost no duplicate. Loose embeddings do exactly the inverse. The tuned threshold is left out: only its total (10 of 14) was recorded, not the split.
Exact search is almost never wrong when it says “same”, but it almost never says it. Embeddings on a loose threshold find every duplicate and flag everything else too. The tuned threshold was picked on these same 14 pairs, and it beats the null control by 2 pairs of 14.
Checking a citation
Verifying “does this ADR say X?” is exact search in a known file. A semantic engine returns what most resembles the claim, including a passage that says the opposite, because it shares the nouns. On this corpus, pairs that were different problems reached 0.77 cosine similarity. Two internal service names that differ by one word came out at 0.930: embeddings blur exactly the identifier that separates them.
So I split the jobs. Semantic search stays for duplicates. The citation check, which only confirmed that the cited document could be found, was to be extended to confirm with exact search that the document says what is attributed to it.
What checking costs
Agentic search, where the agent iterates with grep until it hits the line, spends tool calls:
one agentic search ≈ 5–10 tool calls × ~15 s ≈ 75–150 s
a median turn ≈ 372 s
→ 20% to 40% of a turn, per search
The 5–10 calls are an estimate from the literature; the 15 seconds and the 372-second median turn are from my teams. The agents run on a subscription with a usage allowance per 5-hour window, and tool calls eat into it. Checking a citation happens now and then and can pay for agentic search. Duplicate detection runs every time a report is opened, so it goes through the index.
How this was measured. Four retrieval engines run over a set of 14 labelled pairs of problem reports written by agents in different roles (6 duplicates, 8 not), plus cosine similarities from the same corpus. The tuned embeddings threshold was picked on those same 14 pairs.
Related
- My verifier reported 100% conformance until I measured what it rejects 718 of 718 rounds followed the declared process, but a checker that accepts almost anything also reports 100%. A shuffle control showed the number holds in one team out of six.
- 86% of my agents' code is still there, and most of the drop came from one week Line survival on a production repository written by agents: 85.9%, down from 92.7% two days earlier. Most of the lines lost in between belong to one week and one 2,408-line commit that survived at zero.