news 2026/10/22 9:41:26

Spring AI + RAG实战:从PDF解析到电商客服精准问答

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring AI + RAG实战:从PDF解析到电商客服精准问答

先交代一下背景。去年我在某电商平台的技术团队做客服系统智能化改造,老板的要求很朴素:把售后政策、退换货规则、商品使用说明这些散落在PDF文档里的知识,变成客服机器人能直接回答的问题。最初我天真地以为 Chat Completion + 提示词就够了,直到被两个现实问题打脸:一是大模型的训练数据里根本没有我们内部的手册和规则;二是哪怕结构化的商品数据,牵扯到促销叠加、阶梯运费这种多变规则时,模型会一本正经地瞎编。这两板子下来,才老老实实把 Spring AI + RAG 的全链路完整走了一遍。

这篇文章就记录这套电商智能客服从 0 到 1 的搭建过程,重点是 PDF 文档如何一步步变成精准问答的能力,以及中间那些文档里查不到、只有踩过坑才懂的经验。适合正准备做知识库问答、智能客服,或者已经在用大模型但被"幻觉"折磨的团队参考。

1. 为什么电商客服会盯上 RAG

在动手写代码之前,先想清楚一个问题:电商客服的场景有什么特殊性,为什么非得用 RAG,而不是直接调大模型接口?

1.1 传统客服系统与裸大模型的共同困境

传统客服系统大多是基于关键词匹配或者简单的规则引擎:用户说"退货",系统就去匹配"退货"相关的FAQ。这套逻辑在今天已经很难受用——用户一句话里可能有多个意图,比如"我上周买的手机壳和描述不符,能退吗?运费谁出?",这种复合问题放到旧系统里基本就转人工了。

裸上大模型也不行。电商业务的知识是高度私有的:某个大促期间的价保规则、某条产品线的保修条款、不同仓库的运费计算方式,这些信息既不在通用训练语料里,又随时在变。你让大模型自由发挥,它就会一本正经地编造一个看起来合理的退款比例,这在客服场景里就是实际的经济损失。

RAG(Retrieval-Augmented Generation,检索增强生成)解决的核心问题是:把"模型自己记答案"变成"先从自己的知识库里检索证据,再基于证据生成答案"。知识库里的内容是你能控制的,模型只是组织语言的工具。这在电商客服这种对准确性要求高、知识更新快的场景里,是当前最务实的技术路线。

1.2 RAG 和微调的分工与取舍

很多团队一上来就纠结:要不上微调吧?我的建议是,除非你的知识形态非常固定、表达方式高度统一(比如某种标准合同条款),否则不要优先做微调。原因有三:

第一,电商知识变更太频繁。大促规则一个月改一次,微调一次数据的准备、训练、评测周期至少以周计,等你训完,规则又变了。

第二,微调不适合做"事实记忆"。微调擅长的是改变模型的风格、格式、行为模式,而不是往里塞事实。硬塞也行,但会不稳定,而且训练数据里的噪声会被一并记住。

第三,可解释性要求。客服场景一旦产生纠纷,你需要告诉运营"这个答案是依据哪一条规则生成的"。RAG天然有检索来源,可以直接反查证据链,微调做不到这一点。

所以在这个项目里,我的分工策略是:模型用现成的通用大模型,纯粹负责语义理解和语言组织;知识全部走 RAG 检索,模型不新增任何事实记忆。

1.3 Spring AI 在链路中的生态位置

为什么选 Spring AI?因为我们的公司技术栈是 Java / Spring Boot,不可能为了一个客服模块把核心服务换 Python。Spring AI 是 Spring 官方出的 AI 框架,它做的事情和 LangChain 类似:统一了 PDF 解析、文本分割、向量化、向量存储、增强生成这一条链路的 API,并且提供了一套 Spring Boot 风格的配置方式,可以非常自然地融入现有工程。

