ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

开源Agent Runtime构建客服知识库:问答卡片为何优于纯RAG?

开源Agent Runtime构建客服知识库:问答卡片为何优于纯RAG? 最近我在做一个开源客服知识库的项目核心是用一套开源的 AI Agent Runtime 把散落在各处的客服知识自动整理成问答卡片。不少朋友问我现在有向量库有 RAG 不是可以直接把文档丢进去就能回答了吗为什么还要费劲整理成问答卡片这个问题问得特别好我一开始也是这么想的直到我在真实客服场景里被检索质量、答案准确性和运维成本反复摩擦了几轮才彻底明白这件事的复杂度。这篇文章就把我整个踩坑、设计、实现的过程写出来。内容包括为什么不能跳过问答卡片、Agent Runtime 在整个流程里到底扮演什么角色、问答卡片的数据结构和任务流水线怎么设计、以及从原始数据到卡片入库的完整实操过程。如果你也打算用开源方案给客服场景搭建知识问答系统这篇文章应该能帮你少走一大段弯路。1. 为什么客服知识非要整理成问答卡片直接做 RAG 不行吗我知道现在很多人一提到知识问答就是向量化加余弦相似度这一套恨不得把 Word、PDF 全部灌进知识库就完事。但从我实际跑过的效果来看直接拿原文做 RAG 在客服场景里几乎是灾难。客服知识有几个明显的特征让直接检索这条路走不通。第一是答案通常分散在多处比如一个怎么退款的问题可能充值规则里讲了一部分订单流程里又讲了一部分历史工单里还有一堆客服处理时的经验说明单靠向量的语义相似度很难把这些碎片准确拼到一次检索结果里。第二是客服答案需要非常强的确定性客户来问你们最晚几点发货如果你给 ChatGPT 一个原文片段让它根据内容回答它大概率会啰里啰嗦说一堆通常一般这种模棱两可的话客服管理者看到这种输出是要拍桌子的。第三是原文里的过期信息非常多产品文档更新后旧流程没人删客服聊天记录里更是充满了之前可以这种历史版本的操作直接把这些内容向量化进知识库等于给模型埋了一堆雷。问答卡片解决的就是这个结构化和可控性问题。我理解的问答卡片是**每条知识都以标准问题 标准答案 元信息的形式沉淀下来一个小卡片对应一件确定的事。**它把从原文里找答案变成了从卡片库里找最匹配的卡片命中的卡片直接给答案主体绝对不是说让 Agent 自由发挥。这样的好处在于答案可审计、可运营、可单独修正出问题的时候你永远能定位到是哪张卡片写错了而不是一头扎回几千页的文档里去猜模型到底读了哪个段落。这里借用搜索引擎的思路来打比方原始文档相当于网上的长尾网页问答卡片相当于人工编辑过的精选摘要。搜索可以找到海量页面但可能排序混乱而精选摘要虽然数量有限每一条质量都顶得上。客服场景恰恰需要这种精品压过海量的策略。我刚开始也抱着向量库这么强应该够用的心态做过一个原型把几十篇产品说明直接向量化灌进开源知识库测试时发现那些某个功能的细节变更类问题系统要么答得含糊要么把不相关功能的描述也拉进来。后来我把同样的内容拆成了两百多张问答卡片同样一套检索配置正确率肉眼可见地升上去了。所以如果你现在还在纠结为什么不能省掉整理这一步我只能说整理这一步省掉的成本会在后面每一次答案出错时加倍还回来。2. Agent Runtime 在这个项目里到底起什么作用标题里提到 Agent Runtime很多朋友可能对这个词有点模糊。我用自己的理解说清楚Agent Runtime 不是某一个具体的大模型也不是你最终呈现给用户的聊天界面而是负责运行和编排 Agent 任务的那个底层执行环境。它管理 Agent 的状态、生命周期、工具调用、子任务调度、超时和重试这些脏活。在知识整理这种场景里Agent Runtime 更像是流水线上的动力系统和调度中枢我写的每一个抽取问答对的 Agent 都跑在这个 Runtime 上。我调研了不少开源方案。大方向上有几类选择一类是完整带界面的开源应用平台比如 Dify、FastGPT、RagFlow这类开箱即用适合快速验证另一类是底层编排框架比如 LangGraph、LlamaIndex或者一些基于事件驱动的任务框架这类更灵活适合自定义流程但需要自己处理状态存储、日志、任务队列这些基础设施。我的实际情况是知识整理不是一次性的魔法操作而是需要分成多批次不断重跑、随时断点续运、还把每一步的输出落库审计的持续流程所以最后选择了基于一个开源的任务编排内核自己做了一层薄封装。这个 Runtime 在我的项目里承担了几件具体的事任务分解把一个全量知识整理的大任务拆成数据清洗段落分类QA 对抽取相似内容合并卡片字段校验多个可独立运行的子任务。执行编排控制子任务之间的依赖关系比如清洗完成才能进入抽取环节抽取的批量结果通过后再做合并去重。状态管理记录每个文件的处理进度中间断掉了或者某个子任务报错重新运行时直接从失败点继续不用从头再来。工具调用有些子任务需要调用外部的检索服务或数据库去查重Runtime 负责把我定义好的工具注册给 Agent 并处理调用的入参出参。异常兜底LLM 返回格式不符合预期、单任务超时、输出内容触发安全规则这些情况都在 Runtime 层统一处理不让一个坏任务弄脏整批数据。我画过一张任务流水线图这里不贴图了其实就是一条分阶段的生产线原始资料进入后先经过清洗再按内容类型分成若干束每个束由一个独立的抽取 Agent 处理产物经过审核合格后进卡片库不合格退回。这个流水线能从一段知识里提炼出多张卡片也能把多段相关内容合并成一张卡片而 Runtime 的编排能力就是让这条流水线可以随时暂停、中途观察、针对性修单。最后强调一个认知在整理知识成问答卡片这件事里大模型提供的只是文字处理能力真正让上百个任务有序跑完、每一批结果都能追溯、失败能重试的是这个 Agent Runtime。没有 Runtime你只能在 Python 脚本里写一堆 for 循环加异常处理代码会随着流程复杂度增长迅速变成一摊烂泥。3. 问答卡片的数据结构设计这是一开始就要想明白的我在第一步就强调过卡片的价值但卡片不是简单两行问题答案就完事了。如果目标是让客服 Agent 好用、让运营好维护、让系统能自动质检卡片的字段设计非常关键。先说结论我现在用的卡片核心字段长这样用 JSON 表示{ card_id: kb_ord_refund_0421, category: order_refund, question_core: 订单申请退款后多久到账, question_variants: [ 退款什么时候到, 退款要等几天, 申请退款后钱多久返回 ], answer: 订单退款一般在审核通过后 1-3 个工作日内原路返回若超过 3 个工作日未到账请提供订单号联系人工客服加急处理。, answer_detail: 具体到账时间受到支付渠道影响原路退回通常 1-3 个工作日支付宝/微信余额即时可见但提现到银行卡视渠道 1-2 个工作日。, source_refs: [docs/order/refund_v3.md, ticket/ticket_20250412_001], priority: high, version: 2025-04-refund-v3, valid_from: 2025-04-01, valid_to: null, tags: [退款, 到账时间, 资金], created_by: agent-extractor-v2, reviewed_by: ops-zhang, status: published }逐个字段说下设计考虑。question_core是最标准、最正式的问法它是卡片的主键语义也是检索时最重要的关键词来源。question_variants是变体问法这个字段对客服场景特别重要因为真实用户不可能像文档一样规范地提问会问出各种五花八门的口语表达变体问法越多召回越高。answer是直接给用户看的标准答案我要求它保持在 80 到 150 字以内客服场景里答案太长用户不愿意读太短又说不清楚。answer_detail是扩展内容给需要追问细节的用户或者人工客服参考检索时可以在答案不足时取用也可以设计成用户主动追问才返回。source_refs我很看重它记录了卡片内容到底来自哪些资料来源。这个字段第一是保底万一答案有争议人能追溯到源头第二是知识更新的时候能反向找出所有依赖某个文档的卡片做联动更新。version和valid_from/valid_to是知识治理的基础客服领域经常有临时政策、活动规则设置了有效期的卡片Agent 在检索时就可以主动排除过期内容否则系统很容易出现旧规则还在生效的事故。priority字段也很有用。不同内容的重要程度不一样比如涉及资金安全、法律条款的卡片我设成 high在 Agent 生成答案时对这类卡片做更保守的处理甚至可以要求 Agent 必须基于 high 卡片回答不允许参考闲聊语料。运营上也可以按优先级排审核队列。可能有人会问每张卡片都要填这么多字段靠 Agent 自动抽取靠谱吗答案是高质量抽取需要几个条件一个是清洗后的输入内容足够规整二是抽取任务的 prompt 写得足够具体三是抽取结果必须经过校验规则和人工复核。我在下一节会详细展开整个流程。卡片数量多了以后还需要有卡片库的分层设计。我的做法是分三层核心卡、普通卡、草稿卡。核心卡是经过人工审核、影响面大、答案高度稳定的卡片Agent 回答时优先生效普通卡是自动化流程产出的、经过初步校验但还没人工逐条确认的卡片草稿卡是抽取过程中产生的候选还没跑完校验。每一张卡从草稿一路升到核心都要在运营后台留操作记录。这一步极其重要因为纯自动化知识整理一旦没有分层和升降级机制你会发现自己根本不敢让系统拿这些卡片去回答真实的客户问题。4. 从原始数据到问答卡片完整流水线实操记录理论说了不少这部分我直接复盘我实际搭的流程从原始材料到卡片接近入库存量已经跑通了多个批次。我预想中需要把这条流水线拆成四步数据接入与清洗、内容分析与切分、Agent 抽取问答对、卡片校验与人工审核。4.1 数据接入与清洗脏数据不解决后面全白做客服知识来源有好几类产品帮助文档、运营给的 FAQ 汇总表、历史客服工单、客服聊天记录里已经被标记为优质回复的片段。每一类的脏程度完全不同。产品帮助文档相对干净但存在大量固定页眉页脚和无意义的导航文字向量化后几乎没有用但会干扰抽取FAQ 汇总表的问题是格式千奇百怪有的公司用 Excel有的用 Markdown还有的直接是截长图转出来的文字版表头统一、问答没有一一对应历史工单和聊天记录最麻烦里面有大量人名、订单号、情绪化表达还有很多客服之间互相确认信息的内部对话完全不适合直接进知识库。我做的清洗管线是这样的按顺序跑一遍抽取文本内容转成统一的 Markdown 格式。用规则去掉公共页眉页脚、重复的链接地址、无意义的图片占位符。对工单类数据做敏感信息脱敏比如手机号、邮箱、订单号用占位符替换。识别口语化闲聊段落这类内容没有知识价值直接丢弃。按文档语义切块锚点是二级三级标题每个语义块作为后续抽取的输入单元。这个清洗步骤看起来没什么技术含量全是一些基础文本操作但我强烈建议不要把这一步压缩掉。我第一版就是偷懒想着让抽取 Agent 自己去过滤废话结果 LLM 在长文档里抓重点时经常被干扰尤其客服工单里的客套话特别多抽取出来的问题有不少变成了用户怎么跟客服吵架这种毫无复用价值的东西。清洗耗时十几分钟但能让后续每一步的产出质量提升一大截。4.2 内容分析与切分不要让抽取 Agent 面对过长的上下文清洗完的文档还是太长的不能一股脑丢给抽取 Agent。大模型的上下文窗口虽然现在都比较大但窗口越大抽取时越容易出现中间部分被忽略的问题而且成本也会很高。我的做法是把文档按语义块切分然后让每个抽取任务只面对一个语义块这个语义块大概控制在 2000 到 4000 字以内。这里分享一个我踩过的坑最初我用的是固定字符数硬切比如每 3000 字一刀结果很多完整知识点被拦腰截断。抽取 Agent 拿到的文本是上半段在讲退款规则下半段突然是发货流程产出就很混乱。后来改成按标题结构切分配合一些简单的规则判断段落是否完整效果立刻好了很多。比如退款规则这一大节下面如果既有原路退回小节又有退到余额小节我会直接保留整节作为一个输入单元不去机械切分。切分完之后我给每一个语义单元打上类型标签这个环节我用了一个小分类 Agent。标签包括规则说明、流程指引、常见问题、产品变更、内部备注等。不同的标签在下个环节会走不同的抽取策略。比如流程指引类的单元我要求抽取 Agent 不仅要抽问答对还要识别出流程中的关键步骤数而产品变更类的单元需要额外标注变更生效时间方便后面填valid_from和valid_to字段。这个小细节让后续卡片质量提高非常明显。4.3 Agent 抽取问答对核心环节的参数与提示词设计到了抽取环节这是标题里问答卡片这个动作真正落地的一步。我用的是开源自部署的 LLM 加 Prompt 模板的方式。每个语义单元进去输出一个 JSON 数组每个元素就是一张草稿卡。我的抽取提示词核心结构可以简化成下面这样完整版涉及公司内部细节我脱敏处理你是一个客服知识库编辑助理。你的任务是从给定的产品资料片段中抽取高质量问答对。 要求 1. 站在真实客户的角度提出标准问题。question_core 必须简洁、自然让人一看就知道在问什么。 2. 同一个知识点如果有多种常见问法在 question_variants 里补充 2 到 5 条问法要口语化贴近真实聊天输入。 3. 仅提取片段中有明确依据的信息不要自行推断。没有把握的内容一律不抽取。 4. answer 控制在 150 字以内直接给出准确、可执行的答复。 5. 如果片段包含多个相互独立的知识点请拆分成多张卡片。 6. 输出严格 JSON 数组格式不要输出任何额外文字。有几个关键参数我反复调过。温度我设为 0.2抽取类任务不需要创意温度太高会带出幻觉内容。max_tokens根据输出结构设置如果允许一次输出多张卡片就给 4096 以上防止 JSON 被截断但设置了 JSON Schema 约束的情况下截断会表现为格式错误并不会静默丢数据。我在 Runtime 里还开了一个重试一次的策略如果第一次输出非法 JSON把报错信息回传给它再跑一次很多情况下第二次就能成功。抽取 Agent 跑完后直接进入自检校验阶段这一步不是人工做的是另一组规则加一个校验 Agent 在做。校验逻辑包括检查卡片是否包含要求的所有必填字段。缺字段的卡片直接打回。检查question_core和answer是否来自原文不能有明显的 LLM 补全内容。检测方式是让校验 Agent 对照原文判断答案中的每一句是否能从原文中找到依据。对常识性表述做风险标记。比如 Agent 输出根据规定所有商品均支持七天无理由退货但原文其实只说了数码类商品支持这种过度泛化必须拦截。生成卡片之间的相似度分组。同一个语义单元里很容易产生两张问法不同、答案相似的卡片相似度高于阈值的自动归并避免同一个知识点在库里出现多份。值得一提的是这里我建议不要天真地以为提示词控制一下它就不会乱写。校验 Agent 绝不等于人工审核它只承担粗筛作用把所有明显不合格、字段缺失、有幻觉风险的东西剔除掉。真正的确定性正确性还是要靠后面的运营人员做抽检或逐条复核。4.4 人工审核与入库别为了追求自动化省掉这个环节我经历过一个让团队印象很深的场景某品牌售后政策在一版卡片里被 Agent 从7 天无理由退货自动延展成了所有情况均支持退换要不是审核的时候多看了一眼这种答案发给用户是要出大事的。所以整个流程里我坚持抽样的卡必须有reviewed_by字段哪怕只是运营同事快速浏览。我现在的审核策略是所有标记为 high 风险的卡片必须人工逐条审核。普通卡片按批次抽 20% 人工复核复核通过率低于 95% 的批次整批退回重新抽取。核心卡必须有两个不同的人确认避免单人疏漏。人工审核通过后卡片数据会写进一个结构化表里。这里我用的是 PostgreSQL 存储卡片元数据同时把question_core、question_variants、answer这几个文本字段做向量化存进向量库用于后续检索。两张库之间的同步靠卡片 ID 关联向量库里的一条向量始终带card_id回答时命中了向量再反查 Postgre 拿到完整的卡片字段。这种设计好处是修改卡片内容时只需要更新结构化表再刷新对应向量即可不用在向量库里复制一份完整的业务数据结构。5. 检索与拒答策略卡片做出来是为了让 Agent 用得准问答卡片库只是中间产物最终目标还是让线上客服 Agent 能利用卡片回答用户问题。这一节我讲一讲检索接入和拒答设计这也是从知识整理过渡到在线问答的关键一步。检索阶段我采用的是一种复合检索策略不是单靠向量相似度一个指标。具体来说当用户问退款什么时候到账系统会同时执行三条检索线第一条是把用户问题直接向量化到向量库里找语义最接近的卡片第二条是把用户问题里的关键词提取出来用全文检索方式匹配卡片里的question_variants和tags第三条是针对高频问题配置的规则匹配比如用户输入包含退款、到账、多久这些词时直接置顶对应的高优先级卡片。三条线的结果做加权融合综合得分最高的卡片作为主答案来源。这里要专门强调一下变体问法的威力。我建库的时候录入的大量question_variants在线问答时经常被命中。举个例子用户说钱怎么还不回来语义向量可能匹配不到正规问法但我在变体里提前录过退款怎么还没到钱什么时候退回这类口语全文检索就能精准召回。这也是我为什么坚持卡片要人工或半人工整理的原因纯靠模型自动语义理解这些碎片化口语很难被稳定覆盖。拒答策略也很重要。客服场景里宁可让用户等人工也好过强行给一个编造答案。我的设计是三层拒答机制得分低于阈值时直接拒答得分虽然够但卡片状态不是 published 时拒答卡片原文中没有强支撑论据时也拒答。我还给 Agent 设了一条硬规则禁止用卡片之外的信息来回答知识库问题。你要是问今天心情怎么样它可以陪你闲聊几句但你要是问你们支持哪些支付方式它的知识只能来源于卡片不允许从训练记忆里搜刮答案。判断知识库问题和闲聊问题这个分类本身也是一个小的分类 Agent 在做的准确率实测下来在 95% 以上。另外还有一点有些问题本身是模糊的比如你们贵不贵这种问题很难有标准答案。我的做法是让卡片库维护一个模糊问题清单类似这种问题统一转给人工客服不要强行回答。清单的维护来自每天线上问答的复盘运营人员看到的三五个答非所问的 Query就是下一轮知识整理的最佳输入素材。6. 常见问题排查实录Runtime 和抽取流程的踩坑速查表自动化流程跑起来之后每天都会遇到各种稀奇古怪的问题。我整理了一份排查速查表直接给大家抄作业。现象可能原因处理方式抽取 Agent 输出 JSON 频繁截断max_tokens设置过小单次输出卡片过多限定单次输入单元内最多抽取 5 张卡片超过的拆分子任务启动流水线时报container runtime is not running相关错误运行环境的容器服务没有正常启动Runtime 依赖的后端实例未就绪先检查容器服务和 GPU 推理服务状态确认就绪后再启动任务Agent 执行中途提示agent execution terminated due to error子任务超时、单次调用 LLM 返回异常、或是外部工具返回了错误格式在运行时配置层增大单任务超时时间并启用自动重试同时把工具返回内容做一层 schema 校验抽取的答案里有明显编造成分输入片段语义不完整、温度太高、提示词没有强调仅依据原文降低温度为 0.2 以下在提示词里强制约束没有依据必须跳过并补充校验 Agent 回归检测一张知识点被拆成十几张很碎的卡片切分过细、抽取 Agent 把同一信息从不同角度反复提问切分时确保按语义单元而非字符数同时设置相似卡片合并阈值线上 Agent 回答命中卡片但内容已过期卡片缺少有效期字段或运营没更新valid_to补全字段并在检索阶段过滤所有valid_to早于当前时间的卡片不同来源对同一问题的说法不一致原始文档版本混乱抽取 Agent 把两个版本的信息都当成了依据在预清洗阶段对高重复段落做版本对比确定优先级卡片中的 source_refs 能帮助定位冲突来源向量检索老召回不相关卡片question_core太短、缺少变体、向量模型与行业不匹配补充question_variants和tags尝试更换领域微调过的向量模型这里单独讲讲agent execution terminated due to error这个报错。我第一次跑全量流水线遇到这个错误时第一反应是怀疑模型崩了后来看日志发现是某个子任务处理一个超长工单时超过了 Runtime 默认的 30 秒执行上限。把对长文本的处理拆成更小的切片同时调整单任务超时配置之后问题就再没出现过。所以遇到这类通用报错时先别急着怀疑模型能力优先检查运行时配置和输入数据形态往往真正的坑就藏在这些最基础的地方。再补一个运维层面的建议在 Runtime 的日志设计上一定要让任务 ID卡片 ID来源文档路径形成可追溯链路。我见过很多团队只管把结果写进数据库出了问题根本定位不到是哪一批数据导致的。我现在每个子任务运行都会输出结构化日志包含任务 ID、输入来源 hash、模型调用 ID、校验结果。排查问题的时间从小时级降到了分钟级这个投入绝对值得。7. 知识更新联动与增量整理这个流程后续怎么长期运转前面讲的基本都是全量整理的流程但知识库真正麻烦的地方在于它需要持续更新。产品改版了怎么办、新政策上线怎么处理、用户最近集中遇到的新问题怎么沉淀进库、旧卡片又什么时候该退休。这些事不能让运营天天手工去核对还是得依靠 Agent 流水线运转。我设计了一套增量机制每天收集新增的工单、客服优质回复、以及产品文档的 commit 记录把它们当作新的输入源跑一遍简化的清洗和抽取流程。简化版的不同点在于多了与现有卡片库的比对重复问题直接合并进现有卡片的变体集合新问题才会生成草稿卡。同时每天夜里有一个巡检 Agent 会把所有 published 卡片检查一遍对照产品文档的最新版本确认答案是否仍然成立发现内容冲突时自动把卡片降级为草稿并通知人工复核。还有一点值得说就是在增量阶段source_refs和version字段的重要性格外突出。没有版本信息你根本没法判断一张卡片描述的是哪一年的政策没有来源引用文档一更新你就找不到哪些卡片需要修改。这个联动机制是知识库从一次性搭好的 demo变成能长期维护的基础设施的分水岭。随着卡片库越来越大质量问题的表现形式也会从单张卡片出错变成多个卡片之间的覆盖关系纠缠不清。比如用户问发货时间既有通用发货规则卡又有节假日特殊安排卡还有某个具体地区的例外卡。这几张卡片很可能同时命中顺序如果排错用户得到的就是错误答案。我的处理方式是在卡片元数据里增加overrides覆盖关系和depends_on依赖关系两个字段标识特殊规则覆盖通用规则。检索时按照覆盖优先级重排卡片而不是单纯看向量得分。这种关系网络在存量只有几十张卡时看不出来但上千张卡的时候绝对是决定系统上限的关键设计。8. 给想做同类项目的朋友关于工具选型和投入预期的真心话最后分享一点个人体会。我知道很多人看这个标题是想找一个一键脚本把文档丢进去第二天就有完美问答库。但我必须泼一盆冷水问答卡片的整理流程里自动化程度可以很高但完全无人化目前仍然是不现实的。我现在的流程里清洗、切分、抽取、粗校验这些环节全部自动化基本可以做到一个运营人员管理上千张卡片的程度但核心卡审核和冲突仲裁依然需要人。这不是技术不行而是客服知识本身就带有强业务属性业务判断不是纯文本处理能替代的。工具选型方面如果你想要快速跑通整个概念验证我建议先不要自己从零搭 Runtime直接用 Dify 或者 FastGPT 之类的开源平台把上面讲的流水线以工作流的方式拉出来跑一遍。先用可视化平台验证你的数据质量和 Prompt 是否靠谱等你在小范围数据上看到了预期效果再考虑自己基于底层框架搭建生产级的 Runtime。我自己当时就是先用了现成平台跑了一个小批次确认了Agent 抽取问答对这条路可行才花力气去做定制化的 Runtime 和持久化设计。还有一点数据脱敏在客服场景里绝对不要省。工单和聊天记录里包含大量个人信息整理流程跑完以后原始数据要不要留存、在哪里留存、谁能访问这些都要在项目规划期就定清楚。我的做法是抽取流程只接收经过脱敏和清洗后的文本原始聊天记录不进入知识库所在的环境从源头上避免敏感信息扩散。整个项目做下来最深的体会是不要把问答卡片当成一个简单的数据格式转换它是一个连接着清洗质量、模型能力、运营规范和在线问答策略的综合命题。开源 Agent Runtime 解决的是让整套流程可以可信地运行起来这件事而真正让客服知识库好用的是你愿不愿意把知识治理当成一件日常运营的事持续投入。希望这篇文章能帮你把每一步都看得更清楚少踩一些我已经踩过的坑。
返回列表