agent_9art/product1.0/v3-客户画像自动生成方案.md
jiao bd9920ca24 feat: 实现客户画像自动生成功能
1. 新增客户画像生成相关实体、Mapper、Service和控制器
2. 扩展CustomerProfile实体字段,增加自动生成标记相关属性
3. 新增画像生成日志表和相关业务逻辑
4. 前端客户列表页面增加画像管理Tab和批量生成功能
5. 补充完整的客户画像自动生成方案文档
2026-06-08 10:01:49 +08:00

23 KiB
Raw Blame History

客户画像自动生成与丰满技术方案

版本:v3.0
日期:2026-06-05
状态:设计稿,待评审


一、背景与痛点

1.1 当前画像体系

组件 现状
customer_profiles 表 已有完整字段,但主要靠销售顾问在 sidebar 手动录入
archive_messages 表 沉淀了大量学员对话,尚未用于画像挖掘
ProfileCard.tsx 录入表单只有基础字段(职业、学员类型、基础水平、意向度),其余字段为空
LLM 自动分析 未实现,代码里留了 TODO:"录入基础信息后,系统将通过会话存档自动完善画像"

1.2 核心痛点

  1. 老客户画像缺失:系统上线前已有大量客户,他们从未被人工录入画像,但 archive_messages 中有丰富对话
  2. 画像不够丰满:人工录入只覆盖 4-5 个字段,大量高价值字段(关注点、决策阶段、兴趣课程、预算暗示)为空
  3. 画像更新滞后:客户状态会变化(如从"初步了解"到"方案比较"),人工不会每次手动更新
  4. 顾问负担重:每个客户都要手动填表单,效率低且标准不统一

二、目标

  1. 批量自动生成:为所有有对话记录的老客户自动生成初始画像
  2. 持续自动丰满:每次新会话后,自动分析增量信息并更新画像
  3. 可解释性:每个画像字段标注来源(哪条对话、什么时间点)和置信度
  4. 人工可干预:顾问可修正自动生成的画像,修正后优先级高于 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,验证以下指标:

  1. 准确率:LLM 提取的画像字段,与人工阅读对话后的判断一致率
  2. 召回率:人工能看出的信息,LLM 是否都提取到了
  3. 幻觉率:LLM 是否生成了对话中没有的信息
  4. 稳定性:同一组对话多次调用,结果是否一致

测试通过后再进入开发阶段,可大幅减少返工。