对我来说最大的价值是两点:一是它把"文档加载-转换-向量化-检索-问答"的每个环节都能用 Java 直接操作,不用混布 Python 服务;二是有统一的抽象层,底层的模型和向量库可以随时切换,这对后续降本或替换模型非常关键。

2. PDF 文档解析:最不起眼但最致命的一环

我们常说 RAG 的瓶颈在召回,召回的瓶颈又往往出在解析这一步。PDF 解析不是把文字抠出来那么简单,一个小细节没处理好,后续整个检索质量都会受到影响。

2.1 电商 PDF 文档的真实形态

先盘点一下我们当时要处理的几种典型 PDF:

  1. 售后政策文件:图文混排,条款分章节,经常带层级序号(1.1、1.2、2.3.1)。
  2. 商品使用说明书:表格密集,比如故障代码表和对应处理方式,还有大量示意图。
  3. 价格与运费说明:数字密集,涉及阶梯价格、区域差异、时间区间。
  4. 少量扫描件:门店提供的纸质盖章规则的扫描版,纯图片。

每一种都有各自的坑。图文混排的主要问题是表格和文字在提取时的顺序错乱;数字密集型文档的问题是数字容易被 OCR 或文本提取搞错;扫描件则是整体上就多一层 OCR 识别成本。

这个阶段我给你的第一个实战建议是:先人工盘一遍知识库,把 PDF 按上面的类型分类,再决定用哪种解析策略。不要指望一种解析方案通吃所有文件。

2.2 解析引擎选型与落地配置

Spring AI 内置了PagePdfDocumentReader,底层用的是 Apache PDFBox,适合处理文本型 PDF。但实际用下来你会发现,PDFBox 对复杂版面、表格、多栏布局的还原能力偏弱,尤其遇到横向文本时经常乱序。

所以我在项目里做了分层处理:

  • 纯文本型 PDF,直接用 Spring AI 的PagePdfDocumentReader,按页读取,简单快速。
  • 复杂版面的 PDF,使用 PDFBox 做了二次处理,抽取文本的同时按坐标块进行重组。这段逻辑如果不想自己写,可以直接引入 Apache Tika 作为补充。
  • 扫描件,先接 OCR 服务转成带坐标的文本层,再走文档读取流程。

如果你遇到的是扫描件较多的情况,建议引入独立的 OCR 服务。我用的是 PaddleOCR 的 Docker 部署版本,通过 HTTP 接口集成到 Java 侧。注意这里有个经验:OCR 的模型要针对电商文档做微调才行,否则"优惠券""价保""退换货"这类词经常被识别成同音字,后面检索时全变噪声。我们初期因为 OCR 识别错误导致一大批关于"价保"的问题找不到答案,排查了很久才发现是"价保"被识别成了"嫁保"。

2.3 文档分割:块大小、重叠度怎么定

把 PDF 解析出的文本进行合理切割,是决定检索召回质量的关键一步。切大了,每个块携带太多无关信息,向量化后主题被稀释,检索相关性下降;切小了,单块信息不完整,模型拿到的上下文不足以回答问题。

Spring AI 里最常用的是TokenTextSplitter。我最终确定的一套参数,可以直接抄:

  • 块大小:600 token
  • 重叠:150 token
  • 分割策略:优先按标题层级、段落边界切分

为什么是 600?因为电商的售后条款往往一段就能说明一个完整规则,600 token 大约能覆盖 300-500 个汉字,刚好装下"条件 + 操作 + 例外"这样的完整逻辑链。重叠 150 token 是为了避免检索时正好落在切割缝隙上,让两个块之间有一个缓冲带。

但这里有一个容易走极端的坑:分割规则完全按字数硬切。如果某个条款标题下有一段很长的解释和一个举例表格,硬切会把表格拆到另外一个块里,导致检索的文章"看不懂表格"。所以我在分割器外层加了一层规则:识别到标题节点时强制结束当前块,新起一个块。这是基于常见实践做的补充,效果非常明显——带章节结构的制度类文档,检索命中率会有明显提升。

