简介:这份960页的深度技术文档面向电商产品经理、推荐算法工程师及数据分析师,系统讲解如何借助DeepSeek大模型能力,围绕行为序列分析重构用户旅程地图,并在关键触点上实施个性化增强策略。内容从数据采集规范、预处理去噪、特征工程与意图识别,一路推进到旅程阶段划分、跨设备身份拼接、匿名轨迹还原,以及页面流转可视化下的体验瓶颈定位,路径完整且贴近实战。资源仅含1个PDF文件,包体约21.64MB,支持目录章节跳转与书签大纲快速定位,排版清晰、图表完整,阅读体验顺畅,已有101人学习下载。文档内60个大章节逻辑层层递进,既讲清算法原理与模型结构选型,也覆盖工程化部署与调优细节;对希望建立行为分析驱动体验优化完整认知体系、或正在搭建用户旅程监测与个性化推荐的中高级从业者而言,具备较高参考价值。
1. DeepSeek 电商用户体验优化方案:把行为序列变成可执行的旅程地图,到底解决什么问题
多数运营后台的漏斗报表越堆越厚,可一旦被问到“用户为什么在这里流失”“哪一步劝退了高价值用户”,报表就答不上来:传统漏斗把用户拆成了一串零散的 URL 访问记录,丢了行为顺序,也丢了意图。这份 DeepSeek 电商用户体验优化方案讲的是另一条路:把所有触点行为按时间串成行为序列,用大模型把序列还原成用户旅程阶段,再在关键触点上做个性化增强——同样一次进店,有人看到的是满减券,有人看到的是无门槛包邮,动作背后的预期完全不同。方案适合电商增长、用户运营、数据产品团队落地,也适合已经有自研中台、想用行为序列分析与用户旅程映射重塑体验调优方法的技术团队借鉴。
2. 行为序列数据层:先让点击流变成一段一段可计算的行为链
用户旅程映射的前提是“读得懂用户先做了什么、后做了什么”。这依赖一套能回放完整行为过程的数据层。很多团队直接把前端上报的原始事件丢给大模型分析,结果模型看到的事件名一半是历史遗留的驼峰命名,一半是前端随手写的自定义名,根本拼不出完整流程。所以第一步不是调模型,而是把埋点、会话、序列三件事做扎实。
2.1 电商埋点的事件命名与属性设计:从 PV/UV 升级到五个字段齐全的结构化事件
电商场景下,行为事件至少要携带五个要素:用户标识、会话标识、事件名、事件时间、业务属性。事件名建议统一成“动作 + 对象”的 snake_case,例如cart_add、order_create、payment_attempt,避免出现同一个加购动作在首页叫addCart、在详情页叫buyNow这类双份埋点。
以下是一份可供参考的完整事件样例:
{ "user_id": "u_20240001", "anonymous_id": "a_7f3d9c2b", "session_id": "s_20241012_092351_001", "event": "cart_add", "ts": "2024-10-12 09:23:51.320", "page": "product_detail", "props": { "sku_id": "SKU8842", "sku_name": "双面羊毛大衣 驼色 M", "price": 899.00, "from": "search_result", "source": "algo_rec", "position": 3 } }逐段解释:user_id是登录后的稳定身份,anonymous_id是未登录时的设备 ID,两列并存才能处理登录前后行为归属问题;session_id由前端生成但后文会讲离线端反而要重算;ts精确到毫秒,排序和算时长都靠它;props里除了商品业务属性,最好带上from(用户从哪个页面来)和source(推荐位/搜索/广告),这两个字段是事后判断“行为链从哪一节断掉”的关键。
提示:事件命名一旦上线就别频繁改字面量。宁可新增事件,也不要复用旧事件名换含义,否则历史数据的序列口径会直接错位,这是常见的数据事故起点。
2.2 会话切割与用户识别:session_id 的生成与合并策略
原始事件流里一个用户可能连续逛半小时,也可能凌晨加购后白天再回来,怎么把事件分成“一次有意图的访问”?常见做法是静默超时切割:同一用户相邻两条事件间隔超过阈值就另起新会话。电商场景我一般用 30 分钟静默阈值,但这个值不是拍脑袋——用户可能在看长图文详情、对比价格后长时间不操作,阈值设太短会把同一次决策过程切成多段,设太长又会把多次独立访问粘成一团。
下面这个会话切割脚本是离线数仓侧的逻辑,它重新计算 session_id,不信任前端生成的版本:
import pandas as pd df = pd.read_parquet("events.parquet") df = df.sort_values(["user_id", "ts"]) timeout = pd.Timedelta(minutes=30) def build_session(group): group = group.copy() group["gap"] = group["ts"].diff().fillna(pd.Timedelta(seconds=0)) group["new_session"] = group["gap"] > timeout group["session_id_local"] = group["new_session"].cumsum() + 1 group["session_id"] = group["user_id"].astype(str) + "_" + group["session_id_local"].astype(str) return group df = df.groupby("user_id", group_keys=False).apply(build_session)逻辑说明:先按用户和时间排序,组内计算每条事件与上一条的间隔;gap > 30 分钟就标记为会话边界;用累加方式生成会话序号,最终拼出稳定的session_id。注意这里用.diff()而不是 reqctx 里的第一条事件做零值填充,保证第一个事件一定归属当前会话头部。
参数说明:timeout是唯一需要调的核心参数,可以按类目拆分,比如高价商品类目用户比价时间长,放宽到 45 分钟;但多数场景 30 分钟全局默认足够用。如果数据量超过几亿行,groupby.apply 会偏慢,建议先按日分区再做会话切割,或者用 PySpark 改写同一套偏移逻辑。用户识别上,我的经验是:登录后把anonymous_id近 30 天的历史行为并到user_id下,整合行为序列更完整。
2.3 行为序列构造与压缩:给 DeepSeek 的“原材料”长什么样
得到会话表之后,下一步就是把一个 session 内的事件转换成大模型能读懂的中文文本链。原始事件是全字段 JSON,直接喂给 DeepSeek 一是 token 成本高,二是很多字段(设备型号、页面元素坐标)对意图判断没有帮助,还会干扰注意力。
我常用的压缩逻辑是把每个事件映射成“动作 + 商品 + 价格”的短文本,用箭头串起来:
action_map = { "pv": "浏览", "search": "搜索", "cart_add": "加购", "cart_del": "删购", "order_create": "下单", "payment_attempt": "发起支付", "pay_success": "支付成功", "coupon_use": "用券", } def compact_sequence(events, max_len=40): seq = [] for e in events: act = action_map.get(e["event"], e["event"]) sku = e["props"].get("sku_name", e["props"].get("sku_id", "")) price = e["props"].get("price", 0) seq.append(f"{act}:{sku[:18]}(¥{price})") return " → ".join(seq[:max_len])逻辑说明:只保留对旅程判断有区分度的字段;max_len=40限制最长输出,超长序列只截取末尾 40 个事件,因为 Journey 判断更关注最近行为。token 消耗大约每 10 个事件占用 50 到 80 token,单条会话文本能控制在 150 token 以内,即便批处理千万级用户,成本也可控。
注意:
sku_name最好截断到 18 字以内,超长商品标题会占掉大量 token 且无信息增益。另外不要把cart_del这类负向事件丢掉,“加购后又删购”是判断犹豫期的重要信号。
3. 用 DeepSeek 做用户旅程映射:从贪心序列到阶段标签
数据层就绪后,核心工作才轮到模型。这里的用户旅程映射要做两件事:一是把一条行为序列解释成“用户在旅程的哪个阶段”,二是把阶段结果聚合成可观察的全局旅程地图。DeepSeek 在这类任务上的优势是理解中文口语化行为描述的能力强,且可以通过提示词约束输出 JSON,直接进入下游表结构。
3.1 提示词模板与结构化输出:让模型按固定 JSON 返回阶段判断
旅程阶段不能完全开放让模型自由发挥,否则会出现“犹豫不决期”“比价观望期”这种无法聚合的自造词,整个分析就无法落地。我通常会把阶段收敛到 9 个固定枚举:reach/browse/compare/intent/cart/checkout/purchase/post_purchase/churn,分别对应触达、泛浏览、比较、有意向、加购、结算、购买、购后、流失。
下面是调用 DeepSeek 的完整示例。这里的 base_url 既可以是官方 API,也可以是本地通过 vLLM 部署的推理服务,区分点只在于 model 参数:
from openai import OpenAI client = OpenAI( base_url="http://your-deepseek-endpoint:8000/v1", api_key="EMPTY", # 本地部署常用 EMPTY,官方 API 则填真实 key ) prompt = f"""你是电商用户行为分析助手。下面是一条用户行为序列(按时间顺序)。 行为序列:{compact_seq} 请完成以下分析,并以 JSON 返回: 1. journey_stage:用户当前处于哪个旅程阶段,只能是 reach/browse/compare/intent/cart/checkout/purchase/post_purchase/churn 之一 2. stage_confidence:0-1 的置信度 3. intent_summary:一句话概括用户意图 4. next_best_action:你认为最合适的一个运营动作 5. key_touchpoints:你判断用户接下来最关键的 1-3 个触点 """ resp = client.chat.completions.create( model="deepseek-chat", messages=[ {"role": "system", "content": "你只输出合法 JSON,不输出任何额外文本。"}, {"role": "user", "content": prompt}, ], temperature=0.1, max_tokens=1024, response_format={"type": "json_object"}, ) print(resp.choices[0].message.content)参数说明:temperature=0.1是为了阶段判断的稳定性,这类“分类 + 抽取”任务不适合高随机性;max_tokens=1024防止模型啰嗦输出额外解释;response_format强制 JSON 结构,但注意 OpenAI 兼容协议要求 prompt 里必须出现“JSON”字样,模板里已经满足。
如果走 API 方式,model 填deepseek-chat;如果是本地部署,模型名要填部署时加载的模型路径或服务注册名。本地部署的好处是行为数据不出内网,对电商这类强隐私场景更友好,企业微信接入 DeepSeek 客服消息或内部运营工具时,也建议走内网网关而不是直连外部 API。
3.2 旅程阶段后处理:解析模型输出并做兜底校验
模型输出不能直接写成结果表,至少要做两类兜底。一是 JSON 解析失败的重试;二是枚举值出现异常时的降级。大模型即使给了限定枚举,仍然可能输出cart_page或加购阶段这类变体,没有白名单过滤的话,后续 groupby 聚合就会出现几十个“伪阶段”。
import json VALID_STAGES = { "reach", "browse", "compare", "intent", "cart", "checkout", "purchase", "post_purchase", "churn" } def parse_result(raw: str, fallback_stage="browse"): try: data = json.loads(raw) except json.JSONDecodeError: data = {} stage = data.get("journey_stage", fallback_stage) if stage not in VALID_STAGES: stage = fallback_stage return { "stage": stage, "confidence": float(data.get("stage_confidence", 0.5)), "intent": data.get("intent_summary", ""), "action": data.get("next_best_action", ""), "touchpoints": data.get("key_touchpoints", []), }逻辑说明:解析失败就回退到browse阶段并给 0.5 的中性置信度,宁可保守也不能让脏数据把聚合结果带偏;VALID_STAGES集合是服务端的第二道闸口,模型输出什么都要过这一层。实际生产里我会把fallback_stage按业务调整——比如账号历史有多次购买的用户兜底到browse就不太合适,可以按人群预设不同兜底值。
3.3 从单用户到全量旅程:分群聚合与触点打分
单用户的阶段标签积累成一张事实表后,真正的用户旅程地图是聚合出来的:按新老客、渠道、消费力分群,计算每个分群在 9 个阶段的用户数、平均停留事件数、流失率,再找出流失最集中的阶段。这段逻辑用 Python 表达如下:
result_df = pd.DataFrame(records) # records 是每条 session 的解析结果 journey_map = ( result_df .groupby(["cohort", "stage"]) .agg( user_cnt=("user_id", "nunique"), avg_events=("event_cnt", "mean"), dropoff_rate=("is_dropoff", "mean"), ) .reset_index() ) touchpoint_score = ( result_df.explode("touchpoints") .groupby(["cohort", "touchpoints"]) .agg( user_cnt=("user_id", "nunique"), conv_rate=("converted", "mean"), ) .reset_index() .assign(score=lambda d: d["user_cnt"] * 0.4 + d["conv_rate"] * 0.6) )说明:cohort是预先算好的用户分群标签;stage来自模型;is_dropoff是业务定义的流失标记,比如超过 7 天未回访且未支付的用户记为 1。触点打分用两个维度加权:触达广度(多少用户在这个触点停留)和转化力度(在这个触点出现过的用户最终转化率)。得分高的触点就是下一章要增强的关键触点,但记住这是离线算出来的,不是实时推理结果。
4. 关键触点个性化增强:在你“该出手”的地方出手,且要出不同的手
拿到旅程地图后,业务上最关心的是“在哪改、改成什么样”。关键触点个性化增强要做两件事:先把触点分成两类,再把每类触点的动作策略差异化落地。这个环节最容易做过头,把个性化做成“处处打扰”,所以要先把策略边界定清楚。
4.1 触点识别:先分清“承接触点”和“转机触点”
我习惯把触点分成两类。承接触点指用户主动发起动作的页面,比如搜索框、商品详情页、购物车页,用户预期“在这里获得信息”;转机触点指系统可以主动干预的环节,比如支付失败页、结算页领券入口、购物车放弃后的唤起、公众号模板消息、企业微信客服会话等。
个性化增强应该优先放在转机触点上,因为承接触点有明确用户意图,干预不当反而打断决策。用 3.3 节的touchpoint_score排序,取每个分群 score 最高的 1 到 3 个转机触点作为试点,不要一次性全铺开。比如老客分群在“购物车 → 结算页”流失最重,就只改结算页的优惠展示逻辑,观察一周再动下一处。
4.2 个性化策略生成:行为序列进、运营文案出
确定触点后,需要为处于不同阶段的人群生成不同动作。这分成两步:浅层的动作选择来自规则,比如checkout阶段给“满减券”,compare阶段给“降价提醒”,不用模型参与;深层的文案表达用 DeepSeek 生成,因为文案需要贴合具体行为序列,规则写不出千店千面的措辞。
def gen_coupon_copy(seq_text: str, stage: str, base_coupon: str) -> str: prompt = ( "你是电商运营专家。请根据行为序列和旅程阶段,为这个用户写一句不超过20字的优惠券引导文案。\n" f"行为序列:{seq_text}\n" f"旅程阶段:{stage}\n" f"优惠券:{base_coupon}\n" "要求:贴合当前阶段,不喊口号,不使用'亲爱的'等称呼,只输出文案本身。" ) resp = client.chat.completions.create( model="deepseek-chat", messages=[{"role": "user", "content": prompt}], temperature=0.7, max_tokens=100, ) return resp.choices[0].message.content.strip()参数说明:temperature=0.7是文案生成和阶段判断的关键差异——策略文案需要多样性,同一个优惠券在不同序列下要有不同说法,温度太低会把所有文案生成成一个模子;max_tokens=100足够,文案超长会破坏页面布局。这里只传了seq_text和stage两个上下文,如果传整个历史行为的所有字段,生成的文案会过度拟合噪声。
4.3 触发条件与频控:最小闭环的四个参数
个性化增强最怕变成无差别营销。我一般会为每个转机触点配置一张参数表,核心包含四个维度:触发条件、频控窗口、人群圈选、成本上限。
| 触点 | 触发条件 | 频控 | 人群排除 |
|---|---|---|---|
| 支付失败页 | 支付接口返回失败且失败原因非用户取消 | 每 30 分钟最多 1 次 | 已发券超过 3 张的用户 |
| 购物车放弃召回 | 购物车商品停留超 2 小时未结算 | 每 72 小时最多 1 次 | 近 7 天已触达 2 次的用户 |
| 结算页领券入口 | 到达结算页且购物车金额未达门槛 | 每次会话最多 1 次 | 高活跃老客(月购买超 5 次) |
落地时可以用一段简短的伪代码描述触发链路,方便和前端联调:
def on_checkout_fail(user_id, event): user_ctx = load_user_ctx(user_id) # 读取近 30 天行为序列与阶段标签 if not check_frequency(user_id, "checkout_fail", minutes=30): return if get_recent_coupon_cnt(user_id) >= 3: return seq_text = compact_sequence(user_ctx["recent_events"]) copy = gen_coupon_copy(seq_text, user_ctx["stage"], "满300减40") push_to_user(user_id, copy, channel="app_payment_fail_page")这里的联调要点:触发逻辑放在服务端,文案生成也放服务端,前端只接收最终展示字符串。不要把compact_sequence和gen_coupon_copy拆到不同服务里,否则每次触发都要传两次行为上下文,徒增接口时延。
5. 避坑:用户旅程映射与触点增强最容易翻车的五个环节
光看方案逻辑觉得通顺,一上真实数据就出各种“玄学”问题。这些坑我在实践中几乎每个都踩过一轮,写在这里当血泪经验。
5.1 埋点“看起来有”但关键动作没采集,序列永远缺一块
现象:用户旅程地图里突然出现大段“从浏览直接跳购买”的路径,检查发现搜索、加购全部缺失。
原因:埋点版本迭代时只加了新事件,没有核对旧事件是否仍然上报;另外部分前端组件用了懒加载,用户未滚动到可视区域就不触发上报。
解决:上线前做事件覆盖度审计,列出 top 20 关键事件逐一验证。可以写一个离线脚本统计“每会话平均事件数”和“关键事件覆盖率”,连续三天低于阈值就报警。
5.2 会话 ID 前后端口径不一致,同一段旅程被拆成三截
现象:DeepSeek 把一个连续购物过程识别成三段独立旅程,阶段判断从intent掉回browse,导致旅程地图严重失真。
原因:App 被杀进程后重新启动,前端生成新 session_id;或者前端把会话超时设成 5 分钟,用户看长文详情时被切断。
解决:前端只保留原始session_start事件,不在前端做会话归属;统一在离线数仓用 2.2 节的逻辑重算 session_id。口径收敛后,所有模型输入的序列就基于同一套会话边界。
5.3 DeepSeek 输出幻觉,补上了用户没做过的动作
现象:行为序列里根本没有支付相关动作,模型却把阶段判成checkout,甚至生成“用户支付意愿较强”的意图描述。
原因:大模型在序列不完整时会用常识补全,这是典型的幻觉;加上提示词里给了过多示例阶段,模型倾向选一个“最合理”的。
解决:两个手段叠加:一是temperature=0.1降低随机性;二是后处理只认VALID_STAGES,且当stage_confidence < 0.6时回退到规则模型判定。规则判定很简单——序列里没有cart_add就不能判checkout。
5.4 个性化太“准”反而把毛利打穿
现象:实验组支付转化率提升 12%,但客单价跌了 8%,整组毛利反而下降。
原因:个性化增强被简化成“给券发券”,触达文案越精准,用户越容易集中使用大额优惠,把本可以原价购买的人群也补贴了。
解决:实验指标必须同时盯转化率、客单价、毛利三个数;人群圈选排除自然转化用户(比如购物车金额已超门槛、历史客单价高于券后价)。另外对高频活跃用户降低触发频次,这类用户本来就快下单了,不需要券来打扰。
5.5 实时调用 API 太慢,弹窗把页面卡到转化率不升反降
现象:支付失败页的个性化弹窗接口耗时 800ms 以上,部分机型弹窗延迟导致用户误以为页面卡死,直接关闭 App。
原因:同步调用外部大模型接口,网络往返加模型排队叠加;加上文案生成流式输出被网关缓冲,整体延迟不可控。
解决:做两级链路。离线阶段先把用户分群、阶段标签、推荐动作算好并写入缓存;在线触发时只查缓存,文案用异步预生成或模板兜底。如果坚持实时生成,必须加超时降级:超过 300ms 就返回默认文案,绝不能让 AI 接口拖垮核心支付路径。
6. 最后:这套方案上线后,我建议你先盯三个指标
方案跑通后,最容易陷入“旅程地图画得很精美,但业务没变化”的尴尬。我的做法是只盯三个硬指标。第一个是旅程阶段标注准确率:每周抽取 200 条行为序列做人工复核,比对模型阶段判断与业务专家标注,准确率降到 85% 以下就排查提示词或特征压缩是否出问题;第二个是触点触达覆盖率,即真正命中个性化增强策略的用户占应触发人群的比例,低于 90% 说明链路有静默丢失,多半是频控参数或前端上报问题;第三个是端到端转化率增量,这个是唯一评判个性化增强有没有价值的指标,实验组对比组的差异要维持两到三周才可信,避免某天大促流量造成的误判。
在扩展顺序上,我的习惯是从支付失败页、购物车放弃召回这类低频高意图触点先跑,跑通后再碰首页弹窗和搜索结果页这类高曝光低意图触点。前者用户期待被服务,错了代价小;后者用户期待被“放过”,错了直接伤体验。模型成本方面,阶段标注是离线批任务,可以容忍二次调用;文案生成是高频在线任务,一定要做结果缓存,同一序列同一阶段生成的文案直接复用。
还有一个小习惯强烈建议保留:每次模型升级或提示词调整,都在结果表里落一个model_version和prompt_version字段。没有这两个字段,对比历史实验结果时只能靠猜——一开始我就是没留版本号,后来发现两周的数据换了模型根本没可比性,只能重跑,白白浪费了一个完整实验周期。希望这些经验能帮你的电商用户体验优化方案少走一段弯路。
本文还有配套的精品资源,点击获取