ARTICLE · 1153907
我把公司文档喂给AI,它开始胡说八道
我说这不用训练,喂进去就行。
结果喂完上线,机器人答得比没喂之前还离谱。用户问"保修期多久",它把"七天无理由"和"延保服务"两段揉一起,答了个"七天保修"。
我盯着屏幕想了半天:资料我不是给它了吗,它怎么还瞎编。
(上回聊的是后端转 AI 哪些经验得扔掉,结尾说下篇讲 RAG。这就是。没看过前面也没关系,你只要知道一件事——大模型自己记不住你公司的事。它没见过你们的文档,你问它"我们的退货政策是啥",它只能编。)
先说个反常识的
大模型不是数据库。
你往里塞东西,它不会存起来。每次你问它,它只带着"训练时见过的东西"回答你。你们公司的文档,它一个字都没见过。
所以想让机器人知道你们公司的事,只有两条路。
一条是训练(fine-tune),把知识压进模型里。贵、慢,而且文档一改就得重来。
另一条就是今天要聊的 RAG:别让它记,让它现场查。
查完,把查到的几段塞进问题里,一起发过去。它看着这几段材料,再组织答案。
说白了,RAG 就是给大模型配个外挂资料库,问之前先去库里翻一下。
那这事在哪儿见过?你天天在做。
拆开看,就是一次带缓存的查询
你回想一个普通的查数据的活:
用户传个关键词 → 先查缓存 → 缓存没有就查库 → 结果拼成页面返回。
RAG 一模一样,只是每一步换了个名字。
最后那一步,就是"缓存没命中,去库里查,查回来塞进结果"那个你写了十年的动作。
所以我一看到 RAG 的流程图就觉得眼熟——它不是什么新架构,骨架就是一次查询。
唯一的差别:key 是"意思",不是"字面"
上面那张表,最后一行看着跟普通查询没区别。
真正不一样的地方在这儿:缓存找的是"一样",RAG 找的是"像"。
缓存的 key 你写 `user:1001:order`,命中就是命中,差一个字符都不算。
RAG 不认字面。用户打"退款",文档里写的是"退钱",在它眼里这俩挨着。
你说"我的东西能退吗",它不跟你比对字符串,它算的是"这个问题跟哪些段落意思最近"。
这就带出一个缓存里没有的问题:命中率好办,命中"对"很难。
缓存命中错了,最多是数据旧;RAG 命中错了,模型就拿着一段不相关的话,一本正经给你编答案。
我那次"七天保修"就是这么来的。"保修期多久"和"七天无理由"在向量空间里靠得近,检索把它捞出来了,模型看着这段材料,硬着头皮答了。
(说白了,检索这一步的目标不是"找到唯一正确答案",是"捞回几张可能相关的参考"。你原来那套是精确匹配,现在这个更像 `like %关键词%`——只不过比的不是字符,是意思。)
我踩的坑:切分
我一开始以为,PDF 丢进去就算喂好了。
不是。真正决定效果的,是你怎么切。
三百页文档,切成一页一段,一次检索拉回一整页,模型得从一整页里找那两句话,噪声太大。
切成一句话一段,上下文又被切断了,模型拿到的全是半截话。
我第一版就是按固定字数每 500 字砍一刀。结果正好把"保修期"那张表的表头和内容砍进两段里。你说那还查个啥。
这一步跟建索引一模一样。 索引建在错的字段上,查询再怎么优化都白搭。切分切歪了,后面检索、排序、生成全废。
这块我现在也只敢说摸到了门,还在调。等调顺了,专门写一篇讲怎么切。
到这儿,认知就够用了
一句话收:RAG 不神秘。它就是"问模型之前,先按意思去资料库翻几段相关的,塞给它当参考"。
能带过来的老本行是三样:
把资料组织好——切分、建索引那一套 承认它查不准,所以得留"查不到"和"查错了"的兜底 那几步的延迟、成本、缓存,还是你原来那本账
下个阶段,我要拿代码把这条链路真正跑起来。绕不过去的第一件事是:怎么让 Java 发出第一个请求。这就是下篇。
先问个真想知道的:你们手上那堆文档,现在是咋给模型的? 直接全塞进 prompt、接了个向量库、还是压根还没开始做?
评论区说一声。全塞进去的那批兄弟,我想问问你们扛得住多少页。
下篇:Spring AI 跑通第一个请求,从建项目到出结果,一段不跳。