打造AI数字人:从微信聊天记录到个性化大模型微调全流程指南(数字生命案例)
【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调(全参数/Lora)、部署国内外开源大模型(LLM)/多模态大模型(MLLM)教程项目地址: https://gitcode.com/GitHub_Trending/se/self-llm
本指南以 self-llm 仓库中 examples/数字生命/readme.md 案例为核心,完整讲解"以本人为原型、用真实聊天数据微调出 AI 数字人"的可迁移流程。整个流程分为三大环节:聊天记录数据集的制作与精修、基于讯飞星辰 MaaS 平台的 LoRA 微调、通过 WebSocket 调用微调模型 API 并搭建聊天前端。读完本文,你将掌握从"原始聊天记录"到"可交互 AI 数字人"的端到端实战方案,并理解其中数据集清洗、超参数选择与人格化建模的关键细节。
项目背景:为什么需要"灵魂分身"
现代生活节奏加快,许多人因工作繁忙或地理距离难以时常陪伴家人与朋友,情感上的疏离感日益加剧。AI 情感陪伴类产品因此应运而生,但现有服务普遍存在三大痛点:
- 定制化成本高昂:针对特定个体定制人格的服务难以普及;
- 信息安全难保障:用户隐私数据存在泄露风险;
- 人格化缺失:通用模型的回复容易"出戏",缺乏亲近感。
对此,本项目给出的思路是在角色扮演场景下进行模型微调。微调是在预训练模型基础上的再学习——模型本身已经具备较强的文本理解、逻辑与泛化能力,只需要注入特定人物的个性风格数据,就能较好地扮演目标角色。整个流程可迁移、可复制,而其中最大的亮点正是数据集的制作。
该项目曾获 2024 大模型微调挑战赛(冬季赛)最佳创意奖 Top3,仓库介绍见 examples/readme.md。
第一步:数据集的制作——从微信聊天记录到 ShareGPT 格式
数据集是 AI 数字人的"灵魂素材"。本项目的思路是:把真实的微信聊天记录导出为 JSON,再清洗、精修并转换为适用于多轮对话训练的 ShareGPT 格式。
1.1 获取原始数据:微信聊天记录导出
首先在电脑端登录微信并同步聊天信息,然后借助"留痕"(MemoTrace)工具导出与某位朋友的聊天记录,将聊天内容导出为 JSON 格式保存至本地。导出的原始数据包含conversations、role、content三个核心字段。
1.2 转换为 ShareGPT 格式
为了让模型更好地学习对话模式,需要将原始 JSON 转换为 ShareGPT 格式。参考的转换思路如下:
# -*- coding: utf-8 -*- import json from copy import deepcopy # 标准化角色命名 def convert_to_sharegpt_format(original_data, new_system_value=None): sharegpt_data = [] for conversation in original_data: new_conversation = { "conversations": [], "system": new_system_value, "tools": "[]" # 如果没有工具调用,可以留空或设置为空列表 } system_message = None for msg in conversation["conversations"]: # if msg["role"] == "system": # system_message = msg["content"] if msg["role"] == "user": new_conversation["conversations"].append({ "from": "human", "value": clean_content(msg["content"]) }) elif msg["role"] == "assistant": new_conversation["conversations"].append({ "from": "gpt", "value": clean_content(msg["content"]) }) # 如果原始数据中已存在 "role": "system" 的消息,其内容会优先用于设置新对话的 "system" 字段, # 即使传入了 new_system_value 参数也会被覆盖。 # # 将系统消息设置为system字段 # if system_message: # new_conversation["system"] = system_message sharegpt_data.append(new_conversation) return sharegpt_data # 读取原始JSON数据 with open('z.json', 'r', encoding='utf-8') as f: original_data = json.load(f) # 添加优化系统提示词,可以理解为人设前提 new_system_value = "你是(替换为主角名字,人设),对你来说,他人的需求感受在自己之前。此外,你很喜欢倾听......" sharegpt_formatted_data = convert_to_sharegpt_format(original_data, new_system_value) # 写入新的JSON文件 with open('sharegpt_formatted_data.json', 'w', encoding='utf-8') as f: json.dump(sharegpt_formatted_data, f, ensure_ascii=False, indent=2) print("数据转换完成并保存为 sharegpt_formatted_data.json")选择 ShareGPT 格式的原因有三点:
- 天然适配多轮对话训练,比单轮问答格式更适合角色扮演场景;
- 规范了角色命名(
human/gpt),便于模型理解对话双方身份,一定程度上避免混淆与幻觉; - 便于人设完善补充:通过
system字段注入系统提示词作为"人设前提"。
实际操作中有几个必须注意的坑:
- 记得修改
system的值(替换为主角名字与人设描述); - 记得修改文件保存路径;
- 务必对数据集做敏感信息脱敏(包括电话、密码、地址等),这一点至关重要。
1.3 数据集的"人格化"精修技巧
本项目的数据集有两个特别的优化点,值得保留参考:
- 保留颜文字与表情包文字:例如
[委屈]这类由表情包转成的文字被原样保留。实验证明,这有助于大模型理解话语的情感色彩特征并模仿个性化的表达方式——微调后的模型能根据语境适时配上颜文字和表情包返回给用户; - 改写 MBTI 思维数据集:将自己对应 MBTI 人格的思维数据集按照聊天信息的形式改写,把一些有代表性的问题场景改编成对话加入数据集,便于模型捕捉角色思维模式的特征。
此外还需要对对话片段不完整的数据进行筛选处理,包括补充对话、删除话题跳跃的片段等。本项目约 3000 条数据中,很多话题跳跃严重,需要人为再清洗:对于会给模型带来较大理解难度的跳跃片段直接去除;对于某些存在跳跃但有价值的对话,则添加适当的背景信息,帮助模型建立正确的语境。
更进一步,可以尝试接入对话情绪色彩判断的 API,为数据添加情感标签,或为角色描述添加性格特点、职业背景、兴趣爱好等特征标签,都有利于 AI 数字人的人性化、个性化,示例如下:
{ "from": "gpt", "value": "学会了吗[笑]?", "character_traits": { "personality": "聪明、热情、善良", "occupation": "程序员", "interests": ["编程", "阅读", "旅行"] } }为什么选择聊天记录做数据集?日常交流中的大量细节——语气、口头禅、情感表达习惯——会逐渐在脑海中描摹出一个人的模样。让模型学一个人、模仿一个人,本质上就是在这些细节里磨炼,聊天记录无疑是造就"灵魂分身"最好的模板。
1.4 与本仓库其他数据集的对照
本仓库 dataset/ 目录下提供了同类案例的成品数据集,可以作为格式参考:
- dataset/huanhuan.json:Chat-嬛嬛项目的数据集(18647 行),采用
instruction/input/output三段式结构,例如"instruction": "娘娘。"对应"output": "你放心,本宫到任何时候都不会自轻自贱委屈了这孩子。"; - dataset/huanhuan-100.json:前 100 条子集,便于快速调试;
- dataset/huanhuan.jsonl:同一数据集的 JSONL 行式版本。
可以看到,同样是"打造个性化 AI",不同的任务目标会选择不同的数据组织方式:数字生命案例用 ShareGPT 格式承载多轮聊天记录,而 examples/Chat-嬛嬛/train.py 这类剧本台词驱动的案例则使用instruction/input/output问答对。理解这些差异,有助于你根据自己手头的数据形态选择合适的格式。
第二步:模型微调训练——基于讯飞星辰 MaaS 平台
数据集准备好之后,接下来进入模型微调环节。本项目使用讯飞星辰 MaaS 平台完成训练,核心思路是:选择开源通用大模型,把自制的数据集交给平台进行训练学习(微调)。有一点需要特别留意:按前述步骤得到的数据集属于ShareGPT 格式,在平台上选择数据格式时不要选错。
2.1 超参数设置建议
学习率(Learning Rate)和训练次数(Epochs)是对最终模型性能影响最大的两个关键超参数,选择时需要结合具体任务、数据集特征以及计算资源综合考量:
- 学习率(Learning Rate):可以理解为模型依据学习内容改变自身认知的幅度大小。过大的学习率可能导致模型无法收敛;过小则训练缓慢甚至陷入局部最优。微调阶段建议从较小的值开始,这样能较大程度保证损失函数曲线平缓、不剧烈震荡,避免破坏预训练模型已学到的有用信息;
- 训练次数(Epochs):指整个训练集被遍历的次数。微调通常不需要太多训练周期,因为预训练模型已具备一定的知识基础。如果数据集本身不大(少于 500 条),过多的训练周期会导致过拟合——模型在训练集上表现很好,但在未见过的数据上表现不佳。这两个参数可以结合训练的 Loss 曲线不断调整:曲线不要过于震荡,也不能太平(太平可能过拟合);
- 温度系数(Temperature):实验结果显示0.9 为佳,大家也可以根据回应的效果多调试。
2.2 微调方式选择:LoRA 还是全量精调
本项目最终选择LoRA 微调而非全量精调,原因是综合考虑了时间与资源成本:
- 当数据集规模较小时,实际上没必要对所有参数进行全面调整——大部分预训练模型已经具备良好的初始化和特征提取能力;
- 全量精调不仅增加不必要的计算负担,还可能导致训练过程冗长且低效;
- 当然,如果数据集很大(如几万条),则另当别论。
这一选择与本仓库的整体技术路线一致:self-llm 项目在 models/ 各模型目录下均提供 LoRA 微调教程与代码,例如 examples/Chat-嬛嬛/train.py 中通过LoraConfig配置r=8、lora_alpha=32、lora_dropout=0.1,并对q_proj/k_proj/v_proj/o_proj/gate_proj/up_proj/down_proj等线性层注入 LoRA 适配器,同时配合learning_rate=1e-4、num_train_epochs=3等训练参数,正是"小数据 + 低秩适配"的典型实践。
2.3 微调效果
微调完成并发布后,较好的效果表现为:数字人在回复中自然使用颜文字和表情包,让对方感觉温馨;同时在意标点符号的情感表达——例如对感叹号、波浪号等符号的使用非常"情有独钟"。整体来说,微调后的模型能够模仿出原型的个性化表达方式,效果比较理想。
第三步:前端页面展示——通过 WebSocket 调用微调模型 API
训练好模型并发布 API 后,就可以搭建聊天前端了。本项目做了一个美观的聊天界面,核心是通过WebSocket 连接到训练好的模型 API。以下为 API 调用的关键代码:
async function handleSendMessage() { const message = userInput.value.trim(); if (!message) return; addMessage('用户', message, 'user-message'); userInput.value = ''; // 这里是在讯飞平台里微调好并发布的模型的地址,改成你自己的!! const ws = new WebSocket('wss://maas-api.cn-huabei-XX'); // 以下几行为API调用,在"服务管控"页的右下角"信息调用"处 ws.onopen = () => { const requestData = { // 这要改成你自己的相关API!! header: { app_id: "XXXXXXXX", uid: "XXXXX", patch_id: ["XXXXXXXXXXXXXXXXXXX"] }, parameter: { chat: { // 这里我们选用的是星火13b的模型进行微调,如果不是用的这个,记得看讯飞平台的API调用文档说明,对应地改!! domain: "xspark13b6k", // 这是温度系数 temperature: 0.9 } }, payload: { message: { text: [ { "role": "user", "content": message } ] } } }; console.log(message); ws.send(JSON.stringify(requestData)); }; let fullResponse = ''; // 用于存储完整的AI响应 ws.onmessage = (event) => { const response = JSON.parse(event.data); if (response.header.code === 0) { // 拼接每次接收到的内容 const aiResponsePart = response.payload.choices.text.map(choice => choice.content).join(''); fullResponse += aiResponsePart; // 检查是否是最后一次响应 if (response.payload.choices.status === 2) { addMessage('AI', fullResponse, 'ai-message'); } } else { console.error('Error:', response.header.message); addMessage('AI', '抱歉,服务器出现错误,请稍后再试。', 'ai-message'); } }; ws.onerror = (error) => { console.error('WebSocket Error:', error); addMessage('AI', '抱歉,连接出现错误,请稍后再试。', 'ai-message'); }; ws.onclose = () => { console.log('WebSocket connection closed'); }; }这段代码定义了一个名为handleSendMessage的异步函数,在用户点击发送按钮时被调用:
- 获取用户输入的消息,通过 WebSocket 连接到指定的 API 端点;
- 连接成功后,发送包含用户消息的 JSON 请求数据(
header中包含app_id、uid、patch_id,parameter.chat中指定domain与温度系数,payload.message.text中携带对话内容); - 监听
onmessage事件,接收并处理 API 返回的流式响应,将各片段拼接起来; - 当
response.payload.choices.status === 2(最后一次响应)时,将完整回复显示在聊天界面中; - 发生错误或连接关闭时,在界面中显示相应提示信息。
需要注意:wss://maas-api.cn-huabei-XX地址以及app_id、uid、patch_id均需替换为你在讯飞平台微调发布后"服务管控"页面的实际信息。
成功后,即可在聊天界面与数字人进行沉浸式对话。仓库中该案例的界面效果截图可参考 examples/数字生命/image/readme/1738593252102.png,图中展示了数字人回复用户问候的聊天窗口:
场景拓展与展望
本项目的终极目标是降低成本,让更多人享受到这种形式的暖心陪伴,并探索如何在这个过程中"不让人出戏"——例如在你向它倾诉时,如果因为敏感词规避设置,它回一句"对不起,我只是一个语言大模型",那会瞬间让人心凉。
这个思路可以迁移到更多情感陪伴场景:
- 喜欢的、世界上可能不存在的动漫角色;
- 早已离你而去的亲人;
- 任何需要个性化陪伴的应用场景。
整套流程的核心资产是数据集的制作方法:真实聊天记录 + ShareGPT 格式 + 人设系统提示词 + 情感化表达保留 + MBTI 思维数据注入 + 人工清洗精修。这套方法论在 examples/ 目录下的多个案例(如 examples/Chat-嬛嬛/readme.md 基于剧本台词打造个性化 AI 的流程)中一脉相承,读者可以对照学习。后续该项目还计划探索语音功能的加成,让"灵魂分身"进一步完整。
【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调(全参数/Lora)、部署国内外开源大模型(LLM)/多模态大模型(MLLM)教程项目地址: https://gitcode.com/GitHub_Trending/se/self-llm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考