2.4 清洗与元数据注入,容易被忽略的细节

解析出来的文本不能直接用,还得经过一道清洗管线。我按下图逻辑处理(这里不画图,描述一下):

  • 去掉页眉页脚:电商文档页眉常有品牌名、文档编号,这些信息在分割后容易被误当成正文内容。
  • 合并断行:PDF 里很多地方是硬换行,段落实际是连续的,合并后才能正确分块。
  • 保留标题层级:把"1.1""1.2"这类标题提取出来,作为元数据存下来,后续能辅助检索。

元数据注入是我强烈建议做的一步。每块文本除了正文,还要附加 documentId、category、title、pageNumber 等字段。这个信息的价值在检索阶段才会显现:同一个问题命中多个块时,可以按来源文档分组去重,避免重复计算同一来源的多个片段;在系统运营阶段,运营可以按 category 快速定位哪一类文档的检索质量出了问题。

3. 向量化与向量存储:构建可检索的知识地基

解析和分割做完了,下一步就是把每块文本变成向量,存进向量数据库。这一步的核心不是"会调用 API",而是选型和参数层面的权衡。

3.1 Embedding 模型怎么选才划算

Embedding 模型的选择直接影响检索效果。但这里我想先破一个迷信:不是模型越贵、维度越高越好。在实际项目里,检索效果和业务场景的相关性要高于模型本身的公认排名。

我的选型逻辑是三条:

  • 中文效果优先:客服语料以中文为主,模型在中文语义上的表现必须实测过。
  • 维度适中:维度越高,占用的存储和检索资源越大。比如把 5 万块文本转成 1536 维向量,对比 768 维,存储差距接近一倍,检索耗时的差距也很显著。
  • 稳定性:模型服务如果是第三方提供,要注意 API 稳定性;如果自建部署,要看显存占用和推理速度。

我们上线第一批用的模型维度是 1536,后来在调优阶段换成了同语义能力但维度更低的模型,向量库的存储成本直接下降,检索耗时也缩短了。这里你需要注意一点:切换 Embedding 模型后,已存在的向量必须重新生成,不能混用。我在项目里是写了一个离线任务,在低峰期全量重新向量化,上线时直接切库。

3.2 向量数据库选型与 Spring AI 的抽象

Spring AI 提供了统一的VectorStore接口,这意味着你在选型上不用一开始就锁死。实际项目里我从SimpleVectorStore起步做 Demo,上线前换成了独立的向量数据库。

到底选哪个?我的建议框架如下:

  • 数据量少于 10 万块、维度适中:用 Redis 的 Vector Set 即可,够用且不需要额外维护组件。
  • 数据量大、检索逻辑复杂:优先考虑专用的向量数据库,原因在于索引结构的效率、并发控制、混合检索能力都会好很多。
  • 有重排序和混合检索需求:需要支持"向量相似度 + 关键词权重"的联合检索能力,这一点不是所有向量库都能优雅支持。

我用的是基于 Docker 部署的一个开源向量库,Spring AI 的依赖里提供了对应的实现,配置一个连接地址就能直接注入VectorStore接口。这个抽象层带来的最大收益是:开发阶段用的是本地临时库,上线架构变化后,只要改依赖和配置,业务代码不需要动。

3.3 插入策略与相似度计算的参数细节

向量化的写入阶段就容易踩坑的是批量插入的阈值。最初我用每批次 100 条插入,5 万条数据跑了很久,而且完整写完后才发现有几批失败,导致部分数据缺失。后来调整成每批次 50 条、失败自动重试三次,并且在结束后做了一次总数对账,确保入库块数和分割出的块数一致。

检索阶段的 Top-K 取值也有讲究。K 太小,容易漏掉关键证据;K 太大,噪声会稀释答案质量。在项目早期,我把 Top-K 设为 5,对应 3000 token 左右。后来为了覆盖更多候选,改成了"先取 Top-K=20,再做重排(Rerank)",效果要好得多——先说粗检索保证召回,再用重排模型精排。重排模型虽然多一层调用,但在售后规则这种强上下文场景下非常值。

此外,相似度阈值一定要设。设一个相似度下限,低于下限的检索结果直接丢弃,不要让模型硬答。我们在调试中发现,用户提问"保修期多久"这种泛化问题,检索出来的片段相似度普遍只有 0.5 左右,直接追问会导致模型拿不相关内容去编。设了 0.65 的阈值之后,这类问题会落到兜底回复,准确率反而上来了。

4. Spring AI 问答链路:把检索结果变成可靠的回答

文档解析、向量化、检索,这些环节做得再好,最终用户体验还是要落到"问答"这一步。Spring AI 在这一层的核心能力是QuestionAnswerAdvisor——它把检索增强的流程封装成了对模型调用的一个"顾问"。

4.1 核心调用流程

问答链路的调用本质上只有几步:接收用户问题,用同一个 Embedding 模型把问题向量化,到向量库检索相似片段,把片段拼进 Prompt,再交给大模型生成答案。Spring AI 把这套流程串得很顺:

  • ChatClient负责管理与大模型的对话。
  • QuestionAnswerAdvisor在调用模型之前,先去向量库检索,把检索结果以参考文档形式塞进 Prompt 的上下文里。

我强烈建议你用 Advisor 机制而不是手写拼接。手写拼接的麻烦在于:Prompt 模板、检索结果格式、多轮历史的处理都散落在业务代码里,改一处就要全链路回归。Advisor 机制把这些都统一在了一条链路中,可以链式叠加多个 Advisor,比如一个做敏感词过滤,一个做检索增强,一个做回答格式约束。

4.2 Prompt 编排:从"角色"到"回答边界"

即便有检索,Prompt 的编排仍然直接影响回答质量。我前后迭代了多个版本,最终沉淀了几个关键原则。

首先是系统提示词里的角色与边界定义。我用的中文模板大致包含:

  • 角色设定:你是电商客服助手,只能依据提供的参考文档回答。
  • 约束:如果参考文档中没有明确信息,必须回答"对不起,我暂时无法从现有资料中找到准确答案,建议转人工客服进一步查询"。
  • 格式要求:回答时优先给出结论,再给出依据摘要。
  • 敏感词策略:涉及个人隐私、支付账号、第三方链接等,一律拒绝回答。

然后是用户问题的上下文增强。在把问题交给模型之前,我会先把用户原问题做一次"意图改写",也就是在检索之前生成一个更适合检索的查询词。这个技巧在电商场景效果尤其明显。比如用户说"我那个手机壳是不是能退啊",直接拿去向量检索效果一般,但改写为"手机壳退货政策"后,召回准确率会好很多。实现方式不复杂:用一次低成本的模型调用,先让模型把问题改写为标准的检索句式,再做向量化检索。

4.3 引用溯源与不可答兜底

客服场景还有一个硬需求:回答要带来源。我们在系统提示词里要求模型在回答末尾附上"【参考文档】xxx.docx,第x页"这种格式。因为检索出来的每个片段都带有元数据,模型可以直接读取到文档名和页码。这个设计在线上效果很好,既方便运营抽查回答质量,也方便用户在页面上直接跳转到原始条款。

另一个必须做的是"不可答兜底":当检索结果低于相似度阈值,或者结果为空时,不要进入正常的问答流程,而是走一个降级策略。我在这里给了两个分支:

  • 有低质量检索结果但相似度不够:回复"资料暂时不足",并附上人工客服入口。
  • 完全没有检索结果:直接转人工。

不要小看这两个分支。在灰度期间,我们对比了有兜底和没兜底的输出,"胡编乱造"的问题基本清零,用户对客服的满意度数据也明显回升,因为用户宁可听到"转人工"也不愿意听到一个明显错误的答案。

5. 灰度上线与全链路调优

