
售后客服这行干久了你会发现一个特别拧巴的事客户问的问题十有八九都能在知识库、产品文档、历史工单里找到答案但坐席就是找不到或者找到了也不敢确认是不是最新版。我见过太多新人花十分钟翻文档最后回了一句“我确认一下再答复您”。后来我在项目里尝试把 Viking AI 搜索和 SearchCLI 串起来搭了一个售后助手用户问题进来SearchCLI 先把知识库、FAQ、历史工单搜一遍把命中的资料打包给 Viking AI 搜索做理解和组织最后生成一段带出处的回复。这篇文章就是把这套方案从设计、踩坑到落地的完整过程写出来给同样在做售后自动问答、工单助手的同学一个参考。1. 售后问答为什么必须先“搜”后“答”1.1 售后场景的真实痛点售后回答难难在“知识分散”和“答案多变”。一个稍微复杂一点的产品线售后知识可能分布在好几个地方产品说明书、官网 FAQ、内部工单系统、微信群里的经验文档、甚至老员工脑子里。真出问题的时候坐席要在几个系统之间来回切换先搜文档再翻工单搞不好还要去问组长一套流程下来怎么也要三五分钟客户早就等得不耐烦了。更难搞的是知识更新速度。产品迭代快售后政策也经常变知识库里的旧内容又没有及时下线。坐席如果搜到一篇三个月前的文档很可能给出一个已经失效的答案。这个坑我踩过不止一次客户拿着旧政策的截图来质问坐席还觉得是客户记错了最后发现知识库压根没更新。这类问题的本质是人不可能靠记忆跟上大量、频繁变化的售后知识必须有一个“每次回答前都去资料里查一下”的机制。还有一类问题则是重复劳动。某些常见问题一天能进来几百条内容高度相似但坐席还是得逐条回答。对团队来说这是最浪费的部分对客户来说则是体验最差的部分——排了半天队结果问的问题在 FAQ 里写得清清楚楚。1.2 加入搜索之后回答方式发生了什么变化先查后答看起来只是多了“搜索”这一步实际上把售后回答从“凭记忆”变成了“凭依据”。以前让大模型直接回答售后问题最大的问题是幻觉。模型没见过你们的售后政策、产品参数、历史工单让它硬答它就会一本正经地编语气还挺确定。而搜索结果参与进来之后模型不再依赖自己的记忆它拿到的是一批真实资料任务是“基于这些资料组织回复”。这样回答的准确率、可解释性都会有本质提升。第二个变化是回答可以溯源了。搜索召回的结果自带标题、来源和片段生成回复的时候可以要求模型标注“这个结论来自哪篇文档”。这个对于售后来说极其重要客户对一句裸结论的信任度很低但如果回复后面带了文档链接和精确的政策条款沟通成本会直线下降。坐席拿到带出处的答案也敢直接发出去不用担心“背锅”。第三个变化是知识更新不用重训模型。知识库内容变了搜索召回的结果就变了大模型每次回答都会基于最新检索到的内容去组织语言。不需要为了一个新政策重新微调模型改知识库文档就行了。这意味着售后知识的维护成本从“训练模型”降到了“写文档”门槛低了很多。2. 方案选型Viking AI 搜索和 SearchCLI 各自负责什么2.1 Viking AI 搜索解决的是“生成端”的问题先说 Viking AI 搜索。这款产品背后的思路其实是现在很主流的搜索增强生成Search Grounding / RAG路线大模型不直接回答问题而是先做一个搜索动作拿到搜索结果再把“用户问题搜索结果回答要求”一起提交给模型由模型综合整理后给出最终答案。这种方案解决了我最头疼的两个问题。第一是私有知识的隔离。售后知识库往往包含产品内部参数、合作政策、历史工单这些都是模型训练数据里不存在的。Viking AI 搜索可以对接私有知识库只在允许的知识范围内搜索避免把模型“通用知识”里那些似是而非的内容混进来。第二是引用可控。生成回答时可以要求模型标注依据来源这样最终答复是能被查验的出了问题也能回溯到具体是哪篇文档导致。选型的时候我也对比过“直接拿模型裸答”的路线。裸答实现简单但准确率随知识更新速度下降极快基本不适合业务类的售后场景。也考虑过自己搭一套完整的 RAG 系统向量库、Embedding、重排模型全自己搞但太重了光是数据切分和维护一个稳定的召回链路就要花掉不少精力。Viking AI 搜索把检索和生成放在一起项目初期可以更快跑通先解决“有没有”的问题。2.2 SearchCLI 解决的是“检索端”的工程化问题SearchCLI 这个名字听着像终端里的搜索工具实际职责也差不多把搜索能力封装成一条命令输入查询词输出结构化的命中文档列表。在整套方案里它做的是“先搜”这一步。为什么不让售后助手脚本直接调用搜索服务的 SDK而是要套一个 CLI因为实际售后系统比想象中复杂。工单系统可能是 Java 写的值班机器人可能是 Python 的运维自动化跑批又可能是 Shell 脚本。如果每个系统都去对接一遍 SDK重复代码多还得分别维护。而 SearchCLI 一旦封装好任何系统只需要执行一条命令、解析一段 JSON 就能拿到搜索结果集成成本极低。CLI 还有个好处是调试方便。写代码的时候我最怕遇到那种“库调不通但报错又不明确”的情况。用 CLI 之后可以直接在终端里一条命令试一把看返回结果确认没问题再往代码里接。排查问题的时候也不用开 IDE直接命令行敲一遍就知道是检索服务的问题还是业务代码的问题。2.3 为什么不直接用官方SDK非要包一层CLI顺着上面的思路再补一句我的真实体会直接调 SDK 不是不行但“包一层 CLI”换来的东西很值。第一是团队协作更顺。后端同学维护 SearchCLI售后运营同学也会用他们说“这个关键字搜不到”后端可以立刻在命令行复现。这种统一的交互入口能减少很多“我这里明明有结果你那里怎么没有”的沟通成本。第二是便于做审计和日志。CLI 层统一记录了每次检索的查询词、结果条数、耗时出了问题方便回溯。第三是灵活切换后端。一开始接的是知识库检索后面如果需要接入外网公开资料搜索也可以用相同命令格式内部改实现就行下游业务代码完全不用动。3. 环境准备与基础配置3.1 开通Viking AI搜索相关服务与知识库准备这一步没有太多技巧但有几个点值得注意。首先要开通对应的大模型服务拿到访问密钥。一般是在火山方舟或者对应的 AI 平台里创建应用然后把 API Key 保存好。我习惯把这些敏感配置放在环境变量里而不是写进代码避免提交到代码仓库的时候泄密。然后是知识库的整理。这一步特别重要直接决定后面检索效果。我建议把知识库按类型拆开产品 FAQ 一类、产品文档一类、历史工单一类分别上传到不同的知识库空间。不要把所有文档一股脑塞进去否则检索时会互相干扰。文档格式上尽量用结构清晰的 Markdown 或 PDF重要政策条款不要夹杂在一大段广告文案里因为检索召回的是片段片段太乱模型拿到手也组织不出好答案。准备工作可以参考下表事项建议做法注意事项开通服务创建应用申请 API Key密钥放环境变量别写进代码知识库整理按 FAQ、产品文档、工单分库先小批量测试再全量上传文档清洗删除过时内容保留更新时间缓存的旧知识会造成误答权限规划售后助手只读知识库避免脚本误改线上文档3.2 SearchCLI 安装与参数说明我用的 SearchCLI 是内部封装的命令行工具核心逻辑是调用搜索服务的检索接口。你如果手头没有现成的 CLI可以用任意开源的搜索命令行工具或者自己写一个几十行的 Python 脚本来完成同样的事——核心是保持“命令输入、JSON输出”的交互约定。安装好之后可以用searchcli --help看一看支持哪些参数。常用参数大致有这些query查询词必填。--topk返回前几条结果默认 5。--format输出格式建议用json方便后续程序解析。--knowledge-base指定知识库 ID售后场景建议按库搜索避免跨库干扰。--min-score过滤低相关结果。首次验证搜索功能时可以先用一条简单的查询试一下searchcli query Pro 730 蓝牙配对失败 --topk 5 --format json返回的 JSON 大致长这样[ { title: Pro 730 蓝牙配对常见问题, url: https://docs.example.com/pro730-faq, snippet: 如果搜索不到设备请先长按顶部按钮5秒进入配对模式然后在系统设置中删除旧配对记录后重试。, score: 0.87, source: faq_202504 } ]看到这样的返回说明检索链路已经通了。接下来就可以往售后助手脚本里接了。4. 售后助手核心实现4.1 总体调用链从“用户提问”到“带引用的回答”售后助手不是只做一件事而是一条调用链。我把整条链路拆成了四步每一步都可以单独测试排查问题的时候会方便很多。第一步是接收用户问题做一次预处理。第二步是 Query 改写把口语化的提问变成更适合检索的关键词。第三步是调用 SearchCLI 做检索拿到命中的知识文档。第四步是构造 Prompt把检索结果交给 Viking AI 搜索组织成一段最终回复。从实现角度看最后一步才是真正触发大模型回答的地方但它依赖前三步给出的上下文。链路串起来就是用户问题进来先别急着让模型回答先去“翻资料”资料到了再回答。整个过程对用户是无感的但对回答质量的影响是决定性的。4.2 第一步Query改写售后问题大多口语化严重比如“我的 pro730 怎么连不上蓝牙了重启也没用”。这种句子直接拿去搜索检索系统会把“重启也没用”这种多余信息也带进去影响召回质量。所以需要先做一个 Query 改写把问题压缩成核心关键词组合pro730 蓝牙 连接失败。改写可以用规则也可以用大模型。简单场景下规则就够了比如提取产品型号、问题关键词。但售后问题表达太灵活规则很快就会漏。我建议用大模型做改写调用成本很低收益却很明显。改写时给模型的指令很简单你负责把用户售后问题改写成适合搜索的关键词组合。 要求 1. 保留产品型号和核心问题词 2. 去掉语气词和无关描述 3. 如果有重复含义只保留一个 4. 直接输出关键词不要解释。 用户问题我的 pro730 连不上蓝牙了重启也没用实际效果会输出pro730 蓝牙 连接失败。这一步做好检索召回率能提升不少。4.3 第二步用 SearchCLI 做售后知识检索Query 改写好之后就轮到 SearchCLI 上场了。这一步我会复用环境准备阶段验证过的命令在代码里通过subprocess调用并把返回的 JSON 解析成数组。注意设置一个最低相关度阈值比如--min-score 0.5低于这个分数的结果基本算噪声不用进入下一步。调用示例searchcli query pro730 蓝牙 连接失败 --topk 5 --min-score 0.5 --format json返回结果里我只取三个字段标题、片段、来源 URL。这三个字段足够让大模型组织出一段有依据的回答又不会因为内容过长导致 Prompt 超出上下文限制。如果结果超过 5 条我一般也只保留前 5 条因为售后问题的答案通常集中在最相关的几篇文档里塞太多反而会干扰模型。4.4 第三步把检索结果组织成 Prompt这一步是整个方案里最值得打磨的地方。检索结果是一堆零散段落如何把它们变成模型能理解并严格遵循的上下文完全靠 Prompt 的组织方式。我常用的模板长这样你负责回答用户的售后问题请严格依据下面的检索内容作答不要自行补充未出现的信息。 检索内容 [1] 标题Pro 730 蓝牙配对常见问题 来源https://docs.example.com/pro730-faq 内容如果搜索不到设备请先长按顶部按钮5秒进入配对模式... [2] 标题Pro 730 常见连接故障排查 来源https://docs.example.com/pro730-troubleshooting 内容蓝牙无法连接时建议先删除旧配对记录再重新搜索设备... 用户问题pro730 怎么才能重新连上蓝牙 回答要求 1. 如果检索内容足够回答请直接给出简洁答复并在末尾用【来源1】【来源2】标注依据 2. 如果检索内容不足以回答明确回复“当前资料库未找到相关信息” 3. 不要编造参数、政策或操作步骤。这段 Prompt 做了一件关键的事把“回答问题”这个任务限定成了“依据给定资料回答问题”。模型即使知道一些通用知识也会优先使用检索内容。加上第 2、3 条要求可以有效压制幻觉。4.5 第四步调用 Viking AI 生成最终回答检索和 Prompt 都准备好了最后一步就是调用大模型生成回复。这里我以 OpenAI 兼容接口为例火山方舟的接口也支持类似方式你只需要把基础 URL、模型 ID、API Key 配置成环境变量。参数配置上我把temperature设成 0.2尽量让回答稳定、忠于资料。max_tokens控制在 800 以内因为售后回答一般不需要长篇大论。核心代码如下import os import json import subprocess from openai import OpenAI client OpenAI( api_keyos.environ[ARK_API_KEY], base_urlos.environ[ARK_BASE_URL] ) def search_docs(query, topk5): cmd [searchcli, query, query, --topk, str(topk), --min-score, 0.5, --format, json] result subprocess.run(cmd, capture_outputTrue, textTrue, checkTrue) return json.loads(result.stdout) def build_prompt(user_question, docs): context [] for i, doc in enumerate(docs, 1): context.append(f[{i}] 标题{doc[title]}\n来源{doc[url]}\n内容{doc[snippet]}) context_str \n\n.join(context) return f你负责回答用户的售后问题请严格依据下面的检索内容作答不要自行补充未出现的信息。 检索内容 {context_str} 用户问题{user_question} 回答要求 1. 如果检索内容足够回答请直接给出简洁答复并在末尾用【来源1】【来源2】标注依据 2. 如果检索内容不足以回答明确回复“当前资料库未找到相关信息” 3. 不要编造参数、政策或操作步骤。 def ask_after_sales(question): rewritten rewrite_query(question) docs search_docs(rewritten) if not docs: return 当前资料库未找到相关信息。 prompt build_prompt(question, docs) resp client.chat.completions.create( modelos.environ[ARK_MODEL_ID], messages[{role: user, content: prompt}], temperature0.2, max_tokens800 ) answer_text resp.choices[0].message.content return answer_text其中rewrite_query是前面 Query 改写那一小段逻辑可以单独封装成一个函数。整个脚本跑起来之后输入一句口语化的售后问题就能拿到一段带引用来源的回答。4.6 完整链路验证脚本写完之后我建议做一组覆盖不同场景的测试正常可答的问题、资料库没有答案的问题、表述模糊的问题、包含多个问题点的长句。逐个跑一遍重点看两个指标检索出的文档是否相关回答是否严格引用了检索内容。我实际测过的一条完整链路是这样的。用户问“我的 pro730 关机之后就搜不到蓝牙了别人手机都正常”。Query 改写后成为pro730 关机 蓝牙 搜不到SearchCLI 召回了关于蓝牙配对模式、省电模式导致断连的文档。最终模型给出的回答指向了“长按顶部按钮 5 秒进入配对模式”的解决步骤并标注了来源。整个过程在两秒左右完成比人工翻文档快得多。5. 常见问题排查与实战心得5.1 检索结果不相关或漏召回这是上线初期最可能遇到的问题。明明文档库里有答案但 SearchCLI 搜出来的结果跟用户问题八竿子打不着。绝大多数时候问题出在 Query 改写上用户口语表达和文档的书面表达差异太大。比如用户说“音箱罢工了”文档里写的是“音箱无法开机”。这种情况我会把改写规则调整成“保留口语词作为同义补充”让改写结果同时包含“罢工”和“无法开机”两个词搜索结果就准了。此外还要检查知识库文档质量。一篇文档如果标题醒目、段落开头就能概括核心内容检索命中率会高很多。有些 PDF 扫描件内容全在图片里检索系统根本读不到这类文档不处理的话无论怎么调参数都召回不了。5.2 回答出现幻觉或引用对不上虽然我们做了“严格依据检索内容”的 Prompt 约束但大模型偶尔还是会自己发挥尤其是检索内容本身存在矛盾的时候。我的处理办法是加一道后校验让模型在输出回答之后再单独输出“这条回复依据了哪些来源序号”然后代码里去比对如果模型声称引用了来源 3但回答内容里有来源 3 没提到的信息就判定为可疑回复转人工处理。更简单的兜底是降低检索结果数量。检索结果越多模型越容易混入自己的知识。我把 topk 从 8 调到 5 之后幻觉问题的出现频率明显下降。你也可以在 Prompt 里加一句“当检索内容之间有冲突时优先采用序号靠前的资料”减少模型自己裁决的空间。5.3 延迟、并发与成本控制售后场景对延迟有一定要求但也不必追求毫秒级。我的经验是两秒以内用户基本能接受超过三秒就会觉得卡。主要耗时来自大模型生成检索本身通常很快。控制延迟的手段有三个第一给问答加上缓存高频问题比如“怎么退换货”命中缓存后直接返回不再走模型调用效果立竿见影第二用异步处理售后工单不要求即时响应先把检索结果和生成的回答放进队列回调更新工单即可第三限制单次回答长度max_tokens设小一点生成时间会明显缩短。成本方面大模型按 Token 计费检索结果太长、Prompt 塞太多内容都会增加成本。我建议对检索片段做截断每条 snippet 只保留前 200 到 300 个字符既能保证上下文完整又能控制费用。5.4 上线前必须做的3个校验第一次上线售后助手之前我建议至少做三个校验。第一是敏感信息校验。检索结果可能包含历史工单里的客户隐私生成回复时不能原样带出。我在输出层加了一道过滤逻辑把手机号、邮箱、订单号等敏感字段替换成占位符从源头避免泄露。第二是权限校验。SearchCLI 和方舟平台需要配置只读权限确保助手不会因为误操作修改知识库内容。这个听起来简单但很多团队为了省事用了管理员密钥潜在风险很大。第三是人工抽检机制。不要一开始就全自动回复可以先用“建议答案”的模式系统生成回复坐席确认之后发送。跑一段时间、积累了足够多的准确率数据之后再逐步放开自动回复的比例。常见问题速查表如下现象可能原因处理方式搜索召回结果少Query 改写不够充分加上口语同义词检查文档是否可索引搜索结果相关但排序靠后topk 设置过大或过小调整为 5 左右必要时提高 min-score回答出现编造内容Prompt 约束不足或 topk 过大强化引用要求减少检索条数回答内容是对的但没有出处Prompt 未要求标注来源在回答要求里强制加【来源 n】延迟过高模型生成过长调低 max_tokens增加缓存和异步处理知识库更新后回答仍旧知识库未刷新或缓存未清除更新知识库后清缓存检查文档版本我个人在实际操作中的体会是这套方案跑通并不难真正花时间的是知识库的整理和 Prompt 的反复调试。别指望模型一开始就完美先用“建议答案人工确认”跑起来再根据真实反馈一点点优化。还有一个小技巧每次调整完 Prompt 或知识库保留一批固定的测试问题回归一遍确保旧问题没被改坏。这套售后助手的思路后续还可以扩展到营销问答、售前咨询、内部 IT 支持等场景核心就是把搜索当成大模型的“外挂资料库”让每一次回答都有据可依。