基于FSB编排框架构建高可用AI客服问答系统实战 1. 为什么选 FSB 来做 AI 客服问答系统1.1 从零手搓 RAG 的痛点在哪做过 AI 客服的人都知道最耗时的从来不是调模型接口而是把用户问一句话系统能准确找到答案并组织成人话回复这条链路跑通。早期我试过纯手搓方案自己写文档切片逻辑、自己接向量库、自己拼 Prompt、自己处理多轮上下文结果就是每个环节都能跑但每个环节都不够稳。文档切片切得不好检索召回率直接崩向量库选型纠结半天换一个库就要重写一遍适配层Prompt 模板散落在代码各处改一句话要翻五个文件。更麻烦的是扩展性。客服场景天然是多知识库、多业务线、多轮对话的叠加态今天接产品手册明天要接售后政策后天又要支持工单查询。如果底层没有一套统一的编排框架每加一个数据源就是一次重构。我踩过最深的坑是第一版系统上线两周后业务方要求把问答准确率从 70% 提到 90%我回头一看检索层、重排层、生成层全是硬编码根本没法做 A/B 实验只能推倒重来。FSB 这类编排框架的价值就在这里——它把文档摄取、切片、向量化、检索、重排、生成这条链路抽象成了可配置的节点你不需要从零造轮子而是把精力放在业务逻辑和效果调优上。这不是偷懒是把有限的时间花在真正产生差异化的地方。1.2 FSB 到底解决了哪些核心问题FSB 的核心思路是流程即配置。它把 RAG 链路拆成几个标准阶段数据接入、文本处理、索引构建、检索召回、结果重排、答案生成。每个阶段都有默认实现也允许你替换成自己的逻辑。这意味着什么意味着你可以先用默认配置跑通一个 Demo确认链路没问题后再逐个节点替换成适合自己业务的方案。具体来说它解决了三个层面的问题。第一是工程层面的标准化文档加载器、切片器、Embedding 模型、向量存储、LLM 接口都有统一抽象换模型或换库不需要改业务代码。第二是效果层面的可调优检索参数、重排策略、Prompt 模板都可以独立调整方便做消融实验。第三是扩展层面的可组合多知识库可以并行检索后融合多轮对话可以挂载记忆模块工单查询可以接自定义 Tool。我个人的判断是如果你要做的是一个长期维护、持续迭代的 AI 客服系统而不是一次性 Demo那用编排框架几乎是必然选择。手搓方案在 POC 阶段确实快但进入迭代期后维护成本会指数级上升。1.3 适合哪些人参考这套方案这套方案适合三类人。第一类是有后端经验但没怎么接触过 RAG 的开发者你懂 API 调用、懂数据库、懂服务部署但对向量检索、文本切片这些概念还比较模糊跟着走一遍就能建立完整认知。第二类是已经做过简单问答 Demo 但效果不稳定的团队你们可能已经用 LangChain 或类似工具跑通了流程但召回率上不去、回答经常跑偏需要一套系统性的调优方法。第三类是需要快速交付 AI 客服原型的独立开发者或小团队没有资源从零搭建基础设施需要一套开箱即用又能深度定制的方案。不适合谁如果你只是想让模型回答几个固定问题直接写死 Prompt 调 API 就够了没必要上编排框架。如果你对延迟极度敏感比如要求 200ms 内返回那可能需要更底层的优化编排框架的抽象层会带来额外开销。2. 系统整体架构与核心模块拆解2.1 四层架构从数据到答案的完整链路我把整个系统分成四层每层职责清晰层与层之间通过标准接口通信。这样设计的好处是任何一层出问题可以单独排查和替换不会牵一发动全身。数据接入层负责把各种格式的知识源统一成纯文本。客服场景的知识源通常包括PDF 产品手册、Markdown 帮助文档、Excel FAQ 表、数据库里的工单记录、甚至网页抓取的内容。这一层要处理编码问题、格式解析、元数据提取。我的经验是元数据比正文还重要——每段文本都要带上来源、业务线、更新时间、权限标签后面检索过滤全靠它。索引构建层负责把文本切成合适大小的块转成向量存进向量库。切片策略直接决定召回质量后面会详细讲。这一层还要维护增量更新逻辑知识库变了哪些块需要重新索引哪些可以复用。检索召回层是效果的核心。用户问题进来后先做查询改写把口语化问题转成检索友好的表达然后并行走向量检索和关键词检索各自召回一批候选再用重排模型精排。这一步的召回率和准确率基本决定了最终答案的上限。生成编排层负责把检索到的上下文和用户问题拼成 Prompt调 LLM 生成答案同时处理多轮对话记忆、引用标注、敏感词过滤、兜底策略。这一层还要做流式输出让用户感觉响应快。2.2 为什么检索层要向量关键词双路并行很多人做 RAG 只做向量检索觉得语义相似就够了。但客服场景里大量问题是包含专有名词、产品型号、订单编号的比如XX-2000 型号的保修期是多久。向量检索对这类精确匹配反而不敏感因为 Embedding 模型会把XX-2000这种 token 泛化掉。我实测过纯向量检索在含型号的问题上召回率只有 60% 左右加上关键词检索后能到 85% 以上。双路并行的具体做法是向量检索走语义相似关键词检索走 BM25 或类似算法两路各召回 Top-K然后做融合。融合策略有两种一种是 RRFReciprocal Rank Fusion按排名倒数加权简单且效果稳定另一种是加权分数融合需要归一化分数调参麻烦一些。我一般先用 RRF够用就不折腾。注意双路检索会带来延迟增加因为要等两路都返回。优化方法是并行发起取最慢那路的时间而不是串行相加。另外关键词检索的索引要单独维护增量更新时别忘了同步。2.3 重排模型把差不多相关变成真正相关检索召回阶段追求的是不漏所以会召回比较多候选比如 Top-20。但真正喂给 LLM 的上下文不能太多否则一是超 token 限制二是无关内容会干扰生成。这时候就需要重排模型来精排。重排模型通常是 Cross-Encoder 结构把问题候选文本拼在一起过一遍模型输出相关性分数。它比向量检索的 Bi-Encoder 精度高很多但速度慢所以只适合对少量候选做精排。我的配置是向量关键词各召回 Top-20合并去重后大概 25-30 条重排后取 Top-5 喂给 LLM。重排模型的选择上如果追求效果可以用较大的模型如果追求速度可以用蒸馏后的小模型。我试过在 CPU 上跑重排30 条候选大概要 1-2 秒GPU 上可以压到 200ms 以内。如果延迟敏感可以考虑用轻量级重排或者只对 Top-10 做重排。2.4 生成层的 Prompt 编排与兜底策略生成层看起来简单就是把上下文和问题拼起来调 LLM但实际有很多细节。Prompt 模板要明确告诉模型只根据提供的上下文回答上下文没有的信息不要编造如果无法回答就明确说根据现有资料无法回答。这句话一定要加否则模型很容易自由发挥。上下文拼接也有讲究。我一般按相关性从高到低排列每段前面加上来源标记比如[来源产品手册第 3 章]。这样模型在生成时可以参考来源也方便后续做引用标注。如果上下文总长度超过模型窗口要按相关性截断而不是简单截断尾部。兜底策略分三层第一层是检索结果相关性低于阈值时直接返回抱歉我没有找到相关信息第二层是 LLM 生成时检测到无法回答类表述走兜底话术第三层是系统异常时返回预设的友好提示。这三层要分别配置不能混在一起。3. 核心实操从零搭建的完整步骤3.1 环境准备与依赖安装先把基础环境搭起来。我习惯用 Python 3.10因为很多新库对 3.8 的支持在减弱。虚拟环境用 conda 或 venv 都行我一般用 conda因为后面可能要装一些需要编译的包。conda create -n ai-cs python3.10 conda activate ai-cs核心依赖包括FSB 框架本身、向量库客户端、Embedding 模型 SDK、LLM 接口 SDK、文档解析库。具体装哪些取决于你的技术选型。我一般会装这些pip install fsb-core pip install chromadb pip install sentence-transformers pip install openai pip install pypdf markdown beautifulsoup4向量库我选 Chroma原因是它轻量、本地可跑、API 简单适合快速验证。如果数据量上千万级别可能要换 Milvus 或 Qdrant。Embedding 模型先用开源的 sentence-transformers 跑通后面再换 API 方案。提示依赖版本一定要锁死写进 requirements.txt。我踩过坑某次升级向量库客户端后索引格式不兼容重建了整个知识库。生产环境务必用固定版本。3.2 知识库接入与文本切片策略知识库接入的第一步是统一格式。我写了一个加载器工厂根据文件后缀分发给不同的解析器。PDF 用 pypdfMarkdown 直接读Excel 用 pandas网页用 beautifulsoup。解析出来的文本要带上元数据来源文件、页码、章节标题、业务线标签。切片是重头戏。我的经验是切片大小没有万能值要根据文本类型调。产品手册这种结构化强的按章节切每片 500-800 字FAQ 这种一问一答的按问答对切每片就是一个完整问答长文档用递归切片先按段落切段落太长再按句子切保持语义完整。def split_by_structure(text, max_len800, overlap100): paragraphs text.split(\n\n) chunks [] current for p in paragraphs: if len(current) len(p) max_len: current p \n\n else: if current: chunks.append(current.strip()) current p \n\n if current: chunks.append(current.strip()) return chunksoverlap 的作用是防止关键信息刚好被切在边界上。我一般设 10%-15% 的重叠。切片完每片都要生成唯一 ID存进向量库时一起写入元数据。3.3 向量化与索引构建向量化就是把文本块转成向量。我用的模型是开源的 bge-small-zh中文效果不错速度也快。如果追求更好效果可以换 bge-large 或 API 方案但延迟和成本会上去。from sentence_transformers import SentenceTransformer model SentenceTransformer(BAAI/bge-small-zh-v1.5) def embed_texts(texts): embeddings model.encode(texts, normalize_embeddingsTrue) return embeddings.tolist()normalize 很重要归一化后余弦相似度计算更快而且很多向量库默认用内积归一化后内积等价于余弦。索引构建时我建议分批写入每批 100-500 条避免一次性写入太多导致内存爆掉。写入时把元数据一起存进去后面检索过滤要用。import chromadb client chromadb.PersistentClient(path./chroma_db) collection client.get_or_create_collection( nameknowledge_base, metadata{hnsw:space: cosine} ) def index_chunks(chunks, embeddings, metadatas, ids): batch_size 200 for i in range(0, len(chunks), batch_size): collection.add( documentschunks[i:ibatch_size], embeddingsembeddings[i:ibatch_size], metadatasmetadatas[i:ibatch_size], idsids[i:ibatch_size] )3.4 检索链路配置与参数调优检索链路我配了三路向量检索、关键词检索、元数据过滤。向量检索走 Chroma 的 query 接口关键词检索用 rank_bm25 单独建索引元数据过滤在检索时加 where 条件。def vector_search(query, top_k20, filter_dictNone): query_embedding model.encode([query], normalize_embeddingsTrue).tolist() results collection.query( query_embeddingsquery_embedding, n_resultstop_k, wherefilter_dict ) return results关键词检索我单独维护一个 BM25 索引每次知识库更新时重建。BM25 对中文需要先分词我用 jieba 做分词。import jieba from rank_bm25 import BM25Okapi tokenized_corpus [list(jieba.cut(doc)) for doc in all_documents] bm25 BM25Okapi(tokenized_corpus) def keyword_search(query, top_k20): tokenized_query list(jieba.cut(query)) scores bm25.get_scores(tokenized_query) top_indices sorted(range(len(scores)), keylambda i: scores[i], reverseTrue)[:top_k] return [all_documents[i] for i in top_indices]两路结果用 RRF 融合def rrf_fusion(results_list, k60): scores {} for results in results_list: for rank, doc_id in enumerate(results): scores[doc_id] scores.get(doc_id, 0) 1 / (k rank 1) return sorted(scores.items(), keylambda x: x[1], reverseTrue)k 值一般设 60这是 RRF 论文里的推荐值我实测下来 40-80 之间差异不大。3.5 重排与生成把候选变成最终答案重排我用的是 bge-reranker-base把问题和候选文本拼起来过模型输出相关性分数。from sentence_transformers import CrossEncoder reranker CrossEncoder(BAAI/bge-reranker-base) def rerank(query, candidates, top_k5): pairs [[query, doc] for doc in candidates] scores reranker.predict(pairs) ranked sorted(zip(candidates, scores), keylambda x: x[1], reverseTrue) return [doc for doc, _ in ranked[:top_k]]生成层的 Prompt 模板我固定成这个结构PROMPT_TEMPLATE 你是一个专业的客服助手。请根据以下参考资料回答用户问题。 参考资料 {context} 用户问题{question} 回答要求 1. 只根据参考资料回答不要编造信息 2. 如果参考资料中没有相关信息请回答根据现有资料无法回答该问题 3. 回答要简洁、准确、友好 4. 如果涉及多个要点分条列出 回答上下文拼接时按相关性排序每段前加来源标记。如果总长度超过 3000 token按相关性截断。def build_context(docs, max_tokens3000): context for doc in docs: piece f[来源{doc[source]}]\n{doc[text]}\n\n if len(context) len(piece) max_tokens * 2: break context piece return context.strip()3.6 多轮对话与记忆管理客服场景经常是多轮的用户会追问、补充条件。我的做法是维护一个对话历史列表每次生成时把最近 N 轮拼进 Prompt。但要注意历史太长会挤占上下文空间所以只保留最近 3-5 轮更早的做摘要压缩。class ConversationMemory: def __init__(self, max_turns5): self.history [] self.max_turns max_turns def add(self, role, content): self.history.append({role: role, content: content}) if len(self.history) self.max_turns * 2: self.history self.history[-self.max_turns * 2:] def get_context(self): return \n.join([f{h[role]}: {h[content]} for h in self.history])查询改写也要考虑多轮。比如用户先问XX 型号保修多久再问那 YY 型号呢第二句的那指代前文直接检索会丢上下文。我的做法是用 LLM 做一次查询改写把指代消解掉再检索。4. 效果调优与常见问题排查4.1 召回率上不去的五个排查方向召回率是 RAG 系统的生命线。如果用户问的问题明明知识库里有但系统答不出来八成是召回环节出了问题。我总结了五个排查方向按优先级排序。第一切片是否合理。如果切片太大一个块里混了多个主题向量表示会被稀释如果切片太小关键信息被切散检索时匹配不上。我的经验是先可视化几个典型问题的召回结果看看召回的块是不是真的包含答案。如果不包含先调切片。第二Embedding 模型是否匹配。中文场景用英文模型效果会差很多通用模型用垂直领域效果也会打折。如果知识库是法律、医疗这类专业领域考虑用领域微调过的 Embedding 模型。第三查询改写是否到位。用户口语化表达和知识库书面表达之间有鸿沟。比如用户问东西坏了咋整知识库写的是产品故障处理流程。加一层查询改写用 LLM 把口语转成书面表达召回率能提升 10-20 个百分点。第四关键词检索是否覆盖。纯向量检索对专有名词不敏感加上 BM25 能补上这块。如果知识库里有大量型号、编号、代码关键词检索几乎是必须的。第五元数据过滤是否过严。有时候为了精准加了太多过滤条件结果把正确答案过滤掉了。排查时先把过滤条件去掉看召回是否恢复再逐个加回来定位问题。4.2 回答跑偏与幻觉的抑制方法幻觉是 LLM 的通病客服场景尤其致命因为用户会当真。抑制幻觉有几个层次的手段。最直接的是 Prompt 约束。在 Prompt 里明确写只根据参考资料回答、不要编造并且给几个反例。我试过加了明确约束后幻觉率能降一半左右。其次是检索质量。如果检索到的上下文本身就不相关模型只能瞎编。所以重排环节要把不相关的候选过滤掉宁可少给上下文也不要给错上下文。我一般设一个相关性阈值低于阈值的直接丢弃。第三是生成后的校验。可以用另一个 LLM 做事实核查把生成的答案和检索到的上下文对比看是否有无中生有的内容。这个方案成本高适合对准确性要求极高的场景。第四是兜底话术。当检索结果相关性都低于阈值时直接返回根据现有资料无法回答而不是让模型硬答。这句话虽然用户体验上差一点但比胡编乱造强得多。实操心得我在 Prompt 里加了一句如果参考资料中有相互矛盾的信息请指出矛盾并说明。这句话能触发模型做一致性检查减少盲目采信某一条的情况。4.3 延迟优化的六个实用技巧AI 客服的响应延迟直接影响用户体验。我实测下来一个完整的 RAG 链路从用户提问到首字返回优化前大概 3-5 秒优化后能压到 1-2 秒。以下是六个我常用的技巧。第一并行化。向量检索和关键词检索并行发起不要串行。重排和生成也可以考虑流水线但生成依赖重排结果只能串行。第二缓存。高频问题的检索结果可以缓存下次同样问题直接命中。Embedding 也可以缓存相同文本不用重复计算。我用 Redis 做缓存命中率大概 30% 左右。第三流式输出。LLM 生成是逐 token 的用流式接口可以让用户更快看到首字。虽然总时间没变但感知延迟大幅降低。第四模型选型。Embedding 和重排用轻量模型生成用大模型。不要所有环节都用最大的模型没必要。第五批处理。如果有多个候选要重排一次 batch 过模型比逐条快很多。第六索引优化。向量库的索引类型要选对HNSW 比 IVF 快但内存占用高根据数据量权衡。关键词检索的倒排索引要定期重建避免碎片化。4.4 常见问题速查表问题现象可能原因排查方法解决方案答非所问检索结果不相关打印召回内容人工检查调切片、加查询改写、调重排阈值回答无法回答但知识库有召回失败用答案关键词直接检索测试加关键词检索、放宽元数据过滤回答包含编造信息幻觉对比答案和上下文加强 Prompt 约束、加事实核查响应超过 5 秒链路串行或模型太大打点各环节耗时并行化、换轻量模型、加缓存多轮对话丢失上下文记忆管理问题检查历史拼接逻辑加查询改写、保留最近 N 轮专有名词检索不到向量模型泛化用型号直接检索测试加 BM25 关键词检索知识库更新后检索不到新内容索引未更新检查增量更新逻辑重建索引或补增量写入相同问题答案不一致生成随机性固定随机种子测试降低 temperature、固定 Prompt4.5 扩展性设计从单知识库到多业务线系统上线后业务方一定会提新需求能不能接售后政策库、能不能查工单、能不能支持多语言。如果一开始没做扩展性设计每次加需求都是重构。我的做法是知识库按业务线分 collection检索时根据用户身份或问题类型路由到对应 collection。如果问题跨业务线就并行检索多个 collection 再融合。这样加新业务线只需要新建 collection 和配置路由规则不用改核心代码。工单查询这类结构化数据不适合走向量检索我封装成 Tool让 LLM 决定是否调用。FSB 支持 Tool 编排把工单查询接口注册成 ToolPrompt 里告诉模型如果需要查询工单状态调用 query_ticket 工具。这样模型会根据问题自动决定走知识库还是走 Tool。多语言支持分两步第一步是查询改写时检测语言第二步是检索时用多语言 Embedding 模型。如果知识库本身是多语言的建议按语言分 collection避免跨语言检索的语义漂移。5. 上线部署与持续迭代5.1 服务化部署的三种方案Demo 跑通后要上线部署方案取决于团队规模和运维能力。我经历过三种方案各有适用场景。单机部署最简单一台服务器跑 FastAPI 服务向量库用本地文件适合日活几百的小规模场景。优点是运维简单缺点是单点故障扩容只能垂直升级。容器化部署用 Docker 打包服务向量库用独立容器通过 Docker Compose 编排。适合中等规模可以水平扩容 API 服务向量库单独维护。我用这个方案最多平衡了复杂度和扩展性。Kubernetes 部署适合大规模场景API 服务、向量库、缓存、消息队列都独立部署通过 K8s 做编排和自动扩缩容。运维复杂度高但弹性和可靠性最好。如果团队没有 K8s 经验不建议一上来就上。不管哪种方案都要做健康检查、日志收集、监控告警。我一般用 Prometheus 采集指标Grafana 做看板重点监控 QPS、延迟、错误率、召回率。5.2 效果监控与数据回流上线不是终点而是迭代的起点。我建了一套监控体系记录每次问答的完整链路用户问题、改写后查询、召回内容、重排分数、生成答案、用户反馈。这些数据是调优的燃料。用户反馈我设了两个入口显式的点赞点踩隐式的追问和转人工。点踩和转人工的问题要重点分析看看是召回问题还是生成问题。追问往往意味着上一轮回答不完整也要标记出来。数据回流后我每周做一次 bad case 分析把问题分类切片问题、召回问题、重排问题、生成问题、知识库缺失。每类问题对应不同的优化动作。知识库缺失的反馈给业务方补充召回问题的调检索参数生成问题的改 Prompt。5.3 知识库更新的自动化流程知识库不是一成不变的产品迭代、政策调整都会带来更新。手动更新不现实我搭了一套自动化流程。业务方把更新后的文档放到指定目录触发一个定时任务。任务扫描目录对比文件哈希找出新增和修改的文件。新增文件走完整索引流程修改文件先删除旧索引再重建。删除的文件同步删除索引。import hashlib import os def file_hash(path): with open(path, rb) as f: return hashlib.md5(f.read()).hexdigest() def sync_knowledge_base(source_dir, hash_store): current_files {} for root, _, files in os.walk(source_dir): for f in files: path os.path.join(root, f) current_files[path] file_hash(path) for path, h in current_files.items(): if path not in hash_store or hash_store[path] ! h: reindex_file(path) hash_store[path] h for path in list(hash_store.keys()): if path not in current_files: delete_index(path) del hash_store[path]这套流程跑下来知识库更新基本不用人工干预。但要注意重建索引期间服务不能停所以要用双 collection 切换新索引写到备用 collection写完切换别名再删旧 collection。5.4 成本控制与资源规划AI 客服的成本主要在三块LLM 调用、Embedding 计算、向量库存储。LLM 调用是大头尤其是用大模型 API 的时候。控制成本的手段有几个。第一缓存。高频问题缓存答案直接返回不调 LLM。第二模型分级。简单问题用小模型复杂问题用大模型。可以用一个分类器判断问题难度路由到不同模型。第三上下文压缩。喂给 LLM 的上下文越短token 消耗越少。重排后只取 Top-3 而不是 Top-5能省不少。第四批处理。如果有离线任务攒一批一起调比单条调便宜。Embedding 计算成本相对低但如果知识库很大首次索引也要花不少。我的做法是首次全量索引用离线任务跑增量更新用在线任务。向量库存储成本取决于数据量Chroma 本地存储几乎零成本云服务按量计费要关注。资源规划上我一般按峰值 QPS 的 1.5 倍预留资源。如果日活 1000峰值 QPS 大概 5-10一台 4 核 8G 的机器跑 API 服务够用向量库单独一台 8 核 16G。如果日活上万就要考虑集群和负载均衡了。5.5 安全与合规的底线检查客服系统直接面向用户安全和合规是底线。我上线前会做几项检查。输入过滤用户输入可能包含注入攻击、敏感词、超长文本。要做长度限制、敏感词过滤、特殊字符转义。Prompt 注入尤其要防用户可能在问题里写忽略之前的指令要在 Prompt 里加防护。输出过滤生成的答案要过一遍敏感词和合规检查确保不包含不当内容。我一般用关键词列表加正则匹配复杂场景可以上内容审核 API。权限控制不同用户能访问的知识库不同。内部员工可以查内部文档外部用户只能查公开资料。这个在检索时通过元数据过滤实现用户身份从鉴权系统获取。数据脱敏知识库里的个人信息、订单号、手机号要脱敏后再索引。我一般用正则匹配替换比如手机号替换成***。日志审计所有问答记录要留存方便追溯。但日志里不能存敏感信息要脱敏后再落盘。留存周期根据合规要求定一般 6 个月到 1 年。注意合规要求因行业而异金融、医疗等强监管行业有额外要求。上线前务必和法务确认不要自己想当然。6. 我踩过的坑与实战心得6.1 切片策略的三个反直觉发现第一个发现切片不是越小越好。我一开始觉得切片小检索精度高。结果发现切片太小一个完整答案被切散检索到其中一片但缺少上下文生成时信息不全。后来改成按语义完整性切宁可大一点。第二个发现重叠不是越多越好。重叠太多索引膨胀检索时重复内容多浪费上下文窗口。我最后定在 10%-15%够用。第三个发现元数据比正文还重要。同样的正文带上章节标题、业务线标签后检索准确率明显提升。因为元数据参与了过滤和排序相当于给检索加了先验知识。6.2 关于模型选型的真实对比Embedding 模型我对比过几个开源 small 模型速度快但精度一般large 模型精度好但慢API 方案精度最好但贵且有网络依赖。我的选择是先用 small 跑通效果不够再换 largeAPI 方案作为备选。重排模型我对比过 base 和 largelarge 精度高 5% 左右但延迟翻倍。如果 QPS 不高用 largeQPS 高用 base 加缓存。生成模型我对比过几个主流方案大模型确实好但成本高。我的策略是核心场景用大模型边缘场景用小模型用分类器路由。6.3 上线后最容易被忽略的三件事第一冷启动问题。系统刚上线缓存是空的所有请求都走完整链路延迟会比较高。我的做法是提前预热把高频问题跑一遍填充缓存。第二长尾问题。80% 的请求是常见问题20% 是长尾。长尾问题往往召回差、生成差但用户感知强烈。我专门建了一个长尾问题池定期分析优化。第三用户预期管理。用户对 AI 客服的预期是什么都能答但实际做不到。要在交互上管理预期比如明确告知我可以回答产品相关问题超出范围时引导转人工而不是硬答。6.4 后续可以扩展的方向这套系统跑稳之后可以往几个方向扩展。多模态支持图片问答用户发一张产品照片问怎么用。主动服务根据用户行为预测问题提前推送答案。个性化根据用户历史调整回答风格和详细程度。多语言支持跨境场景。Agent 化从问答扩展到执行任务比如直接帮用户提交工单。每个方向都有坑建议一次只扩展一个跑稳了再加下一个。我见过太多团队一次上太多功能结果每个都不精最后全砍掉重来。这套方案的核心思路是用编排框架把工程复杂度降下来把精力集中在效果调优上。FSB 只是其中一种选择换成其他编排框架思路是一样的。关键是想清楚每一层要解决什么问题然后逐个击破。我个人的体会是AI 客服系统没有一劳永逸的方案上线只是开始持续迭代才是常态。