Tìm kiếm Ngữ nghĩa với TypeScript: Sử dụng embed() và embedMany cho Vector Search
Bài viết này hướng dẫn cách triển khai tìm kiếm ngữ nghĩa (semantic search) trong ứng dụng TypeScript sử dụng SDK NeuroLink. Tìm hiểu về khái niệm vector nhúng (embeddings), cách sử dụng các phương thức `embed()` và `embedMany()` để xử lý dữ liệu, cũng như tích hợp với cơ sở dữ liệu vector để xây dựng hệ thống tìm kiếm thông minh.

Trong thời đại bùng nổ thông tin, tìm kiếm dựa trên từ khóa truyền thống thường không còn đáp ứng được nhu cầu. Người dùng ngày nay không chỉ tìm kiếm các cụm từ khớp chính xác; họ đang tìm kiếm nội dung và ý nghĩa. Đây chính là lúc tìm kiếm ngữ nghĩa (semantic search) phát huy tác dụng, cho phép hệ thống hiểu được ý định đằng sau một truy vấn và trả về các kết quả có tính tương đồng về mặt khái niệm, ngay cả khi không chứa đúng từ khóa.
Trái tim của tìm kiếm ngữ nghĩa nằm ở khái niệm embeddings (vector nhúng) — các biểu diễn số học dense của văn bản giúp nắm bắt ý nghĩa của nó. NeuroLink, SDK AI toàn năng dành cho TypeScript, đã đơn giản hóa quá trình tạo và sử dụng các vector này, giúp việc tích hợp tính năng tìm kiếm ngữ nghĩa mạnh mẽ vào ứng dụng trở nên dễ dàng hơn bao giờ hết.
Bài viết này sẽ hướng dẫn bạn cách tạo embeddings với các phương thức embed() và embedMany() của NeuroLink, thực hiện tìm kiếm tương đồng và tích hợp với cơ sở dữ liệu vector để xây dựng một công cụ tìm kiếm ngữ nghĩa hoàn chỉnh.
Embeddings là gì và tại sao chúng lại quan trọng?
Hãy tưởng tượng việc ánh xạ mọi từ, câu hoặc tài liệu vào một không gian đa chiều, trong đó các mục có ý nghĩa tương tự sẽ nằm gần nhau. Về cơ bản, đó chính là những gì mô hình embedding thực hiện. Mỗi đoạn văn bản được chuyển đổi thành một vector (danh sách các số) có kích thước cố định, bao hàm các thuộc tính ngữ nghĩa của nó.
Đối với tìm kiếm ngữ nghĩa, điều này có nghĩa là:
- Hiểu ngữ cảnh: Một tìm kiếm về "sửa ô tô" có thể trả về kết quả về "bảo trì xe hơi" hoặc "dịch vụ phương tiện" ngay cả khi cụm từ chính xác không xuất hiện.
- Xếp hạng mức độ liên quan: Kết quả có thể được xếp hạng dựa trên sự tương đồng ngữ nghĩa với truy vấn, mang lại kết quả chính xác hơn.
- Thu hẹp khoảng cách từ vựng: Nó khắc phục các vấn đề phát sinh từ từ đồng nghĩa, câu diễn đạt khác hoặc các cách thể hiện cùng một ý tưởng.
NeuroLink cung cấp một API thống nhất để tạo ra các vector quan trọng này từ nhiều nhà cung cấp AI hàng đầu.
Tạo Embeddings với NeuroLink: embed() và embedMany()
NeuroLink cung cấp hai phương thức chính để tạo embeddings thông qua giao diện ProviderFactory: embed() cho các chuỗi văn bản đơn lẻ và embedMany() để xử lý hàng loạt (batch) hiệu quả.
provider.embed(text, modelName?): Nhúng văn bản đơn lẻ
Phương thức embed() nhận một chuỗi văn bản và trả về vector nhúng tương ứng của nó.
import { ProviderFactory } from "@juspay/neurolink";
async function getEmbedding(text: string) {
// Tạo một nhà cung cấp (provider) instance của OpenAI cho embedding.
// NeuroLink hỗ trợ OpenAI, Google AI Studio, Google Vertex và Amazon Bedrock.
const provider = await ProviderFactory.createProvider("openai");
// Tạo vector nhúng
const vector = await provider.embed(text);
console.log(`Văn bản: "${text}"`);
console.log(`Chiều của embedding: ${vector.length}`);
return vector;
}
// Ví dụ sử dụng
const queryEmbedding = await getEmbedding("Làm cách nào để đặt lại mật khẩu?");
const documentEmbedding = await getEmbedding("Xử lý sự cố với mật khẩu");
Các tham số chính:
text(string, bắt buộc): Văn bản đầu vào cần nhúng.modelName(string, tùy chọn): Cho phép bạn ghi đè mô hình embedding mặc định. Ví dụ:text-embedding-3-smallcho OpenAI hoặcgemini-embedding-001cho Google AI Studio.
provider.embedMany(texts, modelName?): Nhúng hàng loạt để tối ưu hiệu suất
Đối với các kịch bản liên quan đến nhiều tài liệu hoặc một kho dữ liệu lớn, embedMany() hiệu quả hơn đáng kể. Nó chấp nhận một mảng các chuỗi văn bản và trả về một mảng các vector nhúng tương ứng.
import { ProviderFactory } from "@juspay/neurolink";
async function getManyEmbeddings(texts: string[]) {
const provider = await ProviderFactory.createProvider("googleAiStudio");
// Tạo embeddings cho nhiều văn bản trong một lần gọi API
const embeddings = await provider.embedMany(texts);
console.log(`Đã tạo ${embeddings.length} embeddings.`);
embeddings.forEach((emb, index) => {
console.log(`Embedding ${index + 1} chiều: ${emb.length}`);
});
return embeddings;
}
// Ví dụ sử dụng với các đoạn tài liệu
const documents = [
"NeuroLink cung cấp API thống nhất cho hơn 13 nhà cung cấp AI.",
"Tìm kiếm ngữ nghĩa giúp tìm tài liệu theo ý nghĩa, không chỉ từ khóa.",
"Ứng dụng AI hướng sự kiện có thể sử dụng lifecycle hooks cho phân tích.",
];
const documentEmbeddings = await getManyEmbeddings(documents);
Các nhà cung cấp được hỗ trợ và lựa chọn mô hình
NeuroLink tích hợp với một số nhà cung cấp embedding hàng đầu:
- OpenAI: Sử dụng các mô hình như
text-embedding-3-small(mặc định) hoặctext-embedding-3-large. - Google AI Studio: Sử dụng
gemini-embedding-001(mặc định). - Google Vertex: Sử dụng
text-embedding-004(mặc định). - Amazon Bedrock: Sử dụng các mô hình như
amazon.titan-embed-text-v2:0(mặc định).
Bạn có thể cấu hình các mô hình mặc định thông qua các biến môi trường (ví dụ: OPENAI_EMBEDDING_MODEL, VERTEX_EMBEDDING_MODEL) hoặc trực tiếp trong các lệnh gọi embed()/embedMany().
Đối với các nhà cung cấp không hỗ trợ embedding gốc (ví dụ: Anthropic, Mistral), bạn vẫn có thể sử dụng NeuroLink để tạo văn bản và sau đó sử dụng một instance NeuroLink riêng được cấu hình cho nhà cung cấp có khả năng embedding để xử lý nhu cầu nhúng dữ liệu của bạn.
import { ProviderFactory } from "@juspay/neurolink";
// Sử dụng Anthropic để tạo văn bản trò chuyện
const chatProvider = await ProviderFactory.createProvider("anthropic");
const response = await chatProvider.generate({
input: { text: "Kể cho tôi nghe một câu chuyện về pháp sư." },
});
// Sử dụng OpenAI để tạo embeddings, độc lập
const embedProvider = await ProviderFactory.createProvider("openai");
const storyEmbedding = await embedProvider.embed(response.text);
Xây dựng công cụ tìm kiếm ngữ nghĩa: Từ Embeddings đến Cơ sở dữ liệu Vector
Sau khi có embeddings, bước tiếp theo là lưu trữ chúng và thực hiện tìm kiếm tương đồng. Điều này thường liên quan đến một cơ sở dữ liệu vector (hoặc vector store), được tối ưu hóa để lưu trữ và truy vấn các vector đa chiều.
Quy trình chung để xây dựng công cụ tìm kiếm ngữ nghĩa trông như sau:
- Lập chỉ mục tài liệu:
- Lấy kho tài liệu của bạn (bài viết, mô tả sản phẩm, vé hỗ trợ...).
- Chia nhỏ (chunk) chúng thành các đoạn dễ quản lý nếu quá lớn.
- Sử dụng
embedMany()để tạo embeddings cho từng đoạn. - Lưu trữ các embeddings này cùng với văn bản gốc và siêu dữ liệu vào cơ sở dữ liệu vector.
- Truy vấn và Truy xuất:
- Khi người dùng gửi truy vấn, sử dụng
embed()để tạo embedding cho truy vấn đó. - Truy vấn cơ sở dữ liệu vector để tìm các embeddings tài liệu "tương đồng" nhất với embedding truy vấn. Sự tương đồng thường được tính bằng các chỉ số khoảng cách như cosine similarity.
- Truy xuất các đoạn văn bản gốc tương ứng với các tương đồng cao nhất.
- Khi người dùng gửi truy vấn, sử dụng
Ví dụ mã thực tế: Tìm kiếm ngữ nghĩa trong bộ nhớ
Dưới đây là ví dụ với một vector store trong bộ nhớ (in-memory), tập trung vào logic nhúng và tương đồng cốt lõi. Đối với hệ thống sản xuất thực tế, bạn nên tích hợp với các cơ sở dữ liệu vector chuyên dụng như Pinecone, Weaviate hoặc ChromaDB.
import { NeuroLink, ProviderFactory, InMemoryVectorStore } from "@juspay/neurolink";
// 1. Chuẩn bị tài liệu của bạn
const articles = [
{ id: "article1", text: "NeuroLink đơn giản hóa tích hợp AI trên 13 nhà cung cấp." },
{ id: "article2", text: "Vector embeddings cho phép tìm kiếm ngữ nghĩa bằng cách nắm bắt ý nghĩa." },
{ id: "article3", text: "Lifecycle hooks trong hệ thống middleware của NeuroLink quản lý các sự kiện AI." },
{ id: "article4", text: "Xây dựng ứng dụng phản ứng với kiến trúc AI hướng sự kiện." },
{ id: "article5", text: "Tầm quan trọng của theo dõi chi phí và phân tích trong ứng dụng AI." },
];
async function buildSemanticSearchEngine() {
const embedProvider = await ProviderFactory.createProvider("openai");
const vectorStore = new InMemoryVectorStore(); // Để đơn giản, dùng in-memory
// 2. Tạo embeddings và lập chỉ mục tài liệu
console.log("Đang lập chỉ mục tài liệu...");
const textsToEmbed = articles.map((a) => a.text);
const embeddings = await embedProvider.embedMany(textsToEmbed);
const documentNodes = articles.map((article, index) => ({
id: article.id,
vector: embeddings[index],
metadata: { text: article.text },
}));
await vectorStore.upsert("docs_index", documentNodes); // Lưu embeddings vào một index
console.log("Đã lập chỉ mục tài liệu thành công.");
// Hàm thực hiện tìm kiếm ngữ nghĩa
async function semanticSearch(query: string, topK: number = 2) {
console.log(`Tìm kiếm: "${query}"`);
const queryVector = await embedProvider.embed(query);
// 3. Truy vấn vector store để tìm tài liệu tương đồng
const searchResults = await vectorStore.query("docs_index", queryVector, topK);
console.log("Kết quả hàng đầu:");
searchResults.forEach((result, i) => {
console.log(
` ${i + 1}. Điểm số: ${result.score.toFixed(4)}, Văn bản: "${result.metadata.text}"`
);
});
return searchResults;
}
// 4. Kiểm tra công cụ tìm kiếm ngữ nghĩa
await semanticSearch("Làm sao để kết nối nhiều dịch vụ AI?");
await semanticSearch("Kể cho tôi nghe về các sự kiện ứng dụng trong AI.");
}
buildSemanticSearchEngine().catch(console.error);
Tích hợp với quy trình RAG
Tính năng rag của NeuroLink đơn giản hóa toàn bộ quá trình bằng cách tự động xử lý việc chia nhỏ tài liệu, tạo embeddings và tìm kiếm tương đồng. Khi bạn sử dụng rag: { files } trong neurolink.generate() hoặc neurolink.stream(), nó minh bạch tận dụng embed() và embedMany() dưới bức ảnh để xây dựng ngữ cảnh cho mô hình AI của bạn.
import { NeuroLink } from "@juspay/neurolink";
const neurolink = new NeuroLink();
// NeuroLink tự động xử lý embedding và truy xuất cho RAG
const result = await neurolink.generate({
input: { text: "Lợi ích của AI hướng sự kiện là gì?" },
rag: {
files: ["./my-event-driven-ai-guide.md", "./middleware-patterns.pdf"], // Tài liệu của bạn
chunkSize: 512,
topK: 3,
},
});
console.log(result.text); // Phản hồi AI được thông tin bởi tìm kiếm ngữ nghĩa từ file của bạn
Kết luận
Tìm kiếm ngữ nghĩa là một bước ngoặt cho việc xây dựng các ứng dụng thông minh, vượt xa việc khớp từ khóa để đạt được sự hiểu biết thực sự. NeuroLink, với các phương thức embed() và embedMany() mạnh mẽ, giúp việc tích hợp tạo embeddings vào các dự án TypeScript trở nên vô cùng đơn giản. Cho dù bạn đang xây dựng một quy trình RAG phức tạp hay một công cụ tìm kiếm ngữ nghĩa độc lập, NeuroLink đều cung cấp các công cụ cần thiết để giải phóng toàn bộ tiềm năng của tìm kiếm vector.
NeuroLink — SDK AI toàn năng cho TypeScript
- GitHub: github.com/juspay/neurolink
- Cài đặt:
npm install @juspay/neurolink - Tài liệu: docs.neurolink.ink
- Blog: blog.neurolink.ink — hơn 150 bài viết kỹ thuật
Bài viết liên quan

Phần mềm
Anthropic ra mắt Claude Opus 4.7: Nâng cấp mạnh mẽ cho lập trình nhưng vẫn thua Mythos Preview
16 tháng 4, 2026

Công nghệ
Qwen3.6-35B-A3B: Quyền năng Lập trình Agentic, Nay Đã Mở Cửa Cho Tất Cả
16 tháng 4, 2026

Công nghệ
Spotify thắng kiện 322 triệu USD từ nhóm pirate Anna's Archive nhưng đối mặt với bài toán thu hồi
16 tháng 4, 2026
