在大模型应用落地过程中,很多开发者都会遇到一个问题:模型本身很强,但在具体业务场景里,仍然经常出现回答不准确、知识过时、无法引用来源、无法处理企业私有数据等情况。

例如:

用户问:我们公司的售后政策是什么?
模型回答:根据一般情况,售后政策通常包括退换货、维修、质保等。

这个回答看起来合理,但并没有真正基于企业内部文档回答。对于企业级 AI 应用来说,这类“泛泛而谈”的回答并不能满足实际使用需求。

为了解决这个问题,RAG,也就是 Retrieval-Augmented Generation,检索增强生成,成为当前大模型应用中非常重要的一种技术架构。

简单来说,RAG 的核心思想是:不要让大模型完全依赖参数记忆,而是在回答问题前,先从外部知识库中检索相关内容,再让模型基于检索结果生成答案。


一、为什么大模型需要 RAG?

大模型本身具备很强的语言理解和生成能力,但它也存在几个天然限制。

第一,知识存在时效性问题。模型训练完成后,参数中的知识不会实时更新。如果用户问的是最新政策、公司最新产品、最新技术文档,模型很可能无法准确回答。

第二,模型无法天然访问企业私有数据。企业内部的合同、SOP、产品手册、销售话术、项目资料、客户案例,并不会自动进入模型参数。

第三,模型容易产生幻觉。所谓幻觉,就是模型在没有足够依据的情况下,生成看似合理但实际错误的内容。

第四,模型回答缺少可追溯来源。在很多业务场景中,用户不只需要一个答案,还需要知道这个答案来自哪份文档、哪一页、哪一段。

RAG 的作用,就是在模型生成答案之前,引入一个外部知识检索环节,让模型“先查资料,再回答”。


二、RAG 的基本架构

一个典型的 RAG 系统可以拆成两个阶段:知识入库阶段和问答生成阶段。

知识入库阶段主要负责把原始文档处理成可检索的数据。

原始文档
  ↓
文本解析
  ↓
内容清洗
  ↓
文本切块
  ↓
向量化 Embedding
  ↓
写入向量数据库

问答生成阶段主要负责根据用户问题检索相关知识,并生成答案。

用户问题
  ↓
问题向量化
  ↓
向量检索
  ↓
候选片段召回
  ↓
重排序
  ↓
Prompt 拼接
  ↓
大模型生成答案
  ↓
返回答案与引用来源

从工程实现角度看,RAG 不是单一模型能力,而是一套系统工程。它包含文档处理、向量检索、排序算法、提示词构造、大模型调用、结果评估等多个环节。


三、知识入库:RAG 的第一道质量关

很多 RAG 系统效果不好,并不是模型不够强,而是知识入库阶段处理得不够好。

常见的原始知识来源包括:

PDF 文档
Word 文档
Markdown 文档
HTML 页面
产品手册
FAQ 文档
数据库记录
客服聊天记录
企业制度文件

这些数据通常不能直接丢给向量数据库,而是要经过预处理。

1. 文本解析

不同格式的文档需要不同的解析方式。

例如,PDF 可能存在分页、页眉页脚、表格错乱、图片文字等问题;Word 文档可能包含标题层级、表格、批注;HTML 页面则需要去除导航栏、广告位、脚本代码等无效内容。

如果文本解析质量差,后续检索效果也会受到影响。

例如,原始 PDF 中的内容是:

第一条:产品质保期为一年。
第二条:人为损坏不在质保范围内。
第三条:售后申请需提供购买凭证。

如果解析后变成:

第一条 产品 质保期 为 一年 第二条 人为 损坏 不在 质保
范围 内 第三条 售后 申请 需 提供 购买 凭证

虽然大致还能理解,但结构已经变差。如果表格、编号、标题层级丢失,模型理解会进一步下降。

2. 文本清洗

文本清洗的目标是去掉对检索无意义的噪声。

常见清洗内容包括:

页眉页脚
重复版权声明
导航菜单
无意义空行
乱码字符
重复段落
广告文案
无关链接

