Skip to content

AI智能客服开发

一、需求背景

刚开始我们项目使用了 WebSocket 技术搭建人工客服系统,但是人工客服无法做到 7 * 24 小时在线。用户咨询客服的时间不固定,有些用户可能在半夜咨询,这时候人工客服不在线,用户体验就不太好。

后面甲方问我们有没有更好的解决方案。刚好当时 AI 应用比较火,我们就给客户推荐开发一个 AI 智能客服模块,让用户可以随时访问 AI 客服。

AI 客服主要解决两个问题:

  • 用户可以随时咨询,不受人工客服在线时间限制。
  • 常见问题由 AI 自动回答,减少人工客服压力。

当然,有些 AI 回答不了的问题,或者涉及复杂业务处理的问题,系统也支持直接转人工客服。

二、框架及模型选型

1. AI 框架选型

项目里我们先做了 AI 框架选型。当时主要考虑了两个方案:

框架特点
LangChain4j出现比较早,生态比较丰富;不是 Spring 项目也能接入;JDK 8 以上即可使用
Spring AI Alibaba和 Spring 项目集成比较方便,适合 Spring Boot 项目

我们项目本身使用的是:

  • JDK 17
  • Spring Boot 3.3 以上版本

所以最终选择了 Spring AI Alibaba。它和 Spring Boot 集成更自然,项目里接入成本也比较低。

2. 大模型选型

大模型这块主要有两种方案:

  • 本地部署大模型
  • 使用第三方大模型平台

本地部署的好处是数据可控,但是服务器成本、运维成本和模型维护成本都比较高。客户希望尽可能减少成本,所以我们最终选择了第三方大模型平台。

我们接入的是阿里百炼平台的通义千问大模型。当时选择它主要有几个原因:

  • 价格相对便宜。
  • 和阿里生态组件集成比较方便。
  • 支持 Function Calling。
  • 支持多模态能力。

当时评估的价格大概是:

类型价格
文本输入0.0018 元 / 千 Tokens
文本输出0.0069 元 / 千 Tokens
图片、视频输入0.0033 元 / 千 Tokens
图片、视频输出0.0626 元 / 千 Tokens

三、整体实现思路

我们主要从几个方面实现 AI 智能客服能力。

1. 给 AI 赋予角色

这部分主要通过 Prompt 提示词工程来实现。

我们会在提示词里告诉 AI:

  • 它是什么角色。
  • 它能回答什么问题。
  • 它不能回答什么问题。
  • 回答时应该使用什么语气。
  • 没有依据时不能乱编。
  • 遇到复杂问题时需要建议转人工。

比如智能客服的定位是:

text
你是一个电商系统的 AI 智能客服。
你需要根据知识库内容、用户上下文和业务查询结果回答用户问题。
不能编造订单状态、退款结果、物流信息。
如果无法确定答案,请提示用户转人工客服。

2. 做上下文记忆

AI 客服不是只回答单轮问题,用户经常会连续追问。

比如用户第一句问:

text
我的订单为什么还没发货?

第二句继续问:

text
那还能取消吗?

第二句里面没有明确说是哪一个订单,所以后端需要把前面的对话上下文带给模型,让模型知道用户还在问上一个订单。

所以我们做了会话存储和消息存储,让 AI 能结合上下文回答问题。

3. 使用 Function Calling / MCP 调用业务能力

有些问题不是模型自己能回答的,需要调用我们系统里的业务接口。

比如:

  • 查询订单状态。
  • 查询物流信息。
  • 查询退款进度。
  • 查询售后单状态。
  • 判断是否支持退货。

这些数据都在我们自己的业务系统里,模型本身不知道。所以我们通过 Function Calling / MCP 机制,把一些安全的只读业务能力封装成工具,让模型在需要时调用。

这里有一个原则:高风险操作不能直接交给 AI 自动执行。比如退款、取消订单、修改地址这类操作,必须走明确的业务校验和用户确认,不能让模型一句话就直接执行。

