瀏覽代碼

feat: implement semantic vector search for product name queries #94

- Modified queryQdrantProducts to use vector similarity search when name filter is provided
- Added generateEmbedding import from qdrant-client.ts
- Search now uses searchPoints() instead of scrollPoints() for name-based queries
- Maintains backward compatibility with scroll-based search for other filters
- Handles Hungarian characters correctly through embedding API
- Faster and more accurate product name matching using semantic search
Claude 5 月之前
父節點
當前提交
d332d907da
共有 1 個文件被更改,包括 24 次插入12 次删除
  1. 24 12
      supabase/functions/_shared/mcp-qdrant-helpers.ts

+ 24 - 12
supabase/functions/_shared/mcp-qdrant-helpers.ts

@@ -5,7 +5,7 @@
  */
 
 import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
-import { scrollPoints, searchPoints, getCollectionName } from './qdrant-client.ts';
+import { scrollPoints, searchPoints, getCollectionName, generateEmbedding } from './qdrant-client.ts';
 import { LlmOrder, LlmCustomer, LlmProduct } from './mcp-types.ts';
 
 // Initialize Supabase client
@@ -119,21 +119,33 @@ export async function queryQdrantProducts(
       qdrantFilter.must.push(priceFilter);
     }
 
-    // Scroll through points (no vector search needed for filtering)
-    const result = await scrollPoints(collectionName, qdrantFilter, limit);
-
-    // If name filter is provided, we need to filter locally (not indexed)
-    let products = result.points.map((point: any) => point.payload);
+    let products: any[];
 
+    // Use semantic vector search if name filter is provided
     if (filters?.name) {
-      const nameLower = filters.name.toLowerCase();
-      products = products.filter((p: any) =>
-        (p.name || p.title || '').toLowerCase().includes(nameLower)
+      console.log(`[MCP Qdrant] Using semantic search for product name: "${filters.name}"`);
+
+      // Generate embedding for the search query
+      const embedding = await generateEmbedding(filters.name);
+
+      // Use searchPoints for semantic similarity search
+      const searchResults = await searchPoints(
+        collectionName,
+        embedding,
+        limit,
+        qdrantFilter
       );
-    }
 
-    // Limit results
-    products = products.slice(0, limit);
+      // Extract payloads from search results
+      products = searchResults.map((result: any) => result.payload);
+
+      console.log(`[MCP Qdrant] Semantic search found ${products.length} products`);
+    } else {
+      // Use scroll-based search for other filters
+      console.log('[MCP Qdrant] Using scroll-based search');
+      const result = await scrollPoints(collectionName, qdrantFilter, limit);
+      products = result.points.map((point: any) => point.payload).slice(0, limit);
+    }
 
     // Format for LLM
     return products.map((p: any) => formatProductForLlm(p));