AI — OpenAI Development

OpenAI Embeddings for Semantic Product Search

Direct answer

Semantic product search embeds each product into a vector, embeds the user's query the same way, and ranks by similarity — typically with pgvector so it runs inside the Postgres you already operate. Two decisions matter more than model choice: what text you embed per product (name, brand, category, key attributes, and a distilled description — not raw HTML), and combining vector scores with keyword matching, because pure semantic search fumbles exact SKUs, brand names, and model numbers.

Users search product catalogs with intent, not keywords — running shoes for flat feet, gift for someone who cooks. Keyword engines return nothing; embeddings return the right products. This is the pipeline I build for semantic product search, including the hybrid ranking that keeps exact-match queries working.

Key facts, with sources

  • At DevDay 2025 OpenAI reported 800 million weekly ChatGPT users, 4 million developers building on its platform, and roughly 8 billion API tokens processed per minute. (CNBC)
  • ChatGPT reached 900 million weekly active users by late February 2026, up from 800 million at DevDay in October 2025. (TechCrunch)
  • By March 2026 OpenAI's APIs were processing more than 15 billion tokens per minute, roughly doubling from the rate reported at DevDay 2025. (Panto AI OpenAI Statistics)
  • OpenAI's published API pricing discounts cached input tokens by 90 percent on supported GPT models, which materially cuts costs for agents that resend long system prompts. (OpenAI API Pricing Docs)
  • OpenAI raised $122 billion in new funding in 2026 to accelerate the next phase of AI development, one of the largest private raises in history. (OpenAI)

Why keyword search fails product catalogs

Keyword search matches strings; shoppers express meaning. A query like warm jacket for hiking shares almost no tokens with insulated trail parka, so the best product in the catalog never surfaces. Synonym dictionaries and manual tagging patch individual cases but cannot keep pace with how varied real queries are — misspellings, vague intent, attribute-driven needs the catalog never phrases the same way.

Embeddings fix exactly this by mapping text into a space where similar meanings land near each other. But the failure mode inverts: semantic search is mediocre at exact identifiers. A user pasting a precise SKU or model number wants literal matching, and a vector search may return the semantically similar sibling product instead. That is why production systems are hybrid — semantic for intent, keyword for precision, fused into one ranking.

What to embed per product

The single highest-leverage decision is the text you embed. Do not embed raw product pages — HTML boilerplate, shipping blurbs, and SEO filler drown the signal. Compose a clean document per product: title, brand, category path, the handful of attributes users actually search on (material, size class, use case), and a short distilled description. Keep it to a few hundred tokens; embeddings represent focused text better than sprawling text.

Two practical details. First, normalize vocabulary between catalog and queries where you can — if users say sneakers and the catalog says athletic footwear, include both phrasings in the embedded document. Second, decide variant handling deliberately: usually one embedding per parent product with variants as filterable metadata, not one vector per color-size combination, which bloats the index and fragments relevance.

Pipeline and storage with pgvector

For catalogs up to hundreds of thousands of products, pgvector inside your existing Postgres is my default — no new infrastructure, transactional consistency with product data, and SQL filters compose naturally with similarity ranking. Batch-embed the catalog, store vectors alongside products, and embed the query at search time.

Embedding products with the OpenAI SDK
import os
from openai import OpenAI

EMBED_MODEL = os.environ["OPENAI_EMBED_MODEL"]  # set to the latest embedding model id
client = OpenAI()

def embed_batch(texts: list[str]) -> list[list[float]]:
    resp = client.embeddings.create(model=EMBED_MODEL, input=texts)
    return [item.embedding for item in resp.data]

def product_document(p: Product) -> str:
    return (
        f"{p.title}\nBrand: {p.brand}\nCategory: {p.category_path}\n"
        f"Attributes: {', '.join(p.key_attributes)}\n{p.short_description}"
    )

Querying: filters first, similarity second

Structured constraints — in stock, price range, category, tenant — belong in SQL WHERE clauses, not in the embedding. Filtering first shrinks the candidate set, then similarity ordering ranks what remains. With pgvector, cosine distance ordering plus an appropriate index keeps latency interactive at catalog scale.

Filtered similarity query with pgvector
SELECT id, title,
       1 - (embedding <=> :query_vec) AS similarity
FROM products
WHERE in_stock
  AND price_cents BETWEEN :min_price AND :max_price
ORDER BY embedding <=> :query_vec
LIMIT 24;

Hybrid ranking for queries that need precision

