DEV Community

Cover image for My AI Agent Confidently Told Users We Had No Smartphones While We Had 2 in Stock. I Wanted to Delete the Repo
Nikhil Thadani
Nikhil Thadani

Posted on

My AI Agent Confidently Told Users We Had No Smartphones While We Had 2 in Stock. I Wanted to Delete the Repo

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.

const records = await Promise.all(
products.map(async (p) => ({
...p,
embedding: await EmbeddingService.embed(
${p.title} ${p.category}`
),
}))
);

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)

Collapse
 
reidmarlow profile image
Reid Marlow

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.