👥 客服机器人实战项目
通过完整的电商客服系统,综合运用 RAG、工具调用、对话管理、 流式输出、人工介入和长期记忆等技术,构建生产级 AI 客服机器人。
📚 项目概述
本项目将构建一个功能完整的电商智能客服系统, 整合前面所有章节学到的技术,实现一个可以直接部署到生产环境的客服机器人。
| 功能模块 | 技术方案 | 应用章节 |
|---|---|---|
| FAQ 智能问答 | 基于 RAG 的语义检索 | 08-rag.html |
| 订单查询和管理 | 自定义工具集成 | 05-tools.html |
| 多轮对话 | Checkpointer 状态管理 | 11-checkpointer.html |
| 用户偏好记忆 | Store 长期存储 | 14-long-term-memory.html |
| 实时响应 | 流式输出 | 12-streaming.html |
| 敏感操作审核 | Human-in-the-Loop | 13-human-in-loop.html |
业务场景
场景背景:某电商平台每天接收大量客户咨询,包括:
- 常见问题:配送时间、退换货政策、支付方式等(占 60%)
- 订单查询:订单状态、物流信息、退款进度等(占 30%)
- 售后服务:退货申请、换货处理、投诉建议等(占 10%)
目标:使用 AI 客服机器人自动处理 80% 以上的咨询, 复杂问题转人工处理,提升效率并保持服务质量。
🏗️ 系统架构设计
FAQ 知识库)] RAG --> Answer1[生成答案] Order -->|是| OrderTools[订单工具集] OrderTools --> OrderDB[(订单数据库)] OrderTools --> Answer2[返回订单信息] Service -->|是| ServiceTools[售后工具集] ServiceTools --> HITL{需要审核?} HITL -->|是| Human[人工审核] HITL -->|否| Execute[执行操作] Human --> Execute Execute --> Answer3[返回处理结果] Answer1 --> Stream[流式输出] Answer2 --> Stream Answer3 --> Stream Stream --> Memory[对话记忆] Memory --> Checkpointer[(Checkpointer
短期记忆)] Memory --> Store[(Store
长期记忆)] Stream --> Response[实时响应用户] style Agent fill:#3b82f6,color:#fff style RAG fill:#10b981,color:#fff style OrderTools fill:#f59e0b,color:#fff style ServiceTools fill:#ef4444,color:#fff style HITL fill:#8b5cf6,color:#fff style Stream fill:#06b6d4,color:#fff
架构说明
| 组件 | 职责 | 技术实现 |
|---|---|---|
| 智能客服 Agent | 理解用户意图,调用合适的工具 | create_agent() + GPT-4 |
| RAG 检索工具 | 从 FAQ 知识库检索相关信息 | Chroma + OpenAI Embeddings |
| 订单工具集 | 查询订单、物流、退款信息 | @tool 装饰器 + SQLite |
| 售后工具集 | 处理退货、换货、投诉 | @tool + HITL Middleware |
| 流式输出 | 实时显示响应过程 | stream_mode="messages" |
| 对话记忆 | 短期对话历史 + 长期用户偏好 | Checkpointer + Store |
📖 第一步:FAQ 智能问答(RAG)
首先实现基于 RAG 的 FAQ 问答功能,让机器人能够回答常见问题。
FAQ 数据准备
// projects/customer-service-bot/data/faq.json
[
{
"question": "配送时间是多久?",
"answer": "一般情况下,订单在提交后 1-2 个工作日内发货。国内配送通常需要 3-5 个工作日,偏远地区可能需要 5-7 个工作日。您可以在订单详情页查看实时物流信息。",
"category": "配送"
},
{
"question": "如何申请退货?",
"answer": "您可以在订单详情页点击'申请售后'按钮,选择退货原因并提交。我们会在 1-2 个工作日内审核您的申请。退货商品需保持原包装完好,未使用,收到退货后 3-5 个工作日退款。",
"category": "售后"
},
{
"question": "支持哪些支付方式?",
"answer": "我们支持多种支付方式:1)支付宝、微信支付 2)银行卡(借记卡/信用卡)3)货到付款(部分地区支持)。所有支付渠道均采用加密技术,保障您的资金安全。",
"category": "支付"
},
{
"question": "会员等级有什么权益?",
"answer": "我们的会员体系分为普通、银卡、金卡、钻石四个等级。等级越高,享受的折扣越多(最高可达 9.5 折),并可获得专属客服、优先配送、生日礼品等特权。会员等级根据年度消费金额自动升级。",
"category": "会员"
},
{
"question": "如何修改收货地址?",
"answer": "订单未发货前,您可以在订单详情页点击'修改地址'进行更改。如果订单已发货,请联系客服协助修改(可能产生额外运费)。建议在个人中心预先设置常用地址,下单时可快速选择。",
"category": "订单管理"
}
]
构建 FAQ 检索工具
"""
FAQ 检索工具实现
功能:基于 RAG 的语义搜索
"""
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
from langchain.tools import tool
import json
# 加载 FAQ 数据
def load_faq_data(file_path: str) -> list[Document]:
"""加载 FAQ 数据并转换为 Document 对象"""
with open(file_path, 'r', encoding='utf-8') as f:
faq_list = json.load(f)
documents = []
for item in faq_list:
# 将问题和答案组合成文档
content = f"问题:{item['question']}\n答案:{item['answer']}"
doc = Document(
page_content=content,
metadata={
"category": item["category"],
"question": item["question"]
}
)
documents.append(doc)
return documents
# 初始化向量存储
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
documents = load_faq_data("data/faq.json")
vectorstore = Chroma.from_documents(
documents=documents,
embedding=embeddings,
collection_name="faq_knowledge"
)
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
# 定义 FAQ 检索工具
@tool
def search_faq(query: str) -> str:
"""
搜索常见问题(FAQ)知识库。
适用于:
- 配送时间、退换货政策、支付方式等常见问题
- 会员权益、优惠活动等通用信息
参数:
query: 用户的问题描述
返回:
相关的 FAQ 答案
"""
# 检索相关文档
docs = retriever.invoke(query)
if not docs:
return "抱歉,我没有找到相关的常见问题解答。您可以详细描述您的问题,或者转接人工客服。"
# 组合检索结果
result = "根据常见问题库,我找到以下相关信息:\n\n"
for i, doc in enumerate(docs, 1):
result += f"{i}. {doc.metadata['question']}\n"
result += f" {doc.page_content.split('答案:')[1]}\n\n"
return result.strip()
测试 FAQ 工具
"""
测试 FAQ 检索工具
"""
# 直接调用工具
result = search_faq.invoke({"query": "我想知道多久能收到货"})
print(result)
# 预期输出:
# 根据常见问题库,我找到以下相关信息:
#
# 1. 配送时间是多久?
# 一般情况下,订单在提交后 1-2 个工作日内发货...
#
# 2. 如何修改收货地址?
# 订单未发货前,您可以在订单详情页点击'修改地址'...
📦 第二步:订单查询和管理工具
实现订单相关的工具集,包括查询订单状态、物流信息和退款进度。
模拟订单数据库
"""
订单数据模拟(生产环境应连接真实数据库)
"""
import sqlite3
from datetime import datetime, timedelta
# 初始化数据库
def init_order_database():
"""创建订单数据库并插入测试数据"""
conn = sqlite3.connect("data/orders.db")
cursor = conn.cursor()
# 创建订单表
cursor.execute("""
CREATE TABLE IF NOT EXISTS orders (
order_id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
product_name TEXT NOT NULL,
quantity INTEGER NOT NULL,
total_price REAL NOT NULL,
status TEXT NOT NULL,
shipping_address TEXT,
tracking_number TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
)
""")
# 插入测试数据
test_orders = [
("ORDER-2024001", "user_123", "iPhone 15 Pro", 1, 7999.0,
"已发货", "北京市朝阳区xxx小区", "SF1234567890",
(datetime.now() - timedelta(days=3)).isoformat(),
(datetime.now() - timedelta(days=1)).isoformat()),
("ORDER-2024002", "user_123", "AirPods Pro 2", 1, 1899.0,
"配送中", "北京市朝阳区xxx小区", "SF0987654321",
(datetime.now() - timedelta(days=2)).isoformat(),
datetime.now().isoformat()),
("ORDER-2024003", "user_123", "MacBook Pro 14", 1, 14999.0,
"处理中", "北京市朝阳区xxx小区", None,
(datetime.now() - timedelta(hours=6)).isoformat(),
(datetime.now() - timedelta(hours=6)).isoformat()),
]
cursor.executemany("""
INSERT OR REPLACE INTO orders VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""", test_orders)
conn.commit()
conn.close()
print("订单数据库初始化完成")
# 执行初始化
init_order_database()
订单查询工具集
"""
订单查询工具集
功能:查询订单状态、物流信息
"""
from langchain.tools import tool
from langchain.tools import ToolRuntime
from typing_extensions import TypedDict
import sqlite3
# 定义上下文 Schema
class CustomerContext(TypedDict):
user_id: str
session_id: str
@tool
def get_my_orders(runtime: ToolRuntime[CustomerContext]) -> str:
"""
查询当前用户的所有订单。
返回:
订单列表,包括订单号、商品名称、状态等信息
"""
user_id = runtime.context["user_id"]
conn = sqlite3.connect("data/orders.db")
cursor = conn.cursor()
cursor.execute("""
SELECT order_id, product_name, quantity, total_price, status, created_at
FROM orders
WHERE user_id = ?
ORDER BY created_at DESC
""", (user_id,))
orders = cursor.fetchall()
conn.close()
if not orders:
return "您目前没有任何订单记录。"
result = f"您共有 {len(orders)} 个订单:\n\n"
for order in orders:
order_id, product, qty, price, status, created = order
result += f"📦 订单号:{order_id}\n"
result += f" 商品:{product} x{qty}\n"
result += f" 金额:¥{price:.2f}\n"
result += f" 状态:{status}\n"
result += f" 下单时间:{created[:10]}\n\n"
return result.strip()
@tool
def get_order_details(order_id: str, runtime: ToolRuntime[CustomerContext]) -> str:
"""
查询特定订单的详细信息,包括物流信息。
参数:
order_id: 订单号(例如:ORDER-2024001)
返回:
订单详细信息和物流状态
"""
user_id = runtime.context["user_id"]
conn = sqlite3.connect("data/orders.db")
cursor = conn.cursor()
cursor.execute("""
SELECT * FROM orders
WHERE order_id = ? AND user_id = ?
""", (order_id, user_id))
order = cursor.fetchone()
conn.close()
if not order:
return f"未找到订单 {order_id},请检查订单号是否正确。"
_, _, product, qty, price, status, address, tracking, created, updated = order
result = f"📦 订单详情\n\n"
result += f"订单号:{order_id}\n"
result += f"商品:{product} x{qty}\n"
result += f"金额:¥{price:.2f}\n"
result += f"状态:{status}\n"
result += f"收货地址:{address}\n"
result += f"下单时间:{created[:16]}\n"
result += f"更新时间:{updated[:16]}\n"
if tracking:
result += f"\n🚚 物流信息\n"
result += f"快递单号:{tracking}\n"
result += f"物流状态:{status}\n"
# 模拟物流轨迹
if status == "已发货":
result += "最新轨迹:您的包裹已从仓库发出,正在运输途中\n"
elif status == "配送中":
result += "最新轨迹:您的包裹已到达北京分拨中心,即将派送\n"
return result
@tool
def cancel_order(order_id: str, reason: str, runtime: ToolRuntime[CustomerContext]) -> str:
"""
取消订单(仅限未发货的订单)。
参数:
order_id: 订单号
reason: 取消原因
返回:
取消结果
"""
user_id = runtime.context["user_id"]
conn = sqlite3.connect("data/orders.db")
cursor = conn.cursor()
# 检查订单状态
cursor.execute("""
SELECT status FROM orders
WHERE order_id = ? AND user_id = ?
""", (order_id, user_id))
result = cursor.fetchone()
if not result:
conn.close()
return f"未找到订单 {order_id}"
status = result[0]
if status != "处理中":
conn.close()
return f"订单 {order_id} 当前状态为 '{status}',无法取消。已发货的订单请申请退货。"
# 更新订单状态
cursor.execute("""
UPDATE orders
SET status = '已取消', updated_at = ?
WHERE order_id = ? AND user_id = ?
""", (datetime.now().isoformat(), order_id, user_id))
conn.commit()
conn.close()
return f"订单 {order_id} 已成功取消。取消原因:{reason}\n退款将在 3-5 个工作日内原路退回。"
💬 第三步:多轮对话和记忆管理
整合 Checkpointer(短期对话历史)和 Store(长期用户偏好)实现智能对话。
用户偏好管理工具
"""
用户偏好管理(长期记忆)
功能:记住用户的语言偏好、常用地址等信息
"""
from langchain.tools import tool, ToolRuntime
from langgraph.store.memory import InMemoryStore
# 初始化 Store
store = InMemoryStore()
@tool
def save_user_preference(
preference_type: str,
preference_value: str,
runtime: ToolRuntime[CustomerContext]
) -> str:
"""
保存用户偏好设置。
参数:
preference_type: 偏好类型(language, default_address, notification 等)
preference_value: 偏好值
返回:
保存结果
"""
user_id = runtime.context["user_id"]
store_obj = runtime.store
# 获取现有偏好
current_prefs = store_obj.get(("users", user_id), "preferences")
if current_prefs:
prefs = current_prefs.value
else:
prefs = {}
# 更新偏好
prefs[preference_type] = preference_value
# 保存到 Store
store_obj.put(("users", user_id), "preferences", prefs)
return f"已保存您的偏好:{preference_type} = {preference_value}"
@tool
def get_user_preference(
preference_type: str,
runtime: ToolRuntime[CustomerContext]
) -> str:
"""
获取用户偏好设置。
参数:
preference_type: 偏好类型
返回:
偏好值
"""
user_id = runtime.context["user_id"]
store_obj = runtime.store
prefs = store_obj.get(("users", user_id), "preferences")
if not prefs:
return f"未设置 {preference_type} 偏好"
value = prefs.value.get(preference_type)
if not value:
return f"未设置 {preference_type} 偏好"
return f"您的 {preference_type} 偏好为:{value}"
@tool
def record_interaction_history(
interaction_summary: str,
runtime: ToolRuntime[CustomerContext]
) -> str:
"""
记录重要的交互历史(用于后续分析和改进服务)。
参数:
interaction_summary: 交互摘要
返回:
记录结果
"""
user_id = runtime.context["user_id"]
store_obj = runtime.store
# 获取历史记录
history = store_obj.get(("users", user_id, "history"), "interactions")
if history:
interactions = history.value
else:
interactions = []
# 添加新记录
interactions.append({
"timestamp": datetime.now().isoformat(),
"summary": interaction_summary
})
# 保留最近 50 条
interactions = interactions[-50:]
# 保存
store_obj.put(("users", user_id, "history"), "interactions", interactions)
return "交互历史已记录"
🎯 第四步:完整系统整合
将所有组件整合成一个完整的客服机器人系统,包含流式输出和人工介入。
"""
完整的电商客服机器人系统
整合:RAG + 工具 + 对话管理 + 流式输出 + 人工介入 + 长期记忆
"""
from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.store.memory import InMemoryStore
from typing_extensions import TypedDict
import uuid
# ==================== 上下文定义 ====================
class CustomerContext(TypedDict):
user_id: str
session_id: str
# ==================== 工具集合 ====================
# 前面定义的所有工具
all_tools = [
# FAQ 工具
search_faq,
# 订单工具
get_my_orders,
get_order_details,
cancel_order,
# 用户偏好工具
save_user_preference,
get_user_preference,
record_interaction_history,
]
# ==================== 敏感操作审核配置 ====================
# 退款和取消订单需要人工审核
hitl_middleware = HumanInTheLoopMiddleware(
interrupt_on={
"cancel_order": True, # 取消订单需要审核
"search_faq": False,
"get_my_orders": False,
"get_order_details": False,
"save_user_preference": False,
"get_user_preference": False,
"record_interaction_history": False,
},
description=lambda req: f"用户请求:{req['name']}({req['args']})"
)
# ==================== 创建客服 Agent ====================
# 初始化 Checkpointer 和 Store
checkpointer = InMemorySaver()
store = InMemoryStore()
customer_service_agent = create_agent(
model="gpt-4o",
tools=all_tools,
middleware=[hitl_middleware],
checkpointer=checkpointer,
store=store,
context_schema=CustomerContext,
system_prompt="""你是一个专业的电商客服助手。
职责:
1. 解答客户关于配送、退换货、支付等常见问题(使用 search_faq 工具)
2. 查询和管理订单信息(使用订单相关工具)
3. 记住用户的偏好,提供个性化服务
4. 对于复杂或敏感的问题,及时转接人工客服
工作原则:
- 始终保持礼貌、专业、耐心
- 优先使用工具查询准确信息,不要猜测
- 对于订单取消、退款等敏感操作,需要人工审核
- 记录重要的交互历史,帮助改进服务
- 如果无法解决问题,主动建议转接人工
回答风格:
- 简洁明了,重点突出
- 使用列表和段落增强可读性
- 提供具体的操作步骤
"""
)
# ==================== 流式对话处理 ====================
def chat_with_customer_service(
user_message: str,
user_id: str = "user_123",
thread_id: str = None
):
"""
与客服机器人进行流式对话
参数:
user_message: 用户消息
user_id: 用户 ID
thread_id: 会话 ID(用于多轮对话)
"""
if thread_id is None:
thread_id = str(uuid.uuid4())
config = {
"configurable": {
"thread_id": thread_id,
},
"context": {
"user_id": user_id,
"session_id": thread_id
}
}
print(f"\n{'='*60}")
print(f"用户: {user_message}")
print('='*60)
# 流式调用
print("\n🤖 客服: ", end="", flush=True)
full_response = ""
interrupted = False
for stream_mode, chunk in customer_service_agent.stream(
{"messages": [{"role": "user", "content": user_message}]},
config=config,
stream_mode=["messages", "updates"]
):
if stream_mode == "messages":
token, metadata = chunk
if token:
print(token, end="", flush=True)
full_response += token
elif stream_mode == "updates":
for step, data in chunk.items():
if "__interrupt__" in data:
interrupted = True
print("\n\n⏸️ 需要人工审核,请稍候...")
print("\n" + "="*60)
return {
"thread_id": thread_id,
"response": full_response,
"interrupted": interrupted
}
# ==================== 测试场景 ====================
def run_test_scenarios():
"""运行多个测试场景"""
print("\n" + "🧪 开始测试电商客服机器人".center(60, "="))
# 场景 1:FAQ 问答
print("\n\n📌 场景 1:查询配送时间")
result1 = chat_with_customer_service(
"我想知道订单一般多久能送到?",
user_id="user_123"
)
thread_id = result1["thread_id"]
input("\n按回车继续下一个场景...")
# 场景 2:查询订单(多轮对话,使用相同 thread_id)
print("\n\n📌 场景 2:查询我的订单")
result2 = chat_with_customer_service(
"帮我查一下我的订单",
user_id="user_123",
thread_id=thread_id # 继续之前的对话
)
input("\n按回车继续下一个场景...")
# 场景 3:查询特定订单详情
print("\n\n📌 场景 3:查询订单详情")
result3 = chat_with_customer_service(
"帮我查一下 ORDER-2024002 的物流信息",
user_id="user_123",
thread_id=thread_id
)
input("\n按回车继续下一个场景...")
# 场景 4:取消订单(会触发人工审核)
print("\n\n📌 场景 4:取消订单(触发审核)")
result4 = chat_with_customer_service(
"我想取消订单 ORDER-2024003,因为买错了",
user_id="user_123",
thread_id=thread_id
)
if result4["interrupted"]:
print("\n💡 提示:此操作需要人工审核")
print(" 在生产环境中,客服人员会在后台审核此请求")
# 模拟审核通过
from langgraph.types import Command
print("\n✅ 模拟审核通过,继续执行...")
approval_result = customer_service_agent.invoke(
Command(resume={"decisions": [{"type": "approve"}]}),
config={
"configurable": {"thread_id": thread_id},
"context": {"user_id": "user_123", "session_id": thread_id}
}
)
print(f"\n最终结果: {approval_result['messages'][-1].content}")
input("\n按回车继续下一个场景...")
# 场景 5:保存用户偏好
print("\n\n📌 场景 5:保存常用地址")
result5 = chat_with_customer_service(
"帮我把常用地址设为:北京市朝阳区xxx小区",
user_id="user_123",
thread_id=thread_id
)
print("\n\n" + "✅ 测试完成!".center(60, "="))
print("\n系统演示了以下功能:")
print(" 1. ✅ FAQ 智能问答(RAG)")
print(" 2. ✅ 订单查询和管理")
print(" 3. ✅ 多轮对话(Checkpointer)")
print(" 4. ✅ 人工审核(HITL)")
print(" 5. ✅ 用户偏好(Store)")
print(" 6. ✅ 流式输出")
# ==================== 主程序 ====================
if __name__ == "__main__":
# 初始化数据
print("正在初始化系统...")
init_order_database()
print("系统初始化完成!\n")
# 运行测试场景
run_test_scenarios()
🔄 完整对话流程
🚀 部署和优化建议
生产环境配置
"""
生产环境配置示例
"""
from langgraph.checkpoint.postgres import PostgresSaver
from langgraph.store.postgres import PostgresStore
import os
# 数据库连接
DB_URI = os.getenv("DATABASE_URL", "postgresql://user:pass@localhost:5432/customer_service")
# 使用 PostgreSQL 持久化
with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
checkpointer.setup()
with PostgresStore.from_conn_string(DB_URI) as store:
store.setup()
# 创建生产级 Agent
production_agent = create_agent(
model="gpt-4o",
tools=all_tools,
middleware=[
hitl_middleware,
# 可添加更多中间件:日志、监控、限流等
],
checkpointer=checkpointer,
store=store,
context_schema=CustomerContext,
system_prompt="""...""" # 生产级提示词
)
性能优化清单
| 优化项 | 方案 | 预期提升 |
|---|---|---|
| FAQ 检索速度 | 使用 Redis 缓存热门问题 | 响应时间减少 70% |
| 数据库查询 | 添加索引、使用连接池 | 查询速度提升 3-5 倍 |
| 并发处理 | 使用异步 Agent(async/await) | 支持 10x 并发用户 |
| 成本控制 | 使用更小的模型(GPT-3.5)处理简单问题 | 成本降低 50% |
| 响应速度 | 启用流式输出 | 首字延迟减少 80% |
监控指标
- 响应时间:P50 < 2s, P95 < 5s
- FAQ 命中率:> 60%
- 问题解决率:> 80%(无需转人工)
- 用户满意度:> 4.0/5.0
- 每日成本:< $50(1000 次对话)
❓ 常见问题
Q1: 如何处理多个用户同时对话?
使用不同的 thread_id 区分不同用户的会话。
每个用户的对话历史独立存储在 Checkpointer 中。
# 用户 A 的会话
config_a = {
"configurable": {"thread_id": "user_a_session_001"},
"context": {"user_id": "user_a"}
}
# 用户 B 的会话
config_b = {
"configurable": {"thread_id": "user_b_session_002"},
"context": {"user_id": "user_b"}
}
# 两个用户可以并发对话,互不影响
agent.invoke({...}, config=config_a)
agent.invoke({...}, config=config_b)
Q2: FAQ 知识库如何更新?
方案 1:定期重建
- 每天凌晨自动从 CMS 或数据库拉取最新 FAQ
- 重新生成 embeddings 并更新向量数据库
- 适合变化不频繁的场景
方案 2:增量更新
# 添加新的 FAQ
new_faq = Document(
page_content="问题:xxx\n答案:xxx",
metadata={"category": "新增"}
)
vectorstore.add_documents([new_faq])
# 删除过时的 FAQ
vectorstore.delete(ids=["outdated_faq_id"])
Q3: 如何防止 Agent 给出错误答案?
多层防护策略:
- 明确工具边界:在工具的 docstring 中说明适用场景
- 验证工具输入:在工具内部验证参数合法性
- 提示词引导:在 system_prompt 中强调"优先使用工具,不要猜测"
- 输出验证:添加中间件检查答案的合理性
- 人工监督:定期审查对话记录,发现问题及时调整
Q4: 对话历史会无限增长吗?
不会。可以通过以下方式控制:
- 限制历史长度:只保留最近 N 轮对话
- 摘要历史:使用 LLM 定期总结对话,替换详细历史
- 定期清理:超过一定时间的会话自动归档
Q5: 如何评估客服机器人的效果?
建立多维度评估体系:
| 指标 | 计算方法 | 目标值 |
|---|---|---|
| 问题解决率 | 无需转人工的对话数 / 总对话数 | > 80% |
| 首次响应时间 | 用户发送消息到收到首个 Token 的时间 | < 1s |
| 平均对话轮次 | 解决问题平均需要的对话轮数 | < 5 轮 |
| 用户满意度 | 对话结束后的用户评分 | > 4.0/5.0 |
| 答案准确率 | 人工抽查答案的正确率 | > 95% |
✨ 最佳实践
1. 提示词设计
- 明确角色定位:"你是专业的电商客服"
- 列举职责范围:解答 FAQ、查询订单、处理售后
- 强调工具优先:不要猜测,优先使用工具
- 设定行为准则:礼貌、专业、及时转人工
- 提供示例:展示期望的回答风格
2. 工具设计
- 单一职责:每个工具只做一件事
- 清晰的 docstring:说明功能、参数、适用场景
- 错误处理:返回友好的错误消息
- 性能优化:添加缓存、批量查询
- 安全验证:验证用户权限和参数合法性
3. 对话管理
- 合理的 thread_id 策略:每个独立咨询一个 thread
- 主动结束会话:问题解决后询问是否还需帮助
- 上下文引用:"您刚才提到的订单"而非"订单"
- 记录关键信息:用户偏好、常见问题保存到 Store
4. 生产环境注意事项
- 使用 PostgreSQL:替代 InMemorySaver 和 InMemoryStore
- 启用监控:集成 LangSmith 追踪执行过程
- 设置限流:防止恶意调用
- 异常告警:工具失败、响应超时等及时通知
- 定期备份:对话历史和用户数据
🔮 扩展方向
功能扩展
| 功能 | 实现思路 | 难度 |
|---|---|---|
| 多语言支持 | 检测用户语言 + 翻译工具 | 🟡 中级 |
| 语音输入 | 集成 Whisper ASR | 🟡 中级 |
| 图片识别 | 使用 GPT-4V 处理产品图片 | 🔴 高级 |
| 情感分析 | 检测用户情绪,调整回答风格 | 🟡 中级 |
| 智能推荐 | 基于用户历史推荐商品 | 🔴 高级 |
| 主动问候 | 识别老客户,个性化问候 | 🟢 基础 |
技术升级
- LangGraph 编排:用状态图实现更复杂的对话流程
- 多 Agent 协作:订单 Agent + FAQ Agent + 售后 Agent 分工协作
- 强化学习:根据用户反馈持续优化回答
- 知识图谱:构建商品和问题的关系图谱