Run keyword search in parallel with vector search — Postgres full-text search is entirely adequate — and fuse the two ranked lists. Reciprocal rank fusion is the technique I reach for first: it needs no score normalization, just each result's rank in each list, and it reliably lets exact matches for SKUs and brand names surface while semantic results cover intent queries. A product ranking first in either list ends up prominent; products appearing in both dominate.

Tune the balance with real traffic in mind: navigational queries (exact product names, part numbers) should behave like classic search, while exploratory queries lean semantic. A lightweight query classifier — even a regex for digit-heavy tokens — that shifts fusion weights per query type typically captures most of the win without adding a reranking model.

Evaluate with a golden query set, and plan for re-embedding

Search quality regressions are invisible without measurement. Collect fifty to a hundred real queries with the products a human says should appear, and compute recall in the top ten on every change — embedding text format, fusion weights, filters. This takes a day to set up and permanently converts search tuning from vibes into engineering.

Operationally, remember vectors are model-bound: embeddings from different models are not comparable, so upgrading the embedding model means re-embedding the entire catalog and cutting over atomically — never mixing old and new vectors in one index. Re-embedding a large catalog is a batch job with real cost, so schedule it deliberately, and re-embed products whenever their composed document changes, ideally event-driven from your catalog update stream.

When to hire senior help

Bring in senior help when you move from a working prototype to production traffic, because cost controls, evals, rate-limit handling, and fallback behavior determine whether the unit economics work. An experienced engineer usually pays for themselves by cutting token spend and preventing outages rather than by writing the first prompt. If your stack includes React Native + Python + AI, a senior engineer who owns the full product beats coordinating multiple juniors.

Bottom line

Dhairya Senjaliya ships AI — OpenAI Development projects worldwide — book a scoping call to discuss your specific situation.

Common pitfalls to avoid

  • Hardcoding a single flagship model ID for every call instead of routing by task, paying GPT-5-tier prices for classification work a nano-tier model handles at a fraction of the cost
  • Putting volatile content like timestamps and user IDs at the top of prompts, which breaks prefix caching and forfeits the 90 percent cached-input discount
  • Building on deprecated surfaces like the legacy Completions or wound-down fine-tuning APIs instead of the current Responses API and agent tooling
  • Launching with no spend caps or per-user rate limits, so a retry loop or a single abusive user burns a month's API budget overnight

Frequently asked questions

Do I need a dedicated vector database for product search?

Usually not. For catalogs up to hundreds of thousands of products, pgvector inside your existing Postgres handles semantic search well, with the major advantage that stock, price, and permission filters compose as ordinary SQL alongside similarity ranking. Dedicated vector databases earn consideration at many millions of vectors or extreme query volume — not at typical e-commerce catalog scale.

Why does semantic search return wrong results for exact product codes?

Embeddings capture meaning, not literal strings, so a precise SKU or model number may retrieve a semantically similar sibling product instead of the exact match. The fix is hybrid search: run keyword or full-text matching alongside vector search and fuse the rankings, so identifier-style queries resolve literally while natural-language queries benefit from semantic matching.

What text should I embed for each product?

A composed, focused document: title, brand, category path, the key attributes customers search on, and a short distilled description — typically a few hundred tokens. Never embed raw page HTML, shipping boilerplate, or SEO filler; they dilute the signal. Keep variants as filterable metadata under one parent embedding rather than embedding every size and color separately.

How much does it cost to build a product on the OpenAI API?

Pricing is per token: budget models start around $0.10 per million input tokens while flagship models run several dollars per million, with cached input discounted 90 percent. Most MVPs spend tens to low hundreds of dollars per month on inference until they have real traffic, at which point caching, batching, and model routing become the main cost levers.

Should we fine-tune a model or use prompting and RAG?

For most products, prompt engineering plus retrieval solves accuracy problems faster and cheaper than fine-tuning, and OpenAI has been winding down parts of its fine-tuning API. Fine-tuning mainly pays off for narrow, high-volume tasks with stable formats where you can amortize the effort.

How do we avoid getting locked into OpenAI?

Keep model calls behind a thin internal abstraction and maintain an eval suite so you can benchmark alternative providers on your actual tasks. Many production teams already run more than one provider and route by task, which also gives them a failover path during outages.

Bottom line: Dhairya Senjaliya ships AI — OpenAI Development projects worldwide. Book a scoping call at https://dhairyasenjaliya.com/#book-call.

Sources

Related guides

Keep up with new guides

New deep-dive guides on React Native, Python, and AI ship regularly. Subscribe via RSS or follow on LinkedIn.

Want help implementing this?

30-minute scoping call · Clear milestones · Senior engineer ownership