# 客户画像自动生成与丰满技术方案 > 版本: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 customerIds, LocalDateTime msgSince); // 合并更新建议到现有画像 public void applyUpdates(String customerId, String corpId, List 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 GET /api/v1/admin/profiles/{customerId}/logs 响应: List ``` ### 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. **稳定性**:同一组对话多次调用,结果是否一致 测试通过后再进入开发阶段,可大幅减少返工。