4. Embedding 和向量数据库基础

RAG 检索依赖 Embedding 和向量数据库,这里先简单说一下这两个东西是干嘛的。

4.1 什么是 Embedding

Embedding 说白了就是把文字变成一串数字。

比如“怎么申请退款”这句话,经过 Embedding 模型后会变成一个几百维的向量。语义相近的话,向量在空间里就比较近。

这样计算机不需要真正“读懂”中文,只要算两个向量之间的距离,就能判断两句话意思像不像。

那向量具体是怎么算出来的呢?大致分三步:

  1. 分词:先把句子拆成一个个 token,比如“怎么申请退款”变成 ["怎么", "申请", "退款"]。
  2. 过神经网络:把这些 token 丢进预训练好的 Embedding 模型里。这个模型在大量文本上学过“哪些词意思相近、哪些句子经常一起出现”。
  3. 取向量:模型最后一层输出一串固定长度的数字,比如 768 维或 1024 维,这就是这句话的向量。

判断两句话像不像,通常用余弦相似度。两个向量夹角越小,距离越近,语义就越相近。

4.2 向量数据库是干嘛的

向量数据库就是专门存这些数字向量的数据库。

普通数据库是按字段条件查,比如 status = 1。向量数据库是按语义相似度查:把用户问题也变成向量,然后找离它最近的那些文档向量。

我们项目用的是 Qdrant,主要因为开源、部署简单,和 Spring AI Alibaba 集成也比较方便。同类工具还有 Milvus、Weaviate,Elasticsearch 现在也能做向量检索。

4.3 Embedding 模型怎么选

Embedding 模型有很多,面试里常见的有这几个:

  • OpenAI text-embedding 系列:比如 text-embedding-3-small、text-embedding-3-large,英文效果好,中文场景不一定最优。
  • 阿里通义千问 Embedding:比如 text-embedding-v1、v2、v3,中文语义理解比较好,和我们项目里用的大模型同生态。
  • BGE:智源开源的中文 Embedding 模型,效果也不错,适合本地部署。
  • M3E:中文社区常用的开源 Embedding 模型。
  • Sentence-BERT:比较老的开源方案,现在用得少了。

我们项目里用的是 阿里百炼平台的通义千问 Embedding API,主要考虑这几点:

  • 客服场景中文为主,中文语义理解更重要。
  • 和大模型同一个平台,接入维护方便。
  • 按调用量付费,不用自己部署模型服务,省服务器成本。
  • Spring AI Alibaba 配置起来比较自然。

如果数据敏感、不能走公网,也可以考虑本地部署 BGE 这类开源模型。

5. 使用 RAG 减少模型幻觉

为了减少模型胡编,我们做了 RAG,也就是信息检索增强。

我们准备了一些知识库文档,主要包括:

  • 常见问题 FAQ。
  • 售后政策。
  • 退换货规则。
  • 订单说明。
  • 平台使用说明。
  • 客服标准话术。

5.1 RAG 处理流程

文档格式主要是 PDF。处理流程是:

text
PDF 文档

文档加载器加载到内存

文档分割器按段落切分

Embedding 模型生成向量

写入 Qdrant 向量数据库

用户提问时检索相关片段

把检索结果和用户问题一起交给大模型回答

5.2 文档切分策略

我们这边业务不算特别复杂,所以第一版文档切分没有做得太细,主要是按段落进行分割。后面根据效果再继续调优。

四、Function Calling 和 MCP 概念梳理

在 AI 智能客服项目里,Function Calling 和 MCP 都是为了让大模型具备“调用外部能力”的能力。简单说,大模型本身只擅长理解和生成文本,但是它不知道我们系统里的实时订单状态、物流信息、退款进度,也不能自己直接操作数据库。所以需要通过工具调用机制,把我们后端已有的业务能力提供给模型使用。

1. Function Calling 是什么

