短剧行业随着内容供给量呈指数级增长,传统“编辑人工精选+热门榜单”的分发模式逐渐暴露短板:用户兴趣匹配精度低、长尾内容曝光不足、留存率与付费转化率增长乏力。在此背景下,AI驱动的个性化推荐系统,正是打破这一循环的关键“解药”。它不是简单的“猜你喜欢”,而是通过深度学习用户行为轨迹(从点击、快进到付费的每一个动作)、解析内容多模态特征(台词、画面、BGM的情绪走向)、捕捉场景上下文(通勤/睡前、WiFi/5G),构建“用户-内容-场景”的三维匹配模型。

源码及演示:v.dyedus.top

一、系统架构设计:从数据到推荐的闭环逻辑

个性化内容分发系统的核心是构建“数据采集-特征工程-算法模型-分发决策-效果反馈”的全链路闭环。针对短剧App的场景特性(内容时长1-10分钟、用户消费碎片化、交互行为丰富),系统采用分层架构设计,如图所示:
在这里插入图片描述

1.1 数据采集层:多源异构数据的实时接入

短剧App的数据来源可分为三类:

  • 用户行为数据:点击、播放(时长/进度)、点赞、评论、分享、付费、搜索等,通过客户端埋点(如友盟+、自研SDK)实时上报,采用Kafka消息队列实现高吞吐接入;
  • 内容元数据:短剧标题、简介、标签(如“甜宠”“悬疑”“逆袭”)、演员、导演、时长、更新状态等,通过CMS系统结构化存储;
  • 上下文数据:用户设备(iOS/Android)、网络环境(WiFi/5G)、时间段(通勤/睡前)、地理位置等,用于场景化推荐。

1.2 特征工程层:从原始数据到模型输入

特征工程是推荐系统的“燃料”,需将异构数据转化为模型可理解的向量特征。核心特征包括:

特征类型 具体维度 处理方式
用户特征 基础属性(年龄、性别)、行为序列(最近100条播放记录)、兴趣标签(从行为中提取的偏好) 离散特征One-Hot编码、序列特征Embedding化
内容特征 文本特征(标题/简介的BERT向量)、视觉特征(封面图的ResNet特征)、标签特征(多标签二值化) 文本/图像特征通过预训练模型提取,标签特征Embedding
上下文特征 时间段(0-23点)、设备类型、网络环境 离散特征直接编码,连续特征归一化

1.3 算法模型层:混合推荐策略的协同优化

单一推荐算法难以覆盖短剧场景的复杂性,系统采用“协同过滤+深度学习+多目标优化”的混合架构:

  • 召回阶段:用Item2Item(I2I)协同过滤快速筛选用户可能感兴趣的候选集(从10万级内容中筛选1000条);
  • 排序阶段:用DeepFM模型融合多维度特征,预测用户对候选内容的点击率(CTR)、完播率(CVR)、付费意愿(PayScore);
  • 重排序阶段:结合业务规则(如新剧加权、去重、多样性打散)生成最终推荐列表。

1.4 分发与反馈层:实时决策与动态迭代

推荐结果通过API服务实时返回给客户端(响应时间<200ms),同时用户对新推荐内容的交互行为(如点击、退出)会实时回流至数据层,触发模型增量更新(每日全量更新+每小时增量更新),形成“推荐-反馈-优化”的闭环。

二、核心算法实现:从召回、排序到重排序

2.1 召回阶段:Item2Item协同过滤的工程化落地

短剧内容的“短平快”特性决定了用户行为具有强时序性(如连续观看同一类型短剧),因此采用基于“用户-内容”交互矩阵的I2I协同过滤,核心思想是“喜欢内容A的用户也喜欢内容B”。

算法逻辑:

  1. 构建用户-内容交互矩阵 R m × n R_{m \times n} Rm×n m m m为用户数, n n n为内容数),元素 r u i r_{ui} rui 表示用户 u u u 对内容 i i i 的交互强度(如播放完成度×1.0 + 点赞×2.0 + 付费×5.0);
  2. 计算内容相似度: s i m ( i , j ) = ∑ u ∈ U ( i , j ) r u i ⋅ r u j ∑ u r u i 2 ⋅ ∑ u r u j 2 sim(i,j) = \frac{\sum_{u \in U(i,j)} r_{ui} \cdot r_{uj}}{\sqrt{\sum_{u} r_{ui}^2} \cdot \sqrt{\sum_{u} r_{uj}^2}} sim(i,j)=urui2 uruj2 uU(i,j)ruiruj(余弦相似度, U ( i , j ) U(i,j) U(i,j)为同时交互过内容 i i i j j j 的用户集合);
  3. 对每个用户,取历史交互内容Top-K相似的候选集,去重后作为召回结果。

工程实现(基于Spark的分布式计算):

# Spark I2I相似度计算核心代码  
from pyspark.sql import SparkSession  
from pyspark.ml.feature import StringIndexer  
from pyspark.sql.functions import col, explode, struct  

