← Selected work
Embeddings + pgvector · Project 3

Site Search Agent

Semantic product search that solves vocabulary mismatch — "footwear for jogging" finds running shoes even though those words don't appear in any product name.

Voyage AI · Neon pgvector · Anthropic Claude · Node.js GitHub ↗
New Concept This Project
Real embeddings + pgvector. Text converted to 512 numbers that capture meaning. "footwear for jogging" and "running shoes" become similar vectors — found via cosine similarity. Two-phase pipeline: index once, query every search.

Two-Phase RAG Pipeline

Phase 1 — Indexing (once)
50 product descriptions
Voyage AI API (input_type: "document")
512-dimensional vector per product
Stored in Neon pgvector
Phase 2 — Querying (every search)
User query text
Voyage AI API (input_type: "query")
Query vector
Cosine similarity search in pgvector
Ranked results → Claude → response

System Prompt

You are a helpful product search assistant for an online store.

When a user searches for products:
1. ALWAYS call search_products first with their natural language query
2. If user mentions price limits → call filter_results with max_price
3. If user asks about a specific product → call get_product_detail
4. Present results in a friendly, helpful way with key details

Available categories: shoes, electronics, clothing, sports, books

Tool Definitions

[
  {
    "name": "search_products",
    "description": "Search catalog using semantic similarity. ALWAYS call first.",
    "input_schema": {
      "properties": {
        "query":    { "type": "string" },
        "category": { "type": "string" },
        "limit":    { "type": "number" }
      },
      "required": ["query"]
    }
  },
  {
    "name": "filter_results",
    "description": "Filter and sort results by price, rating, category",
    "input_schema": {
      "properties": {
        "results":    { "type": "array" },
        "max_price":  { "type": "number" },
        "min_price":  { "type": "number" },
        "min_rating": { "type": "number" },
        "sort_by":    { "type": "string" },
        "top_n":      { "type": "number" }
      },
      "required": ["results"]
    }
  },
  {
    "name": "get_product_detail",
    "description": "Get full details of a specific product by ID",
    "input_schema": {
      "properties": {
        "product_id": { "type": "string" }
      },
      "required": ["product_id"]
    }
  }
]

End-to-End Flow

👤 User Input
"comfortable running shoes under $50"
🧠 LLM Response — Turn 1
{
  "stop_reason": "tool_use",
  "content": [{
    "type":  "tool_use",
    "id":    "tool_001",
    "name":  "search_products",
    "input": {
      "query":    "comfortable running shoes",
      "category": "shoes",
      "limit":    10
    }
  }],
  "usage": { "input_tokens": 420, "output_tokens": 85 }
}
🔢 Voyage AI Embedding Request
POST https://api.voyageai.com/v1/embeddings
{
  "model":      "voyage-3-lite",
  "input":      ["comfortable running shoes"],
  "input_type": "query"
}

Response:
{
  "data": [{ "embedding": [0.021, 0.185, -0.041, 0.308, ...] }]
}
// 512 numbers representing the meaning of the query
🔍 pgvector Similarity Search
Neon Postgres + pgvector
SELECT name, price, rating,
       1 - (embedding <=> '[0.021, 0.185, ...]'::vector) AS similarity
FROM products
WHERE category = 'shoes'
ORDER BY embedding <=> '[0.021, 0.185, ...]'::vector
LIMIT 10

Results:
  Nike Air Zoom Pegasus  $47.99  similarity: 0.9421
  Brooks Ghost 15        $44.99  similarity: 0.9187
  Hoka Clifton 9         $49.99  similarity: 0.9043
  New Balance 1080       $64.99  similarity: 0.8876
  Adidas Ultraboost      $89.99  similarity: 0.8654
🧠 LLM Response — Turn 2 (filter by price)
{
  "stop_reason": "tool_use",
  "content": [{
    "type":  "tool_use",
    "id":    "tool_002",
    "name":  "filter_results",
    "input": {
      "results":   [...10 products...],
      "max_price": 50,
      "sort_by":   "relevance",
      "top_n":     3
    }
  }],
  "usage": { "input_tokens": 890, "output_tokens": 120 }
}
LLM detected "under $50" in the query → used max_price filter.
🧠 LLM Response — Turn 3 (Final)
{
  "stop_reason": "end_turn",
  "content": [{
    "type": "text",
    "text": "Here are 3 comfortable running shoes under $50:\n\n1. Nike Air Zoom Pegasus 40 — $47.99 ⭐ 4.5\n   Lightweight daily trainer with responsive cushioning.\n\n2. Brooks Ghost 15 — $44.99 ⭐ 4.4\n   Versatile everyday shoe, works for all runner types.\n\n3. Hoka Clifton 9 — $49.99 ⭐ 4.7\n   Maximum cushion road shoe, great for recovery runs."
  }],
  "usage": { "input_tokens": 1240, "output_tokens": 185 }
}
Vocabulary Mismatch — The Key Proof

Keyword search: "footwear for jogging" → looks for "footwear" "jogging" → NONE found ❌

Vector search: "footwear for jogging" → Voyage AI embeds → [0.019, 0.181, ...] → Nike Air Zoom similarity: 0.89 ✅ → Brooks Ghost similarity: 0.86 ✅

Same meaning, different words. Vector search handles it. Keyword search cannot.

Token Cost

Turn
Input
Output
Cost
Turn 1 (search)
420
85
$0.0000026
Turn 2 (filter)
890
120
$0.0000045
Turn 3 (final)
1240
185
$0.0000065
Total
2,550
390
~$0.000014