RAG消除AI幻觉:Spring Boot实战教程

2026-06-24阅读 0热度 0
技术原理

之前聊了AI的起源和基础认知,有朋友留言说:

“这些我都懂,我现在的问题是——AI为什么老是胡说?”

这个问题问得很实在。如果你在做AI项目,多半已经被它坑过——明明文档里没有的内容,它能给你编一套完整方案;同一个问题,每次答案还不一样;有时候甚至“自信满满地错”。一开始以为是模型不行,后来才发现——问题根本不在模型,而在于你怎么用它。

这篇不讲概念,直接讲一个你必须搞懂的东西:

RAG(检索增强生成)


一、AI产生幻觉的根源

要理解RAG,得先摸清大模型的本质:它本质不是“查资料”,而是“生成文本”。你问它问题,它不是去数据库查答案,而是根据训练过的数据,“猜一个最像答案的话”。注意,这里说的是“猜”——可能不准确,但好理解。根据训练数据,预测“在当前上下文中最有可能出现的下一个词”(Next Token Prediction)。

这种预测带来一个很现实的问题:不管是公司还是个人,很多资料是不能在互联网上公开的——它不知道你公司的接口文档,不知道你的业务逻辑,更不知道你的私有数据。那它怎么给你答案?它只能“合理地编”。这就是我们常听到的:幻觉(Hallucination)。

而且越是表达能力强的模型,越会编,而且编得越像真的。例如你的代码这样写:

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
public class HallucinationDemo {
 public static void main(String[] args) {
 ChatLanguageModel model = OpenAiChatModel.builder()
 .apiKey("YOUR_API_KEY")
 .modelName("gpt-4o-mini")
 .build();
 String question = "我们公司内部接口 /api/internal/pay/v2 的调用流程是什么?";
 String answer = model.generate(question);
 System.out.println(answer);
 }
}

AI回答得有板有眼,语气非常自信,结构非常完整,看起来“完全正确”。

接口 /api/internal/pay/v2 的调用流程如下:
1. 用户鉴权(Token校验)
2. 参数校验(金额、订单号等)
3. 调用支付服务
4. 返回支付结果

但很明显,这不是我们要的答案——模型本就不知道答案,但必须生成一个“像答案的东西”。它其实是在套模板:“接口调用流程通常是这样”,然后拼一个“合理答案”。


二、RAG到底在解决什么问题?

换个角度。如果是你自己回答一个问题,你会怎么做?比如有人问你:“我们系统A的接口调用流程是什么?”你的第一反应肯定不是“开始编”,而是先去翻文档。而RAG做的事情,和你的反应一模一样:让AI也“先查资料,再回答”。换句话说:RAG = 给AI装一个“可搜索的知识库”。


三、RAG其实很简单

RAG的架构图类似这样:

看起来很复杂,但其实你只要记住下面这个就够了:

  • 第一步:把知识“存进去”
  • 第二步:用户提问时,先去“找相关内容”
  • 第三步:把“资料 + 问题”一起丢给AI

关于第一步,如何把知识存进去。你需要做三件事:

  1. 把文档切成一小段一小段(chunk)
  2. 把每一段转成向量(embedding)
  3. 存进数据库(向量库)

你可以把这个步骤理解为:把“文字”变成“可计算的坐标”。那么,为什么需要把文档切成一小段一小段?不切chunk,检索就不准;检索不准,AI一定胡说。

假设你有一份文档:

《系统设计文档》
- 用户登录流程
- 支付流程
- 订单系统
- 消息队列
- 接口A说明
- 接口B说明

你整篇直接丢进向量库。然后用户问:“接口A怎么调用?”向量检索会发生什么?它会拿“整篇文档”去做相似度计算。问题来了:文档里包含一堆无关内容(登录、支付、订单…),“接口A”只是其中一小部分。最终结果就是:相似度被“稀释”了——要么查不到(分数不够),要么查到一堆无关内容。

为什么切chunk就好了?把刚才那份文档拆开:

chunk1:用户登录流程
chunk2:支付流程
chunk3:接口A说明
chunk4:接口B说明

再问同样的问题:“接口A怎么调用?”这次会发生什么?检索系统会把问题转成向量,和每个chunk分别算相似度。结果:chunk3(接口A)会被精准命中。本质变化:从“一整本书参与匹配”变成“一小段一小段精确匹配”。

再说一个比较关键的点:大模型是有上下文长度限制的,比如4k/8k/128k token。如果不切chunk,你可能会把一整篇文档塞进去,结果要么超长直接截断,要么成本爆炸。chunk的作用之一就是:控制输入长度 + 提高信息密度。chunk本质是让向量搜索具备“段落级命中能力”。


第二步:用户提问时,先去“找相关内容”。用户问:“接口A怎么调用?”系统不会直接问AI,而是先做一件更重要的事:去向量数据库里找“最像这个问题的几段内容”。

EmbeddingStore store = PgVectorEmbeddingStore.builder()
                .datasource(getDataSource())
                .table("knowledge")
                .dimension(1536)
                .build();

EmbeddingModel embeddingModel = getEmbeddingModel();

ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
                .embeddingStore(store)
                .embeddingModel(embeddingModel)
                .maxResults(3)
                .minScore(0.7)
                .build();

        String question = "接口A怎么调用?";

        List contents = retriever.retrieve(question);

        System.out.println("==== 检索结果 ====");
        for (Content content : contents) {
            System.out.println(content.textSegment().text());
            System.out.println("------------------");
        }

第三步:把“资料 + 问题”一起丢给AI。

String question = "接口A怎么调用?";

String context = contents.stream()
                .map(Content::textSegment)
                .map(segment -> segment.text())
                .reduce("", (a, b) -> a + "n" + b);

String prompt = String.format("""
                你是企业内部AI助手,请严格根据“资料”回答问题。
                如果资料中没有相关信息,请回答:“无法确定”,不要编造。

                ===== 资料 =====
                %s

                ===== 问题 =====
                %s

                ===== 输出要求 =====
                - 只基于资料回答
                - 不允许编造
                - 不确定就说无法确定
                """, context, question);

ChatLanguageModel model = OpenAiChatModel.builder()
                .apiKey("YOUR_API_KEY")
                .modelName("gpt-4o-mini")
                .build();

        String answer = model.generate(prompt);
        System.out.println("==== AI回答 ====");
        System.out.println(answer);
    }
}

这一步非常关键。最终给模型的,不是“请回答这个问题”,而是“基于以下资料回答,不要乱编”。你可以理解为:你在“喂答案范围”,而不是让它自由发挥。


五、演示

当我不上传任何文档的时候

我上传一个文档,里面描述了马明聪是谁


六、踩过的几个坑

这部分你一定会遇到。

chunk切分不合理。一开始直接按整段文档丢进去,结果查出来的内容完全不相关。后来改成200~500字一段,效果明显提升。

相似度阈值乱设。.minScore(0.7)这个值没有标准答案,但你要知道:太高→查不到内容,太低→垃圾内容混进来。最好的办法:自己打印日志调试。

以为用了RAG就不会胡说。这是一个大坑。现实是:RAG只能减少胡说,不会消灭。如果你检索不准、prompt没约束、数据本身有问题,那AI照样乱来。

忽略metadata过滤。比如你有多个系统、多个版本,但你不加过滤条件,AI会把A系统的答案用在B系统上。


七、你现在应该有一个新认知

很多人以为:做AI应用 = 调一个大模型API。但真实情况是:模型只占20%,剩下80%是工程问题,包括数据怎么处理、检索怎么做、prompt怎么设计。


你只记住一句话:RAG不是技术名词,而是一种“让AI不胡说的工程手段”。

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策