用 AI API 构建智能客服:意图识别到多轮对话管理的完整落地方案
为什么大多数"AI 客服"只是个聊天框
很多团队上线了一个接入 LLM 的对话窗口,就宣称做了 AI 智能客服构建。但用户问"我的订单什么时候到",模型开始一本正经地编物流信息;用户情绪激动时,系统继续用客气话绕圈子。问题不在模型能力,在于架构缺失。
一套真正可用的智能客服,至少要解决三件事:知道用户在问什么(意图识别)、知道去哪里找答案(知识库检索)、知道什么时候该让人接手(转接判断)。三者缺一,系统就会在某类问题上系统性地失败。
意图分类:用分类器代替"让模型猜"
最常见的错误是把所有问题直接扔给 Claude Opus 4.8 或 GPT-5.5,期待模型自己决定该怎么处理。这在成本和延迟上都不划算,而且意图判断的准确性也无法量化。
更合理的做法是在入口加一个轻量分类层。用 Haiku 4.5 或 GPT-5.4-mini 做意图分类,成本大约是旗舰模型的 1/10,P50 延迟可以控制在 300ms 以内。分类结果直接决定后续的路由策略。
典型的意图分类 prompt 结构:
INTENT_SYSTEM = """
你是一个客服意图分类器,将用户消息分类到以下类别之一,只返回 JSON:
- order_query:订单状态、物流查询
- refund_request:退款、退货申请
- product_consult:产品功能、使用方法咨询
- complaint:投诉、负面情绪
- human_request:用户明确要求转人工
- other:无法归类
输出格式:{"intent": "<类别>", "confidence": 0.0~1.0}
"""
async def classify_intent(user_message: str) -> dict:
response = await client.chat.completions.create(
model="claude-haiku-4-5", # 或 gpt-5.4-mini
messages=[
{"role": "system", "content": INTENT_SYSTEM},
{"role": "user", "content": user_message}
],
max_tokens=60,
temperature=0
)
return json.loads(response.choices[0].message.content)
confidence 低于 0.6 时,走 fallback 流程(通常是追问澄清或直接转人工),而不是硬猜。
知识库检索:RAG 管道的关键参数
意图确定后,多数问题需要从知识库检索答案,而不是让模型凭记忆回答。RAG(Retrieval-Augmented Generation)是标配,但实现质量差距很大。
向量化与检索
知识库条目在写入时切片,推荐每段 512 token,重叠 64 token。Embedding 模型用 text-embedding-3-large 或等效方案,检索时取 top-5,再用 BM25 交叉排名(hybrid search)过滤到 top-3。纯向量检索在精确词匹配场景(如订单号、SKU 编号)表现差,hybrid 能把召回率从约 72% 提升到 88% 左右。
上下文拼装
把检索结果和对话历史一起注入 prompt。知识库内容用 XML 标签包裹,避免模型混淆来源:
def build_rag_prompt(retrieved_docs: list, history: list, user_query: str) -> list:
knowledge_block = "\n".join([
f"<doc id='{i}'>{doc['content']}</doc>"
for i, doc in enumerate(retrieved_docs)
])
system = f"""你是客服助手,只根据以下知识库内容回答。
如果知识库中没有答案,直接说"我需要为您转接专员确认",不要编造。
<knowledge_base>
{knowledge_block}
</knowledge_base>"""
messages = [{"role": "system", "content": system}]
messages.extend(history[-6:]) # 保留最近 3 轮对话
messages.append({"role": "user", "content": user_query})
return messages
历史对话保留 6 条(3 轮)在大多数场景下够用,超过这个数量后 context 成本线性增长,但回答质量提升有限。
多轮对话状态管理
客服场景有个典型问题:用户会在中途切换话题,或者一个问题跨多轮才说清楚。用无状态的单次 API 调用处理这类对话,系统会频繁"失忆"。
状态管理的核心是维护一个 session 对象,存在 Redis 里,TTL 设 30 分钟(超时即视为新会话):
@dataclass
class SessionState:
session_id: str
user_id: str
history: list[dict] # 对话历史
current_intent: str # 当前意图
context: dict # 跨轮共享的上下文,如订单号
escalation_signals: int # 升级信号计数
created_at: float
last_active: float
context 字典在意图为 order_query 时,会把识别到的订单号存进去,后续轮次不需要用户重复说。escalation_signals 是人工转接判断的输入之一。
人工转接:规则 + 模型双保险
转接逻辑是客服系统里最容易被简化处理的环节,结果要么转太多(AI 没发挥作用),要么转太少(用户体验崩掉)。
用规则层 + 情绪检测层双保险:
规则层触发条件(任一满足即转接):
- 意图分类为 human_request
- 意图分类为 complaint 且 escalation_signals >= 2
- 连续 3 轮 RAG 检索置信度均低于阈值(知识库覆盖不到的问题)
- 涉及金额超过业务阈值(如退款金额 > 5000 元)
情绪检测层用 LLM 打分,在每轮回复后异步执行,不阻塞主流程:
async def detect_sentiment(message: str) -> float:
"""返回 0~1 的负面情绪分数"""
resp = await client.chat.completions.create(
model="gpt-5.4-mini",
messages=[{
"role": "user",
"content": f"判断以下客服对话中用户的负面情绪强度,返回0到1的数字,只返回数字:\n{message}"
}],
max_tokens=5,
temperature=0
)
return float(resp.choices[0].message.content.strip())
负面情绪分数超过 0.75 时,给 escalation_signals 加 1。这个异步判断每次大约消耗 50~100 token,成本可以忽略。
转接发生时,系统要把完整的 SessionState 传给人工坐席,包括对话历史和已识别的上下文(订单号、问题类型),让坐席不需要重新问一遍——这一步很多系统做不好,但对用户体验影响很大。
三层架构对比
| 层级 | 模型选择 | 平均延迟 | 单次成本估算 |
|---|---|---|---|
| 意图分类 | Haiku 4.5 / GPT-5.4-mini | ~300ms | ~$0.0001 |
| RAG 问答 | Sonnet 4.6 / GPT-5.4 | ~800ms | ~$0.002 |
| 复杂投诉处理 | Opus 4.8 / GPT-5.5 | ~2000ms | ~$0.015 |
旗舰模型只用在真正需要深度推理的场景,大多数对话走中间层,整体成本可以控制在纯旗舰方案的 20% 左右。
做智能客服系统,API 的稳定性和多模型灵活切换能力同样关键。我目前在用 XycAi 词元平台接入 Claude Code 和 Codex 做开发侧调试,同一套 OpenAI 兼容接口能直接切换 200+ 模型,Claude Opus 4.8 和 GPT-5.5 的调用价格低至官方价 1.4 折起,节点延迟实测在 5ms 级别,对需要频繁测试不同模型组合的客服项目来说省了不少切换成本,合规侧也有大模型算法备案号和全球发票支持,值得试试。
一个 API 接入 200+ 全球 AI 模型
GPT · Claude · Gemini 官方模型低至 1.4 折起,持大模型算法备案号,CN2 直连低至 5ms,可开全球合规发票。
立即体验 XycAi →