1. 新增客户画像生成相关实体、Mapper、Service和控制器 2. 扩展CustomerProfile实体字段,增加自动生成标记相关属性 3. 新增画像生成日志表和相关业务逻辑 4. 前端客户列表页面增加画像管理Tab和批量生成功能 5. 补充完整的客户画像自动生成方案文档
23 KiB
23 KiB
客户画像自动生成与丰满技术方案
版本:v3.0
日期:2026-06-05
状态:设计稿,待评审
一、背景与痛点
1.1 当前画像体系
| 组件 | 现状 |
|---|---|
customer_profiles 表 |
已有完整字段,但主要靠销售顾问在 sidebar 手动录入 |
archive_messages 表 |
沉淀了大量学员对话,尚未用于画像挖掘 |
ProfileCard.tsx |
录入表单只有基础字段(职业、学员类型、基础水平、意向度),其余字段为空 |
| LLM 自动分析 | 未实现,代码里留了 TODO:"录入基础信息后,系统将通过会话存档自动完善画像" |
1.2 核心痛点
- 老客户画像缺失:系统上线前已有大量客户,他们从未被人工录入画像,但 archive_messages 中有丰富对话
- 画像不够丰满:人工录入只覆盖 4-5 个字段,大量高价值字段(关注点、决策阶段、兴趣课程、预算暗示)为空
- 画像更新滞后:客户状态会变化(如从"初步了解"到"方案比较"),人工不会每次手动更新
- 顾问负担重:每个客户都要手动填表单,效率低且标准不统一
二、目标
- 批量自动生成:为所有有对话记录的老客户自动生成初始画像
- 持续自动丰满:每次新会话后,自动分析增量信息并更新画像
- 可解释性:每个画像字段标注来源(哪条对话、什么时间点)和置信度
- 人工可干预:顾问可修正自动生成的画像,修正后优先级高于 AI 结果
三、数据模型
3.1 现有表 customer_profiles(已有)
CREATE TABLE customer_profiles (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
customer_id VARCHAR(64) NOT NULL COMMENT '客户ID(企微external_userid)',
corp_id VARCHAR(64) NOT NULL,
-- 基础画像(当前已有)
student_type VARCHAR(50) COMMENT '学员类型: 在校大学生/转行人员/在职提升/高中毕业生/家长代询',
student_type_confidence DOUBLE DEFAULT 0 COMMENT '置信度 0-1',
skill_level VARCHAR(50) COMMENT '基础水平: 零基础/有美术基础/相关专业/有从业经验',
skill_level_confidence DOUBLE DEFAULT 0,
intent_level VARCHAR(20) COMMENT '意向度: 高/中/低',
intent_score DOUBLE DEFAULT 0 COMMENT '意向分数 0-100',
concern_focus VARCHAR(50) COMMENT '关注点: 就业导向型/兴趣导向型/价格敏感型/品质导向型',
concern_focus_confidence DOUBLE DEFAULT 0,
decision_stage VARCHAR(50) COMMENT '决策阶段: 初步了解/方案比较/决定报名/已报名',
decision_stage_confidence DOUBLE DEFAULT 0,
interested_courses TEXT COMMENT '兴趣课程 JSON数组',
budget_hint VARCHAR(200) COMMENT '预算暗示',
preferred_city VARCHAR(50) COMMENT '意向城市',
age INT COMMENT '年龄',
education VARCHAR(50) COMMENT '学历',
current_occupation VARCHAR(100) COMMENT '当前职业/名称',
-- 元数据(当前已有)
slot_data TEXT COMMENT '槽位数据 JSON',
conversation_count INT DEFAULT 0 COMMENT '会话次数',
last_conversation_time TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_customer_corp (customer_id, corp_id),
INDEX idx_corp_id (corp_id),
INDEX idx_updated_at (updated_at)
) ENGINE=InnoDB COMMENT='客户画像表';
3.2 新增表 profile_generation_logs(建议新增)
记录每次画像生成的来源和变更,用于审计和可解释性。
CREATE TABLE profile_generation_logs (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
customer_id VARCHAR(64) NOT NULL,
corp_id VARCHAR(64) NOT NULL,
generation_type VARCHAR(20) NOT NULL COMMENT '生成类型: BATCH_FULL/INCREMENTAL/MANUAL',
source_msg_count INT DEFAULT 0 COMMENT '分析的消息条数',
source_session_count INT DEFAULT 0 COMMENT '分析的会话数',
analyzed_at TIMESTAMP NOT NULL COMMENT '分析时间',
llm_model VARCHAR(50) COMMENT '使用的模型',
llm_prompt_length INT COMMENT 'Prompt长度',
llm_response_length INT COMMENT 'Response长度',
duration_ms INT COMMENT '耗时毫秒',
success TINYINT DEFAULT 1 COMMENT '是否成功',
error_msg TEXT COMMENT '错误信息',
-- 变更快照(JSON):记录哪些字段发生了变化
changes_snapshot TEXT COMMENT '{"studentType":{"old":"未知","new":"在校大学生","confidence":0.85}}',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_customer (customer_id, corp_id),
INDEX idx_analyzed_at (analyzed_at)
) ENGINE=InnoDB COMMENT='画像生成日志';
3.3 字段置信度规则
| 置信度区间 | 含义 | 前端展示 |
|---|---|---|
| 0.85 ~ 1.0 | 高置信 | 绿色标签,不提示 |
| 0.60 ~ 0.84 | 中置信 | 橙色标签,hover 提示"AI推测,建议确认" |
| 0.30 ~ 0.59 | 低置信 | 灰色标签,hover 提示"信息不足,建议补充" |
| 0 ~ 0.29 | 未知 | 显示"未知",引导录入 |
四、LLM Prompt 设计
4.1 全量画像生成 Prompt
适用场景:首次为老客户生成画像,输入该客户全部历史对话
你是一位专业的教育培训机构客户分析师。请根据以下学员与课程顾问的完整对话历史,提取学员画像信息。
【分析要求】
1. 仔细阅读所有对话,从中提取学员的真实情况和需求
2. 不要凭空猜测,只提取对话中有明确证据支撑的信息
3. 如果某个字段在对话中没有足够证据,请标记为"未知"并给出低置信度
4. 对于同一字段的多个线索,综合判断取最可靠的结论
5. 注意识别"家长代询"的情况(对话中出现"我孩子"、"我家"等表述)
【对话历史】
{conversation_text}
【输出格式】
必须严格返回以下JSON格式,不要包含任何其他文字:
{
"studentType": {"value": "", "confidence": 0, "evidence": ""},
"skillLevel": {"value": "", "confidence": 0, "evidence": ""},
"intentLevel": {"value": "", "confidence": 0, "evidence": ""},
"intentScore": {"value": 0, "confidence": 0, "evidence": ""},
"concernFocus": {"value": "", "confidence": 0, "evidence": ""},
"decisionStage": {"value": "", "confidence": 0, "evidence": ""},
"interestedCourses": {"value": [], "confidence": 0, "evidence": ""},
"budgetHint": {"value": "", "confidence": 0, "evidence": ""},
"preferredCity": {"value": "", "confidence": 0, "evidence": ""},
"age": {"value": null, "confidence": 0, "evidence": ""},
"education": {"value": "", "confidence": 0, "evidence": ""},
"currentOccupation": {"value": "", "confidence": 0, "evidence": ""},
"summary": "", // 用一句话总结这个学员
"keyQuotes": [] // 提取3-5条最能代表学员需求的原话
}
【字段枚举值】
- studentType: 在校大学生/转行人员/在职提升/高中毕业生/家长代询/未知
- skillLevel: 零基础/有美术基础/相关专业/有从业经验/未知
- intentLevel: 高/中/低
- concernFocus: 就业导向型/兴趣导向型/价格敏感型/品质导向型/未知
- decisionStage: 初步了解/方案比较/决定报名/已报名/未知
- interestedCourses: 从对话中提取的课程名称数组,如["3D场景UE地编","次世代角色模型"]
- education: 高中/大专/本科/硕士/博士/未知
【置信度评分标准】
- 0.90-1.00: 学员明确亲口说过(如"我是大学生")
- 0.70-0.89: 有较强暗示或多处线索一致
- 0.50-0.69: 有一处间接线索
- 0.30-0.49: 只有微弱暗示
- 0.00-0.29: 没有任何线索
4.2 增量画像更新 Prompt
适用场景:客户已有画像,分析新增对话后生成更新建议
你是一位客户画像更新分析师。请根据学员的【现有画像】和【新增对话】,判断哪些字段需要更新。
【现有画像】
{current_profile_json}
【新增对话】
{new_conversation_text}
【分析要求】
1. 对比新增对话与现有画像,识别变化
2. 如果新增对话推翻了现有画像的某个结论,建议更新
3. 如果新增对话补充了空白字段,建议填充
4. 如果现有画像已高置信且新增对话无冲突,保持不动
5. 特别关注决策阶段的变化(这是最重要的更新信号)
【输出格式】
{
"updates": [
{
"field": "decisionStage",
"oldValue": "初步了解",
"newValue": "方案比较",
"confidence": 0.85,
"reason": "学员主动询问课程安排和就业情况,表明已进入比较阶段",
"shouldUpdate": true
}
],
"newInsights": [
{
"field": "budgetHint",
"value": "预算约2万",
"confidence": 0.72,
"evidence": "学员提到\"两万左右的课程\""
}
],
"intentChange": {
"oldScore": 55,
"newScore": 72,
"reason": "学员开始询问具体报名流程"
}
}
4.3 对话格式化(输入预处理)
将 archive_messages 按时间排序,格式化为 LLM 可读的对话文本:
【会话 1】2025-05-20 14:30
员工(小王): 您好,请问有什么可以帮您?
学员(张三): 我想了解一下你们的美术课程
...
【会话 2】2025-05-21 10:15
员工(小王): 张同学,昨天说的课程资料发给您了
学员(张三): 看到了,我想问一下学费多少
...
截断策略:
- 单客户对话总长度超过 8000 字时,优先保留最近 6 个月的对话
- 若仍超限,保留最近 10 次会话的完整内容
- 若仍超限,对每条消息截取前 200 字
五、系统架构
5.1 整体架构图
┌─────────────────────────────────────────────────────────────────┐
│ Admin 后台 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ 画像生成任务 │ │ 画像列表/搜索 │ │ 单客户画像详情+编辑 │ │
│ │ (批量触发) │ │ │ │ (含变更历史) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────────┬───────────┘ │
└─────────┼─────────────────┼─────────────────────┼──────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ intent-service (画像服务) │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────┐ │
│ │ ProfileGeneration │ │ ProfileMerge │ │ ProfileQuery │ │
│ │ Service │ │ Service │ │ Service │ │
│ │ (LLM调用+解析) │ │ (置信度合并) │ │ (CRUD) │ │
│ └────────┬─────────┘ └────────┬─────────┘ └──────┬───────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 定时任务: DailyProfileUpdateJob │ │
│ │ (每天凌晨扫描昨日有新增对话的客户,触发增量分析) │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ generation-service (LLM) │
│ ┌────────────┐ ┌────────────┐ │
│ │ 全量生成 │ │ 增量更新 │ │
│ │ /generate │ │ /generate │ │
│ └────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 数据库 │
│ ┌────────────────────┐ ┌────────────────────┐ ┌──────────┐ │
│ │ customer_profiles │ │ profile_generation │ │ customers│ │
│ │ (画像主表) │ │ _logs (生成日志) │ │ (客户基础)│ │
│ └────────────────────┘ └────────────────────┘ └──────────┘ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ archive_messages (会话存档,通过 JDBC 查询,非本服务表) │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
5.2 核心服务类设计
@Service
public class ProfileGenerationService {
// 全量生成:为指定客户从历史对话生成完整画像
public GenerationResult generateFullProfile(String customerId, String corpId);
// 增量更新:分析新增对话,生成更新建议
public IncrementalResult generateIncrementalUpdate(String customerId, String corpId,
LocalDateTime since);
// 批量生成:为多个客户批量生成画像(带进度追踪)
@Async
public void batchGenerate(String corpId, List<String> customerIds,
LocalDateTime msgSince);
// 合并更新建议到现有画像
public void applyUpdates(String customerId, String corpId,
List<FieldUpdate> updates);
}
六、画像合并策略
6.1 置信度加权合并
现有值: V_old, 置信度 C_old
新值: V_new, 置信度 C_new
如果 V_new == V_old:
合并后置信度 = 1 - (1 - C_old) * (1 - C_new * 0.5)
// 相同值时置信度提升,但边际递减
如果 V_new != V_old:
if C_new > C_old + 0.15:
采用新值,置信度 = C_new
else if C_new > C_old:
保持旧值,置信度 = C_old + (C_new - C_old) * 0.3
else:
保持旧值
6.2 特殊字段规则
| 字段 | 合并规则 |
|---|---|
intentScore |
新对话可能推高或拉低,直接采用增量分析的评分,但限制单次变化不超过 ±20 分 |
intentLevel |
基于 intentScore 映射:≥70→高, 40-69→中, <40→低 |
decisionStage |
只能正向推进(初步了解→方案比较→决定报名→已报名),不能回退 |
interestedCourses |
合并数组,去重,新课程追加到末尾 |
age |
数值型,取最新高置信度值 |
conversationCount |
直接累加 |
lastConversationTime |
取最新时间 |
七、接口设计
7.1 Admin 后台接口(新增)
POST /api/v1/admin/profiles/generate/batch
请求: { corpId, customerIds?: string[], timeRange?: [start, end],
onlyMissing?: boolean }
响应: { taskId, message }
GET /api/v1/admin/profiles/generate/tasks/{taskId}/progress
响应: { taskId, status, total, completed, successCount, failCount }
GET /api/v1/admin/profiles
请求: { corpId, keyword?, hasProfile?, page, size }
响应: PageResult<CustomerProfileVO>
GET /api/v1/admin/profiles/{customerId}/logs
响应: List<ProfileGenerationLog>
7.2 Sidebar 接口(复用+扩展)
GET /api/v1/intent/profiles/{customerId} (已有)
响应增加字段:
- autoGenerated: boolean (是否AI生成)
- lastGeneratedAt: timestamp
- fieldSources: { "studentType": "AI分析(置信度0.85)", "age": "人工录入" }
POST /api/v1/intent/profiles (已有,人工修正)
请求增加字段:
- manualOverride: boolean (标记为人工修正,置信度设为1.0)
八、前端设计
8.1 Admin 后台新增「客户画像」页面
页面结构:
┌─────────────────────────────────────────┐
│ 客户画像管理 │
├─────────────────────────────────────────┤
│ [搜索框] [筛选: 已生成/未生成/全部] [批量生成] │
├─────────────────────────────────────────┤
│ 客户列表 │
│ ┌────┬────────┬──────────┬────────────┐ │
│ │姓名│学员类型│意向度 │画像来源 │ │
│ │ │(AI) │高(85分) │AI生成 ✓ │ │
│ │ │(人工) │中(60分) │人工录入 │ │
│ │ │(未生成)│- │点击生成 │ │
│ └────┴────────┴──────────┴────────────┘ │
├─────────────────────────────────────────┤
│ 点击行 → 弹出画像详情 + 编辑 │
│ - 每个字段显示: 值 + 置信度条 + 来源 │
│ - AI生成的字段可人工覆盖 │
│ - 显示变更历史时间线 │
└─────────────────────────────────────────┘
8.2 Sidebar ProfileCard 增强
┌─────────────────────────────────┐
│ 张同学 (AI生成 · 3小时前更新) │
├─────────────────────────────────┤
│ 意向度: 高(82分) ▓▓▓▓▓▓▓▓░░ │
│ 学员类型: 在校大学生 ✓ │
│ 基础水平: 有美术基础 ~ │
│ 关注点: 就业导向型 ✓ │
│ 决策阶段: 方案比较 → │
│ 兴趣课程: UE地编, 角色模型 │
│ 预算: 2-3万 ~ │
│ 意向城市: 上海 ✓ │
├─────────────────────────────────┤
│ [编辑] [查看分析来源] │
└─────────────────────────────────┘
图例: ✓ 高置信 ~ 中置信 ? 低置信/未知
九、实施计划
Phase A:基础设施(1-2 天)
- 新增
profile_generation_logs表 - 在 intent-service 新增
ProfileGenerationService骨架 - 新增
CustomerProfile字段:autoGenerated,lastGeneratedAt,generatedBy - 新增
ProfileGenerationController(Admin 后台接口)
Phase B:全量生成(2-3 天)
- 实现
generateFullProfile():对话聚合 → Prompt 构建 → LLM 调用 → 结果解析 - 实现
batchGenerate():异步批量任务,带进度追踪 - Admin 后台「批量生成」页面
- 为小范围客户(如 10-20 个)试运行,人工校验 LLM 输出质量
- 根据校验结果优化 Prompt
Phase C:增量更新(2 天)
- 实现
generateIncrementalUpdate():增量对话分析 - 实现合并策略(置信度加权 + 特殊字段规则)
- 新增定时任务
DailyProfileUpdateJob(每天凌晨执行) - 画像变更时发送通知(可选:推送到 sidebar 提醒顾问)
Phase D:前端增强(2 天)
- Admin 后台「客户画像」完整页面(列表 + 详情 + 编辑 + 变更历史)
- Sidebar ProfileCard 增强(置信度可视化、来源标注、变更提示)
- 画像生成任务进度页面
十、风险与应对
| 风险 | 影响 | 应对策略 |
|---|---|---|
| LLM 调用成本高 | 每月可能产生数百元 API 费用 | 首次全量控制范围(先活跃客户);增量只分析有变化的用户;使用本地缓存避免重复分析 |
| LLM 输出不稳定 | 画像质量参差不齐 | Prompt 加 Few-shot 示例;输出后做枚举值校验;低置信度字段不展示 |
| 隐私合规 | 对话内容含敏感信息 | LLM 调用时不传输客户真实姓名/手机号;分析结果脱敏存储;保留审计日志 |
| 顾问不信任 AI 结果 | 不愿使用 | 高置信度字段默认采用,低置信度标记为"待确认";提供一键采纳/拒绝交互 |
十一、预期效果
| 指标 | 现状 | 目标 |
|---|---|---|
| 有画像的客户占比 | ~10%(人工录入) | ≥80%(AI 生成 + 人工) |
| 画像字段完整度 | 平均 3-4 个字段有值 | 平均 8-10 个字段有值 |
| 画像更新频率 | 几乎不更新 | 每次新会话后自动更新 |
| 顾问录入时间 | 每个客户 2-3 分钟 | 仅需确认/修正,30 秒 |
附录:Prompt 测试建议
在正式开发前,建议先用 5-10 个真实客户的对话手动测试 Prompt,验证以下指标:
- 准确率:LLM 提取的画像字段,与人工阅读对话后的判断一致率
- 召回率:人工能看出的信息,LLM 是否都提取到了
- 幻觉率:LLM 是否生成了对话中没有的信息
- 稳定性:同一组对话多次调用,结果是否一致
测试通过后再进入开发阶段,可大幅减少返工。