Function Calling 可以理解为:我们提前告诉模型系统里有哪些函数可以用,每个函数叫什么、需要哪些参数、能做什么。用户提问时,模型判断自己是否需要调用某个函数。

比如用户问:

text
我的订单 202406080001 到哪里了?

模型自己不知道这个订单状态,它会判断需要调用查询订单接口,然后生成类似下面的调用意图:

json
{
  "functionName": "queryOrderStatus",
  "arguments": {
    "orderNo": "202406080001"
  }
}

后端收到这个结果后,不是让模型直接查数据库,而是由 Java 后端去调用真实的订单查询接口。查询到结果后,再把订单状态返回给模型,让模型组织成用户能听懂的话。

整个流程大概是:

text
用户提问

模型判断需要调用工具

模型返回函数名和参数

Java 后端校验参数和权限

Java 后端调用真实业务接口

把业务结果交给模型整理

返回用户

Function Calling 的重点是:模型只负责判断要不要调用、调用哪个函数、参数是什么;真正执行动作的一定是后端代码。

2. Function Calling 适合解决什么问题

在智能客服里,Function Calling 比较适合处理实时业务数据查询,比如:

  • 查询订单状态。
  • 查询物流信息。
  • 查询退款进度。
  • 查询售后单状态。
  • 查询用户优惠券。
  • 判断订单是否支持取消。
  • 判断商品是否支持退货。

这些问题不能只靠知识库回答,因为知识库里只有规则,没有用户自己的实时数据。

3. MCP 是什么

MCP 全称是 Model Context Protocol,可以理解为一种更标准化的“模型连接外部工具和数据源的协议”。

Function Calling 更像是某个模型平台提供的一种函数调用能力,而 MCP 更像是一套通用协议。它把外部系统封装成 MCP Server,让模型或智能体通过统一方式访问工具、资源和上下文。

通俗一点说:

  • Function Calling 更像是“我在代码里给模型注册几个函数”。
  • MCP 更像是“我把一个系统封装成标准工具服务,模型可以按协议去调用”。

比如我们可以把订单系统、物流系统、知识库系统分别封装成 MCP Server:

text
AI 智能客服

MCP Client

订单 MCP Server / 物流 MCP Server / 知识库 MCP Server

真实业务系统

这样智能体不用关心底层系统具体怎么实现,只需要按 MCP 协议调用对应工具。

4. MCP 主要包含哪些概念

MCP 里常见的几个概念可以这样理解:

概念通俗理解
MCP Host使用 MCP 能力的宿主,比如 AI 客服应用
MCP Client负责和 MCP Server 通信的客户端
MCP Server对外提供工具、资源和能力的服务
Tools可被模型调用的工具,比如查询订单、查询物流
Resources可被读取的数据资源,比如文档、配置、文件
Prompts可复用的提示词模板

在项目里,AI 智能客服本身可以看作 MCP Host,后端集成 MCP Client,订单查询、物流查询、知识库查询这些能力可以封装成 MCP Server 提供的 Tools。

5. Function Calling 和 MCP 的区别

对比项Function CallingMCP
定位模型调用函数的能力模型连接外部工具和数据源的协议
使用方式在模型请求里声明函数通过 MCP Server 暴露工具和资源
适用范围比较适合少量工具调用更适合多个系统、多个工具统一接入
标准化程度更依赖具体模型平台更强调统一协议
项目复杂度接入较简单架构更清晰,但接入成本更高

项目早期功能不复杂时,Function Calling 接入更快。后面工具越来越多,比如订单、物流、售后、工单、知识库都要接入时,用 MCP 统一管理会更清晰。

6. 在智能客服项目里我是怎么用的

我们在第一版里主要使用 Function Calling,因为项目初期工具数量不算太多,主要是订单查询、物流查询、退款进度查询和售后状态查询。

每个工具都会定义清楚:

  • 工具名称。
  • 工具用途。
  • 入参字段。
  • 出参字段。
  • 权限要求。
  • 超时时间。
  • 失败兜底。

比如订单状态查询工具:

text
工具名称:queryOrderStatus
工具作用:根据订单号查询订单状态
入参:orderNo
出参:orderStatus、payStatus、deliveryStatus、canCancel
限制:只能查询当前登录用户自己的订单

后端执行工具调用前,一定会做权限校验。比如用户只能查询自己的订单,不能随便传一个订单号就查到别人的订单。

后面工具数量变多以后,我们也评估过把这些能力进一步 MCP 化。比如订单服务提供订单 MCP Server,物流服务提供物流 MCP Server,AI 客服统一通过 MCP Client 调用。这样后续其他 AI 应用也能复用这些工具能力。

7. 工具调用的安全边界

无论是 Function Calling 还是 MCP,都不能让模型绕过后端业务规则。

我在项目里主要做了这些限制:

  • 只开放必要工具,不把所有接口都暴露给模型。
  • 第一版只开放查询类工具,写操作必须人工确认。
  • 工具调用前必须校验用户身份和权限。
  • 参数必须由 Java 后端再次校验,不能直接相信模型生成的参数。
  • 工具调用要设置超时时间,避免一直阻塞。
  • 工具调用失败时要返回明确兜底。
  • 敏感字段返回给模型前要脱敏。
  • 所有工具调用都要记录日志,方便排查。

比如退款这种操作,模型最多只能判断“是否满足申请退款条件”,然后引导用户去页面确认,不能直接替用户发起退款。

这块我的理解是:模型可以做助手,但不能做最终执行者。真正改变业务状态的操作,必须由后端规则、用户确认和权限系统共同控制。

五、优化设计

调用大模型会耗时,也会产生费用。所以在真正调用模型前,我们做了几层优化。

1. 敏感词过滤

在调用模型前,先做敏感词过滤。

我们接入了一个叫 Sensitive Word 的敏感词组件,它本身自带一些敏感词规则。但默认词库不够,所以我们又通过数据库管理了一套自定义敏感词库。

处理方式是:

  • 数据库存储自定义敏感词。
  • 后台支持新增、修改、删除敏感词。
  • 敏感词变更后同步到 Sensitive Word 组件。
  • 用户输入命中敏感词时,直接拦截或提示修改。

这样可以避免一些不合规内容直接进入模型,也能减少无效调用。

2. FAQ 优先匹配

很多用户问的问题是高频问题,比如:

  • 怎么申请退款?
  • 订单多久发货?
  • 如何修改收货地址?
  • 退货运费谁承担?

这些问题没有必要每次都调用大模型。我们做了一套 FAQ 管理功能,把常见问题和标准答案维护在数据库中。

为了让用户输入能更准确地匹配 FAQ,我们没有只做关键词匹配,而是结合了向量数据库。

FAQ 写入时:

text
FAQ 问题和答案

保存到业务数据库

问题文本向量化

写入 Qdrant

用户提问时:

text
用户问题

先做向量化

到 Qdrant 匹配相似 FAQ

命中 FAQ 时直接返回标准答案

没有命中 FAQ 时再走 RAG 和模型调用

这样可以减少频繁调用大模型的问题,既提升响应速度,也节省成本。

六、模型上下文存储

为了让模型调用时能记住上下文,Spring AI Alibaba 提供了几种存储方式:

  • 内存存储
  • 数据库存储
  • Redis 存储

我在项目里使用的是 Redis 存储。Redis 主要负责保存当前会话的短期上下文,让模型在连续对话时能拿到最近几轮消息。

同时,为了支持用户下次进入系统后还能看到历史对话,我们又把完整会话记录落到了数据库中。

也就是说:

  • Redis:保存短期上下文,服务模型多轮对话。
  • MySQL:保存完整聊天历史,服务前端历史记录展示。

七、多轮对话存储

这个项目里,多轮对话是单独设计的,不是简单把所有聊天内容都临时放在内存里。因为用户下次进入系统时,需要能看到之前的会话记录;同一个会话里继续提问时,模型也需要知道前面聊过什么。

我把会话存储拆成两张核心表。

1. 会话表

会话表主要记录一次对话主题。

字段说明
id会话 ID
user_id用户 ID
title会话标题
status会话状态
created_at创建时间
updated_at更新时间

2. 消息表

消息表记录每一轮用户和 AI 的消息。

字段说明
id消息 ID
conversation_id会话 ID
user_id用户 ID
role消息角色,比如 user、assistant、system
content消息内容
references引用的知识库来源
input_tokens输入 Token
output_tokens输出 Token
latency_ms本轮耗时
created_at创建时间

前端每次新建聊天时,后端会先创建一条会话记录,并返回 conversationId。后续用户继续在这个聊天窗口里提问,前端都会带上这个 conversationId,后端就能知道这次问题属于哪一段会话。

每轮对话处理时,我会先保存用户问题,再调用 RAG 和大模型。模型返回后,再保存 AI 回答。这样即使模型调用中间失败,也能看到用户问过什么,以及失败原因。

用户下次打开系统时,前端会先调用会话列表接口:

text
GET /api/conversations

后端按 user_id 查询这个用户自己的会话列表,返回标题、最后更新时间和最近一条消息。

用户点击某个会话后,再调用详情接口:

text
GET /api/conversations/{conversationId}/messages

后端根据 conversationId 查询消息表,把历史对话按时间顺序返回给前端展示。

这里必须校验 conversationId 是否属于当前登录用户,不能只凭会话 ID 查询,否则会有越权风险。

3. 多轮上下文怎么传给模型

多轮上下文传给模型时,我没有把全部历史消息都塞进去。因为历史越长,Token 成本越高,响应也越慢。

我的处理方式是:

  • 只取最近几轮关键对话。
  • 对更早的历史做摘要。
  • 当前问题永远优先级最高。
  • RAG 检索结果优先级高于历史闲聊内容。
  • 超过 Token 限制时,优先丢弃低价值历史。

比如用户第一轮问:

text
支付回调失败怎么排查?

第二轮继续问:

text
那 401 这种情况呢?

第二轮的问题本身不完整。后端会加载上一轮上下文,知道这里的 401 还是在支付回调排查场景下,然后再去检索接口鉴权和支付回调相关文档。

这里我遇到过一个问题:历史上下文带太多时,模型容易被前面的问题带偏。后来我做了上下文选择规则,只保留和当前问题相关的最近几轮,同时提示词里明确要求优先回答当前用户问题。这样多轮对话既能连续,又不容易跑题。

八、RAG 调优

1. 文档切片太大

早期一个片段接近两三千字,模型输入 Token 很多,响应慢,而且回答经常抓不到重点。

后来改成按 300 到 800 字左右切片,并保留一小段上下文重叠,效果明显好一些。

2. 文档切片太碎

有些制度条款被切开后,模型只看到半句话,回答不完整。

后来我们按标题层级和段落边界切分,尽量保证一个片段表达完整含义。

3. 错误码和接口名命中不好

只用向量检索时,错误码、接口名这类内容命中效果不稳定。

比如用户问某个错误码,向量相似度不一定高。后来加了关键词检索和标签过滤,把向量检索和关键词检索结合起来,错误码、接口名、订单状态这类问题命中率提升比较明显。

4. 检索结果太多会干扰模型

一开始为了怕漏资料,会塞很多片段给模型,结果模型反而容易混淆。

后来控制 Top K 数量,并设置相似度阈值,只传最相关的几段。

5. 召回率不够高

RAG 里有一个很重要的指标叫召回率,面试里经常会被问到。

召回率可以理解为:用户这个问题,知识库里其实能回答的片段,我们有没有把它们尽量找回来。

比如用户问“退货运费谁承担”,知识库里可能有三处相关:售后政策、FAQ、运费规则。如果只召回了一个,另外两段没召回来,模型就可能回答不完整,甚至说不知道。

召回率低,最直观的现象就是模型经常说“当前知识库没有相关内容”,但实际上文档里是有答案的。

6. 怎么提升召回率

我们在项目里主要做了这几件事。

第一,混合检索。

只用向量检索有时候不够稳,尤其是对错误码、接口名、政策编号、专业术语这些,关键词匹配反而更准。

我们的做法是向量检索和关键词检索一起做,最后把两路结果合并去重,再交给重排序模型排一次,召回率提升很明显。

第二,查询改写。

用户口语化和文档书面语不一定一致。比如用户问“怎么退钱”,文档里写的是“申请退款流程”。

我们会在检索前对问题做改写,补一些同义词或扩展表达,比如把“退钱”扩展成“退款、退货、退运费”,再去检索,能召回更多相关片段。

第三,优化文档切分。

如果切得太碎,一个完整知识点被拆成多个小片段,向量检索时可能只命中其中一部分。

我们后来按语义段落切分,尽量让一段表达一个完整意思;同时在片段头部保留标题或上级标题信息,让模型知道这个片段属于哪个模块。

第四,适当增加 Top K。

一开始只取 Top 3,发现漏召回的情况比较多。后来先取 Top 10 到 Top 20,再通过相似度阈值和重排序精排,最终只把最相关的 3 到 5 段给模型。

这样既能保证召回率,又不会让模型被干扰。

第五,引入重排序模型。

向量检索阶段更关注“语义相似”,但不一定懂“哪个更相关”。我们用了一个轻量级的重排序模型,对召回结果再做一次精排,把真正相关的片段排到前面。

第六,做反馈闭环。

我们会记录哪些问题没有召回、哪些回答被用户点了不满意。定期把这些 bad case 拿出来分析,是切分问题、检索问题,还是知识库本身缺失,然后针对性优化。

简单总结就是:召回率看的是“有没有把该找的文档找回来”。优化方向主要是多路召回、查询改写、合理切分、扩大候选、重排序精排、持续复盘 bad case

九、回答准确性怎么评估

判断 AI 客服回答准不准,我们主要看三条线:和原始资料对不对得上、和业务数据对不对得上、用户满不满意。

1. 对答案

  • 知识库问题:把模型回答和检索出来的文档片段对比,看有没有乱编、漏条件。
  • 业务数据问题:比如订单状态、物流信息,直接和数据库真实数据对比。
  • 规则问题:比如退款条件、运费谁承担,对照售后政策原文看有没有说错。

2. 自动化指标

用 RAGAS 这类工具跑几个指标辅助判断:

指标大白话
Faithfulness回答是不是照着检索内容说的
Answer Relevance回答有没有答非所问
Context Precision找回来的资料里有多少是相关的
Context Recall该找的资料有没有找回来

这些指标只能参考,最终还得人工看。

3. 看用户反馈

  • 点踩、转人工、反复问同一个问题,都是回答不准的信号。
  • 客服工单里标注“AI 答错了”的,必须复盘。

4. 人工抽检

定期抽一些回答,让业务专家打标签:正确、部分正确、错误。重点看退款、售后、投诉这些高风险场景。

5. 一致性检查

同一个问题多问几次,看答案是不是一样。如果答案前后矛盾,说明模型不稳定。

6. 边界行为

不懂的时候不乱答,也是准确。比如知识库没依据时能不能提示转人工,涉及权限外的数据能不能拒绝。

7. 面试一句话

判断 AI 客服回答准不准,核心看三点:有没有依据、和业务数据一不一致、用户满不满意

十、模型响应时间优化

上线测试时,最明显的问题是响应慢。慢的地方主要有三个:

  • RAG 检索。
  • 业务工具调用。
  • 大模型生成。

我做了几类优化。

1. 接入流式响应

前端使用 SSE 接收模型输出,后端边拿到模型内容边推给前端。

虽然总耗时没有完全消失,但用户能更快看到首字,体验提升比较明显。

2. 控制提示词长度

RAG 只传最相关的几个片段,不再把整篇文档塞进去。

多轮会话也不直接拼接全部历史,而是只保留最近几轮和必要摘要。

3. 控制输出长度

普通知识问答要求简洁回答,复杂排障问题才允许输出更长步骤。

这样既降低耗时,也减少 Token 消耗。

4. 高频问题做缓存

像报销标准、请假流程、接口鉴权说明这类高频问题,会把相似问题和答案缓存起来。

命中缓存时不再调用模型。

5. 模型分层

简单意图识别、问题分类用成本更低的小模型或规则判断。

真正需要总结、生成、归纳时,再调用主模型。

6. 异步化耗时操作

用户问题涉及多个业务查询时,比如同时查订单、物流、售后状态,把这些工具调用改成异步并行执行,等结果都回来再交给模型总结,比串行调用省很多时间。

另外一些不阻塞用户的离线任务,比如会话摘要生成、FAQ 批量 Embedding,也用异步处理,避免影响主流程响应。

十一、成本控制

AI 应用成本主要来自 Token。输入越长、输出越长、调用次数越多,费用越高。

我当时做了几个控制点。

1. 限制输入长度

用户问题超过长度会提示用户缩短,避免一次请求带入大量无关内容。

2. 限制输出长度

提示词里要求普通回答控制在一定长度内,排障类问题才允许分步骤详细说明。

3. 减少上下文

多轮对话不会无限拼接历史记录,而是保留最近对话和摘要。

4. 缓存高频问题

缓存命中后可以直接返回,不走模型调用。

5. 记录成本明细

每次调用都会记录:

  • 用户。
  • 会话。
  • 模型。
  • 输入 Token。
  • 输出 Token。
  • 耗时。
  • 是否成功。

后面可以按用户、部门、功能统计消耗。

6. 确定性逻辑不用模型

权限判断、参数校验、路由判断、是否为空、是否超长,这些全部用 Java 代码处理。

模型只负责理解、总结和生成。

十二、边界状态和兜底

AI 项目最怕模型一本正经地答错,所以我对边界状态做了很多兜底。

边界情况处理方式
用户问题为空直接返回“请输入要咨询的问题”,不调用模型
用户问题过长提示用户缩短问题,避免浪费 Token
知识库没有命中可靠资料返回“当前知识库中没有找到明确依据”
检索结果相似度低不进入大模型回答流程,或者提示用户换个问法
模型接口超时返回友好提示,并记录超时日志
模型输出 JSON 格式错误先做一次格式修复重试,失败后走兜底
用户访问无权限知识库直接拦截,相关文档不会进入检索范围
工具调用失败明确提示“业务数据查询失败”
返回内容包含敏感字段后端做脱敏处理
模型回答不了直接转人工客服

敏感字段包括:

  • 手机号
  • 身份证号
  • Token
  • 密钥
  • 用户隐私信息

十三、面试中可以这样总结

我做的这个 AI 智能客服项目,核心不是简单调用大模型接口,而是围绕真实客服场景做了一套完整的智能体流程。

整体上,用户提问后,系统会先做敏感词过滤和 FAQ 匹配。FAQ 命中时直接返回标准答案;FAQ 没命中时,再走 RAG 检索知识库,把相关文档片段和用户问题一起交给大模型生成回答。

对于需要查询业务数据的问题,比如订单状态、物流信息、退款进度,我通过 Function Calling / MCP 把业务只读接口封装成工具,让模型在需要时调用。

为了支持多轮对话,我用 Redis 保存短期上下文,用 MySQL 保存完整历史会话。用户下次进入系统时,可以看到上次的聊天记录;同一个会话里继续追问时,模型也能结合上下文回答。

项目中我重点解决了几个问题:模型幻觉、RAG 命中不准、响应慢、Token 成本高、模型输出格式不稳定和人工客服兜底。最终通过 RAG、FAQ 缓存、敏感词过滤、流式响应、上下文摘要、成本统计和转人工机制,让这个 AI 客服系统能够比较稳定地落地。