模块开发完,只是万里长征走了一半。真正费力的是灰度阶段对效果数据的分析和调优。这个阶段我每天都在三点一线地发现问题和解决问题。

5.1 召回效果差的排查链路

线上第一个明显问题是"问题召回的效果不稳定"。同一个问题,换个问法,明明语料里有一模一样的句子,检索结果却排得很靠后。排查时不要直接上重排序,先把链路拆开逐步复现。

我整理了一套排查顺序:

  1. 先确认问题向量化是否异常。用同一个 Embedding 模型把问题向量化,再和语料块做相似度计算,看分布是否合理。
  2. 再确认语料质量。检查命中的片段是不是纯表格文本、OCR 噪声等异常块。
  3. 然后确认分割策略。看看目标信息是否被切碎或和其他语义混在了一起。
  4. 最后才考虑调模型、加重排。

有一次问题就出在第二步:某商品说明书的"故障代码表"被解析成了多行无序文本,向量化之后语义完全错乱,用户问"冰箱显示E4怎么办",检索到的是"可能原因:请检查室温",怎么调 Top-K 都没用。后来单独对该类文档走了"表格专线"解析流程,把表格按行列结构拼接成自然语句,再重新向量化,这个问题才解决。经验就一条:不要一上来就调模型调参数,先把数据源本身清洗合格。

5.2 幻觉收缩的三板斧

大模型编造答案的问题,我在前面几个环节已经做了不少拦截,但线上还是有过漏网之鱼。总结三个最有效的手段,配合使用才彻底压住:

第一板斧是检索源头控制:相似度阈值 + 无结果转人工。这个前面提过了,不再展开。

第二板斧是生成侧约束:在系统提示词里强调"不得超出参考文档范围""如果信息在文档里找不到,如实说明"。不要觉得这是废话,模型对指令的遵从度在"参考文档里没有"这种明确场景下比什么技巧都有效。

第三板斧是答案校验:模型生成后,做一次简单的证据对齐。我把生成文本里的关键实体(如退款比例、保修年限)抽取出来,去检索结果片段里确认是否出现,不出现则判为可疑答案,走兜底回复。这个校验逻辑不需要精确匹配,语义级别即可,可以用模型调用,也可以整理出高频实体词表做快速匹配。电商场景里像"30天""7天""150%""包邮"这类数字关键词,用词表校验成本更低、效率更高。

5.3 响应延迟与成本控制

客服系统对响应时间的容忍度比聊天工具高一点,但也不能让用户等太久。我们的目标是不超过 3 秒返回首字。实测下来,链路耗时占比大概是:

  • 问题改写检索式:0.3 秒
  • 问题向量化:0.1 秒
  • 向量检索:0.2 秒
  • 模型生成:1.5-2.5 秒不等

优化方向还是老三样:一是把模型服务部署在靠近应用的地域,减少网络往返;二是把问题和语料的向量化做离线缓存,问题向量缓存命中后直接跳过这一步;三是模型输出用流式(Streaming),用户侧"首字响应"的体感会比等全部生成完再展示好很多。

成本控制方面,我的核心策略是分级调用模型:简单的售后政策咨询,用轻量级模型就够;复杂的纠纷判断、多轮深度引导,才调用更强的大模型。这条降本逻辑运营非常认可——毕竟客服场景 80% 的问题都是重复且简单的,没必要每次都上重型模型。

6. 一些踩坑心得与可扩展方向

最后分享几个纯属于"做过才懂"的体会。

第一,RAG 项目的质量上限几乎由数据质量决定,不要指望模型或者说 Prompt 技巧能兜住脏数据。电商知识库每天都在变,一定要有知识更新管线:新增 PDF 自动解析入库、下线文档自动移除对应向量、变更文档需全量重跑该分类语的向量化。我们后来设计了定时任务和人工审核槽位,才算把"知识新鲜度"这个事管起来。

