Logo
返回列表

从零实现一个 RAG 系统:切分、检索、重排与防幻觉

2026 年 07 月 20 日 1 分钟阅读 302 次浏览
从零实现一个 RAG 系统:切分、检索、重排与防幻觉

RAG 解决什么问题

大模型的知识截止于训练时间,也不了解你的私有数据。RAG(检索增强生成)的思路很直接:先从知识库里检索相关片段,再把它们塞进 Prompt 让模型基于事实回答。它比微调更轻、更新更快、可溯源。

最小可用架构

文档 → 切分(chunk) → 向量化(embedding) → 存入向量库

用户提问 → 向量化 → 相似度检索 → Top-K 片段 → 拼进 Prompt → LLM 生成

一、文档切分

切分粒度直接影响召回质量。经验值:

  • 每块 300~800 tokens,块间重叠 10~15%(保留上下文连续性)。
  • 优先按语义边界切(标题、段落),而不是硬按字数切断句子。
function chunk(text: string, size = 500, overlap = 60): string[] {
  const chunks: string[] = [];
  for (let i = 0; i < text.length; i += size - overlap) {
    chunks.push(text.slice(i, i + size));
  }
  return chunks;
}

二、向量化与存储

用 embedding 模型把文本转成向量,存进向量数据库(pgvector、Qdrant、Milvus 等):

const res = await embeddings.create({
  model: "text-embedding-3-small",
  input: chunks,
});
// 将 res.data[i].embedding 与原文一起写入向量库

三、检索与重排

朴素相似度检索会有噪声。生产级 RAG 常加一步 rerank

  1. 向量检索召回 Top-20(粗排,快)。
  2. 用 rerank 模型对 20 条精排,取 Top-5(准)。

四、拼 Prompt 的纪律

const prompt = `请仅依据下面的资料回答问题,若资料不足请回答"不确定"。

资料:
${topChunks.map((c, i) => `[${i + 1}] ${c.text}`).join("\n\n")}

问题:${question}`;

关键约束:“仅依据资料” + “不足就说不知道”,能显著降低幻觉。

常见坑

  • 切太碎:单块信息不完整,模型拼不出答案。
  • 不 rerank:召回里混入不相关片段,干扰生成。
  • 不给引用:无法溯源,用户无法验证。让模型输出 [编号] 引用。
  • 忽略元数据过滤:先按时间/权限过滤,再做向量检索,效果和安全性都更好。

RAG 不是"接个向量库"这么简单,切分、重排、Prompt 约束每一步都在和"幻觉"作斗争。

评论区未配置

.env 中设置 PUBLIC_WALINE_SERVER_URL 即可启用 Waline 评论。