spark = SparkSession.builder.appName("ShortDramaI2I").getOrCreate()  

# 加载用户-内容交互数据(user_id, item_id, interaction_score)  
interaction_df = spark.read.parquet("hdfs:///short_drama/interaction/")  

# 将item_id转换为索引(便于矩阵计算)  
indexer = StringIndexer(inputCol="item_id", outputCol="item_idx")  
indexed_df = indexer.fit(interaction_df).transform(interaction_df)  

# 计算内容共现矩阵  
cooccurrence = indexed_df.groupBy("user_id") \  
    .agg(explode(struct("item_idx")).alias("item_i")) \  
    .join(indexed_df, "user_id") \  
    .filter(col("item_i") < col("item_idx")) \  
    .groupBy("item_i", "item_idx") \  
    .sum("interaction_score") \  
    .withColumnRenamed("sum(interaction_score)", "cooc_score")  

# 计算余弦相似度(简化版,实际需归一化)  
item_norm = cooccurrence.groupBy("item_i").sum("cooc_score").withColumnRenamed("sum(cooc_score)", "norm_i")  
similarity = cooccurrence.join(item_norm, "item_i") \  
    .join(item_norm.withColumnRenamed("item_i", "item_idx").withColumnRenamed("norm_i", "norm_j"), "item_idx") \  
    .withColumn("similarity", col("cooc_score") / (col("norm_i") * col("norm_j")).sqrt()) \  
    .select("item_i", "item_idx", "similarity")  

# 保存相似度矩阵至HBase,供在线服务查询  
similarity.write.format("org.apache.hadoop.hbase.spark") \  
    .option("hbase.table", "short_drama_i2i") \  
    .option("hbase.columns.mapping", "item_i STRING :key, item_idx STRING cf:item, similarity DOUBLE cf:score") \  
    .save()  

2.2 排序阶段:DeepFM模型的端到端训练

排序阶段需精准预测用户对候选内容的“兴趣度”,传统LR模型无法捕捉特征交叉,而DeepFM通过“FM组件+深度神经网络”融合低阶与高阶特征交互,适合短剧场景的复杂特征关系。

模型结构:

  • FM组件:学习一阶特征(如“用户年龄=25”“内容标签=甜宠”)和低阶二阶交叉(如“25岁女性+甜宠标签”);
  • DNN组件:通过多层全连接网络学习高阶特征交叉(如“通勤时段+悬疑标签+短时长内容”的组合偏好);
  • 输出层:融合FM与DNN的结果,经Sigmoid激活输出预测概率(如CTR=0.85表示用户点击概率85%)。

模型训练代码(基于TensorFlow 2.x):

import tensorflow as tf  
from tensorflow.keras.layers import Input, Embedding, Flatten, Dense, Concatenate, Dropout  
from tensorflow.keras.models import Model  

# 定义特征输入(示例:用户ID、内容ID、标签、时间段)  
user_id_input = Input(shape=(1,), name="user_id")  
item_id_input = Input(shape=(1,), name="item_id")  
tag_input = Input(shape=(10,), name="tag_ids")  # 多标签,最多10个  
time_input = Input(shape=(1,), name="time_hour")  # 0-23点  

# 嵌入层(将离散ID转换为低维向量)  
user_embedding = Embedding(input_dim=100000, output_dim=64, name="user_embed")(user_id_input)  
item_embedding = Embedding(input_dim=500000, output_dim=64, name="item_embed")(item_id_input)  
tag_embedding = Embedding(input_dim=1000, output_dim=32, name="tag_embed")(tag_input)  

# FM组件:一阶特征+二阶交叉  
fm_first_order = Concatenate()([Flatten()(user_embedding), Flatten()(item_embedding), Flatten()(tag_embedding)])  
fm_second_order = tf.reduce_sum(  
    tf.multiply(Flatten()(user_embedding), Flatten()(item_embedding)), axis=1, keepdims=True  
)  # 简化版二阶交叉,实际需对所有特征对计算  

# DNN组件:多层特征融合  
dnn_input = Concatenate()([fm_first_order, time_input])  
dnn_layer1 = Dense(256, activation="relu")(dnn_input)  
dnn_layer1 = Dropout(0.3)(dnn_layer1)  
dnn_layer2 = Dense(128, activation="relu")(dnn_layer1)  
dnn_layer2 = Dropout(0.2)(dnn_layer2)  

# 输出层(融合FM与DNN)  
output = Dense(1, activation="sigmoid", name="prediction")(Concatenate()([fm_second_order, dnn_layer2]))  

# 编译模型  
model = Model(inputs=[user_id_input, item_id_input, tag_input, time_input], outputs=output)  
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),  
              loss="binary_crossentropy",  
              metrics=["AUC"])  

# 训练(假设train_data为预处理后的特征数据)  
model.fit(train_data, epochs=10, batch_size=256, validation_split=0.2)  

2.3 重排序阶段:业务规则与多样性的平衡

