ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

开源AI Agent Runtime如何消费客服知识问答卡片:从文档态到结构化应答的工程实践

开源AI Agent Runtime如何消费客服知识问答卡片:从文档态到结构化应答的工程实践 1. 客服知识为什么不能直接塞进 AI Agent做过客服系统的人都有一个共同感受知识库里的内容人看着能用机器一读就废。我见过太多团队把 Confluence 或者语雀里的客服文档直接导出成纯文本切一切丢进向量库然后指望 AI Agent 能对答如流。结果上线第一天用户问“退款要多久到账”Agent 回了一段“根据公司财务制度第三章第七条……”——用户当场关掉对话框。问题的根子不在模型在于知识的组织形态和消费形态不匹配。人类客服读文档时脑子里会自动做三件事定位到相关段落、提取关键结论、用口语重新组织。AI Agent 的 Runtime 如果没有把这套“阅读理解加转述”的流程固化下来它就只能做关键词匹配匹配到的还是原始文档的碎片。所以这篇要聊的核心就是把客服知识从“文档态”转成“问答卡片态”并且让开源 AI Agent Runtime 能稳定地消费这些卡片。关键词里的开源、AI Agent、Runtime、客服知识、问答卡片本质上是一条流水线上的五个环节开源 Runtime 提供执行框架AI Agent 负责调度客服知识是原料问答卡片是中间产物最终输出的是可被检索、可被引用、可被追溯的结构化应答单元。适合谁看如果你正在用开源框架搭客服 Agent或者你手里有一堆客服文档不知道怎么喂给模型再或者你已经在做 RAG 但召回质量一直上不去这篇的内容应该能帮你省掉至少两周的试错时间。我不讲空泛的架构图只讲我实际跑通过的卡片设计、切分策略、Runtime 对接方式和踩过的坑。2. 问答卡片到底长什么样才算合格2.1 一张卡片的最小信息闭环很多人以为问答卡片就是“问题加答案”两行字。我一开始也这么想后来发现这种卡片在 Runtime 里根本没法用。原因很简单Agent 需要知道这张卡片什么时候该被召回、召回后怎么用、用的时候边界在哪。只有问题和答案等于给了一个没有标签的零件装配的时候全靠猜。我最终定下来的卡片结构包含六个字段缺一不可字段名作用是否必填question标准问法用于向量化和关键词匹配必填aliases同义问法列表覆盖用户口语变体必填answer标准答案口语化、可直接回复必填conditions生效条件比如地区、产品线、用户等级选填但强烈建议source知识来源出处用于追溯和人工复核必填confidence_hint置信度提示告诉 Runtime 这张卡片的可靠程度选填question和aliases的区别很关键。question是官方标准问法比如“如何申请退款”aliases是用户实际会打的字比如“退款怎么弄”“我想退钱”“买错了能退吗”。Runtime 在做召回时aliases的权重应该略低于question但不能低太多因为真实用户几乎不会用标准问法。conditions这个字段是我踩坑之后才加上的。早期没有它的时候一张“退款到账时间”的卡片会被所有用户召回但实际业务里不同支付渠道的到账时间完全不同。没有条件约束Agent 就会给出一个“平均正确”但“具体错误”的答案这比不回答还糟糕。2.2 答案字段的写法直接决定 Agent 的回复质量answer字段最容易写坏。我见过两种极端一种是直接把文档原文粘进去三百字带表格带脚注另一种是只写一句“请联系客服”等于没写。合格的answer应该满足三个条件口语化、自包含、可截断。口语化是说读起来像人在说话不是制度文件。比如“退款将在审核通过后 1-3 个工作日原路返回”就比“退款周期为审核通过后 1 至 3 个工作日退回至原支付账户”更适合直接回复。自包含是说这张卡片的答案不依赖其他卡片就能独立成立。如果答案里出现“详见上文”“参考相关规定”这种指代Runtime 在单独召回这张卡片时就会断链。可截断是说答案要分段每段是一个完整语义单元。因为有些 Runtime 在拼接多个卡片时会做长度截断如果答案是一整块截断后可能只剩半句话。我通常会把答案拆成“结论段 补充段”结论段控制在 50 字以内补充段再展开细节。2.3 卡片粒度一张卡片只回答一个问题这是最反直觉但最重要的一条。新手总想把相关的问题合并成一张大卡片觉得这样“信息密度高”。实际恰恰相反卡片粒度越细召回精度越高。举个例子。“退款”这个大主题下至少有这些独立问题退款条件是什么、退款怎么申请、退款多久到账、退款退到哪里、退款被拒怎么办。这五个问题应该做成五张卡片而不是一张“退款说明”大卡片。原因在于向量检索的语义空间。一张卡片如果包含五个问题的答案它的向量会落在五个语义簇的中间地带结果就是每个问题都召回它但每个问题都只匹配到一部分。而五张独立卡片每张的向量都精准落在自己的语义簇里召回准确率会明显提升。代价是卡片数量变多维护成本上升。我的经验是一个中等规模的客服场景卡片数量在 300 到 800 张之间是比较健康的区间。低于 300 说明粒度太粗高于 800 就要考虑是不是把非客服内容也塞进来了。3. 从原始客服文档到卡片的完整加工链路3.1 第一步不是切分是标注文档类型拿到一堆客服文档绝大多数人的第一反应是直接切分。我早期也这么干结果切出来的东西乱七八糟。后来我强制自己先做一步给每份文档打类型标签。客服文档大致分四类流程类怎么操作、政策类什么条件、话术类怎么回复、FAQ 类常见问答。这四类的加工方式完全不同。流程类文档适合抽成“步骤型卡片”答案里带有序步骤。政策类文档适合抽成“条件型卡片”conditions字段会比较多。话术类文档本身就是口语化的加工成本最低基本可以直接转卡片。FAQ 类文档最接近卡片形态但往往粒度太粗需要拆。不打标签直接切分等于把四种不同结构的东西混在一起处理后面无论怎么调优都事倍功半。我现在的做法是文档入库前先过一遍人工分类分类完成后按类型走不同的加工流水线。3.2 切分策略按语义单元切不按字数切按字数切分是最省事也最坑的做法。500 字一刀切下去经常把一句话切成两半或者把两个不相关的问题切进同一块。我用的切分策略是按语义单元切具体规则如下遇到“问”“Q”“问题”这类标记作为新卡片的起点遇到“答”“A”“回复”这类标记作为答案段的起点遇到连续两个换行加标题格式作为潜在的分割点遇到“注意”“例外”“特殊情况”这类词单独成段不并入主答案这套规则听起来简单但实际跑下来切分准确率能到 85% 以上。剩下的 15% 需要人工复核主要集中在没有明确标记的文档里。提示切分完成后不要急着入库先抽样 50 张卡片人工检查。如果这 50 张里有超过 5 张需要大改说明切分规则有问题先调规则再继续。3.3 同义问法的批量生成方法aliases字段如果全靠人工写800 张卡片能写到崩溃。我的做法是半自动生成加人工筛选。先用规则生成一批候选把标准问法里的关键词做同义词替换比如“申请”换成“办理”“操作”“弄”“退款”换成“退钱”“返款”“退单”。再让模型基于标准问法生成 5 到 8 个口语变体。最后人工过一遍删掉明显不合理的保留 3 到 5 个高质量的。这里有个经验不要追求 aliases 数量多要追求覆盖真实用户表达。我通常会从客服聊天记录里捞一批真实问法和生成的 aliases 做比对把真实问法里出现频率高的补进去。这样生成的 aliases 才有实战价值而不是模型自嗨的产物。3.4 卡片入库前的质量门禁卡片写好之后我设了三道门禁过不了的不让入库第一道是完整性检查六个必填字段缺一不可answer字段不能少于 20 字question不能超过 50 字。第二道是重复度检查用向量相似度算一遍相似度超过 0.92 的卡片标记为疑似重复人工确认是合并还是保留。第三道是可回答性检查把卡片单独拿出来问自己“只看这张卡片能不能回答对应的问题”。如果答案是否定的说明卡片不自包含打回重写。这三道门禁跑下来入库卡片的质量会稳定很多。我见过太多团队跳过门禁直接入库结果线上召回一堆半成品卡片Agent 的回复质量惨不忍睹。4. 开源 Runtime 怎么消费这些卡片4.1 Runtime 在整条链路里的角色定位很多人把 Runtime 理解成“跑模型的地方”这个理解太窄了。在客服 Agent 场景里Runtime 的核心职责是编排接收用户输入、决定要不要召回卡片、召回哪些卡片、怎么把卡片内容组织成回复、什么时候该转人工。开源 Runtime 的好处是这套编排逻辑你可以完全掌控。商业方案往往把召回策略、重排逻辑、回复模板都封装成黑盒你只能调几个参数。但客服场景的差异太大了不同业务线的召回策略可能完全不同黑盒方案根本不够用。我选开源 Runtime 的判断标准有三条支持自定义召回器、支持卡片级别的元数据过滤、支持回复内容的引用追溯。这三条缺一条后面都会难受。4.2 卡片索引的构建方式卡片入库后需要建两类索引向量索引和关键词索引。向量索引用于语义召回。我把question和aliases拼接后做 embeddinganswer不参与 embedding因为答案的语义会干扰问题的语义空间。这一点很多人搞反了把整张卡片做 embedding结果召回精度下降明显。关键词索引用于精确匹配。用户输入里如果包含产品名、订单号、特定术语关键词索引能快速定位到相关卡片。我通常用 BM25 做关键词召回和向量召回做混合。两类索引的召回结果需要融合。我用的融合策略是加权求和加去重向量召回权重 0.7关键词召回权重 0.3同一张卡片被两路都召回时取最高分不叠加。这个权重不是拍脑袋定的是我在测试集上跑了一轮网格搜索选出来的。不同业务场景的最优权重可能不同建议你也跑一轮。4.3 召回之后的卡片重排逻辑召回阶段通常会返回 10 到 20 张候选卡片直接全塞给模型效果很差。需要做重排把最相关的 3 到 5 张挑出来。我的重排逻辑分三层第一层是条件过滤把conditions字段和当前用户上下文不匹配的卡片直接剔除。比如用户是海外用户国内专属的退款政策卡片就不该出现。第二层是置信度排序confidence_hint高的卡片优先。这个字段我通常根据卡片来源设定官方政策文档转的卡片给高置信度社区问答转的给中等用户反馈整理的给低。第三层是多样性控制如果前几张卡片来自同一个知识来源强制插入一张其他来源的卡片。这是为了防止 Agent 的回复被单一来源主导导致视角偏颇。重排之后通常保留 3 张卡片进入回复生成阶段。超过 3 张模型的注意力会被分散回复质量反而下降。4.4 回复生成时的卡片引用方式卡片内容不能直接拼起来当回复。我见过最粗暴的做法是把三张卡片的answer用换行符连起来结果回复读起来像三个人各说各话。我的做法是让模型基于卡片内容重新组织语言但在 prompt 里明确要求结论必须来自卡片不得自行发挥如果卡片之间有冲突优先采用置信度高的如果卡片内容不足以回答问题明确告知用户并建议转人工。同时回复里要保留引用追溯。Runtime 在返回回复的同时附带一个sources字段列出这次回复引用了哪几张卡片。这样人工客服在复核时能快速定位到原始知识用户投诉时也能追溯到底哪张卡片出了问题。5. 实测中暴露的五个典型问题5.1 卡片召回对了但答案拼错了这是最常见的问题。召回阶段返回了三张卡片每张单独看都对但拼在一起就矛盾了。比如一张卡片说“退款 1-3 个工作日到账”另一张说“退款 7 个工作日内到账”模型把两个都写进回复用户直接懵了。根因是卡片之间缺少优先级关系。我的解法是在卡片元数据里加一个priority字段同一主题下的卡片按优先级排序回复生成时只采用最高优先级的卡片低优先级的作为补充但不作为结论。5.2 用户问法超出 aliases 覆盖范围用户的实际表达千奇百怪aliases 永远覆盖不全。我遇到过用户问“钱什么时候回来”而卡片里只有“退款到账时间”和“退款多久到账”两个 aliases结果没召回。解法是加一层查询改写。Runtime 在召回前先用一个小模型把用户输入改写成标准问法再拿改写后的问法去召回。改写模型不需要很大我用的方案是在业务数据上微调了一个小模型改写准确率能到 80% 左右召回率提升明显。5.3 条件字段写得太死导致召回为空conditions字段如果写得太具体比如限定到某个具体产品型号那其他型号的用户就完全召回不到。我早期犯过这个错把条件写得过细结果覆盖率暴跌。后来我改成分层条件必选条件比如产品线和可选条件比如具体型号分开。必选条件不匹配直接剔除可选条件不匹配只降权不剔除。这样既保证了相关性又避免了召回为空。5.4 卡片更新后索引没同步卡片是活的业务变了卡片就要改。但很多人改完卡片忘了重建索引导致线上还是旧卡片在召回。我的做法是把卡片更新和索引重建做成原子操作卡片写入数据库的同时触发索引更新任务更新完成前旧索引继续服务更新完成后原子切换。这样用户无感知也不会出现新旧卡片混用的情况。5.5 多轮对话里卡片被重复召回用户第一轮问了退款Agent 回了。第二轮用户追问“那要多久”Agent 又召回了一遍退款卡片回复里重复了上一轮的内容。根因是 Runtime 没有维护对话级的已召回卡片集合。我的解法是在会话状态里记录已经召回过的卡片 ID后续轮次召回时把这些卡片降权。如果用户明确追问同一主题才允许再次召回但回复时要避免重复表述。6. 卡片体系的长期维护经验6.1 建立卡片健康度看板卡片上线不是终点。我维护了一套卡片健康度指标每周看一次指标含义健康区间召回率被召回过的卡片占比60%-80%命中率召回后被采用的卡片占比40%-60%空召回率用户提问但无卡片召回的比例低于 15%冲突率同一次回复中卡片内容冲突的比例低于 5%召回率太低说明卡片覆盖不够太高说明卡片太泛。命中率太低说明召回精度有问题。空召回率高说明 aliases 覆盖不足或者卡片粒度太粗。冲突率高说明优先级管理没做好。这套指标跑起来之后卡片维护就从“凭感觉”变成了“看数据”。6.2 卡片废弃比新增更重要团队做知识库有个通病只加不减。卡片越积越多质量越来越差。我强制要求每季度做一次卡片审计把连续三个月零召回的卡片标记为待废弃人工确认后下线。废弃卡片不是删除是标记为deprecated状态索引里排除但数据库保留。这样万一以后需要追溯还能查到。6.3 人工反馈闭环怎么建Agent 的回复质量最终要靠人工反馈来校准。我在 Runtime 里加了一个反馈接口人工客服在复核 Agent 回复时可以标记“卡片选对了”“卡片选错了”“卡片内容有误”三种状态。这些反馈数据每周汇总一次选错的卡片进入重排逻辑调优内容有误的卡片进入内容修订队列。这个闭环跑起来之后卡片质量会持续提升而不是上线即巅峰然后慢慢腐烂。7. 一个可复现的最小实现路径如果你现在就想动手我建议按这个顺序来不要跳步第一步选 50 条真实客服问答手工做成卡片把六个字段填完整。这一步的目的是让你理解卡片结构不要一上来就搞自动化。第二步用开源 Runtime 搭一个最小召回链路只做向量召回不做重排看看这 50 张卡片能不能被正确召回。如果召回率低于 70%先调卡片质量不要急着加功能。第三步加入关键词召回和混合排序观察召回率变化。这一步通常能把召回率提到 85% 以上。第四步加入条件过滤和优先级重排观察回复质量变化。这一步主要解决“召回对了但回复错了”的问题。第五步接入真实用户流量跑一周收集空召回和错误召回案例针对性补充卡片和 aliases。这个路径我跑过三遍每遍大概两周能到可用状态。跳过任何一步后面都要回头补课。注意不要一开始就追求卡片数量。50 张高质量卡片的效果远好于 500 张半成品卡片。卡片体系的质量下限由最差的那张卡片决定而不是由最好的那张决定。8. 关于开源方案选型的一点个人看法开源 Runtime 的选择很多我不推荐具体项目因为不同团队的技术栈和运维能力差异太大。但我可以分享我的筛选逻辑。首先看召回器是否可插拔。如果 Runtime 把召回逻辑写死了你后面想换 embedding 模型或者加混合召回都会很痛苦。可插拔的召回器意味着你可以先用默认方案跑起来后面再逐步替换。其次看元数据过滤是否原生支持。卡片体系的核心优势就是元数据丰富如果 Runtime 不支持按元数据过滤那卡片里的conditions、priority、confidence_hint就全浪费了。最后看社区活跃度和文档质量。开源项目最怕的是遇到问题没人答。我通常会看最近三个月的 issue 回复率和 PR 合并速度这两个指标比 star 数更能反映项目的真实状态。至于模型选择客服场景不需要最大的模型。我实测下来中等规模的模型配合好的卡片体系效果比大模型配烂卡片好得多。卡片体系是杠杆模型只是执行器。杠杆没搭好执行器再强也撬不动。这套东西我前后折腾了大半年从最初的“文档直接切”到现在的“卡片加 Runtime 编排”中间踩的坑基本都写在这了。如果你正在做类似的事情希望这些经验能让你少走点弯路。卡片体系不是一蹴而就的它更像是一个需要持续喂养和修剪的有机体上线只是开始。
返回列表