Skip to content

RAG实践

RAG经典架构:

数据索引

image-20250528101753546

读取外挂语料库的时候,语料库是一个 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;
}

本节课的实践会用到两个模型:

  1. 在线的 deepseek
  2. 本地模型 nomic-embed-text 用来做向量嵌入

数据查询

image-20250528134121574

余弦相似度计算

/**
* 余弦相似度计算
* @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}`)
}