第二,评估体系要早建。不要上线后凭感觉说"效果还行"。我从项目一开始就维护了一批评测用例,覆盖常见问题、变体问法、疑难纠纷、异常输入四类。每次修改 Prompt、调整分割参数、切换模型,都先跑一遍评测集,用准确率数据来决策,而不是靠印象。

第三,多轮对话的处理比单轮要复杂得多。用户会问"那运费呢?""支持吗?"这类省略主语的问题,单纯把上一轮回答拼接进 Prompt 是不够的。建议对会话里的"指代"做一次梳理,将省略句补充完整后再进检索链路。

至于后续扩展的方向,如果团队把单知识库客服做顺了,可以往两个角度延伸:一个是用同样的链路切换到售后工单分类、商品评论摘要等场景,只替换文档解析规则和 Prompt 模板,其他部分完全复用;另一个是接入人工客服辅助模式,让 AI 在客服对话过程中实时推荐答案,由人来确认发送。这两个方向都不需要重新发明轮子,RAG 基础设施搭好后,扩展就是改改配置的事。

这套系统上线几个月里,我最大的感受是:做 RAG 项目最怕的不是技术复杂,而是被"AI"两个字带偏,以为主要精力都在模型调用上。真正花时间的永远是最枯燥的数据清洗、文档结构和评测打磨。把这些基本功做扎实,剩下的交给 Spring AI 串联起来就好了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 9:40:48

LiteLLM实战:统一大模型API网关,轻松实现多模型路由与成本管控

1. LiteLLM 到底是什么,它在解决哪些痛中之痛如果你同时接过 OpenAI、Anthropic、Azure OpenAI、本地大模型这些接口,一定有过这种体验:每个厂商的 SDK 风格都不一样,请求体字段名不同,错误码格式不同,鉴权…

作者头像 李华
网站建设 2026/10/22 9:40:15

RocketMQ客户端原理详解:从发送到消费的核心机制与实战排查

做后端开发这些年,消息中间件换过好几轮,从早年的 ActiveMQ 到后来团队统一切到 RocketMQ,再到现在看着它成了不少业务系统的事实标配。RocketMQ 给我的直观感受是:部署上手不算难,但客户端内部到底在做什么&#xff0…

作者头像 李华
网站建设 2026/10/22 9:39:26

SpringBoot+Vue二手交易系统实战:前后端分离与订单管理全解析

1. 项目背景与核心需求拆解 1.1 从“bootpf管理系统”说起:这套代码到底解决什么问题 做校园二手交易、社区闲置流转,最烦的是什么?我接触过的类似项目没有十个也有八个,大家的第一版基本都是一个套路:前端写死数据、…

作者头像 李华
网站建设 2026/10/22 9:38:55

OpenClaw开源重制引擎:从源码编译到游戏配置完整指南

1. OpenClaw是什么:重制引擎的项目定位1.1 一句话说清OpenClaw解决什么问题OpenClaw这个项目,说白了就是给那只叼着雪茄、挎着弯刀的海盗猫横版老游戏做的一个开源重制引擎。它用现代代码重新实现老游戏的运行逻辑,让你不用再折腾DOSBox、虚拟…

作者头像 李华
网站建设 2026/10/22 9:38:48

设计到代码闭环实战:Agent编排与自动化生成

1. 设计到代码的闭环为什么突然成了焦点 1.1 从“切图仔”到“Agent 编排者”的角色转变 做了七八年设计工具链相关的工作,我最大的感受是:设计稿和代码之间的那道墙,从来不是靠某一个工具推倒的,而是靠工作流的重构慢慢磨掉的。…

作者头像 李华
网站建设 2026/10/22 9:38:35

Unity显微镜仿真:解决学生手抖不敢操作的实训断层

简介:这是一套基于Unity引擎开发的显微镜操作仿真模拟实验系统,面向中学及高校生物、医学类课程教师与学生,解决实体显微镜设备不足、样本易耗、操作训练受限等教学痛点。系统完整复现载物台移动、粗/细调焦、光路切换等核心操作,…

作者头像 李华