尧图精选

历史工单接入RAG:智能客服Agent知识库构建与检索实战

🕒 发布时间:2026/10/2 4:05:23 📁 来源:尧图网络
1. 接历史工单这件事本质是给 Agent 补“工作经验”上个月我们团队接了一个智能客服类的 Agent 项目刚开始跑出来的效果让人很尴尬——用户问“我的发票开错了怎么办”Agent 能给你回一段大而全的官方流程说明但完全没提到我们业务里真正会遇到的“发票抬头变更后系统自动同步要两个工作日”这种实战细节。说白了它没有见过公司内部这些真实发生过的故障和处理方式。后来我把目光转向了工单系统里堆着的那几万条历史工单思路一下子打开了。这些工单是过去几年一线客服、技术支持、研发处置真实问题的完整记录每一单都包含用户原始描述和处理人员的最终结论。把历史工单和知识库接起来让 Agent 先去检索相似问题再基于检索到的历史工单给出有依据的回答这个方向才是对的。这篇博文就把我们这次改造的完整过程拆开讲为什么历史工单比产品文档更适合先入库、工单数据怎么清洗和向量化、相似问题检索怎么做召回重排和阈值控制、Agent 拿到检索结果后怎么编排应答以及我们踩过的那些坑。适合正在做智能客服 Agent、想通过 RAG 给大模型接企业私有数据的开发者参考也可以当作一个“历史工单 Agent 知识库”三件套的落地案例来看。1.1 为什么历史工单比产品文档更值得先入库很多人做企业知识库第一反应是把产品手册、内部 Wiki、FAQ 往向量数据库里塞。这个思路没错但对一个已经运行了好几年的业务系统来说历史工单的数据价值往往被严重低估。工单本质上是一批经过人工验证的“问题-答案”对。用户在工单里用大白话描述自己遇到的问题客服或研发人员经过排查给出了解决方案并且在结单时基本都会写清楚最终是怎么处理的。这些内容不是从文档里抄出来的理论而是真实场景下验证过的操作路径。比如“客户反馈登录后提示账号异常实际原因是密码连续错误触发风控锁定处理方式是通过管理后台解除锁定”这种一对一的因果信息在标准文档里通常找不到。另外从冷启动的角度看新上线的 Agent 最缺的就是领域语料。通用大模型对行业内部的专有名词、系统名称、特殊流程基本是一无所知而历史工单里恰好包含了这些语言习惯和业务背景。把这些数据接进来Agent 相当于直接获得了这家公司多年的“工作经验”而不是靠 prompt 里写几条规则来假装懂业务。1.2 整个方案的链路设计这次改造的整体链路可以用一句话概括把历史工单清洗成可用语料向量化后放进知识库接到 Agent 的相似问题检索流程里让大模型基于检索结果作答。具体拆开是四个环节。第一工单清洗把脏乱差的历史记录变成规范的问题和答案对。第二知识库构建设计切片策略、选择合适的 Embedding 模型、确定向量库的元数据字段。第三相似问题检索混合召回加精排算相似度分数并设置阈值。第四Agent 编排把检索结果拼进 prompt约束大模型的回答逻辑和引用格式。这里有一点我想强调很多团队做这类项目一开始就把精力花在调 prompt、试各种 Agent 框架上但效果始终上不去。问题的根源往往在数据链路——知识库里装的是垃圾检索再准也是垃圾。所以我们这次把 70% 的时间花在了工单清洗和知识库构建上后面所有环节都顺了。提示别一上来就选 Agent 框架、配对话流程先把数据源的质量和检索链路跑通。数据不行框架再花哨都是白搭。2. 工单知识库构建从脏数据到可用语料历史工单数据直接搬进知识库是行不通的。我见过有人把原始工单原封不动向量化入库结果用户问“账户被锁定了怎么办”检索出来的“相似工单”里掺杂着大量客服之间的内部沟通记录、无意义的系统报错日志甚至还有“该问题请联系某某处理”这种半截话。2.1 工单清洗的五个关键动作老工单系统的数据质量参差不齐我们的清洗流程主要做了五件事。第一是剥离个人信息。工单里通常包含用户手机号、邮箱、公司名称等敏感信息入库前必须脱敏。简单做法是用正则匹配替换成占位符复杂一点的可以用命名实体识别来扫。这块不做好知识库本身就成了隐私泄露风险点。第二是过滤无效内容。工单系统里大量存在“测试单”“重复单”“误提单”特征是标题里带“测试”、描述极短、或者处理结果为空。这些直接过滤掉可以用结单状态加描述长度做组合规则。第三是合并同义表达。用户的口语五花八门“登不上”和“无法登录”、“卡死了”和“没反应”本质是同一类问题。清洗时可以建立同义词表在入库前做一轮归一化替换这样后面检索时的命中率会高很多。这个环节看起来土但收益非常直接。第四是拆分一单多问。有些工单里用户一口气问了三个问题处理人员的答复也是混在一起的。这种如果不拆后面的检索和回答都会很糊。我的做法是按问题语义切分把“问题描述对应处理结论”绑定成一个条目宁可拆碎一点也不要一整块扔进去。第五是标准化方案描述。处理人结单时写的字往往很随意比如“重置一下就好了”。这类描述作为检索结果给大模型用很容易产生歧义。清洗时要补全操作对象和操作路径比如“通过后台用户管理页面重置该用户的登录密码后恢复”。这一步可以靠规则模板加人工抽查来做。2.2 切片策略与向量化入库清洗完的数据下一步就是切片和向量化。这块我们踩过不少坑这里直接给结论。切片策略上工单不同于长文档核心信息密度高不适合按固定字数机械切。我们采用的是“语义单元”方式一条工单处理完后把“问题描述”“处理过程”“最终结论”打包成一个条目整体作为向量化单元。因为工单短的平均也就一两百字直接整条向量化语义完整性最好。对于极少数超长工单比如研发排查了三天、贴了几十屏日志的先按“排查日志”和“结论摘要”分开只把结论摘要部分入库。向量化模型的选择上中文场景推荐 BGE-M3 或者 bge-large-zh前者多语言能力强后者中文精度高实测下来都比 OpenAI 的 text-embedding-ada-002 更懂工单里的中文口语。如果机器资源有限bge-small-zh 也可以作为起步方案后面再换大的。这里要注意一个问题如果你要混合检索向量模型必须固定下来中间不要随意换否则历史向量和新向量的语义空间不一致检索分数就失真了。向量数据库方面工单量在几十万条以内的Chroma、Qdrant 都够用数据量更大或者要跟已有 ES 体系融合的直接用 Elasticsearch 的向量检索插件更省事可以一套系统同时搞定关键词检索和向量检索混合召回的工程成本最低。2.3 时效性处理老工单的生死线历史工单最大的隐患是过时。两年前处理“发票打印格式异常”的方案可能因为系统升级已经完全失效了三年前的某个 bug 工单对应的功能模块可能已经下线。如果不做时效性处理Agent 很可能拿旧方案回答新问题而且答得振振有词。我们采用了分层策略工单入库时根据创建时间分成“活跃区”和“存档区”默认只检索活跃区时间窗口设为最近 18 个月。同时给工单打上业务线和版本标签检索时优先匹配当前系统版本相关的内容。这个设计还有个额外好处向量库规模被控制住了检索延迟会明显下降。注意历史工单的时效性不能只看时间还要看业务变化。如果产品在某个时间点做过大版本升级应该按版本节点重新划定活跃窗口而不是一刀切按月数算。3. 相似问题检索召回、重排、阈值三步定生死知识库建好之后核心问题就变成了用户问一个问题系统能不能在几万条工单里把真正相似的历史工单捞出来。这一步的效果直接影响 Agent 的回答质量。3.1 召回层向量检索与关键词检索的混合策略只靠向量检索在工单场景下是不够的。原因在于用户的实时提问通常非常口语化而工单里客服记录的描述往往半书面化。“我账号怎么登不上了”和工单里写的“用户反馈登录失败”向量距离未必近。另外工单里往往包含大量专有名词比如具体功能模块名、错误码、系统名称这些关键词的精确匹配向量模型反而不如传统检索做得好。我们的方案是关键词检索和向量检索双通道并行。关键词用 BM25跑在 Elasticsearch 上针对问题描述字段做全文索引向量通道负责语义召回用 query 的 embedding 去向量库做 KNN 搜索。两条通道各取 Top 50然后合并去重作为粗排结果送给重排层。两条通道的权重不需要一开始就定死先各取 50 条让重排层自己去学效果会更稳。等到线上跑了小一个月积累了反馈数据再根据实际命中来源调整比例比如发现 70% 的最终命中来自向量通道就可以把向量 TopK 加大到 80。3.2 重排层精排模型怎么选怎么用召回层是广撒网重排层是精准定位。粗排出来的候选集往往有大量“看着像但实际不相干”的工单比如用户问发票问题召回里混着用户问“报销单怎么打”的工单——都跟财务相关但根本不是同一件事。重排我们用 bge-reranker-base交叉编码器直接计算 query 和每个候选工单的相关性分数效果比向量距离靠谱得多。逻辑很简单把候选工单按相关度从高到低排序截取 Top 3 到 Top 5 送给大模型作为参考材料。这里有个工程细节交叉编码器速度慢所以只对粗排的 100 条候选做重排权衡下来单次查询延迟能控制在 300 毫秒以内。重排分数的使用有一点容易忽略不同 query 的重排分数分布差异很大同一个 0.6 分在有些问题下已经算高相关在另一些问题下可能就是不相关。所以我不建议用一个绝对分数做硬性过滤而是先排序再看 Top 结果的分差如果第一名和第二名分差特别大基本可以确认命中如果前三名分数都差不多说明候选集本身区分度不高这时候要降置信度。3.3 阈值控制什么时候宁可说“不知道”这一节是整个检索链路里我特别想强调的部分。很多 Agent 翻车不是因为没有检索到内容而是检索到的内容明明不相关Agent 依然硬着头皮回答。解决这个问题必须设阈值而且这个阈值不是一个拍脑袋的数字。我们的做法是拿历史真实用户问题做了一次回放把过去三个月的用户咨询全部跑一遍检索流程人工标注每一条检索结果是否真的相关然后画出相关分数分布图。最终把“不回答”的阈值定在重排分数的 0.45 分——低于这个分数Agent 直接说“该问题需要进一步确认已为您转接人工”。这个策略牺牲了一点自助解决率但把胡说八道的比例压到了极低。阈值设完不是一劳永逸的。随着知识库持续新增工单、检索策略调整分数分布会漂移建议每季度重新做一次回放校准。4. Agent 应答编排让检索结果变成有依据的回答检索做得好只代表拿到了好的材料。Agent 能不能把材料变成用户听得懂、且准确可靠的回答取决于应答编排这一步。这里说的编排不是 LangChain 里写几个链那种“编排”而是 prompt 约束、引用逻辑和对话状态管理。4.1 Prompt 设计把工单变成依据而不是噪音大模型拿到检索到的工单原文最容易犯的毛病是照抄。工单里有大量内部沟通痕迹比如“让张三帮忙看下”“用户说已经按操作试过了”直接复述给用户非常奇怪。所以 prompt 里要明确几条规则。第一检索结果只是参考依据回答必须提炼成给终端用户的直接表述。第二如果检索结果之间有冲突以工单时间更新的为准。第三所有结论必须对应引用工单编号格式类似“参考工单 #20240315-0089”。第四禁止在回答中出现工单里的系统内部术语、处理人姓名、内部路径。这几条约束写进系统提示词实测能把回答的专业度拉高一大截。Prompt 的结构我们也做了规范化处理系统提示词固定不变中间插入检索结果区最后是用户问题。检索结果区用序号列出每条工单的“问题-结论摘要”并附上相关度和工单号。这个结构的稳定性很重要不要频繁调整措辞否则后面做效果评估时很难分清是检索问题还是 prompt 问题。4.2 引用溯源与置信度展示引用溯源不只是一个好看的格式它是整个系统的信任基石。用户在收到答案时能看到“参考历史工单 #xxx”既方便追问也给客服质检留了后门。我们内部还做了一个小工具Agent 每次回答都会在后台记录命中了哪些工单、重排分数多少质检团队可以快速定位错误答案的根源。置信度展示其实是阈值控制的延伸。我们分了三档重排分数高于 0.75Agent 直接给出确定性回答分数在 0.45 到 0.75 之间回答里加上“根据历史处理经验您可以先尝试……若无法解决请补充信息”低于 0.45直接转人工。这三档提示在 prompt 里也是写死的避免大模型自己发挥。这里有个细节工单检索和知识库问答在置信度上的体验期望是不同的。用户问“这个功能怎么用”Agent 哪怕答得一般也能接受但用户问“我这个问题能不能解决”答错一步就可能让用户白跑一趟。所以对于带明确操作指令的问题我们把置信度要求整体提高了一档。4.3 多轮对话场景下的检索策略多轮对话是 Agent 场景绕不开的也是检索最容易翻车的地方。用户第一轮说“我的发票开错了”第二轮说“那我已经提交了红冲申请怎么办”如果每轮都独立去检索第二轮很容易把“发票开错”的工单再次召回忽略“红冲”这个关键新信息。我们的处理策略是第一轮正常检索并保留命中的候选集第二轮先判断用户的消息是否引入了新的业务关键词如果引入了就在原有候选集上做一次重排过滤并补充检索新关键词如果没有引入新关键词直接沿用第一轮的检索结果不做重复检索。这样既保证了上下文连贯又避免不必要的检索延迟。这种做法简单有效但注意不要做得太复杂。我也试过把整轮对话拼接起来做查询改写效果反而不稳定因为工单场景的 query 本身就短改写之后的语义容易跑偏。5. 常见问题与排查技巧实录这部分是我们线上踩坑两个月的浓缩。每个问题都对应一次真实的故障排查经历大家可以直接拿这份清单做排查手册。5.1 召回率低、命中不准怎么定位症状是用户问题检索出来的工单明显不对。排查顺序我建议从下往上走先看召回层的日志确认向量检索和关键词检索分别返回了什么再看重排层的分数分布判断是粗排漏了还是精排排错了最后看知识库数据确认对应问题的语料是否真的存在。我们遇到最多的情况是语料确实存在但被切片策略切坏了。比如一条工单同时包含登录问题和支付问题清洗时没拆开整条入库后检索“支付失败”时把“登录问题支付问题”的混合体召回了重排分数还不低因为里面确实提到了支付。这种问题纯调检索参数解决不了必须回到清洗环节把切片粒度改细。另一个高发原因是 Embedding 模型的领域适配性差。工单里的说法高度行业化通用模型容易把它们映射到语义相近但完全无关的区域。排查方法是抽取 100 条典型问题人工标注期望命中的工单跑一遍检索看 Top 10 的命中率如果明显偏低建议换更专业的模型做向量化。5.2 工单数据过时导致答错怎么办这是时效性问题的典型表现用户问“发票税率是多少”Agent 基于一条两年前的工单回答了旧税率哪怕检索和生成都是完全正确的流程答案也是错的。这个问题的根源在数据层光靠 prompt 约束“注意时效性”基本没用大模型很难自己判断哪条历史知识已经失效。我们的方案是双管齐下一方面在知识库里给工单加“有效状态”字段业务方定期批量审核标记另一方面在检索结果展示时把工单时间透传给大模型prompt 里明确要求“优先参考最近 6 个月内的工单如果只有超过一年的工单必须进行提示”。还有一种更隐蔽的情况旧工单本身方案没错但操作路径变了。比如原来解决问题是找管理员重置密码现在系统支持用户自助找回。这种场景需要知识库维护人员定期合并同类工单更新方案描述不能只靠自动流程。5.3 线上效果评估与持续迭代知识库和检索系统上线后评估是最容易被忽视的环节。我见过不少项目上线后就只看一个“回答率”指标回答率高就觉得成功了但回答里隐藏的错误没人看。我们的评估方式是每周抽检加月度复盘。每周随机抽 100 条 Agent 的真实回答按“正确”“部分正确”“错误”“无法判断”四档人工标注月度复盘把本周抽检结果按业务线和问题类型分类找出错误集中的模块优先优化。这个机制跑下来我们第二个月的自助解决率提升了近 10 个百分点核心就是靠抽检发现了“发票类问题检索总是召回到报销类工单”这个系统性问题。这里分享一个排查技巧所有 Agent 回答都在后台记录命中的工单 ID 和重排分数。抽检时如果发现某条回答错了第一步不是看大模型生成逻辑而是先看命中的工单本身是不是相关。如果工单相关但答错了那是生成问题如果工单不相关那是检索问题处理路径完全不一样。用这个二分法排查定位问题的速度会快很多。6. 从“查相似问题”到“工单知识闭环”历史工单接进知识库做成相似问题检索只是第一步。项目跑起来后我们发现如果知识库不能持续更新当初的几万条工单会被新的业务问题逐渐稀释准确率会缓慢下降。6.1 自动沉淀新工单的方法堵住知识库老化漏洞的办法是把新工单也自动接进知识库。我们的流程是工单结单后如果处理结果标记为“已解决”就进入待入库队列系统按清洗规则自动过滤无效内容把工单拆成“问题-结论”条目经过一道人工抽检后写入知识库。整个流程用定时任务驱动一天一跑知识库的增长完全跟着真实业务走。自动沉淀里有一个细节不是所有结单工单都值得入库。如果处理人的结论是“无法复现”或者“属于用户操作问题引导即可”这类工单的价值很低入库反而会污染知识库。建议在入库规则里加一层标签过滤把工单分类字段作为一个准入条件。6.2 这个思路还能辐射到哪些场景历史工单接知识库这套打法本质上是把“历史处置经验”变成“可检索的依据”思路完全可以复制到其他场景。做运维排障的团队可以把历史故障工单接进监控告警 Agent告警时直接给出历史上类似的处置方案做销售支持的可以把历史客户询单和报价方案做成知识库让 Agent 在接到客户问题时先查历史记录工业企业可以把设备维修工单接进检修 Agent报修时自动推荐同型号设备的常见故障处理方式。我在实际操盘这个项目时最深的体会是大模型的能力大家都差不多真正拉开差距的是你喂给它的数据质量。历史工单是企业里现成的、最贴近真实业务的知识资产接好这一层数据Agent 的实用性会立刻上一个台阶。先别急着做复杂的功能编排认认真真把历史工单清洗干净、检索链路调准这个“笨功夫”会是你整个项目里性价比最高的一笔投入。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →