RAG & Top-K 檢索概論:使用 Text Embedding
.作者:Jollen/
.日期:Fri Nov 14 2025 09:00:00 GMT+0900 (日本標準時間)
語意關聯-以向量距離排序
有了「語意空間」與「距離」的觀念後,就可以實際打造一個語意搜尋系統,方式如下:
- 先將查詢句向量化;
- 計算查詢與資料庫中所有向量的餘弦相似度;
- 挑選出相似度最高的前 K 筆結果。
上述過程就稱為 Top-K 檢索,這是 RAG 系統中「語境擷取(Context Retrieval)」的第一步。舉例來說,若查詢「退貨流程」,RAG 資料庫會自動挑出語意最接近的句子,如「退款規則」、「商品退換申請」。接著,這些句子將作為 LLM 的參考語境輸入,協助模型生成更準確的回答。
前一篇文章的 semantic-fill-suggestion.js 範例,其實就是 Top-K 檢索的最簡化形式(K=1)。以下將此範例,擴充為 Top-K 語意檢索實作,以了解 RAG 資料庫的基本原理:
// src/examples/topk-semantic-search.js
import OpenAI from 'openai';
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
// 餘弦相似度函式
function cosineSimilarity(a, b) {
const dot = a.reduce((s, v, i) => s + v * b[i], 0);
const norm = Math.sqrt(a.reduce((s, v) => s + v * v, 0)) * Math.sqrt(b.reduce((s, v) => s + v * v, 0));
return dot / norm;
}
async function main() {
const query = '退貨流程';
const documents = [
'商品可於十四天內申請退款。',
'若商品有瑕疵,可於七日內辦理退貨。',
'若地址填寫錯誤,可能導致運送延遲。',
'如何申請售後服務?',
'出貨前可修改訂單內容。'
];
// 生成 Embedding 向量(查詢 + 文件集)
const { data } = await client.embeddings.create({
model: 'text-embedding-3-small',
input: [query, ...documents]
});
const queryVector = data[0].embedding;
const docVectors = data.slice(1).map(d => d.embedding);
// 計算相似度
const results = documents.map((text, i) => ({
text,
score: cosineSimilarity(queryVector, docVectors[i])
}));
// 按相似度排序,取前 K 筆
const K = 3;
const topK = results.sort((a, b) => b.score - a.score).slice(0, K);
console.log(`\n查詢:「${query}」`);
console.log(`Top-${K} 語意相似結果:`);
topK.forEach(r => {
console.log(`${r.text} → 相似度:${r.score.toFixed(3)}`);
});
}
main();
執行結果:
查詢:「退貨流程」
Top-3 語意相似結果:
出貨前可修改訂單內容。 → 相似度:0.474
商品可於十四天內申請退款。 → 相似度:0.441
若商品有瑕疵,可於七日內辦理退貨。 → 相似度:0.435
此範例,同樣以相同的 Text Embedding 技術,實作完整的 Top-K 語意檢索。執行結果顯示「退貨流程」,與以下句子最相似:
- 出貨前可修改訂單內容。
- 商品可於十四天內申請退款。
- 若商品有瑕疵,可於七日內辦理退貨。
若以「AI 客服小助手」的應用程式來說,當使用者提問為「退貨流程」相關問題時,我們就可以主動回應上述句子。
這就是 Top-K 檢索在「語境」搜尋的重要角色:以距離衡量語意間的關聯,先以相似度來排序後挑選出最適語境。
Also read
Tags: rag, llm, text-embedding, top-k