ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于LLM的智能用户画像分析:从多源数据到动态标签的落地实践

基于LLM的智能用户画像分析:从多源数据到动态标签的落地实践 简介基于大语言模型LLM的智能用户画像分析系统是一份面向算法工程、数据挖掘及市场营销分析人员的完整实现方案。系统整合客户画像、用户行为分析、情感识别、消费习惯挖掘、价值观推断、动态标签生成与多源数据融合等技术适用于个性化推荐、精准营销、内容分发和客户洞察等场景。通过对用户评论、反馈、社交媒体文本及行为轨迹的联合建模借助自然语言处理与深度学习能力可输出结构化与非结构化数据融合后的立体用户标签辅助企业制定精细化运营策略。资源共28个文件以Python脚本16个py与Markdown文档3个md为主辅以配置文件、依赖锁定文件、说明文档及附赠资料压缩包整体仅144KB。源码中已包含应用入口、数据层、核心API与模型封装并配有用户画像生成流程详解及核心功能说明便于快速理解工程结构并开展二次开发。目前已有282人学习适合具备一定Python基础、希望深入LLM应用与用户分析实战的中高级开发者参考。1. 基于大语言模型LLM的智能用户画像分析系统为什么规则标签在非结构化数据面前失灵了传统用户画像系统用RFM模型、漏斗分析、规则标签跑结构化订单数据效率不低但一遇到客服对话、用户评论、工单描述这类非结构化文本就僵住了关键词匹配只能数词频正则规则覆盖不了口语化表达。基于大语言模型LLM的智能用户画像分析系统则完全换了一种做法——让模型直接“读”用户在评论和对话里说过什么再结合行为数据做融合推断。它能把情感识别、消费习惯挖掘、价值观推断、动态标签生成串成一条自动化链路。这套思路适合正在搭CRM数字化、精细化运营体系手头有事件数据和文本数据想让画像从“统计表”变成“能对话的人”的团队。别急着选模型先把数据底座拼好。2. 多源数据融合的画像底座把订单、浏览、客服对话拼成一张可喂给LLM的宽表任何智能用户画像分析系统落地时最先卡住的往往不是模型选型而是数据拼装。一个用户可能在订单系统里有一条消费记录在埋点日志里有一串浏览行为在客服系统里留下几段对话。三份数据格式不同、时间口径不同、用户标识也不一定相同。不先把它们拼到一张口径统一的宽表上后面所有LLM推理都会变成无源之水。这一章讲常见做法先给数据分类再做行为序列清洗最后用一份SQL把多源数据落到特征宽表。2.1 结构化与非结构化数据同时摆在你面前先分类再决定预处理策略我一般会把数据按结构和处理方式分成三类不是所有字段都值得进LLM的上下文。数据类型典型来源字段特点是否进LLM预处理建议结构化数据订单表、CRM字段、用户资料字段固定、关系明确否SQL聚合后以文本摘要形式进入提前算好统计特征半结构化数据APP埋点、日志JSON键值嵌套、场景多变低转成行为序列摘要即可JSON拍平后按事件类型重组非结构化数据客服对话、评价、工单描述自由文本、口语化、含噪声是LLM发挥语义理解的主场去隐私、去噪声后再喂给模型业务团队最容易踩的坑有两个一是把订单明细整表丢给LLM让模型自己算客单价二是把客服对话全文无脑塞进提示词上下文被无关内容撑爆。订单明细是结构化信息聚合成统计特征后进上下文又便宜又准确客服对话才是LLM该花token的地方。消费习惯挖掘需要的是两者的组合——订单数据给出“最近30天买了什么、花了多少”评论文本给出“用户为什么这么买”。在做预处理时结构化数据按用户维度聚合出近期行为统计量半结构化数据按会话重组非结构化数据先做隐私脱敏。手机号、地址、身份证号在进入模型前必须替换成占位符这一步不能省否则下游画像即使做对了数据合规上也站不住脚。2.2 用户行为序列的清洗与对齐会话切分、时间窗口与事件去重埋点数据里最典型的问题是时间口径混乱。客户端上报的时间和服务器记录时间混在一起如果直接用会导致行为序列乱序。我通常要求所有事件统一使用服务端时间并且显式指定时区避免跨天会话被错误切开。第二个问题是会话切分。用户打开APP一次性看完10件商品埋点会记下10条曝光事件。如果按天聚合就丢失了“一次浏览决策路径”的关键信息。常见做法是同一用户相邻两条事件间隔超过30分钟就认为进入下一个会话。import pandas as pd def split_sessions(events: pd.DataFrame, gap_minutes: int 30) - pd.DataFrame: 把用户事件序列切分为会话。 参数: events: 必须包含 user_id、event_time、event_name 三列 gap_minutes: 同一用户两条事件间隔超过该值判定为新会话 返回: 原数据基础上增加 session_id 列 df events.sort_values([user_id, event_time]).copy() # 计算同一用户相邻事件的时间差单位换算成分钟 df[time_diff] df.groupby(user_id)[event_time].diff().dt.total_seconds() / 60 # 每个用户的第一条事件 time_diff 是 NaN正好标记为新会话起点 df[is_new_session] df[time_diff].isna() | (df[time_diff] gap_minutes) # 在用户内部做累计计数拼出全局会话ID df[session_seq] df.groupby(user_id)[is_new_session].cumsum() df[session_id] df[user_id].astype(str) _ df[session_seq].astype(str) return df.drop(columns[time_diff, is_new_session])这个切分逻辑里有个细节groupby.diff()对每个用户的第一条记录返回NaN因此is_new_session天然为真确保每个用户的第一条事件一定能开启新会话。session_seq从0开始累计同一用户的不同会话ID不会重复。gap_minutes的取值有讲究。搜索流量用户意图明确给20分钟足够内容推荐流量用户可能边刷边想给40分钟更合理。如果画像后续要识别“跨渠道比价”行为阈值设太短会把一次完整比价过程拆成多个会话特征就失真了。事件去重也是必做项。埋点重试、用户快速双击都会产生重复事件。有event_id的按它去重即可没有event_id时用“用户ID 事件名 页面URL 发生时间”这组复合键去重。但有个例外浏览时长这类连续事件不能直接去重应该取第一次出现的时间和最后一次出现的时间算差值。2.3 多源融合落地一份SQL把三份数据源拼成特征宽表假设你已经通过id-mapping拿到了统一的user_key接下来就是把订单、行为、客服三份数据拼成宽表。下面这段SQL是我常用的模板WITH user_base AS ( SELECT user_key, MIN(paid_at) AS first_paid_at, COUNT(DISTINCT order_id) AS order_cnt, SUM(amount) AS lifetime_value, AVG(amount) AS avg_order_amount FROM orders WHERE paid_at DATE_SUB(CURRENT_DATE, INTERVAL 365 DAY) GROUP BY user_key ), active_sessions AS ( SELECT user_key, COUNT(DISTINCT session_id) AS session_cnt, COUNT(DISTINCT DATE(event_time)) AS active_days FROM events WHERE event_time DATE_SUB(CURRENT_DATE, INTERVAL 90 DAY) GROUP BY user_key ), ticket_summary AS ( SELECT user_key, COUNT(DISTINCT ticket_id) AS ticket_cnt, SUBSTRING_INDEX( GROUP_CONCAT(content_text ORDER BY created_at DESC SEPARATOR \n), \n, 3 ) AS recent_ticket_text FROM service_tickets WHERE created_at DATE_SUB(CURRENT_DATE, INTERVAL 90 DAY) GROUP BY user_key ) SELECT u.user_key, u.first_paid_at, u.order_cnt, u.lifetime_value, u.avg_order_amount, a.session_cnt, a.active_days, t.ticket_cnt, t.recent_ticket_text FROM user_base u LEFT JOIN active_sessions a ON u.user_key a.user_key LEFT JOIN ticket_summary t ON u.user_key t.user_key;这段SQL背后有三个设计点。第一所有指标都带时间窗口窗口外的早期数据不进入LLM上下文让模型聚焦用户最近的状态。第二订单金额类字段由数据库算好而不是交给模型去算——结构化数据用SQL处理既便宜又精确。第三recent_ticket_text用GROUP_CONCAT按时间倒序拼接最近3条客服文本这是平衡信息完整度和token成本的常用做法。如果一段对话特别长我会先做关键句抽取把带负面词或疑问词的句子挑出来再拼而不是全文进上下文。LEFT JOIN是有意为之保留只有订单没有活跃、或有活跃没订单的用户。如果在后续使用中发现某用户两个系统ID对不上那多半是id-mapping漏了这个坑放到第5章详细排查。提示时间窗口的选择跟着决策周期走。冲动消费品类30天窗口即可耐用品类拉长到365天。不要照搬这个SQL的窗口参数。3. 用LLM做情感识别与消费习惯挖掘提示词工程与输出约束的三个关键设计数据底座拼好后LLM才能真正发力。这一章的核心是把自然语言处理能力用在实际业务上——情感识别和消费习惯挖掘。很多团队在这里翻车不是因为模型不够强而是提示词设计得太粗糙只让模型给个“正/负”二分类或者让模型自由发挥输出一段话。要稳定落地需要把情绪拆细、把消费习惯结构化、把输出格式锁死。3.1 情感识别不能只分正负向把情绪类型、强度与指向对象拆开运营同事看到一条“你们发的券用不了”和一条“衣服质量不错但袖子有点线头”都会标记为负面。但前者指向优惠券系统故障后者指向品控问题处理方式完全不同。如果情感识别只输出“负面”画像系统只知道自己不满意不知道哪里不满意根本没法驱动后续动作。我设计的提示词会强制模型输出三个字段情绪类型、强度、指向对象。情绪类型限定在枚举值里强度用0到1的浮点数指向对象也从业务预定义的枚举值里选。SENTIMENT_PROMPT 你是一位用户研究分析师。请分析用户在客服对话或评价中表达的情绪。 要求 1. 先判断这段文本是否带有情绪色彩。 2. 如果没有明显情绪输出 {emotion: neutral, intensity: 0.0, target: none}。 3. 如果有情绪从枚举值中选择情绪类型给出0-1强度分并判断指向对象。 枚举值 - emotion: satisfaction / anger / anxiety / disappointment - target: quality / price / logistics / service / coupon / product / none 只输出JSON不要解释。 用户文本 {text} 输出示例 {{emotion: anger, intensity: 0.6, target: logistics}} 配套的调用函数需要把temperature设为0并开启JSON模式import json from openai import OpenAI # 这里换成你自己部署的LLM服务地址和密钥 client OpenAI(base_urlhttp://your-llm-service/v1, api_keyyour-api-key) def infer_sentiment(text: str) - dict: response client.chat.completions.create( modelyour-llm-deployment, messages[{role: user, content: SENTIMENT_PROMPT.format(texttext)}], temperature0, response_format{type: json_object}, ) content response.choices[0].message.content try: return json.loads(content) except json.JSONDecodeError: # 兜底重试可能是模型在JSON外包了一层说明文字 retry client.chat.completions.create( modelyour-llm-deployment, messages[ {role: user, content: SENTIMENT_PROMPT.format(texttext) \n注意输出必须是合法的JSON不要带任何其他文字。} ], temperature0, response_format{type: json_object}, ) return json.loads(retry.choices[0].message.content)代码里的两个temperature0不是可有可无的。画像系统要跑成千上万次调用如果温度不为0同一句话今天识别成anger明天识别成disappointment下游标签就不可信。response_format让服务端尽量约束输出为JSON对象但有些自部署模型不一定严格支持所以还得在代码里做解析失败处理。重试一次后仍然解析失败就丢进待人工处理队列千万不能直接丢弃——极少数但重要的强情绪投诉往往就藏在这些异常里。3.2 消费习惯挖掘从评论和订单文本中抽取品类、价格带与频次信号消费习惯挖掘的输入通常是两类信号的混合订单统计事实和评论文本。订单统计是结构化的评论文本是非结构化的LLM在这里的用法是把两者拼成一个自然语言的“消费事实摘要”再让模型抽取结构化画像。def build_consumption_context(user_row: dict) - str: return ( f该用户近30天订单数{user_row[order_cnt_30d]} f平均客单价{user_row[avg_order_amount]}元 f主要品类{user_row[main_category]}。 f最近一条评价{user_row[recent_review][:200]} ) CONSUMPTION_PROMPT 根据用户的消费事实和评价文本推测该用户的消费习惯。 输出JSON字段包括 - preferred_categories: 列表从枚举中选择3C数码 / 服饰 / 美妆 / 食品 / 家居 / 其他 - price_band: 该用户更愿意接受的价位档低 / 中低 / 中 / 中高 / 高并附一句话依据 - purchase_frequency: 购买频次低频(月1) / 中频(月1-4) / 高频(月4) - value_drivers: 决策时最看重什么最多选两个性价比 / 品质 / 品牌 / 服务 / 物流速度 消费事实 {context} 只输出JSON。 这里之所以把结构化统计数字转成自然语言是因为LLM对连续文本的语义理解远好于对表格的理解。你把“order_cnt_30d3, avg_order_amount158”直接塞进JSON模型也能看到但“近30天订单数3平均客单价158元”这种句子和评论文本放在一起上下文语义更连贯抽取结果的稳定性明显更高。模型返回的JSON不能直接入库要做枚举校验def parse_consumption_profile(raw: str) - dict: data json.loads(raw) allowed_categories {3C数码, 服饰, 美妆, 食品, 家居, 其他} allowed_bands {低, 中低, 中, 中高, 高} allowed_freq {低频(月1), 中频(月1-4), 高频(月4)} allowed_drivers {性价比, 品质, 品牌, 服务, 物流速度} assert data[price_band] in allowed_bands, price_band 超出枚举范围 assert data[purchase_frequency] in allowed_freq, purchase_frequency 超出枚举范围 assert set(data[preferred_categories]) allowed_categories, categories 超出枚举范围 assert set(data[value_drivers]) allowed_drivers, value_drivers 超出枚举范围 return data你可能会觉得在提示词里已经写清楚了“从枚举中选择”为什么还要在代码里断言一遍。因为模型偶尔会输出枚举词的同义改写比如“性价比敏感人群”而不是“性价比”。程序层做白名单校验是最后一道护栏也是整理脏数据样本的最佳来源。3.3 JSON结构化输出与温度参数让模型产出稳定、可解析的结果整个画像系统由成千上万次LLM调用构成每次输出解析失败都会污染下游标签。我在生产环境里总结了三个经验。第一统一低随机性参数。所有画像推理调用temperature0平台支持的话再把seed固定为常数。有些开源模型默认开了repetition_penalty如果值设得过高模型会为了抑制重复而频繁换词反而破坏枚举输出的稳定性建议关掉或调低到1.0附近。第二JSON Schema校验。把上面的assert扩展成jsonschema或pydantic模型不通过校验的样本不是简单丢弃而是写入“低置信度桶”。这些样本后续可以抽样做人工评审用来优化提示词。第三做文本缓存。客服对话里大量内容是重复的比如“好的”“谢谢”这类高频短语。同一条文本没必要让LLM算第二遍。缓存键必须包含提示词版本号否则提示词一改旧缓存会按过期规则产出标签。import hashlib import json import redis r redis.Redis(hostlocalhost, port6379, decode_responsesTrue) def get_or_infer(text: str, prompt_version: str, infer_func): cache_key llm:cache: hashlib.sha256( (prompt_version text).encode() ).hexdigest() cached r.get(cache_key) if cached: return json.loads(cached) result infer_func(text) r.setex(cache_key, 3600 * 24 * 7, json.dumps(result, ensure_asciiFalse)) return result提示词版本号要写进缓存键这个细节常被忽略。有一次我调整了情绪枚举把anger改成了frustration没换版本号结果旧缓存里全是旧枚举值下游标签表出现脏数据。从那以后我把提示词版本号作为常量统一管理任何改动都要升级版本号。4. 动态标签生成与价值观推断从一次推理到可持续演化的画像体系单次情感识别和消费习惯抽取只是画像的原始信号要变成可查询、可运营的标签体系还需要生命周期管理。这一章回答三个问题标签怎么分层、价值观推断的边界在哪里、什么时候触发重算才不浪费算力。4.1 标签分层基础标签、行为标签与价值观标签的生命周期管理不是所有标签都值得用LLM生成。我按更新频率和来源把标签分成三层标签层示例数据来源更新频率是否依赖LLM基础标签性别、年龄段、注册渠道用户注册信息、实名信息低频、月度否行为标签近30天购买频次、客单价档位、活跃品类订单表、事件表SQL聚合事件触发否或LLM辅助生成描述价值观/态度标签品质敏感、性价比敏感、环保意识非结构化文本 LLM推断周级或事件触发是很多团队把三层混成一个标签体系导致“标签”这个词在内部都对不齐。基础标签和行为标签完全可以用数据库聚合算出来没必要让LLM做。真正必须用LLM的是第三层——用户没有直接告诉你“我注重品质”但他写的评论、提的工单都在暗示这一点。标签不是永久不变的它必须有衰减。用户三个月前反复夸“材质很好”三个月后他对品质的态度可能已经变了。我用指数衰减给标签置信度打折import math def decayed_score( base_score: float, last_evidence_days: int, half_life_days: int 30, ) - float: 按证据距今时间衰减标签置信度。 每过 half_life_days 天标签分数降一半。 只有衰减后仍高于阈值的标签才对外投递。 if last_evidence_days 0: return base_score return base_score * math.exp(-math.log(2) * last_evidence_days / half_life_days) # 示例某用户“性价比敏感”标签上次文本证据距今45天 print(decayed_score(base_score0.8, last_evidence_days45, half_life_days30))指数衰减比线性衰减更适合消费标签因为人对消费态度的遗忘是非线性的。半衰期30天意味着45天前的证据只剩约0.39的权重业务方在标签表里应存last_evidence_date和base_score下游读取时实时做衰减而不是存一个写死的布尔值。4.2 价值观推断的可行边界能推断的消费观念与不能触碰的禁区“价值观推断”是这套画像系统里最容易被误解、也最需要克制的部分。先说结论能推断的是消费价值观不能推断的是用户私人生活中的敏感属性。消费价值观是用户自己在公共文本里表达出来的比如一个用户反复购买环保材质产品、在评价里对比可降解包装给他打“环保意识”标签对推荐系统有明确正向价值。同样“品质敏感”“性价比敏感”“品牌忠诚”这类标签都来自用户可验证的消费表达。不能碰的是医疗健康状况、宗教信仰、政治倾向、财务状况细节等敏感属性。这些信号即使模型能从文本里推断出来置信度通常也不高而且一旦标签被下游运营误用极易引发投诉和合规风险。系统设计在价值观推断这里必须做“防御性过滤”。ALLOWED_VALUE_TAGS {品质敏感, 性价比敏感, 环保意识, 品牌忠诚} def filter_value_tags(raw_tags: list[str]) - list[str]: return [tag for tag in raw_tags if tag in ALLOWED_VALUE_TAGS]这行简洁的过滤是整个画像系统真正的护栏。模型输出先过白名单再进标签库下游业务只能看到白名单里的标签。如果一个用户表达的内容无法归到白名单宁可放弃推断也不要让模型自由发挥生成新标签。自由发挥意味着不可控不可控在用户画像场景里等于风险。输入侧也要脱敏。客服对话里的手机号、地址、订单号在进LLM之前必须先替换成占位符。LLM不会记住这些信息但提示词和输出日志可能被持久化存储脱敏是为了防止画像数据仓库里沉淀不必要的个人敏感信息。4.3 动态更新的触发器设计事件驱动增量重算与成本控制标签不能只在固定时间全量重算。全量重算不仅慢还贵——把全量用户的全部文本重新过一遍LLM账单会直接失控。常见做法是把重算拆成事件驱动和定时批处理两种。事件驱动处理关键业务动作。用户发生退款、投诉、差评时立刻重算该用户画像因为这是客服介入的最佳时机需要最新画像状态。定时批处理则处理日常积累每天凌晨对当日有新增数据的用户重算一次90天无任何事件的用户不再重算标签进入静默衰减直到新事件到来才重新激活。def process_user_if_needed(user_key: str, latest_event_ts: str) - None: state load_state(user_key) # 1. 拉取增量数据只取上次计算时间之后、且未处理过的文本 new_texts fetch_incremental_texts(user_key, sincestate.last_calculated_at) new_texts [t for t in new_texts if fingerprint(t) not in state.processed_fingerprints] if not new_texts: return # 没有新增文本不调用任何LLM # 2. 把新增文本和旧画像摘要一起送LLM生成候选标签 new_tags, new_confidence infer_tags_from_texts(new_texts, state.current_profile) # 3. 平滑合并新结果而不是直接覆盖旧画像 merged_profile merge_profile(state.current_profile, new_tags, new_confidence) # 4. 记录处理进度更新已处理文本指纹集合 save_state( user_key, last_calculated_atlatest_event_ts, processed_fingerprintsstate.processed_fingerprints | {fingerprint(t) for t in new_texts}, current_profilemerged_profile, )这段流程里最关键的是第3步和第4步。new_tags不能直接替换旧画像要用平滑合并的方式更新否则一条极端差评会瞬间把所有历史标签冲掉。processed_fingerprints必须记录否则脚本重复执行时同一批文本会被重复送进模型浪费的钱都是真金白银。文本指纹用sha256即可注意先做规范化处理——把首尾空格、全半角符号统一避免同一句话因微小格式差异被判成新文本。5. 画像系统落地避坑与常见问题排查五条真实的LLM画像踩坑记录前面几章把方案讲完了这一章写真正会卡住人的细节。这些都是我在不同画像项目里实际踩过的坑按“现象 → 原因 → 解决”的方式列出来希望你能绕开。5.1 中性文本被误判为正向情绪模型的默认正向偏差从哪来现象用户说了一句“收到”情感识别直接返回satisfaction强度还给到0.6。评论里只有“到了”两个字也被判成正向。原因语言模型的训练语料里客服对话结尾往往带有正向关怀模型见多了“谢谢”“好的”这类词汇会习惯性给一个小正向分。没有显式中性类别约束时模型倾向于在无明显情绪时输出弱正向。解决提示词里必须先让模型判断“是否带情绪色彩”把neutral设为显式类别并给两条中性示例。PROMPT 判断文本是否带情绪色彩。 - 若文本只是客观事实无情绪倾向输出 {emotion:neutral,intensity:0,target:none}。 - 若文本有明显情绪才选择 anger / satisfaction / disappointment / anxiety并给出0-1强度与目标。 中性样例 - 收到。 - 下午可以发货吗 用户文本{text} 加了这个约束之后中性文本误判率明显下降。另一个辅助手段是把强度分档0到0.2视为中性0.3到0.7视为弱情绪0.7以上视为强情绪。运营只看档位不纠结小数位。5.2 动态标签来回跳变置信度阈值与历史平滑为何不能省现象用户昨天被标成“性价比敏感”今天因为一条物流吐槽被标成“物流敏感”后天又跳回“性价比敏感”。标签来回跳运营无法信任画像。原因LLM只依赖输入文本判断而输入文本是最近几天的新事件。短窗口内行为噪声大且模型没有记忆能力输出会随最新一条文本剧烈波动。解决历史标签分数做平滑。新证据不能直接覆盖历史分数而是按比例融合。def smooth_tag_score(old: float, new: float, alpha: float 0.7) - float: 历史平滑alpha 是历史分数权重。 return alpha * old (1 - alpha) * new updated smooth_tag_score(old_score0.8, new_score0.3) if abs(updated - old_score) 0.15: write_tag(user_key, tag_name, updated)alpha0.7意味着单次新证据最多把标签从0.8拉到0.650.15的阈值恰好能挡住单次噪声。但同一个方向多次出现时平滑后的分数会持续累加最终完成翻转——这就是“动态”的真正含义标签变化要反映趋势而不是响应单次噪声。5.3 用户ID多源对不上id-mapping的设计与更新时机现象订单系统里一个“用户”和客服系统里的“联系人”拼接到宽表后出现两行同一个人的画像被劈成两半标签漏给或者给错。原因业务系统各自独立没有统一的user_key。订单系统用用户ID客服系统用手机号尾号加随机ID两边关联不上。解决建立统一的id-mapping表字段包含user_key, source_type, source_user_id, last_seen_at。合并规则要分强标识和弱标识。def merge_candidates(candidates: list[dict]) - str: 按强标识优先合并返回统一 user_key。 for c in candidates: if c.get(phone_md5) and phone_index.get(c[phone_md5]): return phone_index[c[phone_md5]] if c.get(email_md5) and email_index.get(c[email_md5]): return email_index[c[email_md5]] # 无强标识时生成新 user_key宁拆勿错 new_key generate_uuid() index_candidate(new_key, c) return new_key强标识已核验的手机号、邮箱匹配到就合并。弱标识设备ID、Cookie不单独作为合并依据至少要两个弱标识同时命中才考虑合并避免把两个家庭成员共用的一个平板算成同一个用户。更新时机上每次业务系统写入时做upsert每天凌晨对没有强标识的孤儿用户做一次弱标识扫描重估。5.4 画像推理成本失控增量重算与分层级联是止血手段现象上线两周LLM调用量是预估的7倍。查日志发现批处理脚本对全量用户每天做一次全量重算每个用户近90天的评论、订单、工单全部塞进提示词费用直线上升。原因没有增量策略也没有对文本做分级。部分用户一个月没有新行为仍然每天被重算一遍大量中性文本也不区分一律送进大模型。解决先把第4章的增量触发落地——没有新增文本就不调LLM。再加一层“分层级联”用轻量级规则或小模型先用关键词过滤明显中性的文本只有规则判断存在情绪表达或消费信号的样本才送大模型。成本能降到原来的十分之一。最后把同用户的多条短文本合并成一次请求而不是一句话一次调用。5.5 价值观推断触到合规红线白名单过滤与可验证标签现象画像系统给某用户标了“高收入、单身、易受深夜促销影响”运营据此在深夜推送营销信息用户投诉到平台说隐私被侵犯。原因模型从文本里自由推断出了超出业务授权范围的价值观标签下游运营直接使用了这些不受控标签。解决第4章的白名单过滤在这里必须严格执行。ALLOWED_VALUE_TAGS之外的所有标签一律拦截。处理投诉时调出模型原始输出、输入文本和过滤记录检查是模型自由发挥还是过滤层失效。这个排查链路要事先打通否则出了投诉你连问题出在哪个环节都不知道。6. 画像质量验证与召回校准用一致性评审和A/B测试让LLM标签可信6.1 人工评审抽样的关键参数模型标签不等于正确标签。我每次更新提示词版本后都会抽200条样本做人工评审。注意采样要按业务分层如果正面评论占90%随机抽200条可能只有20条负面模型负面识别能力根本验不出来。我通常按正、负、中性各占三分之一做分层抽样必要时对稀有类别做过采样。一致性用Cohens kappa衡量公式是(p0 - pe) / (1 - pe)其中p0是人工与模型的一致率pe是偶然一致率。kappa大于0.7说明标签可用0.5到0.7之间需要补示例、调提示词低于0.5说明任务设计有问题要先回头检查枚举定义是否清晰。不一致的样本是宝贵资产会回填到few-shot示例里形成持续改进闭环。6.2 A/B测试衡量画像对业务指标的真实影响画像做得再好最终要看业务指标是否有变化。常见实验设计是对照组用统一客服话术实验组按画像标签做个性化话术——对“性价比敏感”用户优先推送优惠信息对“品质敏感”用户讲材质和工艺。观察指标选客服一次性解决率和复购率。样本量用最小可检测提升来算。若想检测5%的提升在常见的显著性水平和功效参数下每组大约需要1.5万次会话。样本量不足时即使画像组指标没有显著提升也不能下结论说画像无效只能说明效果幅度小于可检测范围。等样本攒够再验证一次或者放大干预力度重新实验。我把这套系统跑上线后的习惯是每周保存一次画像快照和提示词版本。模型更新或提示词调整后一旦翻车还能回滚到上一版不至于让所有下游业务对着错误标签空转。做LLM画像系统最怕的不是模型不够聪明而是你无法度量它什么时候在认真工作、什么时候在胡编。有一套评审和回滚机制兜底这个系统才算真正能交给业务用。希望帮到你。本文还有配套的精品资源点击获取
返回列表