例如,一个网页正文如果被解析成这样:

首页 | 产品中心 | 关于我们 | 联系我们
当前位置:首页 > 技术文档
本文介绍 RAG 系统的基本原理……
上一篇:无
下一篇:向量数据库介绍

其中“首页、产品中心、上一篇、下一篇”等信息对问答没有太大帮助,应该在清洗阶段去除。

3. 文本切块

文本切块是 RAG 中非常关键的一步。

因为大模型通常不能一次性处理所有文档,所以需要把长文档切成一个个较小的 chunk,再进行向量化和检索。

常见切块方式包括:

按固定字符数切块
按 token 长度切块
按标题层级切块
按段落切块
按语义边界切块

简单的固定长度切块实现如下:

def split_text(text, chunk_size=500, overlap=100):
    chunks = []
    start = 0

    while start < len(text):
        end = start + chunk_size
        chunk = text[start:end]
        chunks.append(chunk)
        start = end - overlap

    return chunks

这里的 overlap 表示重叠长度。加入重叠可以减少上下文断裂问题。

例如,某个关键解释正好跨越两个 chunk,如果没有重叠,检索结果可能只召回半句话,导致模型无法完整理解。

不过,chunk 并不是越大越好。chunk 太大,会导致一个片段里混入多个主题,检索不够精准;chunk 太小,又容易丢失上下文。

一般来说,技术文档、FAQ、产品说明书可以使用较小 chunk;政策制度、长篇报告类文档可以适当增加 chunk 大小,并保留标题层级。


四、Embedding:把文本转换成向量

RAG 的核心检索能力通常依赖 Embedding。

Embedding 的作用是把文本转换成高维向量,使计算机能够用数学方式衡量文本之间的语义相似度。

例如:

问题:产品质保期多久?
文档片段:本产品自购买之日起享受一年质保。

这两句话表面用词不同,但语义相关。通过 Embedding,它们在向量空间中的距离会比较接近。

一个简化的向量检索过程如下:

query = "产品质保期多久?"

query_vector = embedding_model.encode(query)

results = vector_db.search(
    vector=query_vector,
    top_k=5
)

向量数据库会返回与用户问题语义最接近的若干文档片段。

常见向量相似度计算方法包括:

Cosine Similarity:余弦相似度
Dot Product:点积
Euclidean Distance:欧氏距离

其中余弦相似度比较常见,它关注两个向量方向是否接近,而不是绝对长度。


五、向量数据库:RAG 的检索底座

当文档数量较少时,可以直接在内存里计算向量相似度。但当文档片段达到几十万、几百万甚至更多时,就需要专门的向量数据库。

向量数据库主要解决两个问题:

高维向量存储
近似最近邻检索

常见向量数据库或向量检索方案包括:

FAISS
Milvus
Qdrant
Weaviate
Elasticsearch Vector Search
PostgreSQL + pgvector

一个典型的知识片段入库结构可以设计为:

{
  "id": "doc_001_chunk_003",
  "content": "本产品自购买之日起享受一年质保,人为损坏不在质保范围内。",
  "embedding": [0.012, -0.031, 0.088],
  "metadata": {
    "doc_id": "doc_001",
    "doc_title": "产品售后政策说明",
    "source": "售后政策.pdf",
    "page": 3,
    "chunk_index": 3,
    "updated_at": "2026-06-01"
  }
}

这里除了正文和向量外,metadata 也非常重要。

因为最终回答用户时,系统不仅要给出答案,还要知道答案来自哪里。


六、召回之后为什么还需要重排序?

向量检索返回的 top_k 结果并不一定全部准确。

例如,用户问:

员工试用期离职工资怎么结算?

向量检索可能召回以下内容:

1. 试用期员工工资发放规则
2. 员工离职流程说明
3. 正式员工绩效工资制度
4. 劳动合同签署规范
5. 社保缴纳说明

这些内容都可能和问题有一定相关性,但真正最有价值的可能是前两条。

因此,很多 RAG 系统会在初步召回之后加入 rerank,也就是重排序。

常见流程是:

向量检索召回 top 20
  ↓
重排序模型重新打分
  ↓
选择 top 5
  ↓
拼接到 Prompt

重排序可以提高上下文质量,减少无关内容进入大模型上下文。

如果直接把大量低相关内容塞给模型,模型可能会被干扰,甚至生成错误答案。


七、Prompt 拼接:让模型基于资料回答

检索到相关片段后,需要把它们和用户问题一起拼接成 Prompt。

一个简单的 Prompt 模板如下:

你是一个企业知识库问答助手。
请严格根据【参考资料】回答用户问题。
如果参考资料中没有答案,请回答“资料中未提及”,不要编造。

【参考资料】
资料1:
{chunk_1}

资料2:
{chunk_2}

资料3:
{chunk_3}

【用户问题】
{question}

【回答要求】
1. 回答要准确简洁。
2. 不要使用参考资料之外的信息。
3. 如果涉及制度或政策,请说明依据来自哪条资料。

这个模板的重点是约束模型不要自由发挥,而是基于检索结果回答。

在企业级应用中,Prompt 约束非常重要。否则,模型可能在资料不足时自行补全,从而产生幻觉。


八、RAG 系统常见问题

1. 检索不到正确内容

可能原因包括:

文档没有入库
文本解析失败
切块过大或过小
Embedding 模型不适合当前语言或领域
用户问题和文档表达差异过大
向量数据库 top_k 设置不合理

解决方式包括:

检查原始文档解析结果
优化 chunk 策略
补充同义词和问题改写
调整 top_k 参数
加入关键词检索和混合检索
使用 rerank 模型

2. 检索到了内容,但回答仍然错误

可能原因包括:

Prompt 约束不够
上下文片段过多
多个片段之间存在冲突
模型没有正确理解资料
答案生成时混入了参数知识

解决方式包括:

增强系统提示词约束
减少低相关片段
对文档版本进行管理
要求模型引用依据
对答案进行后处理校验

3. 知识库更新后,答案没有变化

可能原因包括:

新文档没有重新向量化
旧 chunk 没有删除
向量数据库存在重复内容
缓存没有刷新
检索时命中了旧版本文档

解决方式包括:

建立文档版本号
更新时删除旧 chunk
记录 updated_at 字段
检索时优先选择最新版本
增加知识库刷新机制

九、RAG 的评估指标

一个 RAG 系统不能只看“能不能回答”,还要有可量化的评估指标。

常见指标包括:

Recall:是否召回正确文档
Precision:召回内容中有多少是相关的
Answer Accuracy:答案是否准确
Faithfulness:答案是否忠实于参考资料
Citation Accuracy:引用来源是否正确
Latency:整体响应延迟
Cost:单次问答成本

可以设计一个简单的评估数据集:

[
  {
    "question": "产品质保期多久?",
    "expected_doc": "售后政策.pdf",
    "expected_answer": "一年质保"
  },
  {
    "question": "人为损坏能免费维修吗?",
    "expected_doc": "售后政策.pdf",
    "expected_answer": "人为损坏不在免费质保范围内"
  }
]

然后定期跑自动化测试,观察系统升级后效果是否提升。


十、RAG 与微调的区别

很多人容易把 RAG 和模型微调混为一谈。

简单来说:

RAG:让模型查外部资料后回答
微调:改变模型本身的参数或行为模式

RAG 更适合处理:

知识频繁更新
企业内部资料
需要引用来源
需要降低幻觉
需要快速上线

微调更适合处理:

固定任务格式
特定语言风格
特定分类任务
特定领域表达习惯

在实际项目中,RAG 和微调并不是互斥关系。很多企业级 AI 应用会同时使用 RAG 和微调:用 RAG 解决知识问题,用微调或提示词工程解决表达风格和任务稳定性问题。


十一、一个简化版 RAG 伪代码

下面是一个简化版 RAG 流程:

class SimpleRAG:
    def __init__(self, embedding_model, vector_db, llm):
        self.embedding_model = embedding_model
        self.vector_db = vector_db
        self.llm = llm

    def retrieve(self, question, top_k=5):
        query_vector = self.embedding_model.encode(question)
        docs = self.vector_db.search(query_vector, top_k=top_k)
        return docs

    def build_prompt(self, question, docs):
        context = "\n\n".join([
            f"资料{i+1}:{doc.content}"
            for i, doc in enumerate(docs)
        ])

        prompt = f"""
你是一个知识库问答助手。
请严格根据参考资料回答问题。
如果资料中没有答案,请回答“资料中未提及”。

【参考资料】
{context}

【用户问题】
{question}
"""
        return prompt

    def answer(self, question):
        docs = self.retrieve(question)
        prompt = self.build_prompt(question, docs)
        response = self.llm.generate(prompt)

        return {
            "answer": response,
            "sources": [
                {
                    "title": doc.metadata.get("doc_title"),
                    "source": doc.metadata.get("source"),
                    "page": doc.metadata.get("page")
                }
                for doc in docs
            ]
        }

这个伪代码只展示了最核心的流程。真实项目中还需要加入权限控制、日志记录、缓存、异常处理、多轮对话、重排序、引用校验等模块。


十二、RAG 系统工程化需要关注什么?

如果要把 RAG 从 demo 做到生产系统,至少需要关注以下几个方面。

1. 权限控制

企业知识库中可能包含不同权限级别的文档。检索时必须根据用户权限过滤,否则可能出现信息泄露。

例如:

普通员工:只能检索公开制度文档
部门主管:可以检索部门管理文档
财务人员:可以检索财务相关文档
管理员:可以检索全部文档

权限过滤应该发生在检索阶段,而不是生成答案之后。

2. 日志与审计

生产环境中需要记录用户问题、检索结果、生成答案、引用来源、响应时间等信息,便于后续排查问题。

日志结构可以包括:

{
  "user_id": "u_001",
  "question": "试用期离职工资怎么结算?",
  "retrieved_docs": ["doc_001", "doc_008"],
  "answer": "根据资料显示……",
  "latency_ms": 1850,
  "created_at": "2026-06-16 10:30:00"
}

3. 缓存机制

对于高频问题,可以加入缓存,降低模型调用成本和响应延迟。

例如:

相同问题直接返回缓存答案
相似问题复用检索结果
高频 FAQ 预生成答案

但缓存需要注意文档更新问题。如果知识库发生变化,旧缓存需要失效。

4. 答案校验

为了减少幻觉,可以在答案生成后增加校验环节。

例如:

检查答案是否包含参考资料之外的结论
检查引用来源是否真实存在
检查答案中的数字、时间、政策条款是否与原文一致

复杂场景下,还可以再调用一个模型做答案审查。


十三、总结

RAG 是当前大模型应用落地中非常关键的一种技术架构。它不是单纯调用一个大模型接口,而是把文档处理、向量检索、重排序、Prompt 构造和答案生成整合成一套完整系统。

一个高质量的 RAG 系统,关键不在于“模型越大越好”,而在于整个检索链路是否稳定:

文档是否干净
切块是否合理
向量是否准确
召回是否相关
重排序是否有效
Prompt 是否约束清楚
答案是否忠实于资料
引用是否可以追溯

对于企业级 AI 应用来说,RAG 的价值在于让大模型从“凭记忆回答”变成“基于资料回答”。这不仅能提升答案准确性,也能降低幻觉风险,并让 AI 系统真正接入企业自己的知识体系。

未来,随着企业文档、业务系统、知识库和大模型进一步结合,RAG 很可能会成为企业 AI 应用的基础架构之一。

Logo

脑启社区是一个专注类脑智能领域的开发者社区。欢迎加入社区,共建类脑智能生态。社区为开发者提供了丰富的开源类脑工具软件、类脑算法模型及数据集、类脑知识库、类脑技术培训课程以及类脑应用案例等资源。

更多推荐