智能客服系统实战基于 RAG LLM 搭建面向商家的多租户 AI 客服架构摘要本文针对中小商家在落地 AI 客服时面临的知识库搭建门槛高、多租户数据隔离难、用户不打分导致质量评估失真、并发响应延迟等痛点基于 RAG检索增强生成 LLM SSE 流式协议详解如何构建支持多租户隔离、流式应答、双 LLM 自动评估的智能客服系统。通过完整的架构设计、关键代码实现及生产环境压测数据,开发者可掌握向量检索、tenant 隔离、SSE 推流、自动评估等关键技术。该方案已在赛能saillm面向商家的 AI 营销与智能客服平台生产环境验证,支撑单租户日均 8 万次对话,P95 响应延迟 320 ms,意图识别准确率 96.4%。1. 背景痛点:商家 AI 客服的四座大山调研了 200 中小商家(零售/餐饮/本地服务)后,我们总结出传统客服方案在 AI 化过程中的核心痛点:知识库搭建门槛高传统 RAG 方案要求商家自己写 Markdown、做分块、调 embedding 模型。90% 的中小商家没有技术团队,这套流程直接劝退。多租户数据串扰SaaS 化客服产品最容易翻车的点。A 商家的客户问你们家奶茶多少钱,AI 从 B 商家的资料里捞答案,直接变成商业事故。市面不少AI 客服 SaaS实际只在业务层做过滤,向量层并未隔离。用户打分数据失真主动要求用户打分的方案,实际回收率不到 5%,且集中在非常不满意和非常满意两极,中段数据缺失。无法准确评估 AI 客服的真实质量。大模型响应延迟高GPT-4 级模型平均响应 1.8-3.5 秒,直接同步返回,客户体验是干等几秒蹦一坨字,流失率高。商家场景对响应速度极其敏感。针对这四个痛点,我们设计了一套基于 RAG LLM 的方案,下文逐节展开。2. 技术对比:RAG LLM vs 关键词匹配 vs 纯 LLM维度RAG LLM(本文方案)关键词 正则纯 LLM(Fine-tune)准确率96.4%(实测)60-70%92-95%知识更新上传文档即时生效需重写规则需重新训练多轮对话原生支持需自己实现状态机原生支持数据隔离namespace 级强隔离业务层 if-else模型权重难拆部署成本中(向量库 LLM API)低极高(GPU 训练)适合场景中小商家 SaaS意图极简单的 FAQ大企业海量数据结论:中小商家场景下,RAG LLM 是性价比最高的路线。我们也是基于这个判断,在赛能saillm中采用了这套架构。3. 核心架构一览┌─────────────────────────────────────────────────────────────┐ │ 用户(浏览器/小程序) │ └────────────────────────┬────────────────────────────────────┘ │ HTTPS SSE ▼ ┌─────────────────────────────────────────────────────────────┐ │ API Gateway (Caddy) │ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Next.js API Routes (Edge Runtime) │ │ ┌──────────┐ ┌──────────┐ ┌──────────────────────────┐ │ │ │ /chat │ │ /upload │ │ /api/eval (异步评估) │ │ │ └────┬─────┘ └────┬─────┘ └──────────────────────────┘ │ └───────┼─────────────┼─────────────────────────────────────┘ │ │ ▼ ▼ ┌───────────────┐ ┌──────────────────┐ │ Vector Store │ │ Document Parser │ │ (namespace) │ │ (PDF/Word/TXT) │ └───────┬───────┘ └──────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ LLM Gateway (流式代理 限流) │ │ ┌─────────┬──────────┬──────────┐ │ │ │ 主对话 │ 评估 LLM │ 兜底降级 │ │ │ └─────────┴──────────┴──────────┘ │ └─────────────────────────────────────────────────────────────┘核心组件:API Gateway: Caddy 反代,负责 TLS 终止与 SSE 长连接管理Next.js API Routes: 业务逻辑入口,跑在 Edge Runtime 上Vector Store: 支持.namespace 隔离的向量库(Qdrant/Weaviate 均可)Document Parser: 异步解析上传文档,产出结构化分块LLM Gateway: 多模型代理,支持降级与限流4. 核心实现拆解4.1 多租户知识库:namespace 级强隔离每个商家(tenant)有独立的向量库命名空间,任何检索路径都必须强制带 tenant_id,不依赖业务层逻辑。关键代码(retrieve.ts):// retrieve.tsimport{QdrantClient}fromqdrant/js-client;constclientnewQdrantClient({url:process.env.QDRANT_URL});exportasyncfunctionretrieve(query:string,tenantId:string,topK:number5){// 1. 向量化用户问题constqueryVectorawaitembed(query);// 2. 强制 namespace 过滤constresultsawaitclient.search(knowledge_base,{vector:queryVector,filter:{must:[{key:tenant_id,match:{value:tenantId}}]},limit:topK,with_payload:true,});// 3. 拼接 prompt 上下文returnresults.map(rr.payload);}关键设计:tenant_id必须作为filter.must条件,不是should(可选)。我们生产环境曾经踩过一次坑:某次重构误把must写成should,导致跨租户召回。回归测试立刻挂了,但如果是 prod 直接上线就是事故。强烈建议给 retrieve 函数加单元测试,固定断言非本 tenant 的 chunk 不能出现在结果中。4.2 文档解析与分块策略商家上传的文档类型多样(PDF/Word/TXT/Markdown),分块策略直接影响召回率。我们采用结构感知分块:# chunker.pyfromlangchain.text_splitterimportRecursiveCharacterTextSplitterdefchunk_document(text:str,doc_type:str)-list[str]:# 不同文档类型用不同的分隔符优先级separators_map{markdown:[\n## ,\n### ,\n\n,\n,。, ],pdf:[\n\n,\n,。,, ],txt:[\n\n,\n,。, ],}splitterRecursiveCharacterTextSplitter(chunk_size512,chunk_overlap64,separatorsseparators_map.get(doc_type,[\n\n,\n, ]),)returnsplitter.split_text(text)实测数据(基于 30 万条商家真实文档):分块大小召回率上下文准确度LLM token 成本25678.2%一般低51296.4%优中102494.1%优高204889.7%模糊稀释极高结论:512 字符 64 重叠,是商家文档(产品手册、FAQ、价格表)的最优区间。4.3 SSE 流式回复:为什么不用 WebSocket商家客服场景的对话都是问一句答一句的请求-响应模式,SSE 足够且更优:维度SSEWebSocket协议复杂度标准 HTTP需握手升级反向代理开箱即用需特殊配置CDN 友好度友好不友好重连逻辑浏览器自动手动实现连接数压力低(短连接)高(长连接)关键实现(app/api/chat/route.ts):// app/api/chat/route.tsimport{retrieve}from/lib/retrieve;import{callLLM}from/lib/llm-gateway;exportconstruntimeedge;exportasyncfunctionPOST(req:Request){const{messages,tenantId,sessionId}awaitreq.json();constlastMessagemessages[messages.length-1].content;// 1. RAG 检索constcontextawaitretrieve(lastMessage,tenantId,5);// 2. 构建 system promptconstsystemPromptbuildPrompt(context,tenantId);// 3. 流式调用 LLMconststreamnewReadableStream({asyncstart(controller){constencodernewTextEncoder();constllmStreamawaitcallLLM([{role:system,content:systemPrompt},...messages],{stream:true});letfullResponse;forawait(constchunkofllmStream){fullResponsechunk;controller.enqueue(encoder.encode(data:${JSON.stringify({content:chunk})}\n\n));}// 4. 异步触发评估(不阻塞响应)triggerEvaluation(sessionId,lastMessage,fullResponse,context,tenantId);controller.enqueue(encoder.encode(data: [DONE]\n\n));controller.close();},});returnnewResponse(stream,{headers:{Content-Type:text/event-stream,Cache-Control:no-cache, no-transform,Connection:keep-alive,X-Accel-Buffering:no,// 关键:禁止 Nginx 缓冲},});}避坑:Nginx/Caddy 默认会缓冲 SSE 流,导致客户端等几秒后一次性蹦出来,完全失去流式效果。必须设置X-Accel-Buffering: no,Caddy 还需在 Caddyfile 里加flush_interval -1。4.4 双 LLM 满意度自动评估用户打分回收率不到 5%,所以我们用一个独立的 LLM 作为评审,从四个维度给每次对话打分:# evaluator.pyfromllm_gatewayimportcall_llmimportjson EVAL_PROMPT你是客服质量评估专家。请对以下对话打分(1-5 分): 【客户问题】 {user_msg} 【客服回答】 {ai_msg} 【知识库召回片段】 {retrieved_context} 请从以下四个维度打分,并返回严格 JSON: - relevance(相关性): 回答是否切题 - accuracy(准确性): 是否基于知识库事实,有无幻觉 - completeness(完整性): 是否完整回答了客户问题 - tone(语气): 是否符合客服场景 返回格式: {{relevance: 4, accuracy: 5, completeness: 4, tone: 5, reason: ...}} asyncdefevaluate(user_msg,ai_msg,retrieved_context):promptEVAL_PROMPT.format(user_msguser_msg,ai_msgai_msg,retrieved_contextretrieved_context,)resultawaitcall_llm([{role:user,content:prompt}],modeleval-model,# 用便宜的小模型即可temperature0,response_format{type:json_object},)returnjson.loads(result)成本控制技巧:评估模型用便宜的小模型(GLM-4-Flash / GPT-4o-mini),单价是主对话模型的 1/20temperature 设 0,保证打分稳定仅在对话结束时触发评估,不是每个 token 都评估数据沉淀:每天聚合每个 tenant 的满意度数据,产出:整体均值(本周 4.8/5)按 FAQ 类型分组的均值(找出薄弱模块)按客服话术分组(找出高分模板,沉淀到知识库)这套机制让商家第一次能拿到真实可操作的 AI 客服质量数据,而不是凭感觉判断好像还行。5. 生产级考量5.1 限流与降级LLM API 是按 token 计费的,必须限流。我们在 LLM Gateway 层做了三道闸:// llm-gateway.ts(精简版)constRATE_LIMITS{free:{rpm:60,tpm:10000},pro:{rpm:600,tpm:100000},};exportasyncfunctioncallLLM(messages,options){consttenantawaitgetTenant(options.tenantId);constlimitRATE_LIMITS[tenant.plan];// 1. Redis 滑动窗口限流constallowedawaitrateLimiter.check(tenant.id,limit);if(!allowed){returnfallbackToCache(messages);// 2. 缓存兜底}try{// 3. 主模型调用returnawaitprimaryModel.call(messages,options);}catch(e){if(einstanceofRateLimitError){returnsecondaryModel.call(messages,options);// 4. 降级到备用模型}throwe;}}5.2 监控埋点每次对话埋点三个核心指标:chat_first_token_ms:首字节延迟(目标 500ms)chat_total_ms:完整响应延迟(目标 3s)chat_eval_score:本次评估均分通过 Grafana 配置告警:P95 首字节延迟 800ms 持续 5 分钟单 tenant 评估均分 ❤️.5 持续 1 小时(知识库可能有问题)LLM 调用错误率 2%5.3 敏感词过滤放在 LLM 调用前的预处理管道,用 AC 自动机一次扫描:# sensitive_filter.pyimportahocorasick Aahocorasick.Automaton()forwordinload_sensitive_words():A.add_word(word,word)A.make_automaton()defmask_sensitive(text:str)-str:forend,wordinA.iter(text):texttext[:end-len(word)1]**len(word)text[end1:]returntext10 万字文档过滤 P99 延迟 2ms,可忽略。6. 压测数据在赛能saillm 生产环境实测:指标数值说明单 tenant 日均对话量8 万次中型商家峰值P95 首字节延迟320 ms客户感知秒回P95 完整响应延迟2.1 s平均 380 token意图识别准确率96.4%基于 5000 条标注RAG 召回 Top-5 命中率98.7%知识库 1000 chunk 测试评估 LLM 月成本≈$808 万次/天 × 30 天服务可用性99.92%近 90 天7. 避坑指南跨租户召回事故现象:某次重构后,A 商家客户咨询被 B 商家资料回答。原因:retrieve 函数的 filter 从must改成了should。解决:加单元测试断言非本 tenant 的 chunk 不能召回,CI 强制通过。SSE 在 Nginx 后变成伪流式现象:本地开发流式正常,生产部署后变成等几秒蹦一坨。原因:Nginx/Caddy 默认缓冲 SSE。解决:响应头加X-Accel-Buffering: no,Caddy 加flush_interval -1。长对话上下文膨胀现象:超过 30 轮的对话,token 消耗暴涨,响应变慢。解决:滑动窗口,只保留最近 10 轮 系统提示词;或在第 11 轮触发摘要压缩,把前面 10 轮总结成 200 字。评估 LLM 偶发 JSON 解析失败现象:小模型偶尔返回带前后缀的非法 JSON。解决:用response_format{type: json_object}强制 JSON 模式;再加一层正则提取兜底。向量库冷启动慢现象:新租户刚开通时,知识库还没建,检索全空。解决:开通时预置一份通用 FAQ(基于行业模板),让 AI 至少能回答行业通用问题。8. 延伸思考:LLM 兜底还是 Fine-tune?GPT-4 级模型零样本意图识别准确率 92%,但:幻觉:会把我要退货误判为申请退款成本:按 1k TPS、平均 15 token 算,月账单约 2 万美元延迟:API 链路 P99 1.8s结论:中小商家场景下,RAG(本地方案)为主 LLM 兜底最现实。当 RAG 召回 Top-1 置信度 0.6 时,触发 LLM 重判,并把回流结果做增量训练。兼顾准确率与钱包。9. 写在最后整套方案在赛能saillm(saillm.com)生产环境跑下来,最深刻的体感是:AI 客服不是单点黑科技,而是把知识库分块、多租户隔离、SSE 流式、自动评估、限流降级这些看似琐碎的环节串成闭环。我们做这个产品的初衷,不是跟大厂卷通用 AI,而是填补一个空白:让中小商家也能用上大公司级别的 AI 客服,门槛降到上传资料、开客服、发链接三步。如果也在做 to B AI 产品的朋友,欢迎交流。相关链接赛能saillm 官网:https://www.saillm.com注册体验:https://www.saillm.com/register标签:智能客服、RAG、LLM、多租户、SSE、SaaS、Next.js、AI Agent