业务系统接入 AI 客服:全链路思路与落地方案
适用场景:Java / Spring Boot 业务系统 · LLM Tool Calling · 智能推荐 · 轻量 RAG
关键词:Function Calling · ChatMemory · 召回-精排 · 向量检索 · 幻觉防控
本文面向「已有业务中台,想加一层自然语言入口」的后端同学,讲清从提问到回答的完整链路与设计取舍。
前言
很多团队接到「做个 AI 客服」需求时,第一反应是:把文档扔进向量库,再套一个 ChatGPT 窗口。
上线后常见问题是——
- 书名、库存、架位被模型编造;
- 规则答得像官网文案,却和真实接口不一致;
- 「根据我借过的推荐」要么做不了,要么越权查到别人数据。
根因通常不是模型不够强,而是职责切分错了:把「事实查询」和「语言组织」都交给了 LLM。
正确思路可以概括成一句话:
业务事实走 Tool + 权威数据源;大模型只负责理解意图、选工具、组织口语化回复。
下面按「为什么这样设计 → 全链路怎么跑 → 各能力怎么拆 → 怎么渐进落地」展开。
一、问题定义:AI 客服到底要答什么
以书城 / 图书馆类业务为例,高频问题大致分五类:
| 藏书查询 | 「有没有 XX 书」 | 结构化检索(SQL / 搜索服务) |
| 位置与库存 | 「在几楼」「还能借吗」 | 实时库存、架位字段,不能靠向量「猜」 |
| 业务规则 | 「怎么借书」「签到送什么」 | FAQ / 规则库,禁止模型臆造条款 |
| 个人状态 | 「我借的书在哪取」 | 登录态 + 按用户隔离的订单查询 |
| 智能推荐 | 「想学 Redis」「按我兴趣推荐」 | 规则召回 + 可选语义检索 + 画像 |
前四类强调准确;推荐类允许一定模糊性,但仍要求「推荐出的书必须真实存在于库中」。
二、核心架构选型:Tool Calling 为主,RAG 为辅
2.1 为什么查书不适合纯 RAG
纯 RAG(全书目 Embedding → 检索 → 让模型回答)看起来简单,但有硬伤:
更稳妥的模式是:
自然语言 → LLM(理解 + 选 Tool)→ Tool 调现有 Service / SQL
→ 结构化 JSON 回灌模型 → 口语化回复
向量检索只放在真正需要语义模糊匹配的地方(如「想学缓存」「入门后端」),并且召回 ID 后必须回查业务库补齐架位与库存。
2.2 总体链路(一图看懂)
用户提问
↓
Chat API(可选 JWT)
↓
会话层:写入/读取最近 N 轮上下文(Redis)
↓
ChatClient + System Prompt + Tools
↓
大模型(OpenAI 兼容协议,可换 DeepSeek / 通义 / 本地模型)
├─ 决定调用哪个 Tool(可能多轮 Tool Call)
└─ 基于 Tool 返回值生成最终回复
↓
响应:reply(文本)+ cards(书目/推荐卡片,供前端渲染)
职责边界:
| LLM | 意图理解、选 Tool、润色话术 | 编造书名 / 库存 / 规则 |
| Tool 适配层 | 调业务 Service,裁剪字段给模型 | 改写核心业务规则 |
| MySQL | 书目、订单、库存权威源 | — |
| Redis | 会话记忆、限流、缓存 | 存向量(规模上来后不合适) |
| 向量库(可选) | 语义召回候选 ID | 代替实时库存查询 |
三、工程基座:怎么接大模型
3.1 协议统一,模型可换
Chat 与 Embedding 都走 OpenAI 兼容协议,用 base-url + model 指向不同厂商,而不是绑死某一家 SDK。好处是:
- 本地可切 DeepSeek / 通义 / Ollama;
- 业务代码只依赖 ChatClient / EmbeddingModel 抽象;
- 成本与合规变化时切换成本低。
3.2 System Prompt 是「路由说明书」
Prompt 不要写成长篇人设散文,而应写成强制路由规则,例如:
- 查书 / 架位 / 库存 → 必须先调搜索或详情 Tool;
- 规则类问题 → 必须先调 FAQ Tool;
- 个人借阅 → 必须先调个人订单 Tool;未登录要如实提示;
- 推荐 → 必须先调推荐 Tool,只能引用返回结果中的书;
- 超出能力 → 明确说做不到,不编造。
温度建议压到 0.2~0.3:客服场景要稳,不要花。
3.3 向量能力做成开关
向量库(如 Milvus)对本地环境有依赖。推荐:
- 默认 关闭 RAG,规则推荐仍可上线;
- 开启时再装配 VectorStore;
- 关闭时语义召回 Bean 不存在,编排层通过可选注入自动降级。
这样「没起向量库也能启动」是工程友好度的关键指标。
四、会话与鉴权:多轮对话怎么记住、怎么认人
4.1 会话记忆
多轮对话需要把最近若干轮消息带给模型。常见做法:
关键设计点:
- 滑动窗口:例如最多保留 6 轮问答(约 12 条消息),控制 Token;
- TTL 续期:每次对话刷新过期时间(如 30 分钟);
- 隔离:匿名 anon:{sessionId},登录 user:{userId}:{sessionId},避免串会话。
4.2 可选鉴权
聊天接口建议 可匿名访问(降低体验门槛),同时支持带 Token:
- 无 Token → 匿名会话,不能查个人借阅 / 个性化;
- 有 Token → 解析出 userId,注入请求级上下文;
- Token 无效仍返回 401,走前端刷新逻辑。
4.3 用户身份绝不进 Tool 参数
个人相关 Tool(我的借阅、阅读画像、个性化推荐)的 userId 只能来自服务端鉴权上下文(ThreadLocal / SecurityContext),禁止做成 @ToolParam 让模型传入。
否则模型一旦「幻觉」出一个别人的 id,就可能越权。
五、Tool 设计:把能力拆成可调用函数
5.1 适配层原则
Tool 是薄适配层:
- 内部调用已有 Service,不复制一套 SQL;
- 返回给模型的 JSON 裁剪字段(id、title、架位、库存、状态即可);
- 写回前端的「卡片」在 Tool 执行时收集,接口层统一 drain。
5.2 能力清单(建议按此拆)
| searchBooks | 「有没有 XX」 | 关键字分页,过滤下架 |
| getBookDetail | 「在几楼」「库存」 | 返回 shelfLocation、borrowStock |
| searchFaq | 借还规则、签到、预约 | 先关键词,可选语义增强 |
| getMyBorrowOrders | 「我的待取 / 待还」 | 必须登录;按状态过滤 |
| recommendBooks | 各类推荐意图 | intent 枚举,结果带来源理由 |
| getUserReadingProfile | 「我的兴趣」 | 只返回画像,推荐仍走 recommend |
5.3 响应卡片
除了 reply 文本,建议返回结构化 cards:
- type=book:查书结果,前端可跳转详情;
- type=recommend:推荐列表,带 recommendReason。
模型可以「说话」,前端靠 cards 稳定渲染,避免从 Markdown 里再解析书名。
六、FAQ:规则问答怎么做
6.1 MVP:静态知识库 + 关键词打分
业务规则条目不多时(十几条以内),用内存知识库即可:
- 每条:topic + answer + keywords;
- 对用户 query 做包含命中 / 分词命中打分;
- TopN 返回给模型组织话术。
优点:零依赖、可解释、上线快。缺点:换说法容易漏召回。
6.2 增强:FAQ 向量化
在已有向量库上,把 FAQ 做成文档:
文本:{topic} | {answer} | 关键词:…
metadata:type=faq, topic=…
docId:faq:{index}
检索时 filter type == 'faq'。
Tool 策略:语义优先,没命中再降级关键词——RAG 关闭时行为与 MVP 一致。
若框架只绑定单一 collection,可用 metadata type 把图书与 FAQ 分区,不必强行建第二个 VectorStore。
七、推荐引擎:召回 → 精排 → 理由
推荐是 AI 客服里最「像算法」的一块,但仍建议保持工程可解释。
7.1 意图枚举
| EXPLORE | 随便看看 | 热门 / 分类 |
| LEARN | 想学某主题 | 语义 / 关键词 + 分类 |
| SIMILAR | 找类似的 | 种子书同分类 + 可选语义近邻 |
| RELAX | 休闲读物 | 分类 / 热门 |
| PERSONALIZED | 按我的历史 | 画像 + 同分类未读 + 共现 |
7.2 多路召回(Recaller)
把「从哪捞候选」拆成可插拔组件:
HotBookRecaller ← 借阅次数 + 销量加权
CategoryBookRecaller ← 分类 / 书名关键词
SemanticBookRecaller ← 向量近邻(可选)
PersonalizedRecaller ← 偏好分类未读 + 借阅共现
编排服务只做:
7.3 为什么召回后还要回查 MySQL
向量库或热度表里可能只有 bookId。
架位、库存是实时事实,必须以业务库为准——这也是「权威源分层」的落地体现。
7.4 个性化画像
画像建议聚合:
- 借阅历史(全状态)→ 已读集合;
- 在借未还(APPLIED / BORROWED / OVERDUE)→ 推荐排除集;
- 已支付购书 → 补充兴趣;
- 分类命中次数 → 偏好 TopN。
共现可简化为:「借过同样书的人还借过什么」,无需一上来上复杂协同过滤。
未登录请求个性化 → Tool 明确返回「请先登录」,Prompt 要求如实转达。
八、RAG 语义检索:什么时候开、怎么开
8.1 适用场景
- 「想学 Redis / 入门 Spring」——书名未必含「缓存」「入门」;
- FAQ 换说法——「签到七天送什么」vs「连续打卡奖励」。
8.2 图书索引文本
摘要级即可,避免整本书:
{title} | {author} | 分类:{categoryName} | {description 截断}
metadata: bookId, categoryId, type=book, status
docId: book:{bookId}
检索 filter 建议:type == 'book' && status == 1。
8.3 运维接口
提供管理端「全量重建 / 单本刷新 / FAQ 重建」,启动预热做成开关(书量大时别默认开)。
8.4 与规则推荐的关系
语义召回是 加分项:
- LEARN / SIMILAR 有 query 时优先语义;
- 空结果或 RAG 关闭 → 自动走关键词 / 分类 / 热门兜底。
九、安全、幻觉与稳定性
9.1 幻觉防控清单
9.2 数据权威优先级
MySQL(业务事实) > 向量召回(候选) > LLM 生成文本(话术)
9.3 限流与降级
- 按用户 / IP 限流(如每小时 30 次),防刷模型费用;
- 上游超时映射业务错误码;
- 向量不可用时降级规则推荐,而不是整站不可用。
十、渐进式落地路线(建议 2~3 周)
不要一上来「Chat + RAG + 个性化」一起上。推荐顺序:
① 工程基座 + Chat API + 会话
② 查书 Tool(演示价值最高)
③ FAQ Tool
④ 个人借阅 Tool(依赖可选 JWT)
⑤ 规则推荐(热门 + 分类)
⑥ 可选:Milvus 语义检索 + FAQ 向量
⑦ 个性化推荐(画像 + 共现)
⑧ 前端 SSE 流式 + 埋点收尾
MVP(约 1 周):①②③ 就能演示「自然语言查书 + 答规则」。
完整演示:再加推荐与个性化,故事就完整了。
每一步结束都应能在 Postman / 聊天窗跑通,避免「半成品堆在一起无法演示」。
十一、一次完整请求的时序(查书为例)
1. 用户:「Redis 那本书在几楼?」
2. Chat API 生成/复用 sessionId,写入会话记忆
3. 模型根据 Prompt 选择 searchBooks / getBookDetail
4. Tool → CatalogService → MySQL(命中 Redis 详情缓存亦可)
5. 返回 JSON:title, shelfLocation, borrowStock, …
6. Collector 写入 type=book 卡片
7. 模型组织回复:「《xxx》在 2楼 A-01 第3层,当前可借。」
8. 接口返回 { sessionId, reply, cards }
推荐场景多一步:recommendBooks → 多路召回 → 回查 → 精排 → type=recommend 卡片。
个性化场景再多一步:校验登录 → 建画像 → 个性化召回 → 排除在借未还。
十二、常见踩坑
| 模型编造书名 | Prompt 未强制 Tool,或 Tool 未注册成功 |
| 多轮忘上下文 | 未回传同一 sessionId,或 Redis TTL / Key 前缀错误 |
| 个性化查到别人数据 | userId 进了 ToolParam——立刻改成鉴权上下文 |
| 开了向量库启动失败 | 自动装配强连 Milvus——用开关 + exclude / 条件装配 |
| Embedding 维度报错 | 模型输出维、配置维、向量库 schema 必须一致 |
| 语义推荐架位不对 | 召回后未回查业务库 |
十三、总结:全链路的一张心智图
┌─────────────────────────────────────────────────────────┐
│ 入口层:Chat API + 可选 JWT + 会话记忆(Redis) │
└───────────────────────────┬─────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────┐
│ 编排层:System Prompt + ChatClient + Tool Calling │
│ (理解意图 → 选工具 → 组织话术) │
└───────────────────────────┬─────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────┐
│ 能力层:查书 / FAQ / 借阅 / 推荐 / 画像 │
│ 推荐内部:多路 Recaller → 回查 → 精排 → 理由 │
└───────┬─────────────────────────────┬───────────────────┘
▼ ▼
MySQL 权威事实 向量库(可选语义召回)
记住四条原则,整条链路就不会跑偏:
