diff --git a/.env b/.env index 4379d4d..620be85 100644 --- a/.env +++ b/.env @@ -1 +1,3 @@ -HF_ENDPOINT=https://hf-mirror.com \ No newline at end of file +HF_ENDPOINT=https://hf-mirror.com +UNSLOTH_IS_PRESENT=1 +UNSLOTH_DISABLE_RL_TRAINERS=1 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e886a6b --- /dev/null +++ b/README.md @@ -0,0 +1,175 @@ +# 大语言模型微调框架 + +一个基于Unsloth和Transformers的大语言模型微调框架,支持多种模型的全量微调和LoRA微调。 + +## 功能特性 + +- ✅ 支持Gemma3、Qwen3等多种大语言模型 +- ✅ 支持全量微调(Full Fine-tuning)和LoRA微调两种模式 +- ✅ 统一的训练器接口,易于扩展新模型 +- ✅ 配置集中管理,便于调整训练参数 +- ✅ 自动应用模型特定的聊天模板 +- ✅ 支持模型保存和对话测试 + +## 安装依赖 + +```bash +pip install -r requirements.txt +``` + +## 项目结构 + +``` +fine-tuning/ +├── config.py # 配置文件,集中管理模型和训练参数 +├── data_transform.py # 数据预处理和转换工具 +├── main.py # 主程序入口,演示如何使用训练器 +├── train.py # 核心训练器类定义 +├── test.py # 测试脚本 +├── test_trainers.py # 训练器测试 +├── train_data.json # 训练数据 +├── README.md # 项目说明文档 +└── requirements.txt # 依赖包列表 +``` + +## 使用方法 + +### 1. 基础使用 + +```python +from train import Gemma3ModelTrainer, Qwen3ModelTrainer +from data_transform import get_chat_data2 + +# 使用Gemma3模型训练器 +gemma_trainer = Gemma3ModelTrainer("google/gemma-3-4b-it", "lora") +dataset = get_chat_data2() +gemma_trainer.set_dataset(dataset) +gemma_trainer.train() +gemma_trainer.chat("你好,介绍一下你自己") +gemma_trainer.save("gemma-3-4b-finetuned") + +# 使用Qwen3模型训练器 +qwen_trainer = Qwen3ModelTrainer("Qwen/Qwen3-600m", "lora") +qwen_trainer.set_dataset(dataset) +qwen_trainer.train() +qwen_trainer.chat("为什么使用了校验服务后提交到交易所系统还是报错?") +qwen_trainer.save("qwen3-600m-finetuned") +``` + +### 2. 训练模式选择 + +支持两种训练模式: +- `"lora"` (默认): LoRA微调,参数高效,训练速度快 +- `"full"`: 全量微调,所有参数都会更新 + +```python +# LoRA微调 +trainer = Gemma3ModelTrainer("google/gemma-3-4b-it", "lora") + +# 全量微调 +trainer = Gemma3ModelTrainer("google/gemma-3-4b-it", "full") +``` + +### 3. 使用配置文件 + +所有配置现在集中在`config.py`文件中管理: + +```python +# 模型配置 +MODEL_CONFIGS = { + "gemma-3-270m-it": { + "model_name": "unsloth/gemma-3-270m-it", + "chat_template": "gemma-3", + "target_modules": ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"] + }, + "qwen3-600m": { + "model_name": "Qwen/Qwen3-600m", + "chat_template": "qwen3", + "target_modules": ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"] + } +} + +# 训练配置 +TRAINING_CONFIG = { + "per_device_train_batch_size": 2, + "gradient_accumulation_steps": 4, + "warmup_steps": 5, + "max_steps": 300, + "learning_rate": 2e-4, + "logging_steps": 10, + "optim": "adamw_8bit", + "lr_scheduler_type": "linear", + "seed": 3407, + "weight_decay": 0.01, + "report_to": "none" +} +``` + +## 类结构 + +### BaseModelTrainer (基类) +- 抽象基类,定义通用接口 +- 包含训练配置和通用方法 +- 支持LoRA和全量微调 + +### Gemma3ModelTrainer (Gemma3专用) +- 使用Gemma3特定的聊天模板 +- 适配Gemma3的对话格式 +- 支持Gemma3模型的所有功能 + +### Qwen3ModelTrainer (Qwen3专用) +- 使用Qwen3特定的聊天模板 +- 适配Qwen3的对话格式 +- 支持Qwen3模型的所有功能 + +## 快速开始 + +### 1. 准备数据 + +确保`train_data.json`文件包含正确的训练数据格式: + +```json +[ + { + "instruction": "用户问题", + "output": "模型回答" + } +] +``` + +### 2. 运行训练 + +```bash +python main.py +``` + +### 3. 使用自定义配置 + +在`config.py`中可以修改以下配置: + +- `MODEL_CONFIGS`: 模型相关配置 +- `TRAINING_CONFIG`: 训练超参数 +- `LORA_CONFIG`: LoRA微调参数 +- `GENERATION_CONFIG`: 生成参数 + +## 扩展新模型 + +1. 在`train.py`中创建新的训练器类,继承`BaseModelTrainer` +2. 实现必要的抽象方法 +3. 在`config.py`中添加模型配置 +4. 在`main.py`中使用新的训练器 + +## 测试 + +运行测试脚本验证功能: + +```bash +python test_trainers.py +``` + +## 注意事项 + +1. 确保有足够的GPU内存进行训练 +2. 全量微调需要更多显存,建议使用LoRA模式 +3. 模型路径需要正确设置 +4. 训练数据需要符合对话格式要求 \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..11bd385 --- /dev/null +++ b/config.py @@ -0,0 +1,59 @@ +""" +配置文件,集中管理模型训练参数和配置 +""" + +# 模型配置 +MODEL_CONFIGS = { + "gemma-3-270m-it": { + "model_name": "unsloth/gemma-3-270m-it", + "uri": r"C:\Users\123ee\.cache\modelscope\hub\models\unsloth\gemma-3-270m-it", + "chat_template": "gemma-3", + "target_modules": ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"] + }, + "gemma-3-270m": { + "model_name": "unsloth/gemma-3-270m-it", + "uri": r"C:\Users\123ee\.cache\modelscope\hub\models\unsloth\gemma-3-270m", + "chat_template": "gemma-3", + "target_modules": ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"] + }, + "qwen3-600m": { + "model_name": "Qwen/Qwen3-600m", + "uri": r"C:\Users\123ee\.cache\modelscope\hub\models\Qwen\Qwen3-600m", + "chat_template": "qwen3", + "target_modules": ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"] + } +} + +# 训练配置 +TRAINING_CONFIG = { + "per_device_train_batch_size": 2, + "gradient_accumulation_steps": 4, + "warmup_steps": 5, + "max_steps": 300, + "learning_rate": 2e-4, + "logging_steps": 10, + "optim": "adamw_8bit", + "lr_scheduler_type": "linear", + "seed": 3407, + "weight_decay": 0.01, + "report_to": "none" +} + +# LoRA配置 +LORA_CONFIG = { + "r": 128, + "lora_alpha": 128, + "lora_dropout": 0, + "bias": "none", + "random_state": 3407, + "use_rslor": False, + "loftq_config": None +} + +# 生成配置 +GENERATION_CONFIG = { + "max_new_tokens": 1024*16, + "temperature": 1.0, + "top_p": 0.95, + "top_k": 3 +} \ No newline at end of file diff --git a/data/data_transform.py b/data/data_transform.py new file mode 100644 index 0000000..49c9537 --- /dev/null +++ b/data/data_transform.py @@ -0,0 +1,24 @@ +import json + +import pandas as pd +from datasets import Dataset + +def get_chat_data(): + a = pd.read_excel("致远速联日常销售问答话术.xlsx") + a.fillna("", inplace=True) + data = [] + for i in a.values: + if i[1] == "": continue + data.append({"conversations": [{"role": "user", "content": i[1]}, {"role": "assistant", "content": i[2]}]}) + return Dataset.from_pandas(pd.DataFrame(data)) + +def get_chat_data2(): + with open("train_data.json","r",encoding="utf-8") as f: + train_data = json.load(f) + data = [] + for i in train_data: + data.append({"conversations": [{"role": "user", "content": i["instruction"]}, {"role": "assistant", "content": i["output"]}]}) + return Dataset.from_pandas(pd.DataFrame(data)) + +if __name__ == '__main__': + get_chat_data2() \ No newline at end of file diff --git a/data/train_data.json b/data/train_data.json new file mode 100644 index 0000000..805703c --- /dev/null +++ b/data/train_data.json @@ -0,0 +1,257 @@ +[ + { + "instruction": "当需要向客户转发产品宣传资料或推文时,应该如何表达?", + "input": "", + "output": "感兴趣可以看看哈,我们目前已经有200多家上市公司成为签约用户了。感谢xx总支持,有问题随时联系[玫瑰]" + }, + { + "instruction": "发送邮件后如何确认对方是否收到?", + "input": "", + "output": "您有收到邮件吗?邮件内有离线网址和二维码" + }, + { + "instruction": "如何解释智能校验产品与交易所错别字校验工具的区别?", + "input": "对方问到交易所错别字校验工具的区别", + "output": "我们会对业务要素错别字和会影响到投资者实际性的内容做校验。交易所里的校验不做重点校验,不会涉及到问询和被处罚,没有处罚的依据。我们的校验目的是监管的逻辑,不是简单的错别字,和市场上其他机构做的普通ai纠错不一样。市场同类产品基本是《形式校验》,我们追溯到源头,做的《业务实质校验》。校验服务是优先保障,明文规定有可能会被处罚的内容不出错,供上市公司作出慎重参考。深交所的校验工具是事后提醒,我们的校验系统是可以事前进行复核的。" + }, + { + "instruction": "如何向客户介绍回溯校验报告?", + "input": "在每期披露过后,对于感兴趣的公司", + "output": "每期披露过后我都会开放回溯校验报告,这份回溯校验使用的是公开数据,数据量与您实际报送的文件会有出入。" + }, + { + "instruction": "如何介绍智能校验的离线特点?", + "input": "", + "output": "我们的校验服务是离线操作,不联网,不上传任何数据。校验的模型加载在本地,只在本地进行校验。您无需顾虑数据泄露的风险。" + }, + { + "instruction": "如何介绍智能校验的核心功能?", + "input": "", + "output": "正式版可以看《校验报告》中全部校验提示,还有【阅读器】模式可以直接定位到数据点,查错更直观。" + }, + { + "instruction": "如何全面介绍智能校验产品?", + "input": "", + "output": "我们的产品服务是根据最新披露法规的变动,持续更新迭代的,包年服务相当于贵司全年的披露工作,我们解决了大部分问题。您编制时各种准备、免费的信披培训,编制过程中任何信披问题,编制完成后的校验工作等等,我们都有业务老师和技术支持,全程给您服务的。" + }, + { + "instruction": "当客户不知道如何查看校验报告时应该如何指导?", + "input": "", + "output": "建议您使用【阅读器】打开,可以看的更直观,能够快速定位到需注意的位置。相较于人工检查,机器检查更为高效、准确。您可以校验一下已披露数据,看看效果。" + }, + { + "instruction": "如何简要介绍智能校验产品?", + "input": "", + "output": "我们的产品都是离线操作(即登陆后可以断网),每家公司都是独立账号,无需上传数据、下载系统。不用担心信息泄露风险。" + }, + { + "instruction": "北京是否有驻地销售?", + "input": "", + "output": "有" + }, + { + "instruction": "产品支持哪些浏览器?", + "input": "", + "output": "浏览器:Chrome、Edge、Firefox、360、Safari (均 64 位支持)。" + }, + { + "instruction": "服务器部署位置和在线编辑支持情况?", + "input": "服务器放在哪里?可以同时几个人在线编辑?", + "output": "我们产品没有服务器,我们是离线,每个用户自己本地使用,不支持多人在线编辑(多人在线编辑可以买定制企业版)" + }, + { + "instruction": "如何解释信息披露规则中关于外包服务的限制?", + "input": "信息披露规则中指出不得委托其他公司或机构代为编制或审阅信息披露文件", + "output": "法规里是不允许外包,我们这个没有人工参与,是提供工具,公司自己操作,不属于外包服务。这是新征求意见稿的规定,没牌照的不能做了,证券法的规定,证券服务机构需要取得备案的,有信息技术系统服务机构的备案,我们的备案排在序号131,需要重申的是,我们提供的是AI工具,不是人工审阅,原来的信披咨询公司,多数就会加入律所或会计师事务所,并去过的证监会备案,但需要一个过程,这个期间客户面临重新选择,所以对于我们的AI工具是个机会,一是AI工具没有合规方面的问题,二是AI对一些基础性的人工服务会是一个替代。" + }, + { + "instruction": "小智智填能完成多少填报内容?", + "input": "", + "output": "1人3分钟完成年报70%填报,主要体现在3个部分:1)对贵公司过去一年定期报告和临时报告数据整理;2)审计报告/财务报告完成财务数据、财务附注数据提取和数据推理计算得出的数据;3)股东名册里股东信息提取,完成相关指标。" + }, + { + "instruction": "深交所新开放的'文件智能检查'服务是否由致远速联开发?", + "input": "", + "output": "深交所自行研发基于大模型的智能检查,但是每家公司每天限制3次使用,致远速联有同类型大模型智能校验方案,可以在公司本地化部署离线使用,做提交前事先检查,没有次数限制,可以达到类似的业务效果。" + }, + { + "instruction": "文件智能检查的校验范围是什么?", + "input": "", + "output": "主要为上市公司提供报告的文本错误和纠正优化建议服务,例如错别字和文本规范性等低级错误。目前提示内容仅供参考不代表交易所的监管意见。" + }, + { + "instruction": "是否建议使用交易所的校验服务?", + "input": "", + "output": "在能排上队的情况下,争取要用,相当于交易所掏钱帮大家买了大模型,花费在8位数以上" + }, + { + "instruction": "为什么使用了校验服务后提交到交易所系统还是报错?", + "input": "修改后提交到交易所系统还是报了很多错误", + "output": "1、校验效果和模型版本有关;2、大模型的原理和传统规则校验不一样,就算同一份文档在交易所系统检查两次,结果也有差异;3、我们尽量通过事前检查,把比较明确的是错误的修改,这样后续的回执信息,明确的低级错误就可以尽量避免。如果其他都是语义优化类的就没什么关系了。" + }, + { + "instruction": "交易所校验与定期报告增强校验是否有功能交叉?", + "input": "", + "output": "在单一文档财务数据引用的部分,会有一点交叉,其余的部分,历史数据一致性、各种指标的计算和其他的数万条的校验规则,都没有包含" + }, + { + "instruction": "如何使用交易所校验服务的建议?", + "input": "", + "output": "先使用小智复核完成各项实质性内容的校验,然后使用交易所的校验来检查错别字和规范性(资源有限,使用次数和需要排队),不适合做工作过程中的多次校验" + }, + { + "instruction": "第一次加好友时如何打招呼?", + "input": "", + "output": "您好!这里是致远速联" + }, + { + "instruction": "如何礼貌地请求对方提供个人信息?", + "input": "需要别人提供个人信息时", + "output": "麻烦提供一下您的公司代码、姓名、职务和联系方式" + }, + { + "instruction": "当对方打招呼时如何回应?", + "input": "别人说您好", + "output": "请问有什么可以帮您的?" + }, + { + "instruction": "客户试用产品后如何跟进?", + "input": "对方试用时/后", + "output": "您这边对产品服务有任何问题或者有任何信披问题,都可以随时联系我们[玫瑰]" + }, + { + "instruction": "如何主动与客户打招呼?", + "input": "", + "output": "您好!您有任何信披问题,也可以随时联系我们,打扰啦[玫瑰]" + }, + { + "instruction": "因咨询量大延迟回复时如何表达?", + "input": "长时间才回答别人时", + "output": "抱歉,咨询人员较多,让您久等了[玫瑰]" + }, + { + "instruction": "需要专家支持时如何让客户等待?", + "input": "遇到问题需要长时间回答时", + "output": "您好,这边咨询消息较多,正在为您联系信披专家。烦请等候,谢谢" + }, + { + "instruction": "欢迎客户加入交流群的用语", + "input": "别人加群时", + "output": "欢迎添加我们的信披交流群,群内都是董办朋友,我们会在群里发布填报系统的更新信息和相关培训内容,可以多交流哈" + }, + { + "instruction": "客户入群后的提醒事项", + "input": "别人加群后的提醒", + "output": "入群后,麻烦将群名片改成:公司代码/简称+职务+姓名。" + }, + { + "instruction": "客户入群后的服务说明", + "input": "别人加群后的提醒", + "output": "后续相关业务问题,可以在群里直接@我们的信披顾问哦。感谢您对致远速联的支持" + }, + { + "instruction": "常用的礼貌结束语", + "input": "", + "output": "有问题随时联系哈,感谢支持" + }, + { + "instruction": "如何邀请客户预约产品演示?", + "input": "预约演示", + "output": "有时间我们可以约个线上视频会议,给您一边实操一边讲解[愉快]" + }, + { + "instruction": "如何解释与交易所填报系统的区别?", + "input": "填报系统和我们校验的区别", + "output": "我们的校验不同于填报系统的校验,填报系统目前的校验功能没有那么完善,会有一些问题无法校验出来,导致一些错误发现不出来。" + }, + { + "instruction": "如何介绍产品的数据安全性?", + "input": "可断网离线使用功能", + "output": "我们的产品都是离线操作(即登陆后可以断网),每家公司都是独立链接,无需上传数据,无信息安全和内部信息泄漏风险,全程服务合规。" + }, + { + "instruction": "如何解释与竞品的区别?", + "input": "我们这个插件加入进去,与市场上同类竞品区别是?", + "output": "我们是跟监管口径规则对齐的,至于市场上的竞品没有去比较过。" + }, + { + "instruction": "如何说明产品的部署方式和安全性?", + "input": "如何部署?是否离线?运行逻辑是什么?保密性?", + "output": "本地部署,断网离线使用,数据和内幕信息知情报备保密、安全和合规服务。" + }, + { + "instruction": "临时报告是否支持校验?", + "input": "", + "output": "临时报告有另外专门产品,现在正处于测试阶段,很快将会推出的。" + }, + { + "instruction": "产品价格咨询的标准回复", + "input": "使用这个功能进行年报校验还单独收费吗?", + "output": "目前这款产品刚推出,还在市场评估阶段,所以具体价格暂时还没有完全确定下来。" + }, + { + "instruction": "标准版产品的价格说明", + "input": "DS插件定期报告校验,标准版价格怎么定义?", + "output": "标准版就是买我们标品校验,成为我们的VIP客户,本期年报免费赠送,加量不加价。" + }, + { + "instruction": "算力版和企业版的价格说明", + "input": "算力版和企业版的价格呢?", + "output": "目前这款产品刚推出,还在市场评估阶段,所以具体价格暂时还没有完全确定下来。" + }, + { + "instruction": "算力版和企业版是否支持临时公告?", + "input": "", + "output": "未来也会" + }, + { + "instruction": "标准版的系统要求", + "input": "什么电脑可安装标准版?", + "output": "16G笔记本可以跑14B" + }, + { + "instruction": "老客户使用权限说明", + "input": "插件老客户可以用于2024年年报是吗,有次数限制吗", + "output": "是的,有限免,次数为?" + }, + { + "instruction": "24年年报DEEPSEEK插件价格说明", + "input": "", + "output": "包年订阅智能校验,成为VIP。我们会给您发送deepseek安装包,直接电脑上安装即可使用。【定期报告智能校验】2.5万一年,共四个报告期。您订阅了智能校验,这个DEEPSEEK服务" + }, + { + "instruction": "组合产品价格说明", + "input": "【定期报告智能校验】+【小智智填-定期报告专版】什么价格?", + "output": "【定期报告智能校验】+【小智智填-定期报告专版】=35000元/一年(共4个报告期)。我们的优惠都是针对包年服务的,后面我们有其他优惠活动优先通知您" + }, + { + "instruction": "单独产品价格说明", + "input": "【定期报告智能校验】什么价格?【小智智填-定期报告专版】什么价格?", + "output": "【定期报告智能校验】2.5万一年,共四个报告期;【小智智填-定期报告专版】1万一年。" + }, + { + "instruction": "产品性价比说明", + "input": "与其他产品价格对比", + "output": "如果你对比过市场其他价,就知道我们家属于性价比最高的了[愉快],功能也最强大、校验也最准确。" + }, + { + "instruction": "报价后的跟进话术", + "input": "报价后的催话", + "output": "xx总,前阵子给您发的报价方案,这边有新的想法吗?[握手]" + }, + { + "instruction": "报价后的需求确认", + "input": "报价后的催话", + "output": "贵司年报期有这部分的订购想法吗?" + }, + { + "instruction": "简单的报价跟进", + "input": "报价后的催话", + "output": "考虑的如何?[握手]" + }, + { + "instruction": "详细的报价跟进话术", + "input": "报价后的催话", + "output": "xx总早上好[玫瑰],报价这边有跟领导反馈吗?咱价格是比市场同类产品价格更实惠一些的,贵有贵的原因,报送成功率高嘛[社会社会]" + } +] \ No newline at end of file diff --git a/致远速联日常销售问答话术.xlsx b/data/致远速联日常销售问答话术.xlsx similarity index 100% rename from 致远速联日常销售问答话术.xlsx rename to data/致远速联日常销售问答话术.xlsx diff --git a/data_transform.py b/data_transform.py deleted file mode 100644 index f87bd97..0000000 --- a/data_transform.py +++ /dev/null @@ -1,14 +0,0 @@ -import pandas as pd -from datasets import Dataset - -def get_chat_data(): - a = pd.read_excel("致远速联日常销售问答话术.xlsx") - a.fillna("", inplace=True) - data = [] - for i in a.values: - if i[1] == "": continue - data.append({"conversations": [{"role": "user", "content": i[1]}, {"role": "assistant", "content": i[2]}]}) - return Dataset.from_pandas(pd.DataFrame(data*10)) - -if __name__ == '__main__': - get_chat_data() \ No newline at end of file diff --git a/main.py b/main.py index ee94d90..4c4691a 100644 --- a/main.py +++ b/main.py @@ -1,91 +1,49 @@ from dotenv import load_dotenv load_dotenv() -import unsloth -from data_transform import get_chat_data -from datasets import Dataset -from unsloth import FastModel, get_chat_template -from trl import SFTTrainer, SFTConfig -import pandas as pd + +from data.data_transform import get_chat_data2 +from train.train import Gemma3ModelTrainer, Qwen3ModelTrainer +from config import MODEL_CONFIGS, TRAINING_CONFIG -MODEL = "unsloth/gemma-3-270m-it" - -# load model and tokenizer -model, tokenizer = FastModel.from_pretrained( - model_name=MODEL, - max_seq_length=2048, - dtype=None, - load_in_4bit=False, - full_finetuning=False) - -model = FastModel.get_peft_model( - model, - r=128, - target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], - use_gradient_checkpointing="unsloth", - lora_alpha=128, - lora_dropout=0, - bias="none", - random_state=3407, - use_rslor=False, - loftq_config=None -) -tokenizer = get_chat_template( - tokenizer, - chat_template = "gemma-3", -) -def apply_chat_template(examples): - conversations = examples["conversations"] - texts = tokenizer.apply_chat_template(conversations) - return {"text": tokenizer.decode(texts)} - -def chat(model,message): - outputs = model.generate( - **tokenizer( message, return_tensors="pt").to("cuda"), - max_new_tokens=1024, - - temperature=1.0, top_p=0.95, top_k=64, +def main(): + """主函数,演示如何使用训练器类""" + + # 示例1: 使用Qwen3模型训练 + print("开始训练Qwen3模型...") + qwen_trainer = Qwen3ModelTrainer( + model_name=MODEL_CONFIGS["qwen3-600m"]["uri"], + mode="lora" ) - - - return tokenizer.batch_decode(outputs)[0] - - - - -data = get_chat_data() - -dataset = Dataset.from_pandas(pd.DataFrame(data)) -dataset = dataset.map(apply_chat_template) + + dataset = get_chat_data2() + qwen_trainer.set_dataset(dataset) + qwen_trainer.train() + + # 测试对话 + response = qwen_trainer.chat("为什么使用了校验服务后提交到交易所系统还是报错?") + print(f"Qwen3模型回复: {response}") + + # 保存模型 + qwen_trainer.save("qwen3-600m-finetuned") + + # 示例2: 使用Gemma3模型训练(注释状态) + """ + print("开始训练Gemma3模型...") + gemma_trainer = Gemma3ModelTrainer( + model_name=MODEL_CONFIGS["gemma-3-270m-it"]["model_name"], + mode="lora" + ) + + gemma_trainer.set_dataset(dataset) + gemma_trainer.train() + + # 测试对话 + response = gemma_trainer.chat("为什么使用了校验服务后提交到交易所系统还是报错?") + print(f"Gemma3模型回复: {response}") + + # 保存模型 + gemma_trainer.save("gemma-3-270m-finetuned") + """ if __name__ == '__main__': - - trainer = SFTTrainer(model=model, - train_dataset=dataset, - args=SFTConfig( - dataset_text_field="text", - per_device_train_batch_size=2, - gradient_accumulation_steps=4, - warmup_steps=5, - max_steps=100, - learning_rate=5e-5, - logging_steps=10, - optim="adamw_8bit", - lr_scheduler_type="linear", - seed=3407, - weight_decay=0.01, - report_to="none" - ) - ) - trainer.train() - outputs = model.generate( - **tokenizer(["你是谁"], return_tensors="pt").to("cuda"), - max_new_tokens=1024, - - temperature=1.0, top_p=0.95, top_k=64, - ) - - print(tokenizer.batch_decode(outputs)[0]) - - model.save_pretrained("lora_model") # 保存适配器权重 - tokenizer.save_pretrained("lora_model") # 保存分词器 - model.save_pretrained_merged("gemma-3-270m-finetuned", tokenizer, save_method="merged_16bit") \ No newline at end of file + main() \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..060db76 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,14 @@ +unsloth==2025.8.10 +transformers==4.56.0 +datasets==4.0.0 +accelerate==1.10.1 +trl==0.22.1 +peft==0.17.1 +torch==2.8.0+cu129 +pandas==2.3.2 +pandas-stubs==2.3.2.250827 +python-dotenv==1.1.1 +sentencepiece==0.2.1 +protobuf==6.32.0 +ninja==1.13.0 +packaging==25.0 \ No newline at end of file diff --git a/test.py b/test.py deleted file mode 100644 index 5fc3295..0000000 --- a/test.py +++ /dev/null @@ -1,43 +0,0 @@ -from dotenv import load_dotenv - -load_dotenv() -from unsloth import FastLanguageModel, FastModel -from transformers import TextStreamer - -model_name = r"E:\code\python\fine-tuning\gemma-3-270m-finetuned" -model, tokenizer = FastModel.from_pretrained( - model_name=model_name, - max_seq_length=512, - dtype=None, - load_in_4bit=False, - full_finetuning=False) -model = FastLanguageModel.get_peft_model(model, - r=128, - target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", - "up_proj", "down_proj"], - use_gradient_checkpointing="unsloth", - lora_alpha=128, - lora_dropout=0, - bias="none", - random_state=3407, - use_rslor=False, - loftq_config=None) -FastLanguageModel.for_inference(model) - -def chat(model, message): - outputs = model.generate( - **tokenizer([message], return_tensors="pt").to("cuda"), - max_new_tokens=1024, - streamer= TextStreamer(tokenizer, skip_prompt=True), - temperature=1.0, top_p=0.95, top_k=64, - ) - - - -if __name__ == '__main__': - while True: - message = input("user:") - if message == "exit": - break - chat(model, f"user\n{message}\n\nmodel\n") - diff --git a/test/test_trainers.py b/test/test_trainers.py new file mode 100644 index 0000000..350aa03 --- /dev/null +++ b/test/test_trainers.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +""" +测试Gemma3和Qwen3模型训练器 +""" + +from train import Gemma3ModelTrainer, Qwen3ModelTrainer +from datasets import Dataset + +def test_gemma3_trainer(): + """测试Gemma3模型训练器""" + print("测试Gemma3ModelTrainer...") + + # 创建一个简单的测试数据集 + test_data = { + "conversations": [ + [ + {"role": "user", "content": "你好"}, + {"role": "assistant", "content": "你好!有什么可以帮助你的吗?"} + ] + ] + } + dataset = Dataset.from_dict(test_data) + + try: + trainer = Gemma3ModelTrainer("google/gemma-3-4b-it", "lora") + trainer.set_dataset(dataset) + print("✓ Gemma3ModelTrainer 初始化成功") + + # 测试聊天模板应用 + result = trainer.apply_chat_template({"conversations": test_data["conversations"]}) + print("✓ Gemma3聊天模板应用成功") + + return True + except Exception as e: + print(f"✗ Gemma3ModelTrainer 测试失败: {e}") + return False + +def test_qwen3_trainer(): + """测试Qwen3模型训练器""" + print("测试Qwen3ModelTrainer...") + + # 创建一个简单的测试数据集 + test_data = { + "conversations": [ + [ + {"role": "user", "content": "你好"}, + {"role": "assistant", "content": "你好!有什么可以帮助你的吗?"} + ] + ] + } + dataset = Dataset.from_dict(test_data) + + try: + trainer = Qwen3ModelTrainer("Qwen/Qwen3-600m", "lora") + trainer.set_dataset(dataset) + print("✓ Qwen3ModelTrainer 初始化成功") + + # 测试聊天模板应用 + result = trainer.apply_chat_template({"conversations": test_data["conversations"]}) + print("✓ Qwen3聊天模板应用成功") + + return True + except Exception as e: + print(f"✗ Qwen3ModelTrainer 测试失败: {e}") + return False + +if __name__ == "__main__": + print("开始测试模型训练器...\n") + + gemma_success = test_gemma3_trainer() + print() + qwen_success = test_qwen3_trainer() + + print(f"\n测试结果:") + print(f"Gemma3ModelTrainer: {'✓ 通过' if gemma_success else '✗ 失败'}") + print(f"Qwen3ModelTrainer: {'✓ 通过' if qwen_success else '✗ 失败'}") + + if gemma_success and qwen_success: + print("\n🎉 所有测试通过!模型训练器类已正确实现。") + else: + print("\n❌ 部分测试失败,请检查代码。") \ No newline at end of file diff --git a/train.py b/train.py deleted file mode 100644 index 614fab5..0000000 --- a/train.py +++ /dev/null @@ -1,99 +0,0 @@ -from dotenv import load_dotenv -load_dotenv() - -import unsloth -from transformers import TextStreamer -from datasets import Dataset -from unsloth import FastModel, get_chat_template -from trl import SFTTrainer, SFTConfig - - - - - -class Gemma3ModelTrainer: - def __init__(self, model_name): - self.model_name = model_name - self.model = None - self.tokenizer = None - self.trainer = None - self._get_model() - - def _get_model(self): - model, tokenizer = FastModel.from_pretrained( - model_name=self.model_name, - max_seq_length=2048, - dtype=None, - load_in_4bit=False, - full_finetuning=False) - - self.model = FastModel.get_peft_model( - model, - r=128, - target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], - use_gradient_checkpointing="unsloth", - lora_alpha=128, - lora_dropout=0, - bias="none", - random_state=3407, - use_rslor=False, - loftq_config=None - ) - self.tokenizer = get_chat_template( - tokenizer, - chat_template="gemma-3", - ) - - def apply_chat_template(self, examples): - conversations = examples["conversations"] - texts = self.tokenizer.apply_chat_template(conversations) - return {"text": self.tokenizer.decode(texts)} - - def set_dataset(self, data: Dataset): - dataset = data.map(self.apply_chat_template) - self.trainer = SFTTrainer(model=self.model, - train_dataset=dataset, - args=SFTConfig( - dataset_text_field="text", - per_device_train_batch_size=2, - gradient_accumulation_steps=4, - warmup_steps=5, - max_steps=100, - learning_rate=5e-5, - logging_steps=10, - optim="adamw_8bit", - lr_scheduler_type="linear", - seed=3407, - weight_decay=0.01, - report_to="none" - ) - ) - - def train(self): - self.trainer.train() - - def save(self, name: str="gemma-3-finetuned", only_one=False): - if not only_one: - self.model.save_pretrained(f"{name}-lora") # 保存适配器权重 - self.tokenizer.save_pretrained(f"{name}-lora") # 保存分词器 - self.model.save_pretrained_merged(name, self.tokenizer, save_method="merged_16bit") - - def chat(self, message): - outputs = self.model.generate( - **self.tokenizer(["user\n"+message+"\nmodel\n"], return_tensors="pt").to("cuda"), - max_new_tokens=1024, - streamer=TextStreamer(self.tokenizer, skip_prompt=True), - temperature=1.0, top_p=0.95, top_k=64, - ) - - return self.tokenizer.batch_decode(outputs)[0] - - -if __name__ == '__main__': - trainer = Gemma3ModelTrainer("unsloth/gemma-3-270m-it") - from data_transform import get_chat_data - dataset = get_chat_data() - trainer.set_dataset(dataset) - trainer.train() - trainer.chat("介绍智能校验的离线特点") - trainer.save("gemma-3-270m-finetuned") \ No newline at end of file diff --git a/train/train.py b/train/train.py new file mode 100644 index 0000000..8462802 --- /dev/null +++ b/train/train.py @@ -0,0 +1,251 @@ +from abc import abstractmethod, ABCMeta +from dotenv import load_dotenv + +load_dotenv() + +import unsloth +from unsloth import FastModel, get_chat_template +from unsloth_zoo.dataset_utils import train_on_responses_only +from trl import SFTTrainer, SFTConfig +from transformers import TextStreamer +from datasets import Dataset + + +class BaseModelTrainer(metaclass=ABCMeta): + """ + 基础模型微调训练器,支持全量微调和LoRA微调两种模式 + """ + # 训练配置参数 + TRAINING_CONFIG = { + "per_device_train_batch_size": 2, + "gradient_accumulation_steps": 4, + "warmup_steps": 5, + "max_steps": 300, + "learning_rate": 2e-4, + "logging_steps": 10, + "optim": "adamw_8bit", + "lr_scheduler_type": "linear", + "seed": 3407, + "weight_decay": 0.01, + "report_to": "none" + } + + def __init__(self, model_name, mode="lora"): + """ + 初始化模型训练器 + :param model_name: 预训练模型名称或路径 + :param mode: 训练模式,可选"full"(全量微调)或"lora"(LoRA微调) + """ + self.model_name = model_name + self.model = None + self.tokenizer = None + self.trainer = None + self._full_finetuning = (mode == "full") + self._get_model() + + def _get_model(self): + """加载预训练模型并配置微调参数""" + model, tokenizer = FastModel.from_pretrained( + model_name=self.model_name, + max_seq_length=2048, + dtype=None, + load_in_4bit=False, + load_in_8bit=False, + full_finetuning=self._full_finetuning + ) + + if not self._full_finetuning: + self.model = self._init_lora_model(model) + else: + self.model = model + + # 聊天模板由子类具体实现 + self.tokenizer = tokenizer + + @staticmethod + def _init_lora_model(model): + """初始化LoRA微调模型""" + return FastModel.get_peft_model( + model, + r=128, + target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], + use_gradient_checkpointing="unsloth", + lora_alpha=128, + lora_dropout=0, + bias="none", + random_state=3407, + use_rslor=False, + loftq_config=None + ) + + @abstractmethod + def apply_chat_template(self, examples): + """将对话示例应用聊天模板并编码""" + return {"text": ""} + + @abstractmethod + def set_dataset(self, data: Dataset): + pass + + def _get_sft_config(self): + """获取SFT训练配置""" + return SFTConfig( + dataset_text_field="text", + **self.TRAINING_CONFIG + ) + + def train(self): + """开始模型训练""" + if not self.trainer: + raise ValueError("训练器未初始化,请先调用set_dataset方法") + self.trainer.train() + + def save(self, name: str = "gemma-3-finetuned", save_gguf=False): + """ + 保存训练好的模型 + :param name: 模型保存名称 + :param save_gguf: 是否保存为GGUF格式 + """ + if save_gguf: + self._save_gguf_format(name) + else: + if self._full_finetuning: + self.model.save_pretrained(name) + else: + self._save_lora_model(name) + + def _save_gguf_format(self, name): + """保存为GGUF格式""" + self.model.save_pretrained_gguf(f"{name}-gguf", self.tokenizer, quantization_method="q4_k_m") + + def _save_lora_model(self, name): + """保存LoRA模型""" + lora_name = f"{name}-lora" + self.model.save_pretrained(lora_name) + self.tokenizer.save_pretrained(lora_name) + self.model.save_pretrained_merged(name, self.tokenizer, save_method="merged_16bit") + + def chat(self, message: str, max_new_tokens: int = 1024, temperature: float = 1.0, top_p: float = 0.95, + top_k: int = 3) -> str: + """ + 与模型进行对话 + :param message: 用户输入消息 + :param max_new_tokens: 最大生成token数 + :param temperature: 温度参数 + :param top_p: top-p采样参数 + :param top_k: top-k采样参数 + :return: 模型生成的回复 + """ + if not self.model or not self.tokenizer: + raise ValueError("模型或分词器未初始化") + + # 由子类提供具体的对话模板 + prompt = self._format_chat_prompt(message) + + inputs = self.tokenizer([prompt], return_tensors="pt").to("cuda") + streamer = TextStreamer(self.tokenizer, skip_prompt=True) + + outputs = self.model.generate( + **inputs, + max_new_tokens=max_new_tokens, + streamer=streamer, + temperature=temperature, + top_p=top_p, + top_k=top_k, + ) + return self.tokenizer.batch_decode(outputs)[0] + + @abstractmethod + def _format_chat_prompt(self, message: str) -> str: + """格式化聊天提示模板,由子类实现""" + pass + + +class Gemma3ModelTrainer(BaseModelTrainer): + + def __init__(self, model_name, mode="lora"): + """ + 初始化Gemma3模型训练器 + :param model_name: 预训练模型名称或路径 + :param mode: 训练模式,可选"full"(全量微调)或"lora"(LoRA微调) + """ + super().__init__(model_name, mode) + + def _get_model(self): + """加载预训练模型并配置聊天模板""" + super()._get_model() + self.tokenizer = get_chat_template( + self.tokenizer, + chat_template="gemma-3", + ) + + def apply_chat_template(self, examples): + """将对话示例应用聊天模板并编码""" + conversations = examples["conversations"] + texts = self.tokenizer.apply_chat_template(conversations) + return {"text": self.tokenizer.decode(texts)} + + def set_dataset(self, data: Dataset): + """设置训练数据集并初始化训练器""" + _dataset = data.map(self.apply_chat_template) + sft_config = self._get_sft_config() + _trainer = SFTTrainer( + model=self.model, + train_dataset=_dataset, + args=sft_config + ) + self.trainer = train_on_responses_only( + _trainer, + instruction_part="user\n", + response_part="model\n", + num_proc=1 + ) + + def _format_chat_prompt(self, message: str) -> str: + """格式化Gemma3聊天提示模板""" + return f"user\n{message}\nmodel\n" + + +class Qwen3ModelTrainer(BaseModelTrainer): + + def __init__(self, model_name, mode="lora"): + """ + 初始化Qwen3模型训练器 + :param model_name: 预训练模型名称或路径 + :param mode: 训练模式,可选"full"(全量微调)或"lora"(LoRA微调) + """ + super().__init__(model_name, mode) + + def _get_model(self): + """加载预训练模型并配置聊天模板""" + super()._get_model() + self.tokenizer = get_chat_template( + self.tokenizer, + chat_template="qwen3", + ) + + def apply_chat_template(self, examples): + """将对话示例应用聊天模板并编码""" + conversations = examples["conversations"] + texts = self.tokenizer.apply_chat_template(conversations) + return {"text": self.tokenizer.decode(texts)} + + def set_dataset(self, data: Dataset): + """设置训练数据集并初始化训练器""" + _dataset = data.map(self.apply_chat_template) + sft_config = self._get_sft_config() + _trainer = SFTTrainer( + model=self.model, + train_dataset=_dataset, + args=sft_config + ) + self.trainer = train_on_responses_only( + _trainer, + instruction_part="<|im_start|>user\n", + response_part="<|im_start|>assistant\n", + num_proc=1 + ) + + def _format_chat_prompt(self, message: str) -> str: + """格式化Qwen3聊天提示模板""" + return f"<|im_start|>user\n{message}<|im_end|>\n<|im_start|>assistant\n" diff --git a/train_data.json b/train_data.json deleted file mode 100644 index 70f3e8c..0000000 --- a/train_data.json +++ /dev/null @@ -1,770 +0,0 @@ -[ - { - "conversations": [ - { - "role": "user", - "content": "当我们给对方转发产品宣传资料/推文/新产品等时" - }, - { - "role": "assistant", - "content": "感兴趣可以看看哈,我们目前已经有200多家上市公司成为签约用户了。感谢xx总支持,有问题随时联系[玫瑰]" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "当我们给对方发完邮件后,需做确认" - }, - { - "role": "assistant", - "content": "您有收到邮件吗?邮件内有离线网址和二维码" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "之前版的智能校验校验错别字主要在哪?当对方问到交易所的那个错别字校验工具区别时。" - }, - { - "role": "assistant", - "content": "我们会对业务要素错别字和会影响到投资者实际性的内容做校验。交易所里的校验不做重点校验,不会涉及到问询和被处罚,没有处罚的依据。我们的校验目的是监管的逻辑,不是简单的错别字,和市场上其他机构做的普通ai纠错不一样。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "在每期披露过后,对于感兴趣的公司,我们会给对方回溯校验报告。" - }, - { - "role": "assistant", - "content": "每期披露过后我都会开放回溯校验报告,这份回溯校验使用的是公开数据,数据量与您实际报送的文件会有出入。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "介绍智能校验的离线特点" - }, - { - "role": "assistant", - "content": "我们的校验服务是离线操作,不联网,不上传任何数据。校验的模型加载在本地,只在本地进行校验。您无需顾虑数据泄露的风险。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "介绍智能校验的功能" - }, - { - "role": "assistant", - "content": "正式版可以看《校验报告》中全部校验提示,还有【阅读器】模式可以直接定位到数据点,查错更直观。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "介绍智能校验产品" - }, - { - "role": "assistant", - "content": "我们的产品服务是根据最新披露法规的变动,持续更新迭代的,包年服务相当于贵司全年的披露工作,我们解决了大部分问题。您编制时各种准备、免费的信披培训,编制过程中任何信披问题,编制完成后的校验工作等等,我们都有业务老师和技术支持,全程给您服务的。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "当对方不知道怎么查看校验结果报告时" - }, - { - "role": "assistant", - "content": "建议您使用【阅读器】打开,可以看的更直观,能够快速定位到需注意的位置。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "简介智能校验产品" - }, - { - "role": "assistant", - "content": "我们的产品都是离线操作(即登陆后可以断网),每家公司都是独立账号,无需上传数据、下载系统。不用担心信息泄露风险。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "北京有驻地销售吗?" - }, - { - "role": "assistant", - "content": "有" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "支持什么样的浏览器?" - }, - { - "role": "assistant", - "content": "浏览器:Chrome、Edge、Firefox、360、Safari (均 64 位支持)。\n" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "服务器放在哪里?可以同时几个人在线编辑? " - }, - { - "role": "assistant", - "content": "我们产品没有服务器,我们是离线,每个用户自己本地使用,不支持多人在线编辑(多人在线编辑可以买定制企业版)" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "有看到信息披露规则中指出:上市公司不得委托其他公司或机构代为编制或审阅信息披露文件但中国证监会、证券交易所另有规定的除外。上市公司不得向证券公司、证券服务机构以外的公司或机松咨询信息披露文件的编制、公告等事项。这块儿可以帮忙解释一下吗?" - }, - { - "role": "assistant", - "content": "法规里是不允许外包,我们这个没有人工参与,是提供工具,公司自己操作,不属于外包服务。这是新征求意见稿的规定,没牌照的不能做了,证券法的规定,证券服务机构需要取得备案的,有信息技术系统服务机构的备案,我们的备案排在序号131,需要重申的是,我们提供的是AI工具,不是人工审阅,原来的信披咨询公司,多数就会加入律所或会计师事务所,并去过的证监会备案,但需要一个过程,这个期间客户面临重新选择,所以对于我们的AI工具是个机会,一是AI工具没有合规方面的问题,二是AI对一些基础性的人工服务会是一个替代。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "小智智填能完成多少填报内容?" - }, - { - "role": "assistant", - "content": "1人3分钟完成年报70%填报,主要体现在3个部分:1)对贵公司过去一年定期报告和临时报告数据整理;2)审计报告/财务报告完成财务数据、财务附注数据提取和数据推理计算得出的数据;3)股东名册里股东信息提取,完成相关指标。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "深交所新开放的“文件智能检查”服务是不是致远速联开发的?" - }, - { - "role": "assistant", - "content": "深交所自行研发基于大模型的智能检查,但是每家公司每天限制3次使用,致远速联有同类型大模型智能校验方案,可以在公司本地化部署离线使用,做提交前事先检查,没有次数限制,可以达到类似的业务效果。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "文件智能检查的校验范围是什么?" - }, - { - "role": "assistant", - "content": "A:主要为上市公司提供报告的文本错误和纠正优化建议服务,例如错别字和文本规范性等低级错误。目前提示内容仅供参考不代表交易所的监管意见。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "交易所出的校验服务要用吗?" - }, - { - "role": "assistant", - "content": "在能排上队的情况下,争取要用,相当于交易所掏钱帮大家买了大模型,花费在8位数以上" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "为什么使用了致远速联的低级错误校验,修改后提交到交易所系统,还是报了很多错误,如何解决?" - }, - { - "role": "assistant", - "content": "1、校验效果和模型版本有关02、大模型的原理和传统规则校验不一样,就算同一份文档在交易所系统检查两次,结果也有差异。3、我们尽量通过事前检查,把比较明确的是错误的修改,这样后续的回执信息,明确的低级错误就可以尽量避免。如果其他都是语义优化类的就没什么关系了。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "使用交易所出的校验有额外影响吗?---这条不建议放" - }, - { - "role": "assistant", - "content": "目前没有,但在线SAAS服务的特性,会全程各版本留痕" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "交易所提供的校验和目前定期报告增强校验(小智复核)有效果交叉吗?" - }, - { - "role": "assistant", - "content": "在单一文档财务数据引用的部分,会有一点交叉,其余的部分,历史数据一致性、各种指标的计算和其他的数万条的校验规则,都没有包含" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "后续交易所的校验会包含定期报告增强校验的内容吗?(这条不建议回应,目前根据销售反馈也没人提过)" - }, - { - "role": "assistant", - "content": "交易所的校验用的大模型,大模型的原理使然,不会包含目前校验的内容" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "交易所校验使用建议:" - }, - { - "role": "assistant", - "content": "先使用小智复核完成各项实质性内容的校验,然后使用交易所的校验来检查错别字和规范性(资源有限,使用次数和需要排队),不适合做工作过程中的多次校验" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "第一次加好友,打招呼" - }, - { - "role": "assistant", - "content": "您好!这里是致远速联" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "当需要别人提供个人信息时" - }, - { - "role": "assistant", - "content": "麻烦提供一下您的公司代码、姓名、职务和联系方式" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "当别人说您好" - }, - { - "role": "assistant", - "content": "请问有什么可以帮您的?" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "当对方试用时/后" - }, - { - "role": "assistant", - "content": "您这边对产品服务有任何问题或者有任何信披问题,都可以随时联系我们[玫瑰]" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "主动打招呼" - }, - { - "role": "assistant", - "content": "您好!您有任何信披问题,也可以随时联系我们,打扰啦[玫瑰]" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "当长时间才回答别人时" - }, - { - "role": "assistant", - "content": "抱歉,咨询人员较多,让您久等了[玫瑰]" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "当遇到问题,需要长时间回答别人时" - }, - { - "role": "assistant", - "content": "您好,这边咨询消息较多,正在为您联系信披专家。烦请等候,谢谢" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "当别人加群时" - }, - { - "role": "assistant", - "content": "欢迎添加我们的信披交流群,群内都是董办朋友,我们会在群里发布填报系统的更新信息和相关培训内容,可以多交流哈" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "当别人加群后的提醒" - }, - { - "role": "assistant", - "content": "入群后,麻烦将群名片改成:公司代码/简称+职务+姓名。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "当别人加群后的提醒" - }, - { - "role": "assistant", - "content": "后续相关业务问题,可以在群里直接@我们的信披顾问哦。感谢您对致远速联的支持" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "礼貌用语" - }, - { - "role": "assistant", - "content": "有问题随时联系哈,感谢支持" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "在每期披露过后,对于感兴趣的公司,我们会给对方试用产品" - }, - { - "role": "assistant", - "content": "现在23年年报校验和24年半年报校验开放了免费试用的" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "预约演示" - }, - { - "role": "assistant", - "content": "有时间我们可以约个线上视频会议,给您一边实操一边讲解[愉快" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "填报系统和我们校验的区别" - }, - { - "role": "assistant", - "content": "我们的校验不同于填报系统的校验,填报系统目前的校验功能没有那么完善,会有一些问题无法校验出来,导致一些错误发现不出来。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "介绍智能校验" - }, - { - "role": "assistant", - "content": "我们的校验服务是离线操作,不联网,不上传任何数据。校验的模型加载在本地,只在本地进校验服务是获取巨潮同源数据,可以避免跨报告期财务数据(上期数)填写出错;正式版可." - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "介绍智能校验" - }, - { - "role": "assistant", - "content": "我们的产品服务是根据最新披露法规的变动,持续更新迭代的,包年服务相当于贵司全年的信披工作" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "可断网离线使用功能" - }, - { - "role": "assistant", - "content": "我们的产品都是离线操作(即登陆后可以断网),每家公司都是独立链接,无需上传数据,无信息安全和内部信息泄漏风险,全程服务合规." - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "当我们给对方发完邮件后,需做确认" - }, - { - "role": "assistant", - "content": "您有收到邮件吗?邮件内有离线网址和二维码" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "之前版的智能校验校验错别字主要在哪?当对方问到交易所的那个错别字校验工具区别时。" - }, - { - "role": "assistant", - "content": "我们会对业务要素错别字和会影响到投资者实际性的内容做校验。交易所里的校验不做重点校验,不会涉及到问询和被处罚,没有处罚的依据。我们的校验目的是监管的逻辑,不是简单的错别字,和市场上其他机构做的普通ai纠错不一样。\n市场同类产品基本是《形式校验》,我们追溯到源头,做的《业务实质校验》。\n校验服务是优先保障,明文规定有可能会被处罚的内容不出错,供上市公司作出慎重参考。\n深交所的校验工具是事后提醒,我们的校验系统是可以事前进行复核的。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "在每期披露过后,对于感兴趣的公司,我们会给对方回溯校验报告。" - }, - { - "role": "assistant", - "content": "每期披露过后我都会开放回溯校验报告,这份回溯校验使用的是公开数据,数据量与您实际报送的文件会有出入。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "介绍智能校验的离线特点" - }, - { - "role": "assistant", - "content": "我们的校验服务是离线操作,不联网,不上传任何数据。校验的模型加载在本地,只在本地进行校验。您无需顾虑数据泄露的风险。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "介绍智能校验的功能" - }, - { - "role": "assistant", - "content": "正式版可以看《校验报告》中全部校验提示,还有【阅读器】模式可以直接定位到数据点,查错更直观。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "介绍智能校验产品" - }, - { - "role": "assistant", - "content": "我们的产品服务是根据最新披露法规的变动,持续更新迭代的,包年服务相当于贵司全年的披露工作,我们解决了大部分问题。您编制时各种准备、免费的信披培训,编制过程中任何信披问题,编制完成后的校验工作等等,我们都有业务老师和技术支持,全程给您服务的。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "当对方不知道怎么查看校验结果报告时" - }, - { - "role": "assistant", - "content": "建议您使用【阅读器】打开,可以看的更直观,能够快速定位到需注意的位置。相较于人工检查,机器检查更为高效、准确。您可以校验一下已披露数据,看看效果。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "简介智能校验产品" - }, - { - "role": "assistant", - "content": "我们的产品都是离线操作(即登陆后可以断网),每家公司都是独立账号,无需上传数据、下载系统。不用担心信息泄露风险。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "我们这个插件加入进去,与市场上同类竞品区别是?" - }, - { - "role": "assistant", - "content": "我们是跟监管口径规则对齐的,至于市场上的竞品没有去比较过。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "如何部署?是否离线?/运行逻辑是什么?DS部署校验的\n保密性?" - }, - { - "role": "assistant", - "content": "本地部署,断网离线使用,数据和内幕信息知情报备保密、安全和合规服务。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "临时报告能不能校验?" - }, - { - "role": "assistant", - "content": "临时报告有另外专门产品,现在正处于测试阶段,很快将会推出的。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "使用这个功能进行年报校验还单独收费吗?" - }, - { - "role": "assistant", - "content": "目前这款产品刚推出,还在市场评估阶段,所以具体价格暂时还没有完全确定下来。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "DS插件定期报告校验,标准版价格怎么定义?" - }, - { - "role": "assistant", - "content": "标准版就是买我们标品校验,成为我们的VIP客户,本期年报免费赠送,加量不加价。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "算力版和企业版的价格呢?" - }, - { - "role": "assistant", - "content": "目前这款产品刚推出,还在市场评估阶段,所以具体价格暂时还没有完全确定下来。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "算力版和 企业版能用于临时公告吗" - }, - { - "role": "assistant", - "content": "未来也会" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "什么电脑可安装标准版?" - }, - { - "role": "assistant", - "content": "16G笔记本可以跑14B" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "插件老客户可以用于2024年年报是吗,有次数限制吗" - }, - { - "role": "assistant", - "content": "是的,有限免,次数为?" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "24年年报DEEPSEEK插件校验什么价格?" - }, - { - "role": "assistant", - "content": "包年订阅智能校验,成为VIP。我们会给您发送deepseek安装包,直接电脑上安装即可使用\n【定期报告智能校验】2.5万一年,共四个报告期。您订阅了智能校验,这个DEEPSEEK服务" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "【定期报告智能校验】+【小智智填-定期报告专版】什么价格?" - }, - { - "role": "assistant", - "content": "【定期报告智能校验】+【小智智填-定期报告专版】=35000元/一年(共4个报告期)\n我们的优惠都是针对包年服务的,后面我们有其他优惠活动优先通知您" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "【定期报告智能校验】什么价格?【小智智填-定期报告专版】什么价格?" - }, - { - "role": "assistant", - "content": "【定期报告智能校验】2.5万一年,共四个报告期;【小智智填-定期报告专版】1万一年。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "与其他产品价格对比" - }, - { - "role": "assistant", - "content": "如果你对比过市场其他价,就知道我们家属于性价比最高的了[愉快],功能也最强大、校验也最准确。" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "报价后的催话" - }, - { - "role": "assistant", - "content": "xx总,前阵子给您发的报价方案,这边有新的想法吗?[握手]" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "报价后的催话" - }, - { - "role": "assistant", - "content": "贵司年报期有这部分的订购想法吗?" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "报价后的催话" - }, - { - "role": "assistant", - "content": "考虑的如何?[握手]" - } - ] - }, - { - "conversations": [ - { - "role": "user", - "content": "报价后的催话" - }, - { - "role": "assistant", - "content": "xx总早上好[玫瑰],报价这边有跟领导反馈吗?咱价格是比市场同类产品价格更实惠一些的,贵有贵的原因,报送成功率高嘛[社会社会" - } - ] - } -]