排序模型输出的候选集需经过重排序,避免“信息茧房”(如连续推荐同一类型内容)并满足业务目标(如新剧冷启动、付费内容加权)。核心规则包括:

  • 去重:过滤用户7天内已观看内容;
  • 加权:新上线短剧(24小时内)权重×1.5,付费内容权重×1.2;
  • 多样性:同类型内容占比不超过30%,通过MMR(最大边际相关性)算法打散;
  • 长度适配:通勤时段(7-9点、18-20点)优先推荐<3分钟短剧,睡前时段(22-24点)推荐5-10分钟短剧。

三、源码实战:推荐系统的工程化落地

3.1 数据管道:Kafka+Flink实时处理

用户行为数据通过Kafka接入,Flink实时处理并写入特征库(Redis+HBase),核心代码如下:

// Flink实时处理用户播放行为,更新用户兴趣特征  
public class UserBehaviorProcessFunction extends KeyedProcessFunction<String, UserBehavior, UserFeature> {  
    private transient ValueState<UserFeature> userFeatureState;  

    @Override  
    public void open(Configuration parameters) {  
        // 初始化状态:存储用户最近100条行为特征  
        ValueStateDescriptor<UserFeature> descriptor = new ValueStateDescriptor<>(  
            "userFeatureState", UserFeature.class);  
        userFeatureState = getRuntimeContext().getState(descriptor);  
    }  

    @Override  
    public void processElement(UserBehavior behavior, Context ctx, Collector<UserFeature> out) throws Exception {  
        UserFeature feature = userFeatureState.value();  
        if (feature == null) {  
            feature = new UserFeature(behavior.getUserId());  
        }  
        // 更新兴趣标签(如播放悬疑类短剧,悬疑标签权重+1)  
        feature.updateTagWeight(behavior.getTagId(), behavior.getPlayDuration() / behavior.getTotalDuration());  
        // 保留最近100条行为序列  
        feature.addBehaviorSequence(behavior.getItemId());  
        if (feature.getBehaviorSequence().size() > 100) {  
            feature.getBehaviorSequence().remove(0);  
        }  
        userFeatureState.update(feature);  
        out.collect(feature);  // 写入Redis,供推荐服务实时查询  
    }  
}  

3.2 在线服务:Spring Boot+Redis高性能接口

推荐服务需支撑高并发(单接口QPS>10万),采用Spring Boot框架,核心接口代码如下:

@RestController  
@RequestMapping("/recommend")  
public class RecommendController {  
    @Autowired  
    private RedisTemplate<String, Object> redisTemplate;  
    @Autowired  
    private DeepFMModel deepFMModel;  // 加载训练好的排序模型  

    @GetMapping("/{userId}")  
    public List<RecommendItem> getRecommend(@PathVariable String userId,  
                                          @RequestParam int size,  
                                          @RequestParam String scene) {  
        // 1. 从Redis获取用户特征  
        UserFeature userFeature = (UserFeature) redisTemplate.opsForValue().get("user:feature:" + userId);  
        // 2. 召回阶段:从HBase查询I2I候选集  
        List<String> recallItems = recallService.recall(userId, userFeature);  
        // 3. 排序阶段:用DeepFM模型预测得分  
        List<ScoredItem> scoredItems = deepFMModel.predict(userFeature, recallItems);  
        // 4. 重排序:应用业务规则  
        List<RecommendItem> finalItems = rerankService.rerank(scoredItems, scene, size);  
        return finalItems;  
    }  
}  

四、效果评估与优化实践

4.1 核心指标提升

某短剧App接入该系统后,核心指标显著优化:

  • 点击率(CTR):从8.2%提升至15.7%(+91%);
  • 人均播放时长:从12分钟/日提升至21分钟/日(+75%);
  • 付费转化率:从2.3%提升至4.1%(+78%);
  • 长尾内容曝光占比:从12%提升至35%(+192%),解决了“头部内容垄断流量”问题。

4.2 典型问题与优化方案

问题场景 优化方案 效果提升
新用户冷启动(无行为) 基于设备型号、地理位置、注册时选择的兴趣标签推荐 新用户CTR从5.1%→9.3%
模型过拟合(训练集AUC 0.92,测试集0.78) 加入Dropout(0.3)、L2正则化(λ=0.01)、特征选择 测试集AUC提升至0.85
推荐列表同质化 引入MMR多样性算法,限制同标签内容占比≤30% 用户滑动深度从3.2页→5.7页

总结

AI赋能的个性化推荐系统已成为短剧App的核心竞争力,其本质是“数据+算法+工程”的深度融合。本文提出的混合推荐架构,通过I2I召回、DeepFM排序、规则重排序的协同,实现了从“人找内容”到“内容找人”的跨越。未来,随着多模态技术(如视频内容理解、语音情感分析)与强化学习(实时动态调整推荐策略)的发展,短剧推荐系统将向“更懂用户、更具沉浸感”的方向演进,为行业带来新的增长空间。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