[GenAI] RAG实践
RAG经典架构:
数据索引

读取外挂语料库的时候,语料库是一个 pdf 文件,需要一个额外的依赖:pdf-parse
转化为向量嵌入:nomic-embed-text
function getEmbedding(text) {
const res = await fetch("http://localhost:11434/api/embeddings", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "nomic-embed-text",
prompt: text,
}),
});
const result = await res.json();
return result.embedding;
}
本节课的实践会用到两个模型:
- 在线的 deepseek
- 本地模型 nomic-embed-text 用来做向量嵌入
数据查询

余弦相似度计算
/**
* 余弦相似度计算
* @param {*} vecA
* @param {*} vecB
* @returns
*/
function cosineSimilarity(vecA, vecB) {
const dot = vecA.reduce((sum, val, i) => sum + val * vecB[i], 0);
const normA = Math.sqrt(vecA.reduce((sum, val) => sum + val * val, 0));
const normB = Math.sqrt(vecB.reduce((sum, val) => sum + val * val, 0));
return dot / (normA * normB);
}
根据阀值判断是否使用外挂知识库
let userMessage = question;
// 严格判断:要求所有文档的得分都大于阈值
const allDocsRelevant =
relevantDocs.length > 0 &&
relevantDocs.every((doc) => doc.score > RELEVANCE_THRESHOLD);
if (allDocsRelevant) {
console.log(
`✅ 知识库相关 - 所有文档得分都超过阈值 ${RELEVANCE_THRESHOLD}`
);
console.log(
` 文档得分: [${relevantDocs
.map((doc) => doc.score.toFixed(3))
.join(", ")}]`
);
// 将相关的知识库内容添加到用户问题中
const relevantContent = relevantDocs
.filter((doc) => doc.score > RELEVANCE_THRESHOLD)
.map((doc) => doc.content)
.join("\n\n");
userMessage = `参考以下资料回答问题:
${relevantContent}
问题:${question}`;
} else {
const failedDocs = relevantDocs.filter(
(doc) => doc.score <= RELEVANCE_THRESHOLD
);
console.log(`❌ 知识库不相关 - 有${failedDocs.length}个文档得分不足`);
console.log(
` 文档得分: [${relevantDocs
.map((doc) => doc.score.toFixed(3))
.join(", ")}]`
);
console.log(` 阈值要求: ${RELEVANCE_THRESHOLD}`);
}