Let me tell you about the most embarrassing bug I've ever shipped.
I was building an ecommerce AI agent from scratch.
No LangChain.
Just the Anthropic SDK, TypeScript, and a bunch of custom tools.
I was feeling pretty confident.
Then a user asked:
"Can you suggest good smartphones?"
My AI agent confidently replied:
"I'm sorry, we don't carry any smartphones at the moment. Would youlike me to help you find something else? 😊"
It sounded helpful.
It sounded professional.
It was also 100% wrong.
Our catalog already had:
📱 Apple iPhone 17 Pro
📱 Samsung Galaxy S26 Ultra
Both were in stock.
Both were searchable.
Yet my AI insisted they didn't exist.
It was like a waiter saying,
"Sorry, we don't serve pasta."
...while standing next to the pasta station.
The Bug
My search tool looked innocent enough.
products.filter((p) =>
p.title.toLowerCase().includes(query) ||
p.category.toLowerCase().includes(query)
);
The user searched for:
smartphone
Here's what JavaScript saw:
`"Apple iPhone 17 Pro".includes("smartphone")
// false
"Samsung Galaxy S26 Ultra".includes("smartphone")
// false`
No bugs.
No exceptions.
Everything was working exactly as written.
The problem was my assumption.
.includes() doesn't understand meaning.
It only checks whether those exact letters exist.
To JavaScript,
`
iPhone ≠ smartphone
Galaxy ≠ smartphone`
They're just different strings.
Which means my AI confidently concluded:
"We don't sell smartphones."
The Worst Part
I had already shipped this.
Not internally.
Not in development.
I had demonstrated it in three YouTube videos.
Every viewer who tried asking for smartphones got the exact sameconfidently incorrect answer.
Nothing hurts more than watching your AI apologize for inventory thatactually exists.
The Fix
Instead of searching by letters...
I started searching by meaning.
I used:
OpenAI for embeddings
LanceDB for vector search
During ingestion, every product gets converted into an embedding.
${p.title} ${p.category}`
const records = await Promise.all(
products.map(async (p) => ({
...p,
embedding: await EmbeddingService.embed(
),
}))
);
await db.createTable("products", records);
Now, when someone searches:
const embedding = await EmbeddingService.embed(query);
const results = await table
.search(embedding)
.limit(5)
.toArray();`
Instead of comparing strings...
It compares meaning.
embed("smartphone")
↓
Apple iPhone 17 Pro
Similarity: 0.94
Samsung Galaxy S26 Ultra
Similarity: 0.91
The AI finally understood that an iPhone is a smartphone.
No synonym lists.
No manual mappings.
No hardcoded keywords.
Then I Hit Another Bug
I fixed vector search.
Tested again.
Still broken.
This time something stranger happened.
There were:
No logs
No database queries
No tool calls
Claude wasn't even touching my search tool.
Instead, it answered directly from its own training data.
The issue wasn't my code.
It was the tool description.
This description looked fine:
Search for products in the database.
Turns out it wasn't.
After changing it to this:
ALWAYS use this tool before answering ANY product question.
NEVER answer from your own knowledge.
Search FIRST.
Everything started working.
Immediately.
That was the day I realized something important:
Tool descriptions are instructions, not documentation.
If they sound optional...
Claude treats them as optional.
LanceDB Was Surprisingly Simple
Before using LanceDB, I expected:
Docker
A running server
Cloud infrastructure
Database provisioning
Instead, setup was literally one line.
const db = await lancedb.connect("./.lancedb");
That's it.
A folder called .lancedb appears.
Your vectors are stored locally.
No infrastructure.
No deployment.
Just install the package and start searching.
It was much simpler than I expected.
`Before
User
│
▼
"smartphone"
│
▼
.includes()
│
▼
❌ We don't have smartphones 😊`
`After
User
│
▼
"smartphone"
│
▼
Embedding
│
▼
Vector Search
│
▼`
✅ Apple iPhone 17 Pro
✅ Samsung Galaxy S26 Ultra
The Biggest Lesson
Keyword search works only when users think exactly like your database.
They don't.
People search with intent, not exact words.
That's why semantic search makes such a huge difference.
It lets your AI understand what users mean instead of matching whateverletters happen to appear in a product title.
Sometimes the biggest improvement isn't rebuilding your AI.
It's replacing three lines of search logic.
The complete source code and full video walkthrough are in thecomments.
Top comments (2)
This is a good example of a bug hiding in the contract rather than the model. Once the tool says category lookup, exact string matching becomes part of the product spec whether we meant it or not. I would still keep one deterministic fallback for known categories so the vector search has something boring to fail back to.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.