一、引言:当“规则机器人”撞上口语化提问

两年前,我接手了一个电商客服项目。传统机器人基于关键词规则运行,用户问“什么时候发货”它能答,换一种说法问“我昨天下的单怎么还没动静”,它就直接转人工了。口语化提问、同义表达、多轮上下文——任何一个场景都能让规则引擎失效。客服团队每天收到超过40%的重复性问题,而机器人的直接解决率不到45%。

后来我们基于RAG(检索增强生成)架构重构了整个系统。核心思路很简单:模型不再凭空回答,而是先从企业知识库里检索相关文档,再基于检索结果生成答案。 最终效果:解决率提升到86%,人工介入率下降42%。下面从工程角度复盘这趟实战经历,包含可运行的代码和踩坑记录。


二、架构概览:RAG客服系统的四层设计

一套生产级RAG客服智能体包含四个核心层:

层级 组件 职责
知识层 向量数据库 + 结构化FAQ + 元数据标签 提供可检索、可溯源的业务知识
检索层 Embedding模型 + 混合检索 + 重排序 从知识库召回最相关的文档切片
生成层 大语言模型 + 提示词系统 基于检索结果生成回答,控制行为边界
控制层 Agent编排 + 工具调用 + 转人工路由 查订单、改地址、触发工单、人工兜底

关键判断:对90%的企业来说,不需要微调大模型。“RAG + 高质量提示词”足以达到95%以上的准确率。我们的项目全程没有做任何模型微调,效果完全达标。


三、知识库构建:决定系统上限的“黄金加工”

3.1 三类知识的标准化处理

很多团队直接拿产品说明书和历史工单往里扔,结果“垃圾进,垃圾出”。正确的做法是先分类加工:

  • 结构化知识(退货政策、物流时效)→ 整理为FAQ三元组(问题-标准答案-关键词变体)
  • 半结构化知识(如何申请发票)→ 整理为步骤清单 + 前置条件 + 异常分支
  • 非结构化知识(产品使用场景说明)→ 段落切分 + 元数据标注(产品线/适用人群/版本)

3.2 文档分块策略:500字是“黄金分割点”

分块是RAG系统最容易被低估的工程环节。分块过粗,语义被稀释,检索精度下降;分块过细,语义断裂,召回质量差。

我们最终采用的方案是重叠滑动窗口,块大小500字符,重叠50字符:

# 基于LangChain的分块实现
from langchain.text_splitter import RecursiveCharacterTextSplitter

def create_chunks(raw_documents):
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=500,
        chunk_overlap=50,
        separators=["\n\n", "\n", "。", ";", ","]
    )
    chunks = text_splitter.split_documents(raw_documents)
    return chunks

工程踩坑:一开始用按段落分块,发现FAQ类文档的段落通常只有一两句话,向量语义太薄,检索命中率只有60%。换成重叠滑动窗口后,命中率提升到86%。

3.3 向量模型选型

中文客服场景推荐以下Embedding模型:

模型 维度 特点
text-embedding-3-small 1536 OpenAI官方,性价比高
BGE-large-zh 1024 中文优化,可私有部署
M3E 1024 中文开源,支持混合检索

我们选的是BGE-large-zh,因为要私有化部署,且1024维在检索速度和精度之间平衡最好。

3.4 知识库健康度检查

上线前必须验证三项指标,建议抽样100个真实用户问题:

  • 召回率:Top-3切片是否包含答案 → 目标≥90%
  • 精准率:第一个切片是否直接相关 → 目标≥80%
  • 歧义率:是否返回矛盾或过时信息 → 目标≤5%

四、检索模块:匹配距离调参与混合检索

4.1 向量检索 + 相似度阈值

检索的核心问题是:召回什么,以及什么不该召回。我们使用余弦相似度作为度量标准,并设置了一个匹配距离阈值——这是整个系统最需要反复调参的环节

  • 阈值过高 → 匹配结果过少,AI无话可说
  • 阈值过低 → 无关内容被召回,AI被带偏
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

def retrieve_knowledge(query_vec, vector_store, top_k=5, threshold=0.7):
    """
    向量检索 + 相似度阈值过滤
    """
    results = []
    for item in vector_store:
        sim_score = cosine_similarity(query_vec, item["vector"])[0][0]
        if sim_score >= threshold:
            results.append({
                "content": item["content"],
                "score": sim_score,
                "source": item.get("source", "")
            })
    results.sort(key=lambda x: x["score"], reverse=True)
    return results[:top_k]

实战经验:我们最初把阈值设为0.8,结果很多有效答案被筛掉,用户说“AI像个复读机,只会说不知道”。反复测试后调到0.65,召回率和精确率达到了平衡。

4.2 混合检索:向量 + BM25 双路召回

纯向量检索有一个致命弱点:语义相近但表述不同的词容易被漏掉,而表述相同但语义不同的词容易被错误召回。

解决方案是混合检索(Hybrid Search),将BM25关键词检索与向量语义检索结合:

from langchain.retrievers import EnsembleRetriever

def create_hybrid_retriever(vectorstore, bm25_retriever):
    """
    混合检索:BM25关键词检索 + 向量语义检索
    最终得分 = 0.3 × BM25得分 + 0.7 × 向量相似度
    """
    hybrid_retriever = EnsembleRetriever(
        retrievers=[bm25_retriever, vectorstore.as_retriever()],
        weights=[0.3, 0.7]  # BM25权重30%,向量权重70%
    )
    return hybrid_retriever

实测效果:在专业术语场景下,混合检索相比单一向量检索准确率提升28%。尤其是产品型号、政策名称这些精确匹配场景,效果提升非常明显。

4.3 重排序(Reranker):Top-10 → Top-3

检索出来的Top-K文档不能直接塞给模型,因为Top-10里可能有排序靠后但更相关的内容。我们加了一层重排序,用Cross-Encoder模型对检索结果二次排序:

# 重排序策略示例
# 检索Top-10,重排后取Top-3
retriever_kwargs = {
    "search_kwargs": {
        "k": 10  # 先召回10条
    }
}
# 实际使用时,用Cross-Encoder模型对这10条重新打分
# 取打分最高的3条作为最终上下文

五、Prompt工程:客服智能体的“宪法”

5.1 提示词模板设计

检索到了知识并不代表模型能正确使用。我们设计了一套结构化的提示词框架,核心是硬约束 + 兜底策略

SYSTEM_PROMPT_TEMPLATE = """
你是一名企业客服顾问,工号A01。你的风格:专业、耐心、不承诺超出政策的内容。

【知识库检索结果】
{context}

【用户问题】
{query}

【硬约束】
1. 仅根据上述检索结果回答,严禁使用外部知识
2. 优先使用上下文中的原文表述,不要自行发挥
3. 如果检索结果中没有覆盖用户问题,直接说"这个问题我暂时无法回答,正在为您转接人工客服"
4. 涉及退款、投诉时,输出"已为您记录工单"并触发转人工标识
5. 回复长度控制在3句以内
6. 不要在回复中出现"根据检索结果"、"我查了一下"等表述

【输出格式】
先确认问题类型(售后/物流/活动/其他),再给出答案,最后提供下一步动作建议。

【回答】
"""

关键设计点

  • 否定约束:“严禁使用外部知识”——很多模型在上下文不足时会凭“常识”瞎编,这个约束能显著降低幻觉
  • 兜底策略:当检索结果不足时,模型必须诚实说“无法回答”,而不是编造答案
  • 长度约束:3句以内——客服场景的核心是“短平快”,长篇大论反而降低用户体验

5.2 温度参数调优

客服场景需要确定性,不需要创造力。参数配置如下:

  • Temperature = 0.1(追求确定性回复)
  • Top-P = 0.9
  • Max tokens = 500~1000(避免输出废话,也控制成本)

六、工具调用与转人工:让AI“能办事”

6.1 三个必须接通的工具

一个合格的客服智能体不能只“回答问题”,还要能“办事”:

  1. 订单查询:通过手机号/订单号查状态、物流轨迹
  2. 退换货入口:生成售后链接/工单,校验是否在退货期内
  3. 转人工路由:用户明确要求 / 模型置信度低于阈值 / 同一问题重复3次

6.2 Agent编排逻辑(基于LangGraph)

我们使用LangGraph实现了完整的Agent工作流:

用户输入
    │
    ▼
意图识别(轻量分类器)
    │
    ├── 置信度 > 0.85 ──→ 知识检索 ──→ 工具调用(如需) ──→ LLM生成
    │
    └── 置信度 < 0.85 ──→ 转人工(带上下文摘要)

核心代码示意:

# 基于LangGraph的Agent编排(简化版)
from langgraph.graph import StateGraph, END

class CustomerServiceAgent:
    def __init__(self, llm, retriever, tools):
        self.llm = llm
        self.retriever = retriever
        self.tools = tools
        
    def build_graph(self):
        graph = StateGraph(AgentState)
        
        graph.add_node("classify_intent", self.classify_intent)
        graph.add_node("retrieve_knowledge", self.retrieve_knowledge)
        graph.add_node("call_tool", self.call_tool)
        graph.add_node("generate_response", self.generate_response)
        graph.add_node("escalate_human", self.escalate_human)
        
        graph.add_edge("classify_intent", "retrieve_knowledge")
        graph.add_conditional_edges(
            "retrieve_knowledge",
            self.should_use_tool,
            {
                "call_tool": "call_tool",
                "generate": "generate_response"
            }
        )
        # ...
        return graph.compile()

关键设计:工具调用必须设置确认环节(如“您确认要取消订单吗?”),避免不可逆操作由AI自动执行。


七、上线与迭代:四道防线 + 数据飞轮

7.1 上线前的四道防线

  1. 离线测试:构建2000+真实历史对话测试集,评估准确率、拒识率、幻觉率。通过标准:准确率≥90%,幻觉率≤2%

  2. 影子模式:真实流量复制一份给新系统,但不直接回复用户,与人工答案对比运行3~5天,收集失败案例

  3. 在线护栏:输出前检查——若回答涉及退款但知识库无对应政策,拒绝生成;任何时效性承诺必须与业务政策核对

  4. 人工兜底SLA:强制转人工触发词(“转人工”“投诉”);连续2次相同问题无解 → 自动创建工单

7.2 持续迭代:建立数据飞轮

上线只是开始。我们建立了每周迭代机制:

  1. 日志分析:每周导出未被回答成功的问题
  2. 知识补全:高频未覆盖问题加工后入库(增量索引,5分钟内可检索)
  3. 提示词优化:根据失败案例调整约束规则
  4. A/B测试:两个提示词版本同时运行,对比效果

真实数据:持续运营3个月后,解决率从71%提升到89%,人工介入率下降42%。


八、踩坑实录:最常见的5个问题

问题 原因 解决方案
新增话术无法被检索到 Embedding是离线的,新增后未重建索引 引入增量索引机制,新增文档5分钟内可检索
竞品话术被错误复用 知识库中存在跨客户共享内容 增加数据隔离层,按企业ID做向量空间隔离
夏季咨询回复了冬季话术 分块时丢失了时效性上下文 增加时间戳元数据字段,检索时做时间过滤
答非所问 检索到的切片不相关 提高相似度阈值 + 加入重排序(Reranker)
答案过时 知识库混入旧版本 强制时效性过滤 + 更新时间戳校验

九、总结:RAG落地的三个核心认知

复盘整个项目,有三条经验值得反复强调:

  1. 检索质量决定系统上限,模型只是“锦上添花” 。分块策略、相似度阈值、混合检索——这些工程细节比选哪个模型重要得多。

  2. 提示词的“否定约束”比“正向指令”更关键。告诉模型“不能编造”比告诉它“要回答准确”有效得多。兜底策略决定了系统在边界情况下的行为下限。

  3. RAG不是一个“部署即完成”的项目,而是一个需要持续迭代的数据工程系统。上线后的数据飞轮(日志分析→知识补全→提示词优化)才是价值持续释放的关键。

对于正在构建类似系统的团队,建议先用小规模数据集(100~200个真实问题)跑通全链路,再逐步扩大知识库规模和用户量。RAG的路,慢就是快。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