RAG-把文档向量化实现语义搜索
# RAG:把文档向量化,实现语义搜索
大模型的知识来自训练数据,问它不知道的东西,它不会说不知道,而是胡编 — 这就是幻觉。
解决思路很直觉:用户提问时,先从知识库里查出相关文档,塞到 prompt 里当背景知识,再让大模型回答。
这就是 RAG — Retrieval(检索)Augmented(增强)Generation(生成)。
# 核心问题:怎么查?
关键词搜索太弱,搜"东东和光光怎么成为朋友的",不可能靠关键词匹配到。需要的是语义搜索。
做法是把文档转成向量(Embedding),用余弦相似度算相关性。
# 向量化(Embedding)
用嵌入模型把文本转成高维向量,语义相近的文本向量距离近、夹角小。
pnpm install @langchain/classic
import { OpenAIEmbeddings } from '@langchain/openai';
import { MemoryVectorStore } from 'langchain/vectorstores/memory';
import { Document } from '@langchain/core/documents';
// 嵌入模型(比大模型便宜很多)
const embeddings = new OpenAIEmbeddings({
apiKey: process.env.OPENAI_API_KEY,
model: process.env.EMBEDDINGS_MODEL_NAME, // text-embedding-v3
configuration: { baseURL: process.env.OPENAI_BASE_URL },
});
# 存入向量数据库
const documents = [
new Document({
pageContent: '光光是一个活泼开朗的小男孩,最喜欢踢足球...',
metadata: { chapter: 1, character: '光光', type: '角色介绍' },
}),
new Document({
pageContent: '东东是光光最好的朋友,安静而聪明,喜欢读书和画画...',
metadata: { chapter: 2, character: '东东', type: '角色介绍' },
}),
// ...更多文档
];
// 文档向量化 → 存入内存向量数据库
const vectorStore = await MemoryVectorStore.fromDocuments(documents, embeddings);
每个文档转成向量时,元信息(来源、章节等)会一起保存。
# 检索 + 生成
// 创建检索器,返回最相似的 3 个文档
const retriever = vectorStore.asRetriever({ k: 3 });
const question = '东东和光光是怎么成为朋友的?';
// 语义检索
const docs = await retriever.invoke(question);
// 也可以拿到相似度分数
const scoredResults = await vectorStore.similaritySearchWithScore(question, 3);
// 把检索到的文档拼成上下文,增强 prompt
const context = docs.map((doc, i) => `[片段${i + 1}]\n${doc.pageContent}`).join('\n\n');
const prompt = `基于以下故事片段回答问题,如果没提到就说不知道。
故事片段:
${context}
问题: ${question}`;
const response = await model.invoke(prompt);
# 完整流程
文档 → 嵌入模型 → 向量化 → 存入向量数据库
↑
用户提问 → 嵌入模型 → 向量化 → 语义检索 → 拿到相关文档
↓
塞进 prompt 当背景知识
↓
大模型生成回答
# 要点
- 不是关键词匹配,是语义匹配 — 靠向量的余弦相似度(夹角大小)算相关性
- 嵌入模型很便宜 — 专门做向量化的模型,比大模型便宜得多
- metadata 要写好 — 向量的元信息记录了来源文档,方便追溯
- k 值控制召回量 —
asRetriever({ k: 3 })返回最相似的 3 个文档
编辑 (opens new window)
上次更新: 2026/06/09, 01:51:57