电商场景 Agent 设计:从商品推荐到售后客服的完整链路
·
电商场景 Agent 设计:从商品推荐到售后客服的完整链路
一、用户说"这件衣服有我尺码吗",Agent 该如何理解?
电商场景的 AI Agent 和通用 Agent 有本质区别:电商的每一次对话都可能涉及交易,信息的准确性直接影响下单决策和售后体验。
一个典型的用户问题:"这件黑色卫衣有 XXL 吗?红色的同款还有吗?" Agent 需要理解:用户问的是两个维度的库存(黑色/XXL、红色/通用),并且这两个查询和同一件商品关联。
更复杂的是售后场景:"我上周买的那个蓝牙耳机有杂音,能换吗?" Agent 需要先查订单、再查售后政策、最后生成换货工单——这是多轮多工具的联动。
二、电商 Agent 的全链路架构
三、Go 实现电商 Agent 核心逻辑
Agent 入口:意图路由
package ecommerce
import (
"context"
"encoding/json"
"fmt"
"strings"
)
// EcommerceIntent 电商意图类型
type EcommerceIntent string
const (
IntentProductSearch EcommerceIntent = "product_search" // 商品搜索
IntentProductCompare EcommerceIntent = "product_compare" // 商品对比
IntentOrderQuery EcommerceIntent = "order_query" // 订单查询
IntentRefund EcommerceIntent = "refund" // 退款/退货
IntentLogisticsTrack EcommerceIntent = "logistics_track" // 物流追踪
IntentCouponQuery EcommerceIntent = "coupon_query" // 优惠券查询
IntentEscalate EcommerceIntent = "escalate" // 升级人工
)
// EcommerceContext 电商对话上下文
type EcommerceContext struct {
SessionID string
UserID string
UserProfile *UserProfile // 用户画像
OrderHistory []OrderSummary // 最近订单
CurrentProduct *Product // 当前讨论的商品
}
type UserProfile struct {
UserID string
Tags []string // 用户标签: 高消费, 母婴, 数码爱好者
History []string // 浏览历史: 商品 ID 列表
Preferences map[string]string // 偏好: size→XXL, color→黑色
}
type Product struct {
ID string
Name string
Price float64
Stock map[string]int // SKU → 库存: "黑色_XXL" → 10
Category string
Rating float64
}
// EcommerceAgent 电商 Agent
type EcommerceAgent struct {
llm LLMClient
tools *EcommerceToolRegistry // 电商专用工具集
router *IntentRouter
}
// HandleUserQuery 处理用户查询的主入口
func (ea *EcommerceAgent) HandleUserQuery(
ctx context.Context,
sessionCtx *EcommerceContext,
userQuery string,
) (string, error) {
// 1. 意图识别
intent, confidence := ea.router.Classify(userQuery)
fmt.Printf("[AGENT] 意图: %s (置信度: %.2f)\n", intent, confidence)
// 2. 根据意图选择处理策略
switch intent {
case IntentProductSearch:
return ea.handleProductSearch(ctx, sessionCtx, userQuery)
case IntentProductCompare:
return ea.handleProductCompare(ctx, sessionCtx, userQuery)
case IntentOrderQuery:
return ea.handleOrderQuery(ctx, sessionCtx, userQuery)
case IntentRefund:
// 退款操作需要用户已登录
if sessionCtx.UserID == "" {
return "请先登录后再申请退款", nil
}
return ea.handleRefund(ctx, sessionCtx, userQuery)
case IntentLogisticsTrack:
return ea.handleLogisticsTrack(ctx, sessionCtx, userQuery)
case IntentEscalate:
// 无缝转接人工
return ea.transferToHuman(ctx, sessionCtx, userQuery)
default:
// 降级:让 LLM 自由回答
return ea.llm.Generate(ctx, userQuery)
}
}
商品搜索 Agent
// handleProductSearch 商品搜索——多条件筛选 + 库存校验
func (ea *EcommerceAgent) handleProductSearch(
ctx context.Context,
session *EcommerceContext,
query string,
) (string, error) {
// 第一步:提取搜索条件
searchParams, err := ea.tools.ExtractSearchParams(ctx, query)
if err != nil {
return "抱歉,我没能理解您的搜索条件,能再描述一下吗?", nil
}
// 第二步:调用搜索工具
products, err := ea.tools.SearchProducts(ctx, searchParams)
if err != nil {
return "搜索服务暂时不可用,请稍后再试", err
}
if len(products) == 0 {
return fmt.Sprintf("没有找到符合\"%s\"的商品,试试换个关键词?", query), nil
}
// 第三步:结合用户画像做个性化排序
ranked := ea.rankByUserProfile(products, session.UserProfile)
// 第四步:生成推荐文案——突出库存和用户可能关心的属性
return ea.formatProductRecommendation(ranked[:min(5, len(ranked))], session), nil
}
// rankByUserProfile 基于用户画像的个性化排序
func (ea *EcommerceAgent) rankByUserProfile(products []Product, profile *UserProfile) []Product {
if profile == nil {
return products // 无画像时保持原始排序
}
// 评分加权:基础分 + 偏好匹配分
type scored struct {
product Product
score float64
}
var scoredList []scored
for _, p := range products {
score := p.Rating * 0.3 // 基础分:好评率
// 偏好匹配
for _, tag := range profile.Tags {
if strings.Contains(p.Category, tag) {
score += 2.0 // 品类偏好加分
}
}
// 有库存的优先
totalStock := 0
for _, s := range p.Stock {
totalStock += s
}
if totalStock > 0 {
score += 1.0
}
scoredList = append(scoredList, scored{p, score})
}
// 按分数降序排列
sortByScore(scoredList)
result := make([]Product, len(scoredList))
for i, s := range scoredList {
result[i] = s.product
}
return result
}
// formatProductRecommendation 生成推荐文案
func (ea *EcommerceAgent) formatProductRecommendation(products []Product, session *EcommerceContext) string {
var sb strings.Builder
sb.WriteString("为您找到以下商品:\n\n")
for i, p := range products {
sb.WriteString(fmt.Sprintf("%d. **%s**\n", i+1, p.Name))
sb.WriteString(fmt.Sprintf(" 价格: ¥%.2f | 评分: %.1f\n", p.Price, p.Rating))
// 展示库存状态
totalStock := 0
for sku, stock := range p.Stock {
totalStock += stock
if stock <= 3 && stock > 0 {
sb.WriteString(fmt.Sprintf(" ⚠️ %s 仅剩 %d 件\n", sku, stock))
}
}
if totalStock == 0 {
sb.WriteString(" [暂时缺货]\n")
}
sb.WriteString("\n")
}
return sb.String()
}
售后处理 Agent
// handleRefund 退款处理——查订单 + 校验政策 + 创建工单
func (ea *EcommerceAgent) handleRefund(
ctx context.Context,
session *EcommerceContext,
query string,
) (string, error) {
// 第一步:从查询中提取订单信息
orderInfo, err := ea.tools.ExtractOrderInfo(ctx, query)
if err != nil {
return "请提供订单号或告诉我您要退哪件商品", nil
}
// 第二步:查询订单详情
order, err := ea.tools.QueryOrder(ctx, session.UserID, orderInfo.OrderID)
if err != nil {
return fmt.Sprintf("未找到订单 %s,请核对订单号", orderInfo.OrderID), err
}
// 第三步:检查售后资格
eligibility := ea.checkRefundEligibility(order)
if !eligibility.Eligible {
return fmt.Sprintf(
"抱歉,%s(原因: %s)",
eligibility.Message, eligibility.Reason,
), nil
}
// 第四步:执行退款
refundResult, err := ea.tools.ProcessRefund(ctx, session.UserID, order.OrderID, orderInfo.Reason)
if err != nil {
// 退款失败,升级人工
ea.transferToHuman(ctx, session,
fmt.Sprintf("退款失败: 订单 %s, 原因: %v", order.OrderID, err))
return "退款处理遇到问题,已为您转接人工客服,请稍候。", nil
}
return fmt.Sprintf(
"已为您处理退款。订单 %s,金额 ¥%.2f,预计 3-5 个工作日内退回原支付方式。",
order.OrderID, refundResult.Amount,
), nil
}
type RefundEligibility struct {
Eligible bool
Message string
Reason string
}
func (ea *EcommerceAgent) checkRefundEligibility(order *Order) RefundEligibility {
// 规则一:订单已完成且未超过 7 天
daysSinceComplete := time.Since(order.CompletedAt).Hours() / 24
if daysSinceComplete > 7 {
return RefundEligibility{
Eligible: false,
Message: "该订单已超过 7 天无理由退货期",
Reason: "超期",
}
}
// 规则二:非定制/虚拟商品
nonRefundCategories := []string{"定制商品", "虚拟商品", "生鲜食品"}
for _, cat := range nonRefundCategories {
if strings.Contains(order.Category, cat) {
return RefundEligibility{
Eligible: false,
Message: fmt.Sprintf("%s 不支持无理由退货", cat),
Reason: "品类限制",
}
}
}
return RefundEligibility{
Eligible: true,
Message: "符合退货条件,正在为您处理",
}
}
四、边界分析与 Trade-offs
意图识别准确率:
- 电商意图分类比通用场景更难——用户表达方式多样
- "这个怎么样"可能是问评价、问库存、问价格——需要结合上下文消歧
- 建议:意图分类的置信度 < 0.7 时,追问澄清而非猜测
库存实时性:
- 商品搜索必须展示实时库存,不能返回已售罄商品
- 但库存查询本身有成本(数据库+缓存),需要合理设置缓存 TTL
- 高并发场景使用库存预扣减 + 定期同步
金额相关的安全处理:
- 退款金额必须由服务端计算,不能信任 LLM 的参数
- 订单查询必须过滤当前用户的订单(不能跨用户查询)
- 所有写操作(退款、下单)需要有完整的审计日志
人工客服的无缝衔接:
- Agent 转人工时需要传递对话摘要(用户问题、已执行的步骤)
- 避免用户向人工客服重复描述问题
- 摘要应包含:订单号、问题类型、自动处理结果
五、总结
电商 Agent 设计的关键是将"不确定的 LLM 生成"和"确定的电商业务规则"分离开:
- 售前:LLM 负责理解 + 生成文案,搜索结果和库存由确定性 API 提供
- 购买:LLM 不参与金额计算和支付流程,只做引导
- 售后:LLM 负责意图分类和参数提取,退款决策由规则引擎决定
电商场景对准确性要求极高。一个错误的退款金额或库存信息,比"回复不够好"的伤害大得多。
更多推荐


所有评论(0)