AI 客服
用 RAG 做电商客服:怎么用知识库边界把售后强制转人工
客服 AI 最危险的地方,不是它答不上来,而是它答得太顺口。一个「已读乱回」的机器人最多让人哭笑不得;一个在退款、赔偿、时效承诺上张口就来的机器人,会直接把公司拖进说不清的纠纷里。rag-cs-bot 这个 Demo 里最值得拿出来讲的设计,不是它怎么把 AI 接进去,而是它怎么用知识库的边界,从机制上把售后挡在 AI 之外。
背景:99+ 条消息,和 24h / 48h 的考核#
先摆事实。这个 Demo 的起点是真实的运营压力:店铺客服每天 99+ 条客户消息,而平台的回复率考核挂在 24h / 48h 这两个时限上。消息量和时限一叠加,客服工作的性质就变了——它不再是「把问题解决掉」,而首先变成「在时限内把每一条都接住」。
这类场景恰好是 LLM 擅长的:客户问的绝大多数问题是重复的、有标准答案的。项目把这些问题拆成两类:
| 类型 | 典型问题 | 处理方式 |
|---|---|---|
| 售前 | 产品、发货、物流、价格、尺码、咨询 | AI 基于知识库自动回复 |
| 售后 | 退换、退款、投诉、赔偿 | 转人工处理,不喂给 AI |
全链路长什么样#
仓库里已经跑通的链路是这样的:本地 Dify + RAG 知识库 → 客服聊天前端(Flask 后端代理)→ 浏览器自动化(UI-TARS)读取消息 → 调 Dify API 自动回复 → 回填。画成图就是:
TikTok Shop 买家消息
│ (浏览器自动化读取)
▼
UI-TARS / cs_web ──► Dify Chatflow API
│
┌─────────┴─────────┐
▼ ▼
意图识别 知识库检索(RAG)
├─ 售后 → 转人工 └─ 售前 → LLM 生成回答
└─ 售前 → 知识库回答
│
▼
回复买家消息
对应到仓库目录:
rag-cs-bot/
├── README.md # 项目说明
├── 售前AI客服搭建操作指南.md # Dify 侧完整搭建步骤
├── cs_web/ # 客服聊天前端 + 后端代理
│ ├── app.py # Flask 后端:转发到 Dify API + 去 DeepSeek 思考
│ └── static/index.html # 聊天界面
├── ui_tars_demo/ # UI-TARS 浏览器自动化 Demo
│ ├── tars_demo.py # 读取浏览器消息框 → 调 Dify API → 回填回复
│ └── demo_msg.html # 模拟消息框页面
└── dify/ # Dify 开源平台源码(langgenius/dify,已去除运行时产物)
核心设计:知识库只放售前#
整篇文章如果只留一段,应该是这一段:
核心设计
知识库只放售前内容,售后内容不喂给 AI,从而强制售后转人工。
这句话是 README 里原样写着的「关键设计」。它的巧妙之处在于,它把一条业务规则(售后必须人工处理)翻译成了一条数据规则(知识库里没有售后内容)。而这个翻译带来三个连锁效果:
- 模型没有可引用的依据。RAG 的输出天然被检索结果约束;知识库里没有退款政策,模型就检索不到任何可以拿来承诺的条款。
- 失败是可见的。如果 AI 面对售后问题还硬答,说明意图分流那一层出了问题——这是一个可以被发现、被修复的 bug,而不是一个藏在话术里的隐患。
- 维护成本更低。售后政策会变,而且经常涉及金额与责任认定。把它们排除在知识库之外,等于把「谁来更新知识库」这个问题也一并简化了。
为什么不能靠提示词阻止模型谈退款#
很自然会想到另一种做法:知识库照放,然后在提示词里写一句「遇到退款问题请转人工」。这条路在 Demo 里能跑,在生产里靠不住,理由有三层:
| 做法 | 失效方式 |
|---|---|
| 提示词里禁止谈退款 | 用户的问法千变万化,「这个钱什么时候能到我账上」可能就不会命中这条禁令;而且上下文一长,指令的约束力会衰减 |
| 知识库里放售后条款 | 一旦被检索到,模型就会引用它,并且倾向于给出比条款更「热情」的承诺 |
| 让模型自己判断该不该转人工 | 把「转不转人工」变成一个不确定的决策,而这恰恰是最不该不确定的地方 |
关键区别在于:提示词是「建议」,知识库内容是「证据」。模型可以无视建议,但它没法凭空造出一份不存在的证据(造出来就是幻觉,而幻觉是能被检测和拦截的)。所以把约束放在数据层,比放在提示词层可靠得多——这就是「从机制上强制转人工」的含义。
意图分流:售前走 AI,售后转人工#
分流发生在 Dify 侧。README 的操作指南里,这一步被定义为一个「售前 AI / 售后人工」的 Chatflow 工作流:先做意图识别,然后按结果分叉——售前走向知识库检索,售后直接转人工。
这一层与知识库边界是两道独立的闸门,而不是一道:
| 闸门 | 位置 | 失效时的表现 |
|---|---|---|
| 意图识别分流 | Chatflow 的判断节点 | 问题被送进售前分支,但检索不到内容 |
| 知识库边界 | 语料本身 | 即使被送进售前分支,也拿不到可承诺的条款 |
两道闸门同时存在,意味着任何一次售后相关的问询都要连闯两关才会变成一句「AI 承诺」。这种冗余在客服场景里是值得的:省下的每一次误答,都比多花的那点算力贵。
剥掉思考过程:clean_answer()#
链路里有一个很接地气的问题:接进来的推理模型(DeepSeek 一类)会把思考过程一起返回,格式通常是 ...</think>回答 或 ...</thinking>回答。如果不处理,客户看到的回复里会带着一大段自言自语。
cs_web/app.py 里的 clean_answer() 用一个正则把这段剥掉,只保留最终回复,两种格式都覆盖。这一环之所以必须由后端代理来做,而不是在前端过滤,是因为代理层是链路上唯一一个「所有回复都必须经过」的位置:
买家消息 → cs_web/app.py(Flask 代理)
├── 转发到 Dify API
├── clean_answer():剥离思考过程
└── 返回干净回复
把清洗放在必经之路上,而不是放在每个调用点,是这类系统能长期维护的关键。否则每加一个新的入口,都要重新记得「这里也要去一次思考过程」。
浏览器自动化那一环#
ui_tars_demo/tars_demo.py 负责把 AI 的回复送回给买家:读取浏览器消息框中的买家消息 → 调 Dify API 生成回答 → 回填到消息框。仓库里还带了一个 demo_msg.html 作为模拟消息框页面,方便在没有真实店铺的情况下把这一环跑通。
「模拟页面」这个细节值得单独提一句:它让整条链路可以被分段验证——前端、代理、Dify 工作流、浏览器自动化,每一段都能单独跑。相比之下,一上来就对着真实店铺联调,出问题时你连是哪一段坏了都分不清。
README 的声明里写得很清楚:本项目是技术 Demo,生产环境接入 TikTok 需使用官方开放平台 API 或桥接服务。浏览器自动化适合验证链路,不适合当作长期的生产接入方式。
索引卡住的坑:连接池耗尽#
仓库专门留了一节「关键踩坑经验」给二次开发的人,其中一条很有代表性:Dify 知识库索引会因 SQLAlchemy 连接池耗尽而停滞,需要控制并发、串行处理文档。
这类问题的麻烦之处在于症状:任务不报错,只是一直停在「索引中」。你以为它在慢慢跑,其实它已经卡死了。所以处理方式不是「多等等」,而是从提交侧就不给连接池压力:
- 控制并发。文档不要一次性全部丢进去。
- 串行处理。一份处理完再提交下一份,牺牲速度换稳定性。
- 把「建知识库」当成有状态的运维动作,而不是一次性的初始化脚本——它会失败,失败后要能接着跑。
另外两条踩坑经验也一并记在这里:一是思考过程的剥离(见上一节),二是「知识库只放售前」这条核心手段本身。三条经验合起来看,恰好覆盖了这类项目最容易出问题的三个位置:模型输出、基础设施、业务边界。
跑起来需要什么#
本地起 Dify 用的是官方 compose:
cd dify/docker
docker compose up -d
# 访问 http://localhost:80,完成管理员初始化
然后按操作指南接入模型(DeepSeek / 通义千问 / 智谱)、建售前知识库、搭「售前 AI / 售后人工」分流的 Chatflow。前端代理需要两个环境变量:
| 变量 | 作用 | 默认值 |
|---|---|---|
DIFY_BASE_URL | Dify API 地址 | http://localhost/v1 |
DIFY_API_KEY | Chatflow 应用 API Key | 需要自己配置 |
cd cs_web
pip install -r requirements.txt # flask, requests
python3 app.py
# 访问 http://localhost:8000
仓库里的 dify/ 目录是 langgenius/dify 的开源平台源码(保留其原始 LICENSE),已经去掉了运行时产物,用于本地私有化部署。客服 Demo 部分与 Dify 源码各自遵循原项目的许可。
这套方案的边界#
把它当 Demo 看,它解决了一个真问题;把它当生产方案看,还有几件事要先想清楚:
- 接入方式。浏览器自动化能验证链路,但生产环境应当走官方开放平台 API 或桥接服务。
- 转人工之后的闭环。「转人工」不是一个句号,人工接手的时效、话术、记录都需要另外一套流程来兜。
- 知识库的更新责任。价格、尺码、物流时效都会变,谁在什么时候更新知识库,决定了这套系统的保质期。
- 考核指标的口径。24h / 48h 回复率算的是「有没有回」,而不是「回得对不对」——用自动化满足前者的时候,别把后者丢掉。
小结#
rag-cs-bot 最值得借鉴的,不是「用 Dify 接了 RAG」这个动作,而是它对能力边界的处理方式:不是告诉模型「这件事你不能做」,而是让它在数据里根本找不到做这件事的材料。前者是请求,后者是机制。
这个思路可以直接迁移到别的场景:凡是「一旦答错就不可挽回」的问题类型,都不该交给模型自由发挥,而应该在检索层就把它排除掉。换句话说,限制一个 AI 系统最可靠的方式,是控制它能看到什么。