基于 LLM 的用户画像分析:通义千问 + Prompt Engineering 实践

本文范围: 只讨论 LLM 方法构建学生用户画像。在 outputs/cleaned/ 已清洗数据之上,调用通义千问生成结构化画像。不包含 原始清洗与规则画像方法。

摘要: 将学生学业、考勤、消费等指标组装为 Prompt,通过 DashScope 调用 qwen-plus,强制 JSON 输出,再解析为 CSV、画像卡片 txt 与统计图表。


一、为什么用 LLM 做用户画像

传统的学生画像方法主要依赖 规则引擎 + 统计阈值。例如,设定“平均分 < 60 → 成绩待提升”、“考勤异常 > 3次 → 行为需关注”等硬性规则。这种方式虽然稳定、可解释性强,但在面对复杂、多维的学生数据时,暴露出两个核心局限:

  1. 标签碎片化,缺乏整体叙事:规则生成的标签往往是孤立的(如“数学薄弱”、“消费偏高”),难以自动将这些点状信息串联成一个有逻辑、有故事线的完整学生画像。管理者看到的是一堆标签,而非一个立体的“人”。
  2. 难以生成深度的自然语言洞察:规则系统可以输出“是什么”(如“高风险”),但很难自动回答“为什么是这个画像”以及“下一步具体怎么做”。这部分的解读和报告撰写仍需大量人工介入,效率低下。

LLM(大语言模型)的引入,正是为了弥补这些短板。 大模型的核心能力在于 理解结构化数据、进行综合推理、并生成连贯的自然语言结论。在本实践中,我们构建的核心链路是:

清洗后的学生指标 → Prompt 设计 → 通义千问 API → JSON 解析 → 画像卡片 + 图表

这条链路的优势在于:

  • 整体性分析:LLM 能同时考虑学业、行为、消费等多个维度,输出一个综合性的评价(如“艺体特长但理科基础薄弱的波动型学习者”),而非一堆割裂的标签。
  • 可解释的叙事:通过精心设计的 Prompt,可以要求模型不仅给出结论,还要提供推理依据和个性化的改进建议,生成一段120-180字的“完整画像描述”,极大提升了报告的可读性和 actionable insight(可执行洞察)。
  • 灵活适配:当分析维度或评价标准需要调整时,通常只需修改 Prompt 指令,而无需重写复杂的规则代码,迭代成本更低。

因此,LLM 并非要取代传统的数据清洗与特征工程,而是作为其之上的“认知层”,将冰冷的数据转化为有温度、有逻辑、可直接用于沟通和决策的叙事报告。

二、整体架构

outputs/cleaned/student_profile.csv
outputs/cleaned/clean_score.csv
        ↓
load_student_features()        # 补偏科指数、分科摘要、日均消费等
        ↓
build_student_prompt()         # Prompt:角色 + 数据 + 任务 + JSON 格式
        ↓
call_qwen()                    # DashScope 调用 qwen-plus
        ↓
_extract_json() / _normalize_result()
        ↓
format_portrait_card()         # 生成可读 txt 卡片
        ↓
student_portrait_qwen.csv
student_portrait_qwen_cards.txt
outputs/analysis/qwen_figures/

对应脚本:qwen_portrait.py


三、输入数据

LLM 读的是 学生级宽表,不是原始流水。主要字段:

维度字段用途
学籍姓名、班级、性别画像抬头
学业平均成绩、成绩标准差、偏科指数学业等级、学习态度
分科subject_summary学科特征(优势/薄弱科目)
考勤迟到、早退、考勤异常合计行为模式
消费日均消费、消费次数生活规律

其中 subject_summary 由程序从成绩表自动生成,例如:

相对优势学科:音乐(90.0分)、美术(82.0分)、英语(62.3分);
相对薄弱学科:地理(49.6分)、体育(19.2分)、技术(13.9分)

对应代码(节选):

def _build_subject_summary(student_id, score_df):
    sub = score_df[(score_df["bf_StudentID"] == student_id) & score_df["mes_Score"].notna()]
    means = sub.groupby("mes_sub_name")["mes_Score"].mean().sort_values(ascending=False)
    top = "、".join(f"{n}({s:.1f}分)" for n, s in means.head(3).items())
    bottom = "、".join(f"{n}({s:.1f}分)" for n, s in means.tail(3).items())
    return f"相对优势学科:{top};相对薄弱学科:{bottom}"

四、Prompt 设计

采用 「角色 + 数据 + 任务 + JSON 格式」 四段式。

角色: 熟悉学生管理与学业诊断的数据分析专家。

输出字段:

字段含义
academic_level学业等级
subject_profile学科特征
learning_attitude学习态度
behavior_pattern行为模式
strengths / weaknesses优势 / 待改进
suggestions建议
full_portrait120~180 字完整描述
portrait_tags3~5 个短标签
qwen_risk_level低/中/高风险

JSON 输出示例:

{
  "academic_level": "中等偏下",
  "subject_profile": "偏艺体型,音乐美术突出,技术体育薄弱",
  "learning_attitude": "成绩波动大,专注度不够稳定",
  "behavior_pattern": "消费规律,偶有考勤异常",
  "strengths": ["艺术感知力强", "消费自律"],
  "weaknesses": ["理科基础薄弱", "成绩波动大"],
  "suggestions": ["补足薄弱学科基础", "建立周复盘机制"],
  "full_portrait": "一段完整画像描述...",
  "portrait_tags": ["艺体特长", "波动型学习者"],
  "qwen_risk_level": "中风险"
}

Prompt 构建思路(节选):

def build_student_prompt(row):
    fields = [
        ("姓名", row["bf_Name"]), ("班级", row["cla_Name"]),
        ("平均成绩", row["avg_score"]), ("成绩标准差", row["score_std"]),
        ("分科情况", row["subject_summary"]),
        ("考勤异常次数", row["attendance_abnormal"]),
        ("日均消费", row["daily_avg_spend"]),
    ]
    student_block = "\n".join(f"{k}: {v}" for k, v in fields)
    return f"你是学生管理分析专家...\n【学生数据】\n{student_block}\n...仅输出 JSON..."

五、通义千问 API 调用

import dashscope
from dashscope import Generation

dashscope.api_key = os.getenv("DASHSCOPE_API_KEY")

response = Generation.call(
    model="qwen-plus",
    messages=[{"role": "user", "content": prompt}],
    result_format="message",
    temperature=0.3,
)
content = response.output.choices[0].message.content

说明:

  • temperature=0.3:输出更稳定;
  • API Key 写在 .envDASHSCOPE_API_KEY=sk-xxx
  • 支持批量并发:python qwen_portrait.py --limit 30 --batch-size 3 --workers 3

六、JSON 解析与字段标准化

模型返回可能是纯 JSON,也可能带 markdown 包裹,需要容错:

def _extract_json(text):
    text = text.strip()
    fence = re.search(r"```(?:json)?\s*([\s\S]*?)\s*```", text)
    if fence:
        text = fence.group(1).strip()
    return json.loads(text)

def _normalize_result(raw):
    return {
        "qwen_academic_level": raw.get("academic_level", ""),
        "qwen_subject_profile": raw.get("subject_profile", ""),
        "qwen_learning_attitude": raw.get("learning_attitude", ""),
        "qwen_behavior_pattern": raw.get("behavior_pattern", ""),
        "qwen_strengths": "、".join(raw.get("strengths", [])),
        "qwen_weaknesses": "、".join(raw.get("weaknesses", [])),
        "qwen_suggestions": ";".join(raw.get("suggestions", [])),
        "qwen_full_portrait": raw.get("full_portrait", ""),
        "qwen_risk_level": raw.get("qwen_risk_level", ""),
    }

七、画像卡片输出

解析后生成两类产物:

1. CSV: student_portrait_qwen.csv(结构化字段,便于统计)
在这里插入图片描述

2. TXT 卡片: student_portrait_qwen_cards.txt
在这里插入图片描述

格式化逻辑(节选):

def format_portrait_card(record):
    lines = [
        f"学生: {record['bf_Name']}{record['bf_sex']}{record['cla_Name']})",
        f"均分: {record['avg_score']:.1f} | 考勤异常: {record['attendance_abnormal']}次",
        f"  学业等级: {record['qwen_academic_level']}",
        f"  学科特征: {record['qwen_subject_profile']}",
        f"  学习态度: {record['qwen_learning_attitude']}",
        f"  行为模式: {record['qwen_behavior_pattern']}",
        f"  优势: {record['qwen_strengths']}",
        f"  待改进: {record['qwen_weaknesses']}",
        f"  建议: {record['qwen_suggestions']}",
        f"  【完整画像描述】\n  {record['qwen_full_portrait']}",
    ]
    return "\n".join(lines)

真实输出示例(脱敏):

学生: 陈某某(女,白-高二(01))
均分: 56.47 | 考勤异常: 2次 | 日均消费: 10.09元

  学业等级: 待提升
  学科特征: 显著偏艺体型,音乐、美术优势突出,技术体育薄弱
  学习态度: 成绩波动剧烈,学习状态不够稳定
  行为模式: 消费规律,偶有考勤异常
  优势: 艺术感知力强、消费自律
  待改进: 核心学科低于及格线、缺考次数偏多
  建议: 补足技术地理基础;建立周复盘机制

  【完整画像描述】
  陈某某整体学业待提升,但艺术禀赋突出。技术仅13.9分,
  成绩标准差高达34.65,说明学习状态起伏大。消费与考勤整
  体可控,建议聚焦基础补缺与学习节奏重建。

  风险等级: 中风险
  画像标签: 艺体特长生、基础薄弱型、波动型学习者

八、可视化

基于 LLM 结果自动生成 14 张图,目录:outputs/analysis/qwen_figures/

文件说明
风险分布01_qwen_risk_distribution_pie.png低/中/高风险占比
学业等级02_academic_level_pie.png学业等级分布
待改进主题05_weakness_themes_bar.png偏科、波动等主题
成绩-风险07_score_risk_scatter.png成绩与波动散点
画像卡片图11_sample_portrait_card.pngtxt 卡片渲染成图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

只重新出图:

python qwen_portrait.py --plots-only

九、如何复现

pip install dashscope python-dotenv pandas matplotlib

# 1. 清洗数据
python clean.py

# 2. 跑 LLM 画像(默认 30 人)
python qwen_portrait.py

# 3. 小样本试跑
python qwen_portrait.py --limit 5 --batch-size 1

# 4. 不调 API,看格式
python qwen_portrait.py --mock --limit 2

.env 配置:

DASHSCOPE_API_KEY=你的密钥

十、方法小结

环节做法
Prompt 设计角色 + 结构化数据 + JSON 约束
LLM 推理通义千问 qwen-plus
结构化输出JSON → CSV
画像卡片格式化 txt + 图片渲染
可视化14 类统计图

十一、结语

基于 LLM 的用户画像,不是让大模型替代数据工程,而是:

Python 准备事实 → Prompt 规定分析方式 → JSON 接回系统 → 卡片与图表呈现给人看。

完整实现见 qwen_portrait.py


声明:文中学生姓名与数据均已脱敏,仅用于技术学习与交流。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