别让你的大模型一本正经胡说八道了!手把手教你搭一个 RAG 问答系统

举报
yd_286179743 发表于 2026/10/22 13:39:18 2026/10/22
【摘要】 摘要:大模型很强,但它有个致命的毛病——会「幻觉」。你问它一个它没学过的问题,它不会说「我不知道」,反而会一本正经地编一个答案给你。本文用最接地气的方式,带你搞懂 RAG(检索增强生成)的原理,并手把手用代码搭一个能「查资料再回答」的私有知识库问答系统。 一、先说个扎心的场景假设你花大价钱接入了大模型 API,做了一个公司内部的「制度问答机器人」,结果同事问它:「咱们公司的年假是怎么算的?」...

摘要:大模型很强,但它有个致命的毛病——会「幻觉」。你问它一个它没学过的问题,它不会说「我不知道」,反而会一本正经地编一个答案给你。本文用最接地气的方式,带你搞懂 RAG(检索增强生成)的原理,并手把手用代码搭一个能「查资料再回答」的私有知识库问答系统。


一、先说个扎心的场景

假设你花大价钱接入了大模型 API,做了一个公司内部的「制度问答机器人」,结果同事问它:

「咱们公司的年假是怎么算的?」

它回答得头头是道、条理清晰,唯一的问题——全是编的。公司根本没有这个制度,它把网上看过的某家公司的规定安到了你头上。

这就是大模型的「幻觉」(Hallucination):模型不是故意骗你,而是它的知识截止到训练那一刻,训练完之后发生的事、你们公司内部的私密信息,它根本不知道,但它的机制又决定了它「必须给出一个像样的答案」。

于是,一本正经地胡说八道,就这么发生了。


二、RAG 到底是什么?

RAG,全称 Retrieval-Augmented Generation(检索增强生成)。别被英文名唬住,拆开看就三件事:

  1. Retrieval(检索):先从你的知识库里,把跟问题相关的内容「搜」出来。
  2. Augmented(增强):把这些搜出来的资料,作为「参考答案」塞进提示词里。
  3. Generation(生成):让大模型基于这些真实资料来回答,而不是凭空编。

一句话总结:让大模型「开卷考试」,而不是「闭卷瞎编」。

一张图看懂区别:

❌ 传统问答(闭卷):  用户问题 ──► 大模型 ──► 答案(可能瞎编)

✅ RAG 问答(开卷):
   用户问题 ──► 检索 ──► 找到相关文档片段
                            │
                            ▼
              大模型 + 文档片段 ──► 答案(有据可查)

三、一个最小可跑的 RAG 系统

原理讲完了,下面直接上代码。我们用 Python + 几个常用库,搭一个能跑的最小系统。

3.1 准备数据:把文档切成小段

RAG 的第一步是把你的资料(Word、PDF、Markdown 都行)切成一小段一小段(chunk),方便检索时精准匹配。

# 把长文档切分成带重叠的小块
def split_text(text, chunk_size=500, overlap=50):
    chunks = []
    start = 0
    while start < len(text):
        end = start + chunk_size
        chunks.append(text[start:end])
        start = end - overlap  # 保留一点重叠,避免句子被切断
    return chunks

with open("公司制度.txt", "r", encoding="utf-8") as f:
    doc = f.read()

chunks = split_text(doc)
print(f"文档被切成了 {len(chunks)} 个小段")

3.2 向量化:让机器「看懂」文字

计算机不能直接比两个句子的意思,所以我们要把文字转成「向量」(一串数字),意思相近的句子,向量在空间里也离得近。这一步叫 Embedding。

from sentence_transformers import SentenceTransformer

# 加载一个中文友好的向量模型
model = SentenceTransformer("BAAI/bge-small-zh-v1.5")

# 把所有小段转成向量
embeddings = model.encode(chunks, normalize_embeddings=True)
print("向量化完成,维度:", embeddings.shape)

3.3 建索引:存起来方便查

向量存哪?最简单的是用 FAISS,一个向量检索库,几行代码搞定:

import faiss
import numpy as np

dim = embeddings.shape[1]
index = faiss.IndexFlatIP(dim)  # 内积相似度
index.add(embeddings.astype("float32"))
print(f"索引已建好,共 {index.ntotal} 条")

3.4 检索 + 生成:把答案「拼」出来

最后一步,用户提问 → 检索最相关的几段 → 塞给大模型回答:

def rag_answer(question, top_k=3):
    # 1. 把问题也转成向量
    q_vec = model.encode([question], normalize_embeddings=True)
    
    # 2. 检索最相关的 top_k 个文档片段
    scores, idxs = index.search(q_vec.astype("float32"), top_k)
    retrieved = [chunks[i] for i in idxs[0]]
    
    # 3. 拼成提示词,交给大模型
    context = "\n\n".join(retrieved)
    prompt = f"""请根据以下资料回答问题,如果资料中没有相关信息,请直接回答"资料中未找到相关内容"。

【资料】
{context}

【问题】
{question}

【回答】"""
    
    # 这里调用你的大模型(以华为云盘古 / 其他大模型 API 为例)
    answer = call_llm(prompt)  # 替换成你的实际调用逻辑
    return answer

print(rag_answer("公司年假是怎么算的?"))

到这里,一个最小可用的 RAG 问答系统就搭起来了。核心逻辑不过几十行代码。


四、几个避坑建议

RAG 虽然思路简单,但真正落地时,有几个坑要提前想清楚:

坑 现象 建议
切分太随意 检索出来的片段断章取义 按语义切分,保留重叠,控制 chunk 大小
向量模型选错 检索结果驴唇不对马嘴 中文场景优先选 bge、m3e 等中文模型
只检索一段 答案不完整 多召回几段(top_k=3~5)再让模型综合
模型不认资料 还是继续瞎编 提示词里明确写「资料中没有就直说」
知识库更新 新资料查不到 定期重建索引,或做增量更新

五、进阶方向(附华为云方案)

如果你的场景变复杂了,手动拼向量索引会越来越吃力。这时可以考虑用现成的平台能力,比如华为云的 ModelArts / MaaS 就提供了一站式的 RAG 与知识库服务,把「切分、向量化、检索、大模型调用」整条链路都封装好了,你只需上传文档、配置大模型即可,省去大量工程细节。

当然,不管用自建还是平台,RAG 的核心思想是不变的:让模型在有依据的前提下回答,这是把大模型从「玩具」变成「可靠生产工具」的关键一步。


六、写在最后

大模型的幻觉问题,短期内很难根治。但 RAG 给了我们一条非常务实的路:既然它记不住,就每次现查现答。

希望这篇能帮你把「一本正经胡说八道」的模型,变成「有据可查」的靠谱助手。如果你在搭建过程中遇到问题,欢迎在评论区交流,我们一起把它调好。


标签:#AI #大模型 #RAG #检索增强生成 #知识库 #ModelArts

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。