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

507 lines
23 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 客户画像自动生成与丰满技术方案
> 版本: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`(已有)
```sql
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`(建议新增)
记录每次画像生成的来源和变更,用于审计和可解释性。
```sql
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 核心服务类设计
```java
@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. **稳定性**:同一组对话多次调用,结果是否一致
测试通过后再进入开发阶段,可大幅减少返工。