Build AI Search Component Với OpenAI Embeddings + React
Tìm hiểu cách xây dựng semantic search component sử dụng OpenAI embeddings và React. Kết quả search thông minh hơn keyword matching truyền thống.
Keyword search đã cũ. Users ngày nay expect search hiểu được intent — tìm "cách làm animation mượt" phải ra kết quả về CSS transitions, Framer Motion, GSAP. Đó là semantic search, và với OpenAI embeddings, bạn có thể build trong một buổi chiều.
Embeddings là gì?
Embedding là vector representation của text. Hai đoạn text có nghĩa gần nhau sẽ có vectors gần nhau trong không gian nhiều chiều. OpenAI cung cấp model text-embedding-3-small — nhanh, rẻ, và đủ accurate cho hầu hết use cases.
Architecture
Flow đơn giản: Index content thành embeddings → store trong database (Postgres + pgvector) → khi user search, convert query thành embedding → tìm vectors gần nhất.
Backend: API Route tạo embeddings
// app/api/search/route.ts
import { openai } from "@ai-sdk/openai";
import { embed } from "ai";
import { prisma } from "@/lib/prisma";
export async function POST(req: Request) {
const { query } = await req.json();
// Tạo embedding cho search query
const { embedding } = await embed({
model: openai.embedding("text-embedding-3-small"),
value: query,
});
// Tìm documents gần nhất bằng cosine similarity
const results = await prisma.;
return Response.json({ results });
}
Frontend: Search Component
// components/ai-search.tsx
"use client";
import { useState, useCallback } from "react";
import { useDebounce } from "@/hooks/use-debounce";
interface SearchResult {
id: string;
title: string;
summary: string;
similarity: number;
}
export function AISearch() {
const [query, setQuery] = useState("");
const [results, setResults] = useState<SearchResult[]>([]);
const [loading, setLoading] = useState(false);
const search = useCallback(async (q: string) => {
if (q.length < 3) return;
setLoading(true);
try {
const res = await fetch("/api/search", {
method: "POST",
body: JSON.stringify({ query: q }),
});
const data = await res.json();
setResults(data.results);
} finally {
setLoading(false);
}
}, []);
useDebounce(() => search(query), 300, [query]);
return (
<div className="relative max-w-xl mx-auto">
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Tìm kiếm thông minh..."
className="w-full px-4 py-3 border rounded-xl"
/>
{results.length > 0 && (
<ul className="absolute w-full mt-2 bg-white border rounded-xl shadow-lg">
{results.map((r) => (
<li key={r.id} className="p-3 hover:bg-gray-50 cursor-pointer">
<p className="font-medium">{r.title}</p>
<p className="text-sm text-gray-500">{r.summary}</p>
<span className="text-xs text-blue-500">
Match: {(r.similarity * 100).toFixed(0)}%
</span>
</li>
))}
</ul>
)}
</div>
);
}
Lưu ý quan trọng
- Pgvector extension: Cần enable trong Postgres —
CREATE EXTENSION vector; - Batch indexing: Đừng gọi API từng document một, batch 100 documents mỗi request
- Caching: Cache embedding results trong Redis để giảm API calls
- Dimension:
text-embedding-3-smalloutput 1536 dimensions, đủ cho hầu hết apps
Semantic search không còn là feature xa xỉ. Với OpenAI embeddings + pgvector, bạn có thể add intelligent search vào bất kỳ React app nào. Users sẽ notice sự khác biệt ngay lập tức.
Admin
Bình luận (0)
Đăng nhập để bình luận
Chưa có bình luận nào. Hãy là người đầu tiên!