Skip to content
Andrew Voirol
WorkLogAboutContact
HomeWorkLog

AboutContact

✦ Just one prompt away from figuring it all out.

Wednesday, August 12, 2026

Embedding dedup and the 0.80 threshold

AgenticVisualization

The graph extraction engine was producing duplicate nodes. "Can't initiate phone calls" and "Phone call avoidance" are the same friction, but string matching can't see that.

Solution: 768-dimensional embedding vectors via gemini-embedding-001. Every new node gets embedded. Every existing node has a cached embedding. Cosine similarity determines duplicates.

The threshold design has three zones:

  • ≥ 0.85: Automatic merge. The nodes are semantically identical.
  • 0.80–0.85: Fuzzy zone. An additional LLM call arbitrates — are these genuinely the same friction, or subtly different?
  • < 0.80: New node. Distinct enough to stand on its own.

The EmbeddingCache class (71 lines) stores embeddings in memory with findBestMatch() returning the best candidate above 0.80. The cosineSimilarity() function is pure math — no API calls, runs client-side.

The user specifically approved using gemini-embedding-001 over the legacy text-embedding-004, noting: "Lever your Gemini documentation skills and plugins to verify you're doing this well with the latest and greatest." The newer model supports MRL dimensionality scaling — 768 dims matches the original spec while getting better quality vectors.

Test script at scripts/test-dedup.ts (183 lines) verifies cosine similarity math, identical/orthogonal/similar vector cases, and merge operations.

← Previous

Making the graph readable

Next →

768 dimensions to catch 'phone call avoidance' and 'can't initiate phone calls' as the same friction


Andrew Voirol

Builder, hacker, shipper. Currently leaving localhost.

Navigate

WorkBuilder’s LogAboutContactRSS Feed

Connect

X / TwitterGitHubLinkedIn

© 2026 Andrew Voirol·Back to top ↑
✦Just one prompt away from figuring it all out.