共计 2762 个字符,预计需要花费 7 分钟才能阅读完成。
背景痛点:为什么技能推荐如此具有挑战性
在构建 Agent Skill 推荐系统时,我们面临几个关键的技术难点:

- 冷启动问题 :新上线的技能缺乏用户交互数据,难以准确匹配
- 特征稀疏性 :用户与技能的交互矩阵极度稀疏(99.5% 以上为零值)
- 实时性要求 :P99 延迟必须控制在 200ms 以内,包括特征获取 + 模型推理
- 动态变化 :技能库每天更新 15-20%,需要快速适应分布变化
架构演进:从规则匹配到深度学习
1. 基于规则的匹配(v1)
flowchart LR
A[用户请求] --> B[关键词匹配]
B --> C[业务规则过滤]
C --> D[随机推荐]
- 优点:实现简单,零冷启动时间
- 缺点:召回率 <30%,无法处理语义相似性
2. 协同过滤(v2)
flowchart LR
A[用户历史] --> B[矩阵分解]
B --> C[潜在因子]
C --> D[TopK 推荐]
- 优点:能发现隐含关联
- 缺点:无法处理新技能,更新周期长(天级别)
3. 双塔模型(v3)
flowchart TB
subgraph User Tower
U[用户特征] --> UE[Embedding 层]
UE --> UM[多层 MLP]
end
subgraph Skill Tower
S[技能特征] --> SE[Embedding 层]
SE --> SM[多层 MLP]
end
UM --> DOT[点积相似度]
SM --> DOT
- 优势:支持在线学习,天然解决冷启动
- 创新点:引入行为序列 Transformer 编码
核心实现:双塔模型的工程细节
特征工程设计
用户侧特征
- 基础属性:地域、设备类型
- 行为序列:最近 50 次交互事件的 Attention 编码
- 统计特征:周活跃天数、偏好类别分布
技能侧特征
# 技能元特征处理示例
class SkillFeatureProcessor:
def __init__(self):
self.encoder = {}
def fit(self, skills):
# 构建分类特征编码
categories = set(s['category'] for s in skills)
self.encoder = {c:i for i,c in enumerate(categories)}
def transform(self, skill):
return {'category': self.encoder[skill['category']],
'is_new': int(skill['create_time'] > time.time()-86400*3),
'avg_rating': skill.get('rating', 3.0)
}
模型训练代码
import tensorflow as tf
from tensorflow.keras.layers import Input, Embedding, Dense
# 用户塔架构
def build_user_tower():
inputs = {'device_type': Input(shape=(1,), dtype='int32'),
'behavior_seq': Input(shape=(50,), dtype='int32')
}
# 设备类型 Embedding
device_emb = Embedding(10, 8)(inputs['device_type'])
# 行为序列处理
seq_emb = Embedding(1000, 16)(inputs['behavior_seq'])
seq_encoded = tf.keras.layers.LSTM(32)(seq_emb)
# 合并特征
concat = tf.concat([tf.squeeze(device_emb, axis=1), seq_encoded], axis=1)
# 多层感知机
output = Dense(128, activation='relu')(concat)
output = Dense(64, activation='relu')(output)
return tf.keras.Model(
inputs=inputs,
outputs=output,
name='user_tower'
)
# 负采样损失函数
def sampled_softmax_loss(user_embed, skill_embed):
batch_size = tf.shape(user_embed)[0]
# 计算正样本相似度
pos_sim = tf.reduce_sum(user_embed * skill_embed, axis=1)
# 随机采样负样本
neg_skill = tf.random.shuffle(skill_embed)
neg_sim = tf.reduce_sum(user_embed * neg_skill, axis=1)
# 构造损失
loss = -tf.math.log_sigmoid(pos_sim - neg_sim)
return tf.reduce_mean(loss)
生产环境实战经验
模型热更新方案
graph LR
A[新模型训练] --> B[影子模式部署]
B --> C[AB 测试分流]
C --> D[指标对比]
D -->| 达标 | E[全量切换]
D -->| 不达标 | F[回滚]
关键指标对比维度:
- 业务指标:点击率、使用时长
- 系统指标:P99 延迟、CPU 利用率
- 安全指标:极端值比例
性能优化三把斧
- 模型量化 :FP32 -> INT8(体积减小 75%)
- 缓存策略 :
- 高频用户 embedding 缓存(TTL=5min)
- 技能向量预加载
- 异步计算 :
- 非实时特征通过消息队列更新
- 离线特征预计算
常见陷阱与解决方案
特征穿越预防
# 时间戳验证装饰器
def prevent_feature_leakage(func):
def wrapper(features, timestamp):
assert features['event_time'] <= timestamp, \
"特征时间戳不能晚于请求时间"
return func(features, timestamp)
return wrapper
稀疏特征处理
- 频次过滤:剔除出现 <5 次的类别值
- 哈希分桶:对长尾特征进行哈希分桶
- 默认值:UNK 类别统一编码为 0
在线学习保障
- 数据快照:每小时保存 checkpoint
- 异常检测:监控 loss 突增(3σ 原则)
- 回滚机制:
- 模型版本回退
- 特征数据重放
扩展思考:多模态技能推荐
当技能包含图文、音视频等多模态内容时:
- 在 Skill Tower 增加:
- CNN 处理图像缩略图
- Transformer 处理技能描述文本
- 跨模态对比学习:
- 让相似技能的 embedding 靠近
- 对比损失函数:InfoNCE
- 在线服务优化:
- 模态特征预提取
- 分级缓存策略
写在最后
实际落地过程中,我们发现业务规则与机器学习模型的混合使用效果最佳:
- 新技能期(<3 天):走规则通道
- 成长期(3- 7 天):采用内容相似度推荐
- 成熟期(>7 天):进入主推荐流
这种分层策略使得新技能曝光率提升 42%,同时保持整体点击率不变。推荐系统永远没有银弹,持续迭代才是王道。
正文完
