RAG Retrieval — Published Products & Chat History
How the chat pipeline selects knowledge chunks for retrieval: published storefront products only, conversation-aware embedding, and link follow-up handling.
Related: RAG & chat API · Product sync · Conversation history · Vector call stack · Storefront product cards
Two history settings (env)
Section titled “Two history settings (env)”| Env var | Default | Used for |
|---|---|---|
CHAT_HISTORY_MESSAGES | 50 | LLM reply — how many prior user/assistant turns are sent to OpenRouter in buildPrompt() |
CHAT_RAG_HISTORY_MESSAGES | 8 | RAG retrieval only — how many recent turns are prepended when embedding the search query |
They are independent on purpose:
- 50 messages → better multi-turn answers (“what about that one?”, long threads).
- 8 messages → enough context for follow-ups like “what is the link?” without embedding an entire long thread every turn (lower cost, sharper vector search).
Both are set in .env / .env.sample.
RAG search query (conversation context)
Section titled “RAG search query (conversation context)”Module: app/lib/rag-search-query.server.js → buildRagSearchQuery(message, historyForPrompt)
Before vector search, the app embeds text like:
Recent conversation:Customer: what is the minimum price product you have?Assistant: The minimum price product we have is Matching Separates, priced at $7,000.Current customer message: and what is that product link?Flow in app/lib/rag.server.js:
- Load up to
CHAT_HISTORY_MESSAGESfrom the thread (newest first, reversed to chronological). ragSearchText = buildRagSearchQuery(message, historyForPrompt)— uses lastCHAT_RAG_HISTORY_MESSAGESof that history.getEmbeddingsBatched([ragSearchText])→searchSimilarChunks(...).
The current user message is not duplicated in DB history when embedding (history is loaded before saving the current turn).
Link follow-up boost
Section titled “Link follow-up boost”When the customer asks for a link / URL / “that product” (isProductLinkFollowUp), and there is no focusProduct from a product card:
- Parse product titles from the last assistant reply (
extractProductTitlesFromAssistantHistory). - Resolve published catalog rows (
findPublishedProductsByTitles). - Merge that product’s chunks ahead of vector results (
mergeChunksProductFirst). - Inject Product from conversation context with
Product page URL: …for the LLM.
Prompt rules (prompt-builder.server.js): when the customer explicitly asks for a link, include a markdown link from Store Context; do not fall back to the homepage only.
Published products only
Section titled “Published products only”Draft, archived, and unpublished products must not appear in RAG answers or product cards. Zero inventory is OK if the product is published.
Module: app/lib/product-storefront.server.js
- Shopify Admin search:
status:active published_status:published(buildShopifyProductsSearchQuery). - GraphQL field
publishedAtstored onproducts.published_at(migration20260523150000_add_product_published_at).
Ingestion
Section titled “Ingestion”ingestProduct: if !isProductPublishedOnStorefront(product) → purge embeddings/chunks for that Shopify product ID and skip ingest.
purgeIneligibleProductsFromRag(shopId) runs at the start of each product sync to clean stale draft/unpublished embeddings.
Vector search
Section titled “Vector search”vector-search.server.js SQL excludes product-linked chunks unless:
lower(p.status) = 'active' AND p.published_at IS NOT NULLNon-product chunks (FAQ, website knowledge, policies) are unchanged (product_id IS NULL).
Product cards
Section titled “Product cards”product-cards.server.js — catalog lookups use storefrontVisibleProductWhere() (active + publishedAt set).
Chunks
Section titled “Chunks”chunker.server.js — product overview chunks include Product page: {url} when available.
Deploy & re-sync
Section titled “Deploy & re-sync”npx prisma migrate deploy # includes products.published_atThen run a full product sync in admin so:
published_atis populated for live catalog items- draft/unpublished products are purged from embeddings
| File | Role |
|---|---|
app/lib/product-storefront.server.js | Eligibility, sync query, purge RAG |
app/lib/rag-search-query.server.js | buildRagSearchQuery, link follow-up helpers |
app/lib/rag.server.js | Orchestration: embed search text, conversation product boost |
app/lib/vector-search.server.js | pgvector search with published-product filter |
app/lib/ingestion.server.js | Gate + purge on ingest |
app/lib/product-sync.server.js | Sync filter + publishedAt |
app/lib/prompt-builder.server.js | Link-on-request + published-only rules |