很多团队做 FAQ 机器人,第一步是把产品手册整段丢给模型,然后发现它答得比不答更糟。
我做外贸 15 年,前年带团队搭过一套客服问答,前后推倒数次才跑通。
这篇讲落地时真正卡人的那几处,不聊概念。

一、动手之前,先看这三个坎

先说清楚坑在哪,能省掉很多试错。

第一坎:知识不在文件里。

我们以为产品资料都在手册上。实际一整理才发现,客户最常问的二十个问题,有一半手册里没有。

比如「你们这批货能不能用我们自己的包装箱」「换柜之后交期会不会变」「能不能分两批发」,这些都是业务员脑子里的经验,从没写下来过。

知识库搭不起来,八成的原因在这。不是技术问题,是没人把散的经验落到纸上。

第二坎:FAQ 是给人看的,不是给机器看的。

一份典型的 FAQ 长这样:一段话讲完产品特色、适用场景、注意事项,中间夹着三四个不同的问题。

人看没问题,机器人检索就麻烦了。它不知道这段该对应哪个问题,答案边界在哪里。

所以原样搬进来是不行的,必须重切。

第三坎:没人管更新。

这个坎最要命,也最容易被低估。

知识库最怕的不是答不出来,是答得太有底气,但内容已经过期。

我踩过这个坑。我们的付款方式前年改过一次,知识库没同步,机器人照旧按老政策答了两个月,直到有个客户拿着聊天记录来对质。那次之后我定了个规矩:政策类的内容,每季度必须有人复核一次,复核完签字。

知识库不是一次性工程,是个需要维护的东西。想清楚这一条,再决定要不要做。

先说清楚这套东西能干什么、不能干什么。

它能干的是:把最重复的那部分问答接过去,让业务员的时间从「回答同样的问题二十遍」里省出来。

它不能干的是:替业务员谈生意。

我见过有团队指望机器人接下全部咨询,省掉客服人力。跑到第三周就放弃了。原因很简单,客户真正下单之前的那几个问题,全是需要判断的。机器人答得越顺,客户越以为对面是个人,一旦发现不是,信任感掉得更快。

我们现在的定位是:机器人处理「信息型问题」,人处理「决策型问题」。

信息型问题是那种答案唯一的问题,比如起订量、认证有哪些、包装规格。决策型问题是答案取决于情况的问题,比如能不能便宜点、能不能早两周发货。

按这条线分,边界就清楚了。

二、知识库该怎么切

切分是这套东西里最核心的环节,比选模型重要得多。

我的做法是:一条知识只回答一个问题。

具体结构用四个字段:

字段说明例子
问题客户会怎么问,用客户的口语写起订量是多少
答案直接能发出去的话常规款起订量 500 件,定制款 1000 件起
同义问法同一问题的其他说法最少订多少、MOQ 多少、最小批量
类别与更新日期用于分类和过期提醒订单类,2026-08-15

第三个字段是我后来加的,很关键。

客户不会按你写的问题提问。「起订量是多少」在客户嘴里可能是「最少订多少」「MOQ」「small order 可以吗」。把这些说法都列进同义问法里,命中率会明显提高。

类别和更新日期这两个字段平时用不上,但过期检查的时候全靠它。

切分的时候有个原则:一条知识点的长度控制在三到五行。

太长了,机器人会在回答里夹带无关内容。太短了,信息不完整。三到五行大概就是一个客户问题该有的答案长度。

切分这件事,我吃过亏。

第一版我是按产品手册的章节切的,一章一条。结果上线之后发现,客户问「能不能做定制包装」,机器人返回的是一整段「产品特性与包装说明」,里面确实提到了包装,但没回答能不能定制。

问题在于那一段回答了三个问题,但都没有给明确结论。

重切的时候我换了个思路:不看资料怎么写的,看客户怎么问的。

我把过去一年的咨询记录导出来,按问题归了类,然后照着客户的问法重写知识条目。这样切出来的每条,都是一问一答,长度也自然。

这个方法笨,但一次就切对了。后来给我省了几个月的返工。

三、检索怎么匹配,答不出来怎么办

知识库建好了,接下来是「客户问一句,怎么找到该答哪条」。

匹配方式有三种做法,复杂度递增:关键词匹配、相似度匹配、向量检索。小团队从中间那种开始就够用。

比匹配更重要的,是兜底设计。

我见过太多机器人,答不上来的时候硬编一段话,客户以为你在敷衍。这个体验比「不回答」更差。

我的兜底规则是这样的:

  • 相似度低于阈值:不回答,转人工,并且明确告诉客户「这个问题我需要跟同事确认一下,稍后回你」
  • 命中两条以上相近知识:把两条都给出来,让客户选,而不是猜一条
  • 涉及报价、交期、合同类问题:不管命中多准,一律不自动答,直接转人工

第三条是我们踩坑后加的。有次机器人自动答了一个交期,客户拿这个数字催货,我们没法兑现。从那次起,这类内容一律不进自动回答范围。

说白了,机器人只答「确定的事」,不确定的一律交给人。这是这套东西能不能用的分界线。

四、脚本怎么写

下面这段是简化实现,用标准库做相似度匹配,不依赖任何外部服务。小团队几十条知识用这个足够。

import math
import re
from collections import Counter

# FAQ 问答脚本(标准库版)。
# 为什么不用向量库?小团队的知识条数一般在一百条以内,
# 用词频相似度就够用,还省掉了向量化和外部依赖,断网也能跑。
# 等知识条数超过几百条、同义问法开始打架的时候,再考虑升级。

# 阈值定在 0.35,是实测出来的经验值:
# 定太高会大量漏答,定太低会把不相干的答案推给客户。
SIMILARITY_THRESHOLD = 0.35

# 停用词:这些字在中文里到处都是,参与计算只会稀释有效信息
STOP_CHARS = set("的了是我你他她它们和与及在有吗呢吧啊请问一下么怎样多少")

def tokenize(text):
    """中文按字切分,英文按词切分。
    为什么按字不按词?因为按词需要分词库,而外贸场景里产品名、型号很多是自造的,
    分词库切不对,反而按字更稳。代价是精度略低,靠同义问法来补。"""
    text = text.lower()
    # 英文单词和数字整体保留,其余中文按单字
    tokens = re.findall(r"[a-z0-9\.\-]+|[\u4e00-\u9fff]", text)
    return [t for t in tokens if t not in STOP_CHARS]

def vectorize(tokens):
    """转成词频向量,用 Counter 就够了,不需要 numpy"""
    return Counter(tokens)

def cosine_similarity(v1, v2):
    """余弦相似度:只看方向不看长度,这样长问题短问题可以公平比较"""
    if not v1 or not v2:
        return 0.0
    common = set(v1) & set(v2)
    numerator = sum(v1[k] * v2[k] for k in common)
    denom1 = math.sqrt(sum(v * v for v in v1.values()))
    denom2 = math.sqrt(sum(v * v for v in v2.values()))
    return numerator / (denom1 * denom2) if denom1 and denom2 else 0.0

class FaqBot:
    def __init__(self, knowledge_base):
        """knowledge_base 每条包含:question, answer, aliases(同义问法), category"""
        self.entries = []
        for item in knowledge_base:
            # 把主问题和所有同义问法合并成一份文本,一起参与匹配
            texts = [item["question"]] + item.get("aliases", [])
            self.entries.append({
                "vectors": [vectorize(tokenize(t)) for t in texts],
                "answer": item["answer"],
                "category": item.get("category", ""),
                "question": item["question"],
            })

    # 这几类内容不做自动回答,一律转人工。
    # 为什么写成类目判断而不是关键词判断?因为类目是维护知识库时定的,
    # 比事后猜关键词更可靠,也不会因为换了说法就漏掉
    MANUAL_ONLY = {"报价", "交期", "合同"}

    def ask(self, user_question):
        u_vec = vectorize(tokenize(user_question))

        scores = []
        for entry in self.entries:
            best = max(cosine_similarity(u_vec, v) for v in entry["vectors"])
            scores.append((best, entry))
        scores.sort(key=lambda x: -x[0])

        if not scores or scores[0][0] < SIMILARITY_THRESHOLD:
            # 兜底:不硬答。承认不知道,比编一个答案对客户关系的伤害小得多
            return {"action": "human", "reply": "这个问题我需要跟同事确认一下,稍后回复您。", "score": 0}

        best_score, best_entry = scores[0]

        if best_entry["category"] in self.MANUAL_ONLY:
            return {
                "action": "human",
                "reply": "您这个问题涉及具体条件,我让负责的同事直接跟您对接。",
                "score": best_score,
            }

        # 命中两条相近知识时,两条都给出来让客户选,不要替客户猜
        second = scores[1] if len(scores) > 1 else (0, None)
        if second[1] and second[0] > best_score - 0.08:
            return {
                "action": "choose",
                "reply": f"您是想问「{best_entry['question']}」还是「{second[1]['question']}」?",
                "score": best_score,
            }

        return {"action": "auto", "reply": best_entry["answer"], "score": best_score}

if __name__ == "__main__":
    kb = [
        {
            "question": "起订量是多少",
            "aliases": ["最少订多少", "moq 多少", "small order 可以吗", "最小批量"],
            "answer": "常规款起订量 500 件,定制款 1000 件起。少量试单可以单独商量。",
            "category": "订单",
        },
        {
            "question": "交期多久",
            "aliases": ["什么时候能发货", "lead time", "多久出货"],
            "answer": "常规款 25 到 30 天,旺季会到 40 天。",
            "category": "交期",
        },
        {
            "question": "样品怎么申请",
            "aliases": ["想要样品", "how to get sample", "能不能打样"],
            "answer": "样品 3 到 5 天可以寄出,具体运费我按您的地址核算后告诉您。",
            "category": "样品",
        },
    ]

    bot = FaqBot(kb)
    tests = ["请问 moq 是多少", "交货要多久", "给我报个价", "你们公司有几个人"]
    for q in tests:
        r = bot.ask(q)
        print(f"问:{q}")
        print(f"答:[{r['action']}] {r['reply']}(相似度 {r['score']:.2f})\n")

跑了一遍,四条测试里两条正常回答,一条交期问题按规则转人工,一条无关问题走了兜底。行为符合预期。

这套东西上线之后,能自动处理的比例大概三成多。听起来不高,但这三成是最重复、最没价值的那部分。业务员省下来的时间,都花在了需要判断的对话上。

跑了一个季度之后,我总结出三个要注意的地方。

一是**转人工要转得干脆。**客户的问题一旦要转,就立刻转,别让机器人再猜一次。我们早期的做法是先让机器人试两次,答不上再转。客户体验很差,因为那两次的答案都是错的。

二是**转人工要说清楚为什么。**只说「我需要确认一下」客户会等,说「这个问题我需要跟技术确认,大概两小时回你」客户就不会一直追问。

三是**每周看一次转人工的记录。**这些记录就是知识库的待办清单。哪类问题转得最多,就说明哪类知识该补。我们第一周转人工最多的三类问题,补进知识库之后,自动处理比例从三成提到了接近五成。

这三件事都不涉及技术,但比换模型管用。

五、三种问答方式对比

方案做法优点缺点
人工查手册回复业务员翻资料再答答案准确,能随机应变慢,新人翻不到,同一问题每次答法不一样
关键词机器人按关键词命中固定答案快、可控、成本低说法一变就答不上,容易答错
模型 + 私有知识库语义检索后由模型组织答案覆盖广,表达自然可能编内容,必须配兜底和人工抽查

我的建议是:先把知识库切好,用什么方式检索是第二步。

切分和兜底这两件事做对了,哪怕用的是最笨的关键词匹配,机器人也是可用的。这两件事没做,接了再好的模型也还是不能用。

日常运营上,我们多个号的客户消息是聚在 WADesk 这类工具里处理的,机器人答不了的会自动进人工队列,不会漏掉。工具管的是「消息不丢」,知识库管的是「答得对不对」,两件事分开看。

写在最后

今天就能做的一件事:打开你的产品资料,随手挑出客户最常问的十个问题,写成十行。

每一行并排写两栏:客户会怎么问、标准答案是什么。就这两栏。

写完这十行,你就有了一个最小可用的知识库。剩下的问题,等这十个跑顺了再往里加。

Logo

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

更多推荐