├── 001.png ├── 002.png ├── README.md ├── dataAugmentation ├── 001.png ├── README.md ├── dataset │ ├── combine_and_split.py │ ├── enhanced_data.zip │ └── enhanced_more │ │ ├── misc_filter.json │ │ ├── price_bound.json │ │ ├── price_range.json │ │ └── results.json ├── enhanceBasic │ ├── __init__.py │ ├── add_bye_turn.py │ ├── add_qa_turn.py │ ├── add_qa_turn2.py │ ├── enhance.py │ ├── my_llm.py │ ├── paraphrase.py │ ├── raw_data │ │ ├── 0000.json │ │ ├── 0001.json │ │ ├── 0002.json │ │ ├── 0003.json │ │ ├── 0004.json │ │ ├── 0005.json │ │ ├── 0006.json │ │ ├── 0007.json │ │ ├── 0008.json │ │ ├── 0009.json │ │ ├── 0010.json │ │ ├── 0011.json │ │ ├── 0012.json │ │ ├── 0013.json │ │ ├── 0014.json │ │ ├── 0015.json │ │ ├── 0016.json │ │ ├── 0017.json │ │ ├── 0018.json │ │ ├── 0019.json │ │ ├── 0020.json │ │ ├── 0021.json │ │ ├── 0022.json │ │ ├── 0023.json │ │ ├── 0024.json │ │ ├── 0025.json │ │ ├── 0026.json │ │ ├── 0027.json │ │ ├── 0028.json │ │ ├── 0029.json │ │ ├── 0030.json │ │ ├── 0031.json │ │ ├── 0032.json │ │ ├── 0033.json │ │ ├── 0034.json │ │ ├── 0035.json │ │ ├── 0036.json │ │ ├── 0037.json │ │ ├── 0038.json │ │ ├── 0039.json │ │ ├── 0040.json │ │ ├── 0041.json │ │ ├── 0042.json │ │ ├── 0043.json │ │ ├── 0044.json │ │ ├── 0045.json │ │ ├── 0046.json │ │ ├── 0047.json │ │ ├── 0048.json │ │ └── 0049.json │ ├── raw_data_all.zip │ └── rewrite.py ├── enhanceMore │ ├── api_keys.env │ ├── db_client.py │ ├── generate_by_filter_search.py │ ├── generate_by_hotel_name.py │ ├── my_llm.py │ └── names.json └── requirements.txt ├── qwen2 ├── README.md ├── arguments.py ├── data_preprocess.py ├── dataset │ ├── dev.full.jsonl │ ├── test.full.jsonl │ └── train.full.jsonl ├── eval.sh ├── evaluate.py ├── finetune.py ├── image │ ├── 001.png │ ├── 002.png │ ├── 003.png │ ├── 004.png │ ├── 005.png │ ├── 006.png │ ├── 007.png │ ├── 008.png │ ├── 009.png │ ├── 010.png │ ├── 011.png │ ├── 012.png │ ├── 013.png │ ├── 014.png │ ├── 015.png │ ├── 016.png │ ├── 017.png │ ├── 018.png │ ├── 019.png │ ├── 020.png │ ├── 021.png │ ├── 022.png │ ├── 023.png │ ├── 024.png │ └── 025.png ├── merge.py ├── merge.sh ├── requirements.txt └── train.sh ├── weaviate ├── README.md ├── api_keys.env ├── db_client.py ├── hotel.json ├── image │ ├── 001.png │ ├── 002.png │ ├── 003.png │ ├── 004.png │ ├── 005.png │ ├── 006.png │ ├── 007.png │ ├── 008.png │ ├── 009.png │ ├── 010.png │ ├── 011.png │ ├── 012.png │ ├── 013.png │ ├── 014.png │ ├── 015.png │ ├── 016.png │ ├── 017.png │ ├── 018.png │ ├── 019.png │ ├── 020.png │ ├── 021.png │ ├── 022.png │ ├── 023.png │ └── 024.png └── requirements.txt ├── webApiDemo ├── README.md ├── __pycache__ │ └── db_client.cpython-311.pyc ├── api.py ├── api.sh ├── api_keys.env ├── db_client.py ├── image │ ├── 001.png │ ├── 002.png │ ├── 003.png │ ├── 004.png │ ├── 005.png │ └── 006.png ├── requirements.txt └── webui.py └── webDemo ├── README.md ├── api_keys.env ├── db_client.py ├── image ├── 001.png ├── 002.png ├── 003.png ├── 004.png └── 005.png ├── qwen2_lora.sh └── webui_qwen2.py /001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/001.png -------------------------------------------------------------------------------- /002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/002.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 1、项目介绍 2 | **项目对应视频:** 3 | https://www.bilibili.com/video/BV1NVzwYnEwJ/?vd_source=30acb5331e4f5739ebbad50f7cc6b949 4 | https://youtu.be/aHjNlTxcMGQ 5 | 6 | **南哥AGI研习社YouTube频道:** https://www.youtube.com/@NangePlus2024 7 | **南哥AGI研习社B站频道:** https://space.bilibili.com/509246474 8 | 9 | 10 | ## 1.1 项目简介 11 | 本项目旨在提供一个微调酒店推荐垂直领域大模型并应用的完整闭环案例作为大家的参考案例。本项目使用的基础大模型为Qwen2.5-7B-Instruct 12 | **完整的垂直应用案例闭环** 13 | **项目源码剖析开源共享** 14 | **详实的图文指导手册** 15 | **手把手全流程实操演示视频** 16 | 17 | ## 1.2 主要内容 18 | **(1)构建业务数据库** 19 | 详情见weaviate文件夹 20 | **(2)数据增强、制作数据集** 21 | 详情见dataAugmentation文件夹 22 | **(3)轻量化大模型微调** 23 | 详情见qwen2文件夹 24 | **(4)大模型应用测试** 25 | 详情见webDemo文件夹 26 | **(5)封装大模型推理应用接口并测试** 27 | 详情见webApiDemo文件夹 28 | 29 | ## 1.3 什么是微调 30 | 不严谨的类比,通俗理解什么是大模型微调 31 | 32 | 轻量化微调流程图 33 | 34 | 35 | 36 | # 2、前期准备工作 37 | ## 2.1 集成开发环境搭建 38 | anaconda提供python虚拟环境,pycharm提供集成开发环境 39 | **具体参考如下视频:** 40 | 【大模型应用开发-入门系列】03 集成开发环境搭建-开发前准备工作 41 | https://youtu.be/KyfGduq5d7w 42 | https://www.bilibili.com/video/BV1nvdpYCE33/ 43 | 44 | ## 2.2 大模型LLM服务接口调用方案 45 | (1)gpt大模型等国外大模型使用方案 46 | 国内无法直接访问,可以使用代理的方式,具体代理方案自己选择 47 | 这里推荐大家使用:https://nangeai.top/register?aff=Vxlp 48 | (2)非gpt大模型方案 OneAPI方式或大模型厂商原生接口 49 | (3)本地开源大模型方案(Ollama方式) 50 | **具体参考如下视频:** 51 | 【大模型应用开发-入门系列】04 大模型LLM服务接口调用方案 52 | https://youtu.be/mTrgVllUl7Y 53 | https://www.bilibili.com/video/BV1BvduYKE75/ 54 | 55 | ## 2.3 GPU服务器 56 | 这里大模型微调所使用的服务器是租用的AutoDL算力平台 57 | https://www.autodl.com/home 58 | GPU:RTX 4090D(24GB) 59 | CPU:16 vCPU Intel(R) Xeon(R) Platinum 8481C 60 | 内存:80GB 61 | 硬盘:系统盘30GB、数据盘50GB 62 | GPU驱动:550.107.02 63 | CUDA版本:<=12.4 64 | 65 | 66 | # 3、项目初始化 67 | ## 3.1 下载源码 68 | GitHub或Gitee中下载工程文件到本地,下载地址如下: 69 | https://github.com/NanGePlus/FineTuningLab 70 | https://gitee.com/NanGePlus/FineTuningLab 71 | 72 | ## 3.2 构建项目 73 | 使用pycharm构建一个项目,为项目配置虚拟python环境 74 | 项目名称:FineTuningLab 75 | 76 | ## 3.3 将相关代码拷贝到项目工程中 77 | 直接将下载的文件夹中的文件拷贝到新建的项目目录中 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /dataAugmentation/001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/dataAugmentation/001.png -------------------------------------------------------------------------------- /dataAugmentation/README.md: -------------------------------------------------------------------------------- 1 | # 1、数据预处理简介 2 | 轻量化微调流程图 3 | 4 | ## 1.1 业务数据增强 5 | 根据业务数据特性进行数据增强,使用的数据为开源的预定酒店场景下的酒店数据库 6 | 主要内容:基于原始的数据利用大模型进行数据增强 7 | (1)对酒店设施的描述进行口语化重写 8 | (2)补充一定比例的多轮问答和结束语对话 9 | (3)补充按酒店名(简称)、价格上限查询等对话 10 | 11 | ## 1.2 制作数据集及拆分训练集、验证集、测试集 12 | 根据增强后的业务数据进行数据集整理,按照规则处理成特定的数据组织格式 13 | 最后按照8:1:1拆分训练集、验证集、测试集 14 | 15 | 16 | # 2、项目测试 17 | 打开命令行终端,执行 `cd weaviate` 指令进入到weaviate文件夹 18 | 执行如下命令安装依赖包 19 | `pip install -r requirements.txt` 20 | 每个软件包后面都指定了本次视频测试中固定的版本号 21 | **注意:** 建议先使用要求的对应版本进行本项目测试,避免因版本升级造成的代码不兼容。测试通过后,可进行升级测试 22 | 23 | ## 2.1 数据增强处理1 24 | enhanceBasic目录中脚本包含以下功能: 25 | (1)将原始数据中设施相关的说法,改为更口语化的表达 26 | (2)在原始数据中,补充针对上文已推荐的酒店的问答,如:“XXX多少钱”,“XXX地址在哪” 27 | (3)在原始数据中,补充针对上文已推荐的酒店的比较型问答,如:“哪个更便宜” 28 | (4)在原始数据中,补充结束语,如:“就住XXX吧”“祝您入住愉快” 29 | 打开命令行终端,运行如下命令进行测试 30 | `cd enhanceBasic` 31 | `python enhance.py` 32 | 33 | ## 2.2 数据增强处理2 34 | enhanceMore目录中脚本包含以下功能 35 | (1)限制价格上/下界的查询 36 | (2)限制价格区间的查询 37 | (3)组合价格与其他条件的查询 38 | (4)按酒店名称查询(包括用户不说酒店全名的情况) 39 | 打开命令行终端,运行如下命令进行测试 40 | `cd enhanceMore` 41 | `python generate_by_filter_search.py` 42 | `python generate_by_hotel_name.py` 43 | 44 | ## 2.3 制作数据集 45 | 打开命令行终端,运行如下命令进行测试 46 | `cd dataset` 47 | `python combine_and_split.py` 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /dataAugmentation/dataset/combine_and_split.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import random 4 | import copy 5 | 6 | 7 | # 随机数生成器在不同运行时返回相同的随机数序列 8 | random.seed(42) 9 | 10 | 11 | # 用于处理一个对话(dialog),并将其转换为带有上下文和回复的单轮次格式,然后追加到 data 列表中 12 | # dialog:表示整个对话的列表,每个元素是该对话的一个轮次(turn),包含角色(如用户或助手)和内容等信息 13 | # data:用于存储处理后数据的列表,每个元素包含上下文(context)和回复(response) 14 | def process_dialog(dialog, data): 15 | # 初始化空列表 buffer,用于临时存储当前对话中的轮次,构建上下文 16 | buffer = [] 17 | # 遍历 dialog 中的每一轮对话 turn 18 | for turn in dialog: 19 | # 检查当前轮次的角色是否为 "assistant" 或 "search",并确保 buffer 中已有内容 20 | # 此条件判断意味着,当助手或搜索角色的回复到达时,当前 buffer 的内容会作为上下文,构成上下文-回复对 21 | if (turn["role"] == "assistant" or turn["role"] == "search") and len(buffer)>0: 22 | # 当满足条件时,将当前上下文和对应的回复格式化为字典形式,并添加到 data 列表中 23 | # context:将 buffer 转换为 JSON 格式字符串,表示该回复的上下文 24 | # response:将当前轮次 turn 转换为 JSON 格式字符串,作为上下文对应的回复 25 | data.append({ 26 | "context" : json.dumps(buffer,ensure_ascii=False), 27 | "response" : json.dumps(turn,ensure_ascii=False) 28 | }) 29 | # 无论当前轮次是否符合条件,都会将其添加到 buffer 中,确保后续轮次能够包含完整的上下文 30 | buffer.append(turn) 31 | # 返回 data 列表,其中包含处理好的上下文和回复对 32 | return data 33 | 34 | 35 | # 将对话数据集 data 转换为一系列单一轮次对话(turns)的列表 36 | # data:包含多个对话(dialog)数据的列表 37 | # shuffle:布尔值,指示是否在处理后对数据进行随机排序,默认为 False 38 | def data_to_turns(data,shuffle=False): 39 | # 初始化空列表 ans,用于存储处理后的单轮次对话数据 40 | ans = [] 41 | # 遍历 data 中的每个对话 dial,并调用 process_dialog 函数来处理每个对话,将结果追加到 ans 列表中 42 | for dial in data: 43 | # 根据每个对话的角色,将对话转换成适合后续使用的格式,并将处理后的结果添加到 ans 中 44 | process_dialog(dial,ans) 45 | # 检查 shuffle 参数是否为 True。如果是,则对 ans 列表中的元素顺序进行随机打乱 46 | # 在某些情况下,将数据顺序随机化可以帮助提升模型在训练时的泛化能力 47 | if shuffle: 48 | random.shuffle(ans) 49 | # 返回 ans 列表,其中包含处理后的单轮次对话数据 50 | return ans 51 | 52 | 53 | # 用于判断一个对话中是否包含多次搜索请求 54 | # dialog:表示对话内容,是一个包含多个对话轮次的列表 55 | def is_multi_search(dialog): 56 | # 初始化计数器 count,用于统计该对话中 "search" 类型的轮次数量 57 | count = 0 58 | # 遍历 dialog 列表中的每个 turn,即每个对话轮次。每个 turn 是一个字典,包含了该轮对话的相关信息(如角色和内容) 59 | for turn in dialog: 60 | # 判断 turn 字典中的 role 字段是否为 "search" 61 | # 如果 role 的值为 "search",则表示该轮次为搜索操作,count 增加 1 62 | if turn["role"] == "search": 63 | count += 1 64 | # 返回一个布尔值,表示 count 是否大于 1 65 | # 如果 count > 1,说明该对话中有多次搜索操作,则返回 True;否则返回 False 66 | return count > 1 67 | 68 | 69 | # 主要用于读取指定目录下的 JSON 文件,并将其按多轮和单轮搜索对话分类 70 | # dir_path:数据文件所在的目录路径 71 | # data:传入的空数据列表,用于保存加载的对话数据 72 | # n:限制单轮搜索对话的数量,默认为 None 表示不限制 73 | def process_dir(dir_path,data,n=None): 74 | files = [] 75 | # 遍历指定目录 dir_path 下的文件,将文件路径加入 files 列表 76 | # os.listdir(dir_path):列出目录下的所有文件和子目录名 77 | # os.path.join(dir_path, filename):将目录路径和文件名组合成完整路径 78 | # os.path.isfile(file_path):确保只添加文件路径,忽略子目录 79 | for filename in os.listdir(dir_path): 80 | file_path = os.path.join(dir_path, filename) 81 | if os.path.isfile(file_path): 82 | files.append(file_path) 83 | # 逐个读取 files 中的文件内容,假设每个文件是一个 JSON 格式的对话列表,将其解析为 dialog 对象并添加到 data 列表中 84 | for file_path in files: 85 | with open(file_path,'r',encoding="utf-8") as fp: 86 | # 解析 JSON 文件内容并加载为 Python 对象 87 | dialog = json.load(fp) 88 | data.append(dialog) 89 | # 初始化两个空列表,分别用于保存多轮(multi)和单轮(single)搜索对话 90 | multi = [] 91 | single = [] 92 | # 遍历 data 中的对话,利用 is_multi_search 函数判断每个对话是否为多轮搜索对话 93 | # is_multi_search(dial):返回 True 表示该对话包含多次搜索,添加到 multi 列表,否则添加到 single 列表 94 | for dial in data: 95 | if is_multi_search(dial): 96 | multi.append(dial) 97 | else: 98 | single.append(dial) 99 | # 使用 random.shuffle 函数对 single 列表进行随机打乱,以增加数据多样性 100 | random.shuffle(single) 101 | # 如果 n 不为 None,则截取 single 列表的前 n - len(multi) 条数据 102 | # 目的是确保 single 列表的数量不会超过指定的最大数量 n,但同时保证 multi 列表中的所有多轮对话都被保留 103 | if n is not None: 104 | single = single[:n-len(multi)] 105 | # 将 multi 和 single 列表合并并返回,保证多轮对话在前,单轮对话在后 106 | return multi+single 107 | 108 | 109 | # 用于从指定目录 dir_path 中读取文件内容,并将每个文件中的对话数据添加到 data 列表中 110 | # dir_path:包含数据文件的目录路径 111 | # data:用于存储所有对话数据的列表 112 | def process_dir_v2(dir_path, data): 113 | # 遍历指定目录 dir_path 下的文件,将文件路径加入 files 列表 114 | # os.listdir(dir_path):列出目录下的所有文件和子目录名 115 | # os.path.join(dir_path, filename):将目录路径和文件名组合成完整路径 116 | # os.path.isfile(file_path):确保只添加文件路径,忽略子目录 117 | for filename in os.listdir(dir_path): 118 | file_path = os.path.join(dir_path, filename) 119 | if os.path.isfile(file_path): 120 | with open(file_path,'r',encoding="utf-8") as fp: 121 | dialogs = json.load(fp) 122 | for dial in dialogs: 123 | data.append(dial) 124 | #process_dialog(dial,data) 125 | # 返回更新后的 data 列表,该列表包含了 dir_path 目录中所有文件中的对话数据 126 | return data 127 | 128 | 129 | # 用于将数据集 data 按比例 ratio 划分为训练集、验证集和测试集 130 | # data:需要划分的数据集,通常为包含对话或数据样本的列表 131 | # ratio:验证集和测试集的比例。例如,若 ratio 为 0.1,则验证集和测试集各占数据集的 10% 132 | def split_data(data,ratio): 133 | # 打乱数据集 data 中的样本顺序,以确保划分后的数据集分布尽可能随机和均匀 134 | # 通过随机打乱数据样本顺序,减少原始顺序带来的数据偏差 135 | random.shuffle(data) 136 | # 根据比例 ratio 计算验证集的大小 dev_size 137 | # 将数据集总长度 len(data) 乘以 ratio,然后转换为整数,得到验证集所需的样本数量 138 | dev_size = int(len(data)*ratio) 139 | # 设置测试集的大小 test_size,与验证集大小相同 140 | test_size = dev_size 141 | # 计算训练集的大小 train_size 142 | # 通过总数据集大小减去验证集和测试集的大小,得到剩余的数据量作为训练集的大小 143 | train_size = len(data)-dev_size-test_size 144 | # 从打乱后的 data 中提取前 train_size 个样本作为训练集 train_data 145 | train_data = data[:train_size] 146 | # 从 data 中提取训练集之后的 dev_size 个样本作为验证集 dev_data 147 | dev_data = data[train_size:train_size+dev_size] 148 | # 从 data 中提取剩下的样本作为测试集 test_data 149 | test_data = data[train_size+dev_size:] 150 | # 返回划分后的训练集、验证集和测试集 151 | return train_data, dev_data, test_data 152 | 153 | 154 | # 用于将数据列表 data 写入指定的 .jsonl 文件 filename 中,每个数据项作为独立的一行 JSON 格式字符串存储 155 | def write_jsonl(data,filename): 156 | # 以写入模式 ("w") 打开指定的文件 filename,编码格式为 "utf-8",并将文件对象引用赋予 fp 变量 157 | # 使用 with 语句确保文件在操作完成后自动关闭,避免文件泄露或损坏 158 | with open(filename,"w",encoding="utf-8") as fp: 159 | # 遍历 data 列表中的每个元素 example,其中每个元素是一个字典,表示一个上下文-回复对 160 | for example in data: 161 | # 将当前元素 example 转换为 JSON 格式的字符串,并确保不使用 ASCII 转义(ensure_ascii=False),这样可以保留非 ASCII 字符(如中文字符) 162 | # json_str 是 example 的 JSON 字符串表示形式 163 | json_str = json.dumps(example,ensure_ascii=False) 164 | # 将 json_str 写入文件 fp 中,并在每个 JSON 字符串后添加换行符 \n,以确保每条记录独占一行,符合 .jsonl(JSON Lines)文件格式 165 | fp.write(json_str+"\n") 166 | 167 | 168 | # 定义 main 函数,用于数据预处理、数据集拆分和结果写入 169 | # raw_data_path: 原始数据的路径 170 | # more_data_path: 额外数据的路径,默认为 None 171 | # output_dir: 输出文件夹的路径,默认为当前目录 "." 172 | # ratio: 用于划分验证集和测试集的比例,默认为 0.1 173 | # n: 限定返回的单轮“search”对话的最大数量,默认为 None 174 | def main(raw_data_path, more_data_path=None, output_dir=".",ratio=0.1,n=None): 175 | # 检查输出目录是否存在,如果不存在则创建该目录 176 | if not os.path.exists(output_dir): 177 | os.makedirs(output_dir) 178 | # 初始化空列表 data 179 | data = [] 180 | # 会返回包含多轮和单轮“search”对话的列表 181 | data = process_dir(raw_data_path,data,n) 182 | # 检查是否提供了 more_data_path。如果提供,则调用 process_dir_v2 读取更多的对话数据并添加到 data 列表中 183 | # process_dir_v2 与 process_dir 不同,它逐个文件处理并追加每个文件中所有的对话记录 184 | if more_data_path is not None: 185 | data = process_dir_v2(more_data_path,data) 186 | # 调用 split_data 函数,按指定的 ratio 将数据拆分为训练集、开发集和测试集 187 | train_data, dev_data, test_data = split_data(data,ratio) 188 | # 将训练集 train_data 转换为对话轮次格式,然后写入 .jsonl 文件 189 | # 如果 n 参数为 None(即不限制单轮对话数量),则文件命名为 train.full.jsonl;否则为 train.jsonl 190 | write_jsonl( 191 | data_to_turns(train_data), 192 | os.path.join(output_dir,"train.jsonl" if n is not None else "train.full.jsonl") 193 | ) 194 | # 将开发集 dev_data 转换为对话轮次格式,并写入文件 195 | write_jsonl( 196 | data_to_turns(dev_data), 197 | os.path.join(output_dir,"dev.jsonl" if n is not None else "dev.full.jsonl" ) 198 | ) 199 | # 将测试集 test_data 转换为对话轮次格式并写入文件 200 | write_jsonl( 201 | data_to_turns(test_data), 202 | os.path.join(output_dir,"test.jsonl" if n is not None else "test.full.jsonl") 203 | ) 204 | 205 | 206 | 207 | if __name__ == "__main__": 208 | # 指定原始数据目录 enhanced_data,额外数据目录 enhanced_more,和 n=None(即不限制 single 数量) 209 | #main("enhanced_hotel_data",more_data_path="enhanced_more",n=1500) 210 | main("enhanced_data",more_data_path="enhanced_more",n=None) -------------------------------------------------------------------------------- /dataAugmentation/dataset/enhanced_data.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/dataAugmentation/dataset/enhanced_data.zip -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/dataAugmentation/enhanceBasic/__init__.py -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/add_bye_turn.py: -------------------------------------------------------------------------------- 1 | from langchain_core.prompts import PromptTemplate 2 | from langchain.output_parsers import PydanticOutputParser, OutputFixingParser 3 | import json 4 | import re 5 | from pydantic import BaseModel, Field 6 | from typing import List 7 | from enum import Enum 8 | # 导入本应用程序提供的方法 9 | from my_llm import myLLM 10 | 11 | 12 | 13 | PROMPT_TEMPLATE = """ 14 | 给定一段user与assistant的对话,其中search表示搜索条件,return表示返回的结果: 15 | ``` 16 | {dialog} 17 | ``` 18 | 19 | 请补充生成一轮对话,模拟user表示愿意入住这个酒店。你可以使用不同的说法。用很口语的方式表达。亲切、礼貌一些。 20 | 并模拟assistant,回答“好的,祝您入住愉快”。 21 | 对话必须先由user开始,然后assistant回复。每人只一轮。 22 | 只输出一轮对话,不需要输出多轮对话,不要重复以上的对话内容。 23 | 确保你输出与原句语言保持一致。 24 | 按以下形式输出结果: 25 | {format_instruction} 26 | """ 27 | 28 | 29 | class Role(str, Enum): 30 | USER = "user" 31 | ASSISTANT = "assistant" 32 | 33 | 34 | class Turn(BaseModel): 35 | role: Role = Field(description="对话角色") 36 | content: str = Field(description="对话内容") 37 | 38 | 39 | class Bye(BaseModel): 40 | dialog: List[Turn] = Field(description="对话内容") 41 | 42 | 43 | # 为对话生成一轮结束语:例如“好的,祝您入住愉快” 44 | class ByeGen: 45 | def __init__(self): 46 | self.llm = myLLM() 47 | self.output_parser = PydanticOutputParser(pydantic_object=Bye) 48 | self.robust_parser = OutputFixingParser.from_llm(parser=self.output_parser, llm=self.llm) 49 | self.prompt = PromptTemplate.from_template(PROMPT_TEMPLATE).partial( 50 | format_instruction=self.output_parser.get_format_instructions(), 51 | ) 52 | 53 | self.chain = self.prompt | self.llm 54 | 55 | def gen(self, dialog: List) -> List|None: 56 | response = self.chain.invoke( 57 | { 58 | "dialog": json.dumps(dialog, indent=4, ensure_ascii=False), 59 | } 60 | ) 61 | try: 62 | response = re.search(r'```json\n(.*?)\n```', response.content, re.S).group(1) 63 | qa = json.loads(response).get("dialog", []) 64 | if isinstance(qa,list): 65 | if len(qa) != 2: 66 | raise Exception("Invalid format") 67 | for turn in qa: 68 | if "role" not in turn or "content" not in turn: 69 | raise Exception("Invalid format") 70 | if qa[0]["role"] != "user" or qa[1]["role"] != "assistant": 71 | raise Exception("Invalid format") 72 | ans = qa 73 | else: 74 | raise Exception("Invalid format") 75 | except: 76 | qa = self.robust_parser.parse(response) 77 | 78 | ans = [] 79 | for turn in qa.dialog: 80 | t = { 81 | "role": turn.role, 82 | "content": turn.content, 83 | } 84 | ans.append(t) 85 | if len(ans) != 2: 86 | return None 87 | return ans 88 | 89 | 90 | 91 | if __name__ == "__main__": 92 | text = ''' 93 | [ 94 | { 95 | "role": "user", 96 | "content": "这么多好玩的地方啊,真不错啊,溜达完我想找个地方休息,你可以帮我推荐一个价格是400-500元的酒店吗?" 97 | }, 98 | { 99 | "role": "search", 100 | "arguments": { 101 | "price_range_lower": 400, 102 | "price_range_upper": 500 103 | } 104 | }, 105 | { 106 | "role": "return", 107 | "records": [ 108 | { 109 | "name": "北京圆山大酒店", 110 | "type": "舒适型", 111 | "address": "北京西城区裕民路2号", 112 | "subway": "安华桥地铁站A口", 113 | "phone": "010-62010033", 114 | "facilities": [ 115 | "酒店各处提供wifi", 116 | "宽带上网", 117 | "国际长途电话", 118 | "吹风机", 119 | "24小时热水", 120 | "中式餐厅", 121 | "残疾人设施", 122 | "会议室", 123 | "健身房", 124 | "无烟房", 125 | "酒吧", 126 | "棋牌室", 127 | "早餐服务", 128 | "接站服务", 129 | "接机服务", 130 | "接待外宾", 131 | "洗衣服务", 132 | "行李寄存", 133 | "租车", 134 | "叫醒服务" 135 | ], 136 | "price": 416.0, 137 | "rating": 4.3, 138 | "hotel_id": 180 139 | } 140 | ] 141 | }, 142 | { 143 | "role": "assistant", 144 | "content": "你觉得北京圆山大酒店怎么样呢,我个人还是觉得不错的。" 145 | } 146 | ] 147 | ''' 148 | 149 | dialog = json.loads(text) 150 | 151 | new_turns = ByeGen().gen(dialog) 152 | print('new_turns is :',new_turns) 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/add_qa_turn.py: -------------------------------------------------------------------------------- 1 | import random 2 | import re 3 | from langchain_core.prompts import PromptTemplate 4 | from langchain.output_parsers import PydanticOutputParser, OutputFixingParser 5 | import json 6 | from pydantic import BaseModel, Field 7 | from typing import List 8 | from enum import Enum 9 | # 导入本应用程序提供的方法 10 | from my_llm import myLLM 11 | 12 | 13 | 14 | PROMPT_TEMPLATE = """ 15 | 给定一段user与assistant的对话,其中search表示搜索条件,return表示返回的结果: 16 | ``` 17 | {dialog} 18 | ``` 19 | 20 | 请补充生成一轮对话,模拟user,针对assistant提供的酒店,随机选则酒店的任意一个属性进行提问,包括:价格、评分、地址、电话、是否包含某设置等。 21 | 例如: 22 | {examples} 23 | etc. 24 | 25 | 请用很口语的方式提问,可以说酒店的名字也可以说”这个酒店“,或”这家酒店“。Try your best to paraphrase the question!尽可能改写问题! 26 | 注意不要重复提问之前对话中assistant已经提供的信息。 27 | 28 | 然后模拟assistant,根据酒店的实际属性值,回答该问题。答案必须与给出的酒店的真实信息一致。 29 | 对话必须先由user提问,然后assistant回答。每人只一轮。 30 | 只输出一轮对话,不需要输出多轮对话,不要重复以上的对话内容。 31 | 确保你输出与原句语言保持一致。 32 | 按以下形式输出结果: 33 | {format_instruction} 34 | """ 35 | 36 | 37 | # examples 是一个包含问答示例的字符串列表,表示常见的用户问询,例如房价、评分、地址、电话和设施情况等 38 | examples = [ 39 | "“多少钱/什么价格/每晚房价?”", 40 | "“评分多少?”", 41 | "”在什么位置/详细地址是什么?”", 42 | "“电话是多少/电话发我一下?”", 43 | "“有没有免费wifi?”", 44 | "“有没有商务中心?”" 45 | ] 46 | 47 | # 定义了一个枚举类 Role,继承自 str 和 Enum,用于描述对话中角色的身份 48 | # USER 表示用户角色,ASSISTANT 表示助手角色 49 | # 这种枚举方式确保角色字段只能取 user 或 assistant 这两个值,从而提高数据一致性 50 | class Role(str, Enum): 51 | USER = "user" 52 | ASSISTANT = "assistant" 53 | 54 | # 定义了一个 Turn 类,继承自 Pydantic 的 BaseModel,用于表示对话中的一轮发言 55 | # role 属性使用 Role 枚举来标识是谁在发言(用户或助手),并提供了描述性注释“对话角色” 56 | # content 属性是一个字符串,用于存储发言的具体内容,带有描述性注释“对话内容” 57 | # Pydantic 的 Field 方法用于提供额外的元数据,例如描述,方便文档生成和可读性 58 | class Turn(BaseModel): 59 | role: Role = Field(description="对话角色") 60 | content: str = Field(description="对话内容") 61 | 62 | # 定义了一个 QA 类,继承自 Pydantic 的 BaseModel,用于表示一个完整的对话问答 63 | # dialog 属性是一个 Turn 对象的列表,表示整个对话的内容 64 | # 使用 Field 方法提供描述性注释“对话内容”,说明这是对话的主体部分 65 | class QA(BaseModel): 66 | dialog: List[Turn] = Field(description="对话内容") 67 | 68 | 69 | # QAGen 类的作用是为对话生成一轮问答 70 | # 它使用预训练的大型语言模型(如 GPT-3.5)来生成用户提问和助手回答的对话回合 71 | # 通过模板、示例和解析器的组合,它能够处理和修复模型输出的格式问题,并确保返回符合预期结构的问答数据 72 | # 如果生成的问答格式无效,它会尝试修复输出并返回正确的格式 73 | # 定义了一个 QAGen 类,其目的是为对话生成问答,例如询问酒店的价格、评分、地址、电话等信息 74 | class QAGen: 75 | # __init__ 是类的构造函数,在创建 QAGen 类的实例时会被调用 76 | def __init__(self): 77 | # 设置大模型 78 | self.llm = myLLM() 79 | # 创建一个 PydanticOutputParser 对象 output_parser,用于解析从模型生成的输出,并将其转换为 QA 数据模型的实例。QA 应该是一个预定义的 Pydantic 数据模型,定义了问答数据的格式 80 | self.output_parser = PydanticOutputParser(pydantic_object=QA) 81 | # 创建一个 OutputFixingParser 对象 robust_parser,它使用 output_parser 和 llm(语言模型)来修复和解析输出 82 | # OutputFixingParser 是一种增强型的解析器,会修复模型输出中的格式问题 83 | self.robust_parser = OutputFixingParser.from_llm(parser=self.output_parser, llm=self.llm) 84 | # 这里使用 PromptTemplate.from_template(PROMPT_TEMPLATE) 从模板 PROMPT_TEMPLATE 创建一个 PromptTemplate 对象 85 | # partial() 方法用于在模板中插入必要的格式化指令,这里传递了从 output_parser 获取的格式化指令 86 | self.prompt = PromptTemplate.from_template(PROMPT_TEMPLATE).partial( 87 | format_instruction=self.output_parser.get_format_instructions(), 88 | ) 89 | 90 | # 创建一个chain,它将语言模型 llm 和格式化的 prompt 结合在一起,形成一个可以运行的链式处理流程 91 | self.chain = self.prompt | self.llm 92 | 93 | 94 | # gen 方法用于生成一轮问答,接收一个对话列表 dialog,并返回生成的问答对,或返回 None(如果格式无效) 95 | def gen(self, dialog: List) -> List|None: 96 | # 随机打乱 examples 列表的顺序 97 | # examples 是一个包含对话示例的列表,用于提供给模型,帮助模型理解上下文 98 | random.shuffle(examples) 99 | # 将 dialog 转换为格式化的 JSON 字符串,并传递给 LLMChain 的 run 方法 100 | # 将 examples 列表中的示例连接为一个字符串,每个示例之间用换行符分隔,传递给 run 方法,模型将使用这些示例来生成合理的回答 101 | response = self.chain.invoke( 102 | { 103 | "dialog":json.dumps(dialog, indent=4, ensure_ascii=False), 104 | "examples":"\n".join(examples), 105 | } 106 | ) 107 | try: 108 | # 使用正则表达式从返回信息中结构出完成对话 109 | response = re.search(r'```json\n(.*?)\n```', response.content, re.S).group(1) 110 | # 尝试将模型生成的响应 response 解析为一个 JSON 对象。如果解析成功,将其赋值给 qa 111 | qa = json.loads(response).get("dialog", []) 112 | 113 | # 检查 qa 是否是一个列表,并且该列表的长度是否为 2(因为问答应该有两个部分:用户提问和助手回答) 114 | if isinstance(qa, list): 115 | if len(qa) != 2: 116 | raise Exception("Invalid format") 117 | # 检查每个 turn(回合)是否包含 role(角色)和 content(内容)。如果缺少这两个字段,则认为格式无效 118 | for turn in qa: 119 | if "role" not in turn or "content" not in turn: 120 | raise Exception("Invalid format") 121 | # 检查 qa 列表的第一个回合是否为用户提问,第二个回合是否为助手回答。如果角色顺序不对,则抛出异常 122 | if qa[0]["role"] != "user" or qa[1]["role"] != "assistant": 123 | raise Exception("Invalid format") 124 | # 如果上述检查都通过,将 qa 赋值给 ans,作为最终的问答结果 125 | ans = qa 126 | # 如果 qa 不是列表,抛出异常,表示格式无效 127 | else: 128 | raise Exception("Invalid format") 129 | # 如果上述 try 块中的任何一行抛出异常,则使用 robust_parser 来解析响应 130 | # robust_parser 是一个更强健的解析器,能够处理格式问题 131 | except: 132 | qa = self.robust_parser.parse(response) 133 | 134 | # 将 qa.dialog 中的每个回合(turn)转换为字典形式,包含 role 和 content 字段,并将其添加到 ans 列表中 135 | ans = [] 136 | for turn in qa.dialog: 137 | t = { 138 | "role": turn.role, 139 | "content": turn.content, 140 | } 141 | ans.append(t) 142 | # 检查 ans 列表的长度是否为 2。如果不是,返回 None,表示生成的问答无效 143 | if len(ans) != 2: 144 | return None 145 | # 返回生成的问答列表 ans 146 | return ans 147 | 148 | 149 | 150 | if __name__ == "__main__": 151 | text = ''' 152 | [ 153 | { 154 | "role": "user", 155 | "content": "这么多好玩的地方啊,真不错啊,溜达完我想找个地方休息,你可以帮我推荐一个价格是400-500元的酒店吗?" 156 | }, 157 | { 158 | "role": "search", 159 | "arguments": { 160 | "price_range_lower": 400, 161 | "price_range_upper": 500 162 | } 163 | }, 164 | { 165 | "role": "return", 166 | "records": [ 167 | { 168 | "name": "北京圆山大酒店", 169 | "type": "舒适型", 170 | "address": "北京西城区裕民路2号", 171 | "subway": "安华桥地铁站A口", 172 | "phone": "010-62010033", 173 | "facilities": [ 174 | "酒店各处提供wifi", 175 | "宽带上网", 176 | "国际长途电话", 177 | "吹风机", 178 | "24小时热水", 179 | "中式餐厅", 180 | "残疾人设施", 181 | "会议室", 182 | "健身房", 183 | "无烟房", 184 | "酒吧", 185 | "棋牌室", 186 | "早餐服务", 187 | "接站服务", 188 | "接机服务", 189 | "接待外宾", 190 | "洗衣服务", 191 | "行李寄存", 192 | "租车", 193 | "叫醒服务" 194 | ], 195 | "price": 416.0, 196 | "rating": 4.3, 197 | "hotel_id": 180 198 | } 199 | ] 200 | }, 201 | { 202 | "role": "assistant", 203 | "content": "你觉得北京圆山大酒店怎么样呢,我个人还是觉得不错的。" 204 | } 205 | ] 206 | ''' 207 | 208 | dialog = json.loads(text) 209 | 210 | new_turns = QAGen().gen(dialog) 211 | print('new_turns is :',new_turns) 212 | 213 | -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/add_qa_turn2.py: -------------------------------------------------------------------------------- 1 | import random 2 | from langchain_core.prompts import PromptTemplate 3 | from langchain.output_parsers import PydanticOutputParser, OutputFixingParser 4 | import json 5 | import re 6 | from pydantic import BaseModel, Field 7 | from typing import List 8 | from enum import Enum 9 | # 导入本应用程序提供的方法 10 | from my_llm import myLLM 11 | 12 | 13 | 14 | PROMPT_TEMPLATE = """ 15 | 给定一段user与assistant的对话,其中search表示搜索条件,return表示返回的结果: 16 | ``` 17 | {dialog} 18 | ``` 19 | 20 | 请补充生成一轮对话,模拟user,针对assistant提供的酒店,随机选则酒店的任意一个属性进行比较性提问,包括:价格、评分、地址、电话、是否包含某设置等。 21 | 例如: 22 | {examples} 23 | etc. 24 | 25 | 请用很口语的方式提问。Try your best to paraphrase the question!尽可能改写问题! 26 | 注意不要重复提问之前对话中assistant已经提供的信息。 27 | 28 | 然后模拟assistant,根据酒店的实际属性值,回答该问题。答案必须与给出的酒店的真实信息一致。 29 | 对话必须先由user提问,然后assistant回答。每人只一轮。 30 | 只输出一轮对话,不需要输出多轮对话,不要重复以上的对话内容。 31 | 确保你输出与原句语言保持一致。 32 | 按以下形式输出结果: 33 | {format_instruction} 34 | """ 35 | 36 | examples = [ 37 | "“哪个便宜?”", 38 | "“哪个高档一些?”", 39 | "“哪个评分高?”", 40 | "”哪个有wifi”", 41 | "“有带商务中心的吗”", 42 | "“有带棋牌室的吗”", 43 | ] 44 | 45 | class Role(str, Enum): 46 | USER = "user" 47 | ASSISTANT = "assistant" 48 | 49 | 50 | class Turn(BaseModel): 51 | role: Role = Field(description="对话角色") 52 | content: str = Field(description="对话内容") 53 | 54 | 55 | class QA(BaseModel): 56 | dialog: List[Turn] = Field(description="对话内容") 57 | 58 | 59 | # 为对话生成一轮对比型问答:例如哪个酒店便宜、高档、评分高、有wifi等 60 | class QAGen2: 61 | def __init__(self): 62 | # 设置大模型 63 | self.llm = myLLM() 64 | self.output_parser = PydanticOutputParser(pydantic_object=QA) 65 | self.robust_parser = OutputFixingParser.from_llm(parser=self.output_parser, llm=self.llm) 66 | self.prompt = PromptTemplate.from_template(PROMPT_TEMPLATE).partial( 67 | format_instruction=self.output_parser.get_format_instructions(), 68 | ) 69 | 70 | self.chain = self.prompt | self.llm 71 | 72 | def gen(self, dialog: List) -> List|None: 73 | random.shuffle(examples) 74 | response = self.chain.invoke( 75 | { 76 | "dialog": json.dumps(dialog, indent=4, ensure_ascii=False), 77 | "examples": "\n".join(examples), 78 | } 79 | ) 80 | try: 81 | response = re.search(r'```json\n(.*?)\n```', response.content, re.S).group(1) 82 | qa = json.loads(response).get("dialog", []) 83 | if isinstance(qa, list): 84 | if len(qa) != 2: 85 | raise Exception("Invalid format") 86 | for turn in qa: 87 | if "role" not in turn or "content" not in turn: 88 | raise Exception("Invalid format") 89 | if qa[0]["role"] != "user" or qa[1]["role"] != "assistant": 90 | raise Exception("Invalid format") 91 | ans = qa 92 | else: 93 | raise Exception("Invalid format") 94 | except: 95 | qa = self.robust_parser.parse(response) 96 | 97 | ans = [] 98 | for turn in qa.dialog: 99 | t = { 100 | "role": turn.role, 101 | "content": turn.content, 102 | } 103 | ans.append(t) 104 | if len(ans) != 2: 105 | return None 106 | return ans 107 | 108 | 109 | 110 | if __name__ == "__main__": 111 | text = ''' 112 | [ 113 | { 114 | "role": "user", 115 | "content": "游玩结束我想找一家提供无烟房的酒店住宿,有什么推荐的吗?" 116 | }, 117 | { 118 | "role": "search", 119 | "arguments": { 120 | "facilities": [ 121 | "无烟房" 122 | ] 123 | } 124 | }, 125 | { 126 | "role": "return", 127 | "records": [ 128 | { 129 | "name": "北京贵都大酒店", 130 | "type": "高档型", 131 | "address": "北京西城区广安门内大街217号", 132 | "subway": "菜市口地铁站D口", 133 | "phone": "010-51979888", 134 | "facilities": [ 135 | "公共区域和部分房间提供wifi", 136 | "宽带上网", 137 | "吹风机", 138 | "24小时热水", 139 | "西式餐厅", 140 | "中式餐厅", 141 | "会议室", 142 | "健身房", 143 | "无烟房", 144 | "商务中心", 145 | "接站服务", 146 | "接机服务", 147 | "洗衣服务", 148 | "行李寄存", 149 | "叫醒服务" 150 | ], 151 | "price": 1354.0, 152 | "rating": 4.7, 153 | "hotel_id": 0 154 | }, 155 | { 156 | "name": "瑞尔威连锁饭店(北京西客站店)", 157 | "type": "舒适型", 158 | "address": "北京丰台区莲花池东路116-2号", 159 | "subway": "北京西站地铁站A口", 160 | "phone": "010-63959988", 161 | "facilities": [ 162 | "酒店各处提供wifi", 163 | "宽带上网", 164 | "国际长途电话", 165 | "吹风机", 166 | "24小时热水", 167 | "暖气", 168 | "会议室", 169 | "无烟房", 170 | "接待外宾", 171 | "行李寄存", 172 | "叫醒服务" 173 | ], 174 | "price": 558.0, 175 | "rating": 4.3, 176 | "hotel_id": 1 177 | } 178 | ] 179 | }, 180 | { 181 | "role": "assistant", 182 | "content": "这边为您推荐北京贵都大酒店和瑞尔威连锁饭店(北京西客站店)。" 183 | } 184 | ] 185 | ''' 186 | 187 | dialog = json.loads(text) 188 | 189 | new_turns = QAGen2().gen(dialog) 190 | print('new_turns is :',new_turns) 191 | 192 | 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/enhance.py: -------------------------------------------------------------------------------- 1 | # 导入 random 模块:用于生成随机数或随机选择 2 | # 导入 os 模块:用于访问操作系统功能,如路径和文件操作 3 | # 导入 json 模块:用于解析和生成 JSON 数据格式 4 | import random, os, json 5 | # 从 rewrite 模块导入 UtteranceRewriter 类。自定义模块,提供了一个重写语句的功能 6 | from rewrite import UtteranceRewriter 7 | # 从 paraphrase 模块导入 Paraphraser 类,用于对输入句子进行复述或重构 8 | from paraphrase import Paraphraser 9 | # 从 add_qa_turn 模块中导入 QAGen 类,用于生成问答回合 10 | from add_qa_turn import QAGen 11 | # 从 add_qa_turn2 模块中导入 QAGen2 类,另一种生成问答回合的方法 12 | from add_qa_turn2 import QAGen2 13 | # 从 add_bye_turn 模块导入 ByeGen 类,可能用于生成结束对话的内容 14 | from add_bye_turn import ByeGen 15 | 16 | 17 | 18 | 19 | # 创建 UtteranceRewriter 类的实例,赋值给 rewriter 变量,用于重写语句 20 | rewriter = UtteranceRewriter() 21 | # 创建 Paraphraser 类的实例,赋值给 paraphraser 变量,用于复述输入内容 22 | paraphraser = Paraphraser() 23 | # 创建 QAGen 类的实例,赋值给 qa_gen 变量,准备用于生成问答回合 24 | qa_gen = QAGen() 25 | # 创建 QAGen2 类的实例,赋值给 qa_gen2 变量,准备用于其他类型的问答生成 26 | qa_gen2 = QAGen2() 27 | # 创建 ByeGen 类的实例,赋值给 bye_gen 变量,用于生成结束对话的内容 28 | bye_gen = ByeGen() 29 | 30 | 31 | # 定义:flip_a_coin 是一个用于模拟掷硬币的函数 32 | # 参数:p 是成功的概率值(0 到 1 之间的浮点数) 33 | # random.random() 生成一个 [0, 1) 范围内的随机浮点数 34 | # 如果生成的随机数小于 p,则返回 True,表示“成功” 35 | # 否则返回 False,表示“失败” 36 | # 用途:此函数可用于决定随机事件是否发生,概率由参数 p 控制 37 | def flip_a_coin(p): 38 | return random.random() < p 39 | 40 | 41 | # 定义:one_hotel_only 检查对话中是否仅返回一个酒店信息,验证对话是否包含唯一的酒店信息 42 | # 参数:dialog 是一个对话的列表,其中每个元素是字典,包含对话回合的信息 43 | def one_hotel_only(dialog): 44 | # 初始化 hotel_found 为 False 45 | hotel_found = False 46 | # 遍历 dialog 中的每个 turn(对话回合) 47 | for turn in dialog: 48 | # 如果 turn["role"] 为 "return",表示是包含酒店信息的回合 49 | if turn["role"] == "return": 50 | # 将 hotel_found 设为 True 51 | hotel_found = True 52 | # 检查 turn["records"] 的长度是否大于 1(即返回了多个酒店),如果是则返回 False 53 | if len(turn["records"]) > 1: 54 | return False 55 | # 循环结束后,如果 hotel_found 为 True 且没有返回多个酒店,则返回 True 56 | return hotel_found 57 | 58 | 59 | # 定义:one_turn_only 检查对话中是否只有一个 assistant 回合,验证对话中是否只有一个助手发言回合 60 | # 参数:dialog 是一个对话的列表,其中每个元素是字典,包含对话回合的信息 61 | def one_turn_only(dialog): 62 | # 初始化 assistant_count 为 0 63 | assistant_count = 0 64 | # 遍历 dialog 中的每个 turn 65 | for turn in dialog: 66 | # 如果 turn["role"] 为 "assistant",增加 assistant_count 67 | if turn["role"] == "assistant": 68 | assistant_count += 1 69 | # # 循环结束后,返回 assistant_count == 1,表示是否仅有一个 assistant 回合 70 | return assistant_count == 1 71 | 72 | 73 | # 定义:get_last_user_turn 返回 dialog 列表中从索引 i 向前找到的最后一个用户发言回合,在对话中查找并返回给定位置之前的最近一次用户发言,用于分析上下文或处理响应 74 | # 参数:dialog 是一个对话的列表,i 是当前索引位置,从该位置开始向前搜索用户发言 75 | def get_last_user_turn(dialog, i): 76 | # 从 i - 1 开始递减,遍历 dialog,直到 0 77 | for j in range(i - 1, -1, -1): 78 | # 如果 dialog[j]["role"] 为 "user",返回该 turn 79 | if dialog[j]["role"] == "user": 80 | return dialog[j] 81 | # 如果找不到用户发言,返回 None 82 | return None 83 | 84 | 85 | 86 | # 定义:enhance 函数用于对 dialog(对话列表)进行增强,可能修改用户发言并添加新的问答回合或结束语 87 | # 参数:dialog 是一个列表,每个元素是一个包含对话回合信息的字典 88 | # 返回:修改后的 dialog 和布尔值 changed,指示是否进行了任何修改 89 | def enhance(dialog): 90 | # 初始化 changed 变量为 False,用于跟踪对话是否被修改 91 | changed = False 92 | # 调整酒店设施相关语句 93 | # 循环遍历 dialog,i 是当前回合的索引,turn 是当前的对话回合 94 | for i, turn in enumerate(dialog): 95 | # 检查当前回合的 role 是否是 "search",只有这种回合才会被处理 96 | if turn["role"] == "search": 97 | # 如果 turn["arguments"] 中包含 facilities 键,则将其值赋给 facilities 变量 98 | if "facilities" in turn["arguments"]: 99 | facilities = turn["arguments"]["facilities"] 100 | # 遍历 facilities 列表,j 是索引,facility 是当前的设施名称 101 | for j, facility in enumerate(facilities): 102 | # 如果 facility 的长度大于 4 或者 flip_a_coin(0.2) 返回 True,则满足修改条件 103 | if len(facility) > 4 or flip_a_coin(0.2): 104 | # 调用 get_last_user_turn 获取 i 索引之前的最后一个用户回合。如果存在,将 user_turn 赋值为该回合 105 | user_turn = get_last_user_turn(dialog, i) 106 | if user_turn is not None: 107 | # 获取 user_turn 的 content(用户发言),如果 facility 不在发言中,跳过该 facility 108 | utterance = user_turn["content"] 109 | if facility not in utterance: 110 | continue 111 | # 使用 paraphraser.gen 生成 facility 的同义词 112 | paraphrase = paraphraser.gen(facility) 113 | # 调用 rewriter.rewrite 用同义词替换用户发言中的 facility 114 | new_utterance = rewriter.rewrite(utterance, facility, paraphrase) 115 | # 更新 user_turn 的 content 为新的发言 116 | user_turn["content"] = new_utterance 117 | # 更新 facilities 列表中的对应元素为同义词 118 | facilities[j] = paraphrase 119 | # 设置 changed 为 True,表示对话已被修改 120 | changed = True 121 | 122 | 123 | # 如果 one_hotel_only(dialog) 返回 True 且 flip_a_coin(0.3) 成功 124 | if one_hotel_only(dialog): 125 | if flip_a_coin(0.3): 126 | # 调用 qa_gen.gen 生成新的问答回合,并将其添加到 dialog,同时设置 changed 为 True 127 | new_turns = qa_gen.gen(dialog) 128 | if new_turns is not None: 129 | dialog.extend(new_turns) 130 | changed = True 131 | 132 | # 如果 dialog 包含多个酒店信息且 flip_a_coin(0.3) 成功 133 | else: 134 | if flip_a_coin(0.3): 135 | # 调用 qa_gen2.gen 生成新的问答回合,并将其添加到 dialog,同时设置 changed 为 True 136 | new_turns = qa_gen2.gen(dialog) 137 | if new_turns is not None: 138 | dialog.extend(new_turns) 139 | changed = True 140 | 141 | # 如果 dialog 包含唯一的酒店信息且 flip_a_coin(0.5) 成功 142 | if one_hotel_only(dialog): 143 | if flip_a_coin(0.5): 144 | # 调用 bye_gen.gen 生成新的结束语回合,并将其添加到 dialog,同时设置 changed 为 True 145 | new_turns = bye_gen.gen(dialog) 146 | if new_turns is not None: 147 | dialog.extend(new_turns) 148 | changed = True 149 | 150 | # 返回修改后的 dialog 和 changed 布尔值,指示是否进行了修改 151 | return dialog, changed 152 | 153 | 154 | 155 | # 定义:main 函数用于遍历 raw_data 文件夹中的所有 JSON 文件,对其中的对话数据进行增强处理,并将结果输出到 enhanced_data 文件夹 156 | # start(默认值为 0):开始处理的文件编号 157 | # end(默认值为 None):结束处理的文件编号 158 | def main(start=0,end=None): 159 | # 定义输出目录为 enhanced_data,用于存储处理后的对话文件 160 | output_dir = "enhanced_data" 161 | # 使用 os.listdir 获取 raw_data 文件夹中的所有文件名并逐一遍历 162 | for filename in os.listdir("raw_data"): 163 | # 将文件名去掉 .json 后缀,并将其转换为整数,作为 id 164 | # 如果 id 小于 start,跳过当前文件 165 | # 如果 end 非空且 id 大于等于 end,停止遍历 166 | id = int(filename.replace(".json", "")) 167 | if id < start: 168 | continue 169 | if end is not None and id >= end: 170 | break 171 | 172 | # 打印当前正在处理的文件名 173 | print(filename) 174 | 175 | # 使用 open 以只读模式打开 raw_data 文件夹中的文件,编码为 utf-8 176 | # 使用 json.load 将文件内容加载为 Python 数据结构(dialog 对象) 177 | with open(os.path.join("raw_data", filename), 'r', encoding='utf-8') as ifp: 178 | dialog = json.load(ifp) 179 | # 使用 try-except 块调用 enhance 函数对 dialog 进行处理,并捕获可能的异常 180 | # 如果处理过程中发生异常,设置 changed 为 False 表示未进行修改 181 | try: 182 | dialog, changed = enhance(dialog) 183 | except: 184 | changed = False 185 | 186 | # 如果 changed 为 True,修改文件名,在原文件名的基础上添加 _,表明文件已被增强 187 | # 打印“Enhanced [filename]”来记录增强的文件 188 | if changed: 189 | filename = filename.replace(".json", "_.json") 190 | print("Enhanced {}".format(filename)) 191 | 192 | # 打开 output_dir 文件夹中的对应输出文件,以写模式存储增强后的 dialog,编码为 utf-8 193 | # 使用 json.dump 将 dialog 转储到文件中,缩进为 4 格,确保非 ASCII 字符正常保存 194 | # 使用 ofp.close() 关闭文件以释放资源 195 | ofp = open(os.path.join(output_dir, filename), 'w', encoding='utf-8') 196 | json.dump(dialog, ofp, indent=4, ensure_ascii=False) 197 | ofp.close() 198 | 199 | 200 | 201 | if __name__ == "__main__": 202 | main() -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/my_llm.py: -------------------------------------------------------------------------------- 1 | import os 2 | from langchain_openai import ChatOpenAI 3 | 4 | # 模型全局参数配置 根据自己的实际情况进行调整 5 | # openai模型相关配置 根据自己的实际情况进行调整 6 | OPENAI_API_BASE = "https://api.wlai.vip/v1" 7 | OPENAI_CHAT_API_KEY = "sk-dsLvfvO3OLzr6jKpjgFBaEra3sZVM5UWVCpYlZ34QIjmIbVs" 8 | OPENAI_CHAT_MODEL = "gpt-4o-mini" 9 | # 非gpt大模型相关配置(oneapi方案 通义千问为例) 根据自己的实际情况进行调整 10 | ONEAPI_API_BASE = "http://139.224.72.218:3000/v1" 11 | ONEAPI_CHAT_API_KEY = "sk-iEokjc8sQa9yvf8c655eCa8b0b834aB2Ab67213e639259Df" 12 | ONEAPI_CHAT_MODEL = "qwen-max" 13 | # 本地大模型相关配置(Ollama方案 qwen2.5:7b为例) 根据自己的实际情况进行调整 14 | OLLAMA_API_BASE = "http://localhost:11434/v1" 15 | OLLAMA_CHAT_API_KEY = "ollama" 16 | OLLAMA_CHAT_MODEL = "qwen2.5:7b" 17 | 18 | # 选择使用哪一个大模型 19 | # openai:调用gpt大模型 20 | # oneapi:调用非gpt大模型(国产大模型等) 21 | # ollama:调用本地大模型 22 | LLM_TYPE = "openai" 23 | 24 | # 定函数 模型初始化 25 | def myLLM(): 26 | llmType = LLM_TYPE 27 | 28 | if llmType == "oneapi": 29 | # 实例化一个oneapi客户端对象 30 | llm = ChatOpenAI( 31 | base_url=ONEAPI_API_BASE, 32 | api_key=ONEAPI_CHAT_API_KEY, 33 | model=ONEAPI_CHAT_MODEL, # 本次使用的模型 34 | temperature=0.8, # 发散的程度 35 | # timeout=None,# 服务请求超时 36 | # max_retries=2,# 失败重试最大次数 37 | ) 38 | 39 | elif llmType == "ollama": 40 | # 实例化一个ChatOpenAI客户端对象 41 | os.environ["OPENAI_API_KEY"] = "NA" 42 | llm = ChatOpenAI( 43 | base_url=OLLAMA_API_BASE, # 请求的API服务地址 44 | api_key=OLLAMA_CHAT_API_KEY, # API Key 45 | model=OLLAMA_CHAT_MODEL, # 本次使用的模型 46 | temperature=0.8, # 发散的程度 47 | # timeout=None,# 服务请求超时 48 | # max_retries=2,# 失败重试最大次数 49 | ) 50 | 51 | else: 52 | # 实例化一个ChatOpenAI客户端对象 53 | llm = ChatOpenAI( 54 | base_url=OPENAI_API_BASE, # 请求的API服务地址 55 | api_key=OPENAI_CHAT_API_KEY, # API Key 56 | model=OPENAI_CHAT_MODEL, # 本次使用的模型 57 | # temperature=0.7,# 发散的程度,一般为0 58 | # timeout=None,# 服务请求超时 59 | # max_retries=2,# 失败重试最大次数 60 | ) 61 | 62 | return llm -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/paraphrase.py: -------------------------------------------------------------------------------- 1 | from langchain_core.prompts import PromptTemplate 2 | from langchain.output_parsers import PydanticOutputParser, OutputFixingParser 3 | import re 4 | from pydantic import BaseModel, Field 5 | # 导入本应用程序提供的方法 6 | from my_llm import myLLM 7 | 8 | 9 | class Phrase(BaseModel): 10 | text: str = Field(description="改写后的文本") 11 | 12 | 13 | PROMPT_TEMPLATE = """ 14 | 给定短语: 15 | {phrase} 16 | 17 | 请用口语的方式paraphrase这个短语。例如: 18 | 公共区域和部分房间提供wifi: 有wifi | 无线上网 | 无线网 19 | 中式餐厅: 中餐厅 | 中餐 20 | 国际长途电话: 国际电话 | 国际长途 21 | 免费市内电话: 免费电话 | 免费市话 22 | 酒店各处提供wifi: wifi全覆盖 | 无线上网 | 无线网 23 | 24 | 确保你输出的短语与原短语不同。 25 | 确保你输出的是中文(wifi这个词可以保留)。 26 | 按以下形式输出结果: 27 | {format_instruction} 28 | """ 29 | 30 | 31 | # 为给定短语生成一个口语化的改写 32 | class Paraphraser: 33 | def __init__(self): 34 | # 设置大模型 35 | self.llm = myLLM() 36 | self.output_parser = PydanticOutputParser(pydantic_object=Phrase) 37 | self.robust_parser = OutputFixingParser.from_llm(parser=self.output_parser, llm=self.llm) 38 | self.prompt = PromptTemplate.from_template(PROMPT_TEMPLATE).partial( 39 | format_instruction=self.output_parser.get_format_instructions(), 40 | ) 41 | 42 | # 定义chain 43 | self.chain = self.prompt | self.llm 44 | 45 | def gen(self,phrase: str) -> str: 46 | response = self.chain.invoke( 47 | { 48 | "phrase": phrase 49 | } 50 | ) 51 | 52 | # 使用正则表达式从返回信息中结构出完成对话 53 | response = re.search(r'```json\n(.*?)\n```', response.content, re.S).group(1) 54 | phrase = self.robust_parser.parse(response) 55 | 56 | if ":" in phrase.text: 57 | phrase.text = phrase.text.split(":")[1] 58 | return phrase.text 59 | 60 | 61 | 62 | if __name__ == "__main__": 63 | text = '国际长途电话' 64 | 65 | new_text = Paraphraser().gen(text) 66 | print('new_text is :',new_text) 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0000.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "这几家店中,哪家的评分在4.5分以上?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 400, 10 | "price_range_upper": 500, 11 | "rating_range_lower": 4.5 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "北京京泰龙国际大酒店", 19 | "type": "高档型", 20 | "address": "北京东城区珠市口东大街19号", 21 | "subway": "珠市口地铁站C口", 22 | "phone": "010-67075888", 23 | "facilities": [ 24 | "酒店各处提供wifi", 25 | "宽带上网", 26 | "国际长途电话", 27 | "吹风机", 28 | "24小时热水", 29 | "西式餐厅", 30 | "中式餐厅", 31 | "残疾人设施", 32 | "会议室", 33 | "无烟房", 34 | "商务中心", 35 | "酒吧", 36 | "早餐服务", 37 | "接站服务", 38 | "接机服务", 39 | "接待外宾", 40 | "洗衣服务", 41 | "行李寄存", 42 | "叫醒服务" 43 | ], 44 | "price": 440.0, 45 | "rating": 4.6, 46 | "hotel_id": 17 47 | } 48 | ] 49 | }, 50 | { 51 | "role": "assistant", 52 | "content": "推荐您选择北京京泰龙国际大酒店,评分为4.6分。" 53 | } 54 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0001.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,我想找一个提供叫醒服务,评分是4分以上的经济型酒店住宿,可以帮我推荐一个吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "叫醒服务" 11 | ], 12 | "rating_range_lower": 4.0, 13 | "type": "经济型" 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "中安之家北京东单宾馆", 21 | "type": "经济型", 22 | "address": "北京东城区东单北大街120号", 23 | "subway": "东单地铁站5号线F口", 24 | "phone": "010-65250569", 25 | "facilities": [ 26 | "酒店各处提供wifi", 27 | "宽带上网", 28 | "国际长途电话", 29 | "24小时热水", 30 | "中式餐厅", 31 | "无烟房", 32 | "早餐服务", 33 | "接待外宾", 34 | "行李寄存", 35 | "叫醒服务" 36 | ], 37 | "price": 446.0, 38 | "rating": 4.5, 39 | "hotel_id": 244 40 | }, 41 | { 42 | "name": "欣燕都连锁酒店(北京珠市口店)", 43 | "type": "经济型", 44 | "address": "北京西城区西城区棕树斜街42号", 45 | "subway": "珠市口地铁站A口", 46 | "phone": "010-63035112", 47 | "facilities": [ 48 | "部分房间提供wifi", 49 | "24小时热水", 50 | "无烟房", 51 | "早餐服务", 52 | "行李寄存", 53 | "叫醒服务" 54 | ], 55 | "price": 227.0, 56 | "rating": 4.1, 57 | "hotel_id": 262 58 | } 59 | ] 60 | }, 61 | { 62 | "role": "assistant", 63 | "content": "好的,我觉得中安之家北京东单宾馆和欣燕都连锁酒店(北京珠市口店)还是不错的,你可以考虑一下。" 64 | } 65 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0002.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,帮我推荐一个价位在400-500元之间的酒店,评分要在4.5分以上的,谢谢。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 400, 10 | "price_range_upper": 500, 11 | "rating_range_lower": 4.5 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "雅悦酒店(北京西直门店)", 19 | "type": "经济型", 20 | "address": "北京西城区西直门内大街126号", 21 | "subway": "新街口地铁站D口", 22 | "phone": "010-66180070", 23 | "facilities": [ 24 | "部分房间提供wifi", 25 | "宽带上网", 26 | "免费市内电话", 27 | "国际长途电话", 28 | "24小时热水", 29 | "暖气", 30 | "中式餐厅", 31 | "会议室", 32 | "无烟房", 33 | "商务中心", 34 | "早餐服务", 35 | "接待外宾", 36 | "洗衣服务", 37 | "行李寄存", 38 | "叫醒服务" 39 | ], 40 | "price": 441.0, 41 | "rating": 4.5, 42 | "hotel_id": 144 43 | } 44 | ] 45 | }, 46 | { 47 | "role": "assistant", 48 | "content": "为您推荐雅悦酒店(北京西直门店)。" 49 | } 50 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0003.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "游玩结束我想找一家提供无烟房的酒店住宿,有什么推荐的吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "无烟房" 11 | ] 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "北京贵都大酒店", 19 | "type": "高档型", 20 | "address": "北京西城区广安门内大街217号", 21 | "subway": "菜市口地铁站D口", 22 | "phone": "010-51979888", 23 | "facilities": [ 24 | "公共区域和部分房间提供wifi", 25 | "宽带上网", 26 | "吹风机", 27 | "24小时热水", 28 | "西式餐厅", 29 | "中式餐厅", 30 | "会议室", 31 | "健身房", 32 | "无烟房", 33 | "商务中心", 34 | "接站服务", 35 | "接机服务", 36 | "洗衣服务", 37 | "行李寄存", 38 | "叫醒服务" 39 | ], 40 | "price": 1354.0, 41 | "rating": 4.7, 42 | "hotel_id": 0 43 | }, 44 | { 45 | "name": "瑞尔威连锁饭店(北京西客站店)", 46 | "type": "舒适型", 47 | "address": "北京丰台区莲花池东路116-2号", 48 | "subway": "北京西站地铁站A口", 49 | "phone": "010-63959988", 50 | "facilities": [ 51 | "酒店各处提供wifi", 52 | "宽带上网", 53 | "国际长途电话", 54 | "吹风机", 55 | "24小时热水", 56 | "暖气", 57 | "会议室", 58 | "无烟房", 59 | "接待外宾", 60 | "行李寄存", 61 | "叫醒服务" 62 | ], 63 | "price": 558.0, 64 | "rating": 4.3, 65 | "hotel_id": 1 66 | } 67 | ] 68 | }, 69 | { 70 | "role": "assistant", 71 | "content": "这边为您推荐北京贵都大酒店和瑞尔威连锁饭店(北京西客站店)。" 72 | } 73 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0004.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "这么多好玩的地方啊,真不错啊,溜达完我想找个地方休息,你可以帮我推荐一个价格是400-500元的酒店吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 400, 10 | "price_range_upper": 500 11 | } 12 | }, 13 | { 14 | "role": "return", 15 | "records": [ 16 | { 17 | "name": "北京圆山大酒店", 18 | "type": "舒适型", 19 | "address": "北京西城区裕民路2号", 20 | "subway": "安华桥地铁站A口", 21 | "phone": "010-62010033", 22 | "facilities": [ 23 | "酒店各处提供wifi", 24 | "宽带上网", 25 | "国际长途电话", 26 | "吹风机", 27 | "24小时热水", 28 | "中式餐厅", 29 | "残疾人设施", 30 | "会议室", 31 | "健身房", 32 | "无烟房", 33 | "酒吧", 34 | "棋牌室", 35 | "早餐服务", 36 | "接站服务", 37 | "接机服务", 38 | "接待外宾", 39 | "洗衣服务", 40 | "行李寄存", 41 | "租车", 42 | "叫醒服务" 43 | ], 44 | "price": 416.0, 45 | "rating": 4.3, 46 | "hotel_id": 180 47 | } 48 | ] 49 | }, 50 | { 51 | "role": "assistant", 52 | "content": "你觉得北京圆山大酒店怎么样呢,我个人还是觉得不错的。" 53 | } 54 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0005.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "没关系,那就帮我推荐一个能提供商务中心的酒店吧。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "商务中心" 11 | ] 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "北京龙鼎华鼎云酒店", 19 | "type": "舒适型", 20 | "address": "北京朝阳区潘家园东里18号", 21 | "subway": "劲松地铁站D口", 22 | "phone": "010-52001188", 23 | "facilities": [ 24 | "公共区域和部分房间提供wifi", 25 | "宽带上网", 26 | "国际长途电话", 27 | "吹风机", 28 | "24小时热水", 29 | "中式餐厅", 30 | "会议室", 31 | "无烟房", 32 | "商务中心", 33 | "洗衣服务", 34 | "行李寄存", 35 | "叫醒服务" 36 | ], 37 | "price": -1.0, 38 | "rating": 4.3, 39 | "hotel_id": 24 40 | } 41 | ] 42 | }, 43 | { 44 | "role": "assistant", 45 | "content": "为您推荐北京龙鼎华鼎云酒店。" 46 | } 47 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0006.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "您好,请帮我找一家提供中式餐厅、提供接站服务的经济型酒店,谢了!" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "中式餐厅", 11 | "接站服务" 12 | ], 13 | "type": "经济型" 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "格林豪泰(北京首都机场新国展地铁站店)", 21 | "type": "经济型", 22 | "address": "北京顺义区空港工业园A区天柱西路24号", 23 | "subway": "国展地铁站B口", 24 | "phone": "010-80485188", 25 | "facilities": [ 26 | "公共区域和部分房间提供wifi", 27 | "宽带上网", 28 | "吹风机", 29 | "24小时热水", 30 | "暖气", 31 | "中式餐厅", 32 | "会议室", 33 | "无烟房", 34 | "早餐服务", 35 | "接站服务", 36 | "接机服务", 37 | "接待外宾", 38 | "洗衣服务" 39 | ], 40 | "price": 188.0, 41 | "rating": 4.5, 42 | "hotel_id": 65 43 | } 44 | ] 45 | }, 46 | { 47 | "role": "assistant", 48 | "content": "为您推荐格林豪泰(北京首都机场新国展地铁站店。" 49 | } 50 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0007.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,我想找一家评分是5分的经济型酒店住宿,有好地方吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "rating_range_lower": 5.0, 10 | "rating_range_upper": 5.0, 11 | "type": "经济型" 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "7天优品酒店(北京国贸劲松地铁站店)", 19 | "type": "经济型", 20 | "address": "北京朝阳区劲松南路5号院", 21 | "subway": "劲松地铁站D口", 22 | "phone": "010-87722388", 23 | "facilities": [ 24 | "部分房间提供wifi", 25 | "宽带上网", 26 | "24小时热水", 27 | "早餐服务" 28 | ], 29 | "price": 288.0, 30 | "rating": 5.0, 31 | "hotel_id": 272 32 | } 33 | ] 34 | }, 35 | { 36 | "role": "assistant", 37 | "content": "为您推荐7天优品酒店(北京国贸劲松地铁站店)。" 38 | } 39 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0008.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,请给我推荐一家评分4分以上有国际长途电话和吹风机服务设施的酒店住宿。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "吹风机", 11 | "国际长途电话" 12 | ], 13 | "rating_range_lower": 4.0 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "瑞尔威连锁饭店(北京西客站店)", 21 | "type": "舒适型", 22 | "address": "北京丰台区莲花池东路116-2号", 23 | "subway": "北京西站地铁站A口", 24 | "phone": "010-63959988", 25 | "facilities": [ 26 | "酒店各处提供wifi", 27 | "宽带上网", 28 | "国际长途电话", 29 | "吹风机", 30 | "24小时热水", 31 | "暖气", 32 | "会议室", 33 | "无烟房", 34 | "接待外宾", 35 | "行李寄存", 36 | "叫醒服务" 37 | ], 38 | "price": 558.0, 39 | "rating": 4.3, 40 | "hotel_id": 1 41 | } 42 | ] 43 | }, 44 | { 45 | "role": "assistant", 46 | "content": "推荐您去瑞尔威连锁饭店(北京西客站店)。" 47 | } 48 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0009.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "您好,请帮我找个经济型的酒店,酒店设施要有看护小孩服务与宽带上网。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "宽带上网", 11 | "看护小孩服务" 12 | ], 13 | "type": "经济型" 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "7天连锁酒店(北京首都机场店)", 21 | "type": "经济型", 22 | "address": "北京顺义区天竺镇府前二街1号院10号楼", 23 | "subway": "T2航站楼地铁站", 24 | "phone": "010-64587122", 25 | "facilities": [ 26 | "部分房间提供wifi", 27 | "宽带上网", 28 | "吹风机", 29 | "24小时热水", 30 | "暖气", 31 | "无烟房", 32 | "早餐服务", 33 | "接机服务", 34 | "行李寄存", 35 | "叫醒服务" 36 | ], 37 | "price": 180.0, 38 | "rating": 4.3, 39 | "hotel_id": 23 40 | }, 41 | { 42 | "name": "格林豪泰酒店北京市首都机场第二店", 43 | "type": "经济型", 44 | "address": "北京顺义区天竺镇天竺中街4号", 45 | "subway": "T2航站楼地铁站", 46 | "phone": "010-52138888", 47 | "facilities": [ 48 | "公共区域和部分房间提供wifi", 49 | "宽带上网", 50 | "吹风机", 51 | "24小时热水", 52 | "无烟房", 53 | "早餐服务", 54 | "接待外宾", 55 | "行李寄存", 56 | "叫醒服务" 57 | ], 58 | "price": 199.0, 59 | "rating": 4.4, 60 | "hotel_id": 12 61 | } 62 | ] 63 | }, 64 | { 65 | "role": "assistant", 66 | "content": "抱歉,没有找到提供看护小孩服务的酒店,为您查到两家有宽带上网的酒店,格林豪泰酒店北京市首都机场第二店和7天连锁酒店(北京首都机场店)。" 67 | } 68 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0010.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "好的,有就好,溜达完,我得找个地方住,能帮我推荐一个价格是300-400元,提供酒店各处提供wifi和暖气的酒店吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "暖气", 11 | "酒店各处提供wifi" 12 | ], 13 | "price_range_lower": 300, 14 | "price_range_upper": 400 15 | } 16 | }, 17 | { 18 | "role": "return", 19 | "records": [ 20 | { 21 | "name": "北京仁和轩酒店", 22 | "type": "舒适型", 23 | "address": "北京海淀区小西天志强北园1号院", 24 | "subway": "积水潭地铁站A口", 25 | "phone": "010-62217878", 26 | "facilities": [ 27 | "酒店各处提供wifi", 28 | "宽带上网", 29 | "吹风机", 30 | "24小时热水", 31 | "暖气", 32 | "无烟房", 33 | "酒吧", 34 | "行李寄存" 35 | ], 36 | "price": 344.0, 37 | "rating": 4.4, 38 | "hotel_id": 164 39 | } 40 | ] 41 | }, 42 | { 43 | "role": "assistant", 44 | "content": "北京仁和轩酒店非常符合你的要求。" 45 | } 46 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0011.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "好的,再帮我推荐一家评分4.5分以上的舒适型酒店。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "rating_range_lower": 4.5, 10 | "type": "舒适型" 11 | } 12 | }, 13 | { 14 | "role": "return", 15 | "records": [ 16 | { 17 | "name": "北京紫玉饭店", 18 | "type": "舒适型", 19 | "address": "北京海淀区增光路55号", 20 | "subway": "花园桥地铁站D2口", 21 | "phone": "010-68411188", 22 | "facilities": [ 23 | "公共区域和部分房间提供wifi", 24 | "宽带上网", 25 | "国际长途电话", 26 | "吹风机", 27 | "24小时热水", 28 | "中式餐厅", 29 | "会议室", 30 | "无烟房", 31 | "商务中心", 32 | "早餐服务", 33 | "接站服务", 34 | "接机服务", 35 | "洗衣服务", 36 | "行李寄存", 37 | "叫醒服务" 38 | ], 39 | "price": 560.0, 40 | "rating": 4.6, 41 | "hotel_id": 40 42 | }, 43 | { 44 | "name": "北京都季商旅酒店", 45 | "type": "舒适型", 46 | "address": "北京东城区南河沿大街C座和D座", 47 | "subway": "王府井地铁站", 48 | "phone": "010-85116665", 49 | "facilities": [ 50 | "酒店各处提供wifi", 51 | "国际长途电话", 52 | "吹风机", 53 | "24小时热水", 54 | "暖气", 55 | "中式餐厅", 56 | "会议室", 57 | "无烟房", 58 | "商务中心", 59 | "早餐服务", 60 | "接待外宾", 61 | "行李寄存", 62 | "叫醒服务" 63 | ], 64 | "price": 1160.0, 65 | "rating": 4.5, 66 | "hotel_id": 9 67 | }, 68 | { 69 | "name": "维也纳国际酒店(北京首体店)", 70 | "type": "舒适型", 71 | "address": "北京海淀区中关村南大街52号", 72 | "subway": "国家图书馆地铁站B口", 73 | "phone": "010-62197778", 74 | "facilities": [ 75 | "公共区域提供wifi", 76 | "国际长途电话", 77 | "吹风机", 78 | "24小时热水", 79 | "暖气", 80 | "残疾人设施", 81 | "会议室", 82 | "无烟房", 83 | "早餐服务", 84 | "接待外宾", 85 | "行李寄存", 86 | "叫醒服务" 87 | ], 88 | "price": 638.0, 89 | "rating": 4.7, 90 | "hotel_id": 37 91 | } 92 | ] 93 | }, 94 | { 95 | "role": "assistant", 96 | "content": "推荐您去北京都季商旅酒店、维也纳国际酒店(北京首体店)、北京紫玉饭店。" 97 | } 98 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0012.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "那接下来就是找地方住了,你看哪家的酒店最低价格是500-600元,评分是4.5分以上的呀?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 500, 10 | "price_range_upper": 600, 11 | "rating_range_lower": 4.5 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "北京君颐润华酒店", 19 | "type": "豪华型", 20 | "address": "北京丰台区丰管路20号院", 21 | "subway": "泥洼地铁站A2口", 22 | "phone": "010-53225566", 23 | "facilities": [ 24 | "酒店各处提供wifi", 25 | "宽带上网", 26 | "国际长途电话", 27 | "吹风机", 28 | "24小时热水", 29 | "中式餐厅", 30 | "会议室", 31 | "无烟房", 32 | "商务中心", 33 | "棋牌室", 34 | "接待外宾", 35 | "洗衣服务", 36 | "行李寄存", 37 | "租车", 38 | "叫醒服务" 39 | ], 40 | "price": 538.0, 41 | "rating": 4.5, 42 | "hotel_id": 499 43 | } 44 | ] 45 | }, 46 | { 47 | "role": "assistant", 48 | "content": "我看北京君颐润华酒店就挺符合你的要求的。" 49 | } 50 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0013.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "好的,吃完饭我想找一家评分4.5分以上最低价格在200-300元的酒店住宿,给我推荐一家吧。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 200, 10 | "price_range_upper": 300, 11 | "rating_range_lower": 4.5 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "北京畅悦时尚酒店(原乐活酒店)", 19 | "type": "舒适型", 20 | "address": "北京石景山区苹果园南路东口9号", 21 | "subway": "苹果园地铁站C口", 22 | "phone": "010-68882332", 23 | "facilities": [ 24 | "公共区域和部分房间提供wifi", 25 | "宽带上网", 26 | "吹风机", 27 | "24小时热水", 28 | "暖气", 29 | "中式餐厅", 30 | "无烟房", 31 | "行李寄存", 32 | "叫醒服务" 33 | ], 34 | "price": 269.0, 35 | "rating": 4.5, 36 | "hotel_id": 84 37 | } 38 | ] 39 | }, 40 | { 41 | "role": "assistant", 42 | "content": "推荐您去北京畅悦时尚酒店(原乐活酒店)住宿。" 43 | } 44 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0014.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "好的,我知道了,游玩结束以后我打算找个提供商务中心,评分是5分的高档型酒店住宿,你能给我点建议吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "商务中心" 11 | ], 12 | "rating_range_lower": 5.0, 13 | "rating_range_upper": 5.0, 14 | "type": "高档型" 15 | } 16 | }, 17 | { 18 | "role": "return", 19 | "records": [ 20 | { 21 | "name": "北京丰荣君华酒店", 22 | "type": "高档型", 23 | "address": "北京顺义区首都机场国门商务区李天路27号", 24 | "subway": "T3航站楼地铁站", 25 | "phone": "010-81463366", 26 | "facilities": [ 27 | "公共区域提供wifi", 28 | "国际长途电话", 29 | "吹风机", 30 | "24小时热水", 31 | "中式餐厅", 32 | "会议室", 33 | "无烟房", 34 | "商务中心", 35 | "早餐服务", 36 | "接机服务", 37 | "接待外宾", 38 | "洗衣服务", 39 | "叫醒服务" 40 | ], 41 | "price": -1.0, 42 | "rating": 5.0, 43 | "hotel_id": 237 44 | } 45 | ] 46 | }, 47 | { 48 | "role": "assistant", 49 | "content": "为你找到唯一一个完全符合你要求的北京丰荣君华酒店,你感兴趣不?" 50 | } 51 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0015.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,我想去酒店住宿。请帮我找一家最低价格是300-400元的带健身房的酒店。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "健身房" 11 | ], 12 | "price_range_lower": 300, 13 | "price_range_upper": 400 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "北京牡丹宾馆", 21 | "type": "舒适型", 22 | "address": "北京海淀区花园东路31号-2", 23 | "subway": "牡丹园地铁站B口", 24 | "phone": "010-62025544", 25 | "facilities": [ 26 | "免费市内电话", 27 | "国际长途电话", 28 | "吹风机", 29 | "24小时热水", 30 | "西式餐厅", 31 | "中式餐厅", 32 | "残疾人设施", 33 | "会议室", 34 | "健身房", 35 | "SPA", 36 | "无烟房", 37 | "商务中心", 38 | "桑拿", 39 | "洗衣服务", 40 | "行李寄存", 41 | "叫醒服务" 42 | ], 43 | "price": 393.0, 44 | "rating": 4.3, 45 | "hotel_id": 449 46 | } 47 | ] 48 | }, 49 | { 50 | "role": "assistant", 51 | "content": "有好多的呢,推荐您去北京牡丹宾馆。" 52 | } 53 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0016.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "吃完饭晚上我想要找地方住,希望找一家提供西式餐厅和国际长途电话的高档型酒店。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "国际长途电话", 11 | "西式餐厅" 12 | ], 13 | "type": "高档型" 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "北京天伦松鹤大饭店", 21 | "type": "高档型", 22 | "address": "北京东城区灯市口大街88号", 23 | "subway": "灯市口地铁站A口", 24 | "phone": "010-58168999", 25 | "facilities": [ 26 | "公共区域和部分房间提供wifi", 27 | "宽带上网", 28 | "免费市内电话", 29 | "国际长途电话", 30 | "吹风机", 31 | "24小时热水", 32 | "西式餐厅", 33 | "中式餐厅", 34 | "残疾人设施", 35 | "会议室", 36 | "健身房", 37 | "无烟房", 38 | "商务中心", 39 | "酒吧", 40 | "早餐服务", 41 | "接机服务", 42 | "洗衣服务", 43 | "行李寄存", 44 | "叫醒服务" 45 | ], 46 | "price": 535.0, 47 | "rating": 4.5, 48 | "hotel_id": 174 49 | } 50 | ] 51 | }, 52 | { 53 | "role": "assistant", 54 | "content": "还挺多符合您要求的,北京天伦松鹤大饭店这家看起来还不错。" 55 | } 56 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0017.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "好的,时间还是可以的,吃完饭我可能会在这边住下,能帮我推荐一个提供暖气的高档型酒店吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "暖气" 11 | ], 12 | "type": "高档型" 13 | } 14 | }, 15 | { 16 | "role": "return", 17 | "records": [ 18 | { 19 | "name": "北京东方花园饭店", 20 | "type": "高档型", 21 | "address": "北京东城区东直门南大街6号", 22 | "subway": "东直门地铁站D口", 23 | "phone": "010-64168866", 24 | "facilities": [ 25 | "公共区域和部分房间提供wifi", 26 | "宽带上网", 27 | "国际长途电话", 28 | "吹风机", 29 | "24小时热水", 30 | "暖气", 31 | "西式餐厅", 32 | "中式餐厅", 33 | "残疾人设施", 34 | "会议室", 35 | "健身房", 36 | "无烟房", 37 | "商务中心", 38 | "酒吧", 39 | "棋牌室", 40 | "早餐服务", 41 | "接机服务", 42 | "接待外宾", 43 | "洗衣服务", 44 | "行李寄存", 45 | "租车", 46 | "叫醒服务" 47 | ], 48 | "price": 677.0, 49 | "rating": 4.6, 50 | "hotel_id": 87 51 | } 52 | ] 53 | }, 54 | { 55 | "role": "assistant", 56 | "content": "那就建议你去北京东方花园饭店好了,比较经济实惠。" 57 | } 58 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0018.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,我想找一个评分是4.5分以上,提供残疾人设施和免费市内电话的酒店,你有这方面的资源吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "免费市内电话", 11 | "残疾人设施" 12 | ], 13 | "rating_range_lower": 4.5 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "北京柏悦酒店", 21 | "type": "豪华型", 22 | "address": "北京朝阳区建国门外大街2号", 23 | "subway": "国贸地铁站D口", 24 | "phone": "010-85671234", 25 | "facilities": [ 26 | "公共区域和部分房间提供wifi", 27 | "宽带上网", 28 | "免费市内电话", 29 | "国际长途电话", 30 | "吹风机", 31 | "24小时热水", 32 | "暖气", 33 | "西式餐厅", 34 | "中式餐厅", 35 | "残疾人设施", 36 | "室内游泳池", 37 | "会议室", 38 | "健身房", 39 | "SPA", 40 | "无烟房", 41 | "商务中心", 42 | "酒吧", 43 | "桑拿", 44 | "早餐服务", 45 | "接机服务", 46 | "接待外宾", 47 | "洗衣服务", 48 | "行李寄存", 49 | "租车", 50 | "叫醒服务" 51 | ], 52 | "price": 1918.0, 53 | "rating": 4.7, 54 | "hotel_id": 268 55 | }, 56 | { 57 | "name": "北京红杉假日酒店", 58 | "type": "高档型", 59 | "address": "北京海淀区双清路89号A座", 60 | "subway": "清华东路西口地铁站B口", 61 | "phone": "010-82398888", 62 | "facilities": [ 63 | "公共区域和部分房间提供wifi", 64 | "宽带上网", 65 | "免费市内电话", 66 | "国际长途电话", 67 | "吹风机", 68 | "24小时热水", 69 | "西式餐厅", 70 | "中式餐厅", 71 | "残疾人设施", 72 | "室内游泳池", 73 | "会议室", 74 | "健身房", 75 | "SPA", 76 | "无烟房", 77 | "商务中心", 78 | "酒吧", 79 | "桑拿", 80 | "接站服务", 81 | "接机服务", 82 | "接待外宾", 83 | "洗衣服务", 84 | "行李寄存", 85 | "叫醒服务" 86 | ], 87 | "price": 748.0, 88 | "rating": 4.6, 89 | "hotel_id": 288 90 | } 91 | ] 92 | }, 93 | { 94 | "role": "assistant", 95 | "content": "你可以去北京柏悦酒店,北京红杉假日酒店,我感觉这两家酒店还是挺好的。" 96 | } 97 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0019.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "最后我要找个舒适型酒店住宿,最好酒店的价格在700-800元之间,您看下有什么好推荐。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 700, 10 | "price_range_upper": 800, 11 | "type": "舒适型" 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "全季酒店(北京宣武门店)", 19 | "type": "舒适型", 20 | "address": "北京西城区宣武门外大街92号", 21 | "subway": "宣武门地铁站G口", 22 | "phone": "010-63189988", 23 | "facilities": [ 24 | "酒店各处提供wifi", 25 | "宽带上网", 26 | "国际长途电话", 27 | "吹风机", 28 | "24小时热水", 29 | "中式餐厅", 30 | "无烟房", 31 | "商务中心", 32 | "洗衣服务", 33 | "行李寄存", 34 | "叫醒服务" 35 | ], 36 | "price": 712.0, 37 | "rating": 4.8, 38 | "hotel_id": 440 39 | }, 40 | { 41 | "name": "全季酒店(北京朝阳门店)", 42 | "type": "舒适型", 43 | "address": "北京东城区朝内大街130号(朝阳门桥旁边)", 44 | "subway": "朝阳门地铁站H口", 45 | "phone": "010-52828001", 46 | "facilities": [ 47 | "公共区域和部分房间提供wifi", 48 | "宽带上网", 49 | "吹风机", 50 | "24小时热水", 51 | "中式餐厅", 52 | "无烟房", 53 | "早餐服务", 54 | "接待外宾", 55 | "行李寄存", 56 | "叫醒服务" 57 | ], 58 | "price": 712.0, 59 | "rating": 4.7, 60 | "hotel_id": 238 61 | }, 62 | { 63 | "name": "北京东直门智选假日酒店", 64 | "type": "舒适型", 65 | "address": "北京东城区春秀路1号", 66 | "subway": "东四十条地铁站B口", 67 | "phone": "010-64169999", 68 | "facilities": [ 69 | "公共区域和部分房间提供wifi", 70 | "宽带上网", 71 | "国际长途电话", 72 | "吹风机", 73 | "24小时热水", 74 | "中式餐厅", 75 | "残疾人设施", 76 | "会议室", 77 | "健身房", 78 | "无烟房", 79 | "酒吧", 80 | "早餐服务免费", 81 | "接待外宾", 82 | "洗衣服务", 83 | "行李寄存", 84 | "叫醒服务" 85 | ], 86 | "price": 745.0, 87 | "rating": 4.6, 88 | "hotel_id": 209 89 | } 90 | ] 91 | }, 92 | { 93 | "role": "assistant", 94 | "content": "北京东直门智选假日酒店、全季酒店(北京朝阳门店)、全季酒店(北京宣武门店)都符合您的住宿要求。" 95 | } 96 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0020.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,你能帮我找一家可以接待外宾和吹风机服务的评分在4分以上的酒店吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "吹风机", 11 | "接待外宾" 12 | ], 13 | "rating_range_lower": 4.0 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "北京都季商旅酒店", 21 | "type": "舒适型", 22 | "address": "北京东城区南河沿大街C座和D座", 23 | "subway": "王府井地铁站", 24 | "phone": "010-85116665", 25 | "facilities": [ 26 | "酒店各处提供wifi", 27 | "国际长途电话", 28 | "吹风机", 29 | "24小时热水", 30 | "暖气", 31 | "中式餐厅", 32 | "会议室", 33 | "无烟房", 34 | "商务中心", 35 | "早餐服务", 36 | "接待外宾", 37 | "行李寄存", 38 | "叫醒服务" 39 | ], 40 | "price": 1160.0, 41 | "rating": 4.5, 42 | "hotel_id": 9 43 | } 44 | ] 45 | }, 46 | { 47 | "role": "assistant", 48 | "content": "那你可以去北京都季商旅酒店住呀。" 49 | } 50 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0021.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "我想去一家评分4.5分以上的豪华型酒店住宿,给我推荐一家吧。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "rating_range_lower": 4.5, 10 | "type": "豪华型" 11 | } 12 | }, 13 | { 14 | "role": "return", 15 | "records": [ 16 | { 17 | "name": "北京鹏润国际大酒店", 18 | "type": "豪华型", 19 | "address": "北京朝阳区霄云路26号", 20 | "subway": "三元桥地铁站C2口", 21 | "phone": "010-51086688", 22 | "facilities": [ 23 | "公共区域和部分房间提供wifi", 24 | "宽带上网", 25 | "国际长途电话", 26 | "吹风机", 27 | "24小时热水", 28 | "西式餐厅", 29 | "中式餐厅", 30 | "残疾人设施", 31 | "室内游泳池", 32 | "会议室", 33 | "健身房", 34 | "SPA", 35 | "无烟房", 36 | "商务中心", 37 | "酒吧", 38 | "早餐服务", 39 | "接机服务", 40 | "接待外宾", 41 | "洗衣服务", 42 | "行李寄存", 43 | "叫醒服务" 44 | ], 45 | "price": 762.0, 46 | "rating": 4.6, 47 | "hotel_id": 2 48 | } 49 | ] 50 | }, 51 | { 52 | "role": "assistant", 53 | "content": "推荐您去北京鹏润国际大酒店住宿。" 54 | } 55 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0022.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "您好,我要找一家舒适型酒店住宿,然后希望酒店提供暖气与行李寄存。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "暖气", 11 | "行李寄存" 12 | ], 13 | "type": "舒适型" 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "北京香江戴斯酒店", 21 | "type": "舒适型", 22 | "address": "北京东城区南河沿大街南湾子胡同1号", 23 | "subway": "天安门东地铁站B口", 24 | "phone": "010-65127788", 25 | "facilities": [ 26 | "酒店各处提供wifi", 27 | "国际长途电话", 28 | "吹风机", 29 | "24小时热水", 30 | "暖气", 31 | "西式餐厅", 32 | "中式餐厅", 33 | "残疾人设施", 34 | "会议室", 35 | "无烟房", 36 | "商务中心", 37 | "早餐服务", 38 | "接机服务", 39 | "接待外宾", 40 | "洗衣服务", 41 | "行李寄存", 42 | "租车", 43 | "叫醒服务" 44 | ], 45 | "price": 328.0, 46 | "rating": 4.2, 47 | "hotel_id": 10 48 | } 49 | ] 50 | }, 51 | { 52 | "role": "assistant", 53 | "content": "那推荐您北京香江戴斯酒店,符合您的全部住宿要求并且价格又比较合适的酒店。" 54 | } 55 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0023.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "还能帮我再找一个提供会议室和无烟房的酒店吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "会议室", 11 | "无烟房" 12 | ] 13 | } 14 | }, 15 | { 16 | "role": "return", 17 | "records": [ 18 | { 19 | "name": "北京贵都大酒店", 20 | "type": "高档型", 21 | "address": "北京西城区广安门内大街217号", 22 | "subway": "菜市口地铁站D口", 23 | "phone": "010-51979888", 24 | "facilities": [ 25 | "公共区域和部分房间提供wifi", 26 | "宽带上网", 27 | "吹风机", 28 | "24小时热水", 29 | "西式餐厅", 30 | "中式餐厅", 31 | "会议室", 32 | "健身房", 33 | "无烟房", 34 | "商务中心", 35 | "接站服务", 36 | "接机服务", 37 | "洗衣服务", 38 | "行李寄存", 39 | "叫醒服务" 40 | ], 41 | "price": 1354.0, 42 | "rating": 4.7, 43 | "hotel_id": 0 44 | } 45 | ] 46 | }, 47 | { 48 | "role": "assistant", 49 | "content": "推荐您去北京贵都大酒店,有您需要的一切设施。" 50 | } 51 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0024.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "好的,这回就放心了,这几个酒店里哪个的最低价格是400-500元。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 400, 10 | "price_range_upper": 500 11 | } 12 | }, 13 | { 14 | "role": "return", 15 | "records": [ 16 | { 17 | "name": "北京骏马国际酒店", 18 | "type": "高档型", 19 | "address": "北京海淀区中关村东路南1条2号", 20 | "subway": "知春里地铁站B口", 21 | "phone": "010-82885858", 22 | "facilities": [ 23 | "公共区域和部分房间提供wifi", 24 | "国际长途电话", 25 | "吹风机", 26 | "24小时热水", 27 | "中式餐厅", 28 | "会议室", 29 | "无烟房", 30 | "商务中心", 31 | "接待外宾", 32 | "洗衣服务", 33 | "行李寄存", 34 | "叫醒服务" 35 | ], 36 | "price": 518.0, 37 | "rating": 4.5, 38 | "hotel_id": 33 39 | } 40 | ] 41 | }, 42 | { 43 | "role": "assistant", 44 | "content": "推荐你们去北京骏马国际酒店住宿,但是它的价格是518元。" 45 | }, 46 | { 47 | "role": "user", 48 | "content": "那这个酒店提供洗衣和SPA服务吗?" 49 | }, 50 | { 51 | "role": "search", 52 | "arguments": { 53 | "price_range_lower": 400, 54 | "price_range_upper": 500, 55 | "facilities": [ 56 | "SPA", 57 | "洗衣服务" 58 | ] 59 | } 60 | }, 61 | { 62 | "role": "return", 63 | "records": [] 64 | }, 65 | { 66 | "role": "assistant", 67 | "content": "不好意思,这个酒店提供洗衣服务,但是没有SPA服务。" 68 | } 69 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0025.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,能为我挑选一个提供酒吧,价格是700-800元的酒店吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "酒吧" 11 | ], 12 | "price_range_lower": 700, 13 | "price_range_upper": 800 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "北京中成天坛假日酒店", 21 | "type": "高档型", 22 | "address": "北京丰台区南三环定安东里1号", 23 | "subway": "景泰站地铁站B口", 24 | "phone": "010-67626688", 25 | "facilities": [ 26 | "酒店各处提供wifi", 27 | "宽带上网", 28 | "免费市内电话", 29 | "国际长途电话", 30 | "吹风机", 31 | "24小时热水", 32 | "西式餐厅", 33 | "中式餐厅", 34 | "残疾人设施", 35 | "室内游泳池", 36 | "会议室", 37 | "健身房", 38 | "无烟房", 39 | "商务中心", 40 | "酒吧", 41 | "桑拿", 42 | "洗衣服务", 43 | "叫醒服务" 44 | ], 45 | "price": 775.0, 46 | "rating": 4.4, 47 | "hotel_id": 435 48 | }, 49 | { 50 | "name": "北京国泰饭店", 51 | "type": "高档型", 52 | "address": "北京朝阳区建国门外永安西里12号", 53 | "subway": "永安里地铁站A口", 54 | "phone": "010-65683366", 55 | "facilities": [ 56 | "公共区域和部分房间提供wifi", 57 | "宽带上网", 58 | "免费市内电话", 59 | "国际长途电话", 60 | "吹风机", 61 | "24小时热水", 62 | "西式餐厅", 63 | "中式餐厅", 64 | "残疾人设施", 65 | "会议室", 66 | "无烟房", 67 | "商务中心", 68 | "酒吧", 69 | "早餐服务", 70 | "接站服务", 71 | "接机服务", 72 | "接待外宾", 73 | "洗衣服务", 74 | "行李寄存", 75 | "叫醒服务" 76 | ], 77 | "price": 716.0, 78 | "rating": 4.5, 79 | "hotel_id": 328 80 | } 81 | ] 82 | }, 83 | { 84 | "role": "assistant", 85 | "content": "你可以去北京国泰饭店和北京中成天坛假日酒店。" 86 | } 87 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0026.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "玩累了,我想找一家酒店休息,帮我推荐一个能提供行李寄存的经济型酒店吧,最好评分在4.5分以上的。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "行李寄存" 11 | ], 12 | "rating_range_lower": 4.5, 13 | "type": "经济型" 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "锦江之星(北京奥体中心店)", 21 | "type": "经济型", 22 | "address": "北京朝阳区安定门外安苑里1号院", 23 | "subway": "安贞门地铁站A口", 24 | "phone": "010-64917666", 25 | "facilities": [ 26 | "公共区域提供wifi", 27 | "宽带上网", 28 | "国际长途电话", 29 | "24小时热水", 30 | "中式餐厅", 31 | "会议室", 32 | "早餐服务", 33 | "接待外宾", 34 | "洗衣服务", 35 | "行李寄存", 36 | "叫醒服务" 37 | ], 38 | "price": 351.0, 39 | "rating": 4.5, 40 | "hotel_id": 44 41 | } 42 | ] 43 | }, 44 | { 45 | "role": "assistant", 46 | "content": "推荐您去锦江之星(北京奥体中心店)住宿。" 47 | } 48 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0027.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "好的,我还想预约一家酒店,评分在5分,价格在100-200元的就可以!" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 100, 10 | "price_range_upper": 200, 11 | "rating_range_lower": 5.0, 12 | "rating_range_upper": 5.0 13 | } 14 | }, 15 | { 16 | "role": "return", 17 | "records": [ 18 | { 19 | "name": "北京布提克精品酒店", 20 | "type": "高档型", 21 | "address": "北京顺义区天竺镇府前一街24号", 22 | "subway": "国展地铁站C口", 23 | "phone": "010-84163601", 24 | "facilities": [ 25 | "酒店各处提供wifi", 26 | "国际长途电话", 27 | "免费国内长途电话", 28 | "吹风机", 29 | "24小时热水", 30 | "暖气", 31 | "会议室", 32 | "无烟房", 33 | "接站服务", 34 | "接机服务", 35 | "洗衣服务", 36 | "行李寄存", 37 | "租车", 38 | "叫醒服务" 39 | ], 40 | "price": 196.0, 41 | "rating": 4.8, 42 | "hotel_id": 161 43 | } 44 | ] 45 | }, 46 | { 47 | "role": "assistant", 48 | "content": "推荐您去北京布提克精品酒店,价格是196元,评分是4.8分,可以么?" 49 | } 50 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0028.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,请帮我找一家最低价格是300-400元的经济型酒店,我想带我父母去住。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 300, 10 | "price_range_upper": 400, 11 | "type": "经济型" 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "锦江之星(北京奥体中心店)", 19 | "type": "经济型", 20 | "address": "北京朝阳区安定门外安苑里1号院", 21 | "subway": "安贞门地铁站A口", 22 | "phone": "010-64917666", 23 | "facilities": [ 24 | "公共区域提供wifi", 25 | "宽带上网", 26 | "国际长途电话", 27 | "24小时热水", 28 | "中式餐厅", 29 | "会议室", 30 | "早餐服务", 31 | "接待外宾", 32 | "洗衣服务", 33 | "行李寄存", 34 | "叫醒服务" 35 | ], 36 | "price": 351.0, 37 | "rating": 4.5, 38 | "hotel_id": 44 39 | } 40 | ] 41 | }, 42 | { 43 | "role": "assistant", 44 | "content": "好的,我推荐您去锦江之星(北京奥体中心店),这家酒店很不错。" 45 | } 46 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0029.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,帮我推荐一个价位在300-400元之间的经济型酒店。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 300, 10 | "price_range_upper": 400, 11 | "type": "经济型" 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "汉庭酒店(北京南站南店)", 19 | "type": "经济型", 20 | "address": "北京丰台区马家堡西里38号", 21 | "subway": "马家堡地铁站", 22 | "phone": "010-65003030", 23 | "facilities": [ 24 | "公共区域和部分房间提供wifi", 25 | "宽带上网", 26 | "国际长途电话", 27 | "吹风机", 28 | "24小时热水", 29 | "无烟房", 30 | "早餐服务", 31 | "行李寄存", 32 | "叫醒服务" 33 | ], 34 | "price": 364.0, 35 | "rating": 4.3, 36 | "hotel_id": 1111 37 | } 38 | ] 39 | }, 40 | { 41 | "role": "assistant", 42 | "content": "为您推荐汉庭酒店(北京南站南店)。" 43 | } 44 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0030.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,可以帮我找一个评分4.5分以上的高档型酒店吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "rating_range_lower": 4.5, 10 | "type": "高档型" 11 | } 12 | }, 13 | { 14 | "role": "return", 15 | "records": [ 16 | { 17 | "name": "北京万方苑国际酒店", 18 | "type": "高档型", 19 | "address": "北京丰台区南三环西路4号", 20 | "subway": "马家堡地铁站B口", 21 | "phone": "010-67526666", 22 | "facilities": [ 23 | "公共区域提供wifi", 24 | "宽带上网", 25 | "免费市内电话", 26 | "国际长途电话", 27 | "吹风机", 28 | "24小时热水", 29 | "暖气", 30 | "西式餐厅", 31 | "中式餐厅", 32 | "残疾人设施", 33 | "会议室", 34 | "健身房", 35 | "无烟房", 36 | "商务中心", 37 | "早餐服务", 38 | "接待外宾", 39 | "行李寄存", 40 | "租车", 41 | "叫醒服务" 42 | ], 43 | "price": 2133.0, 44 | "rating": 4.5, 45 | "hotel_id": 39 46 | }, 47 | { 48 | "name": "北京新侨诺富特饭店", 49 | "type": "高档型", 50 | "address": "北京东城区崇文门西大街1号", 51 | "subway": "崇文门地铁站A2口", 52 | "phone": "010-65133366", 53 | "facilities": [ 54 | "公共区域和部分房间提供wifi", 55 | "宽带上网", 56 | "国际长途电话", 57 | "吹风机", 58 | "24小时热水", 59 | "西式餐厅", 60 | "中式餐厅", 61 | "残疾人设施", 62 | "会议室", 63 | "健身房", 64 | "SPA", 65 | "无烟房", 66 | "商务中心", 67 | "温泉", 68 | "早餐服务", 69 | "接待外宾", 70 | "洗衣服务", 71 | "行李寄存", 72 | "叫醒服务" 73 | ], 74 | "price": 657.0, 75 | "rating": 4.5, 76 | "hotel_id": 21 77 | } 78 | ] 79 | }, 80 | { 81 | "role": "assistant", 82 | "content": "北京新侨诺富特饭店和北京万方苑国际酒店都是不错的地方,推荐给您吧。" 83 | }, 84 | { 85 | "role": "user", 86 | "content": "我希望酒店提供国际长途电话和免费市内电话,这两家酒店满足吗?" 87 | }, 88 | { 89 | "role": "search", 90 | "arguments": { 91 | "rating_range_lower": 4.5, 92 | "type": "高档型", 93 | "facilities": [ 94 | "免费市内电话", 95 | "国际长途电话" 96 | ] 97 | } 98 | }, 99 | { 100 | "role": "return", 101 | "records": [ 102 | { 103 | "name": "北京万方苑国际酒店", 104 | "type": "高档型", 105 | "address": "北京丰台区南三环西路4号", 106 | "subway": "马家堡地铁站B口", 107 | "phone": "010-67526666", 108 | "facilities": [ 109 | "公共区域提供wifi", 110 | "宽带上网", 111 | "免费市内电话", 112 | "国际长途电话", 113 | "吹风机", 114 | "24小时热水", 115 | "暖气", 116 | "西式餐厅", 117 | "中式餐厅", 118 | "残疾人设施", 119 | "会议室", 120 | "健身房", 121 | "无烟房", 122 | "商务中心", 123 | "早餐服务", 124 | "接待外宾", 125 | "行李寄存", 126 | "租车", 127 | "叫醒服务" 128 | ], 129 | "price": 2133.0, 130 | "rating": 4.5, 131 | "hotel_id": 39 132 | } 133 | ] 134 | }, 135 | { 136 | "role": "assistant", 137 | "content": "北京万方苑国际酒店满足您的需求,你还是去这里吧。" 138 | } 139 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0031.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好你帮我找一个价格是300-400元的酒店,可以吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 300, 10 | "price_range_upper": 400 11 | } 12 | }, 13 | { 14 | "role": "return", 15 | "records": [ 16 | { 17 | "name": "北京世纪星豪酒店", 18 | "type": "舒适型", 19 | "address": "北京海淀区远大路1号世纪金源购物中心B座", 20 | "subway": "长春桥地铁站A口", 21 | "phone": "010-88841399", 22 | "facilities": [ 23 | "公共区域和部分房间提供wifi", 24 | "宽带上网", 25 | "免费市内电话", 26 | "国际长途电话", 27 | "吹风机", 28 | "24小时热水", 29 | "残疾人设施", 30 | "无烟房", 31 | "商务中心", 32 | "早餐服务", 33 | "接待外宾", 34 | "洗衣服务", 35 | "行李寄存", 36 | "叫醒服务" 37 | ], 38 | "price": 301.0, 39 | "rating": 4.2, 40 | "hotel_id": 83 41 | } 42 | ] 43 | }, 44 | { 45 | "role": "assistant", 46 | "content": "你可以去北京世纪星豪酒店住。" 47 | } 48 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0032.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,请给我推荐一个最低价格在300-400元的经济型酒店住宿。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 300, 10 | "price_range_upper": 400, 11 | "type": "经济型" 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "锦江之星(北京奥体中心店)", 19 | "type": "经济型", 20 | "address": "北京朝阳区安定门外安苑里1号院", 21 | "subway": "安贞门地铁站A口", 22 | "phone": "010-64917666", 23 | "facilities": [ 24 | "公共区域提供wifi", 25 | "宽带上网", 26 | "国际长途电话", 27 | "24小时热水", 28 | "中式餐厅", 29 | "会议室", 30 | "早餐服务", 31 | "接待外宾", 32 | "洗衣服务", 33 | "行李寄存", 34 | "叫醒服务" 35 | ], 36 | "price": 351.0, 37 | "rating": 4.5, 38 | "hotel_id": 44 39 | } 40 | ] 41 | }, 42 | { 43 | "role": "assistant", 44 | "content": "推荐您去锦江之星(北京奥体中心店)。" 45 | } 46 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0033.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "那帮我找一家经济型的酒店,最好评分在4.5分以上,价格在300-400元之间。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 300, 10 | "price_range_upper": 400, 11 | "rating_range_lower": 4.5, 12 | "type": "经济型" 13 | } 14 | }, 15 | { 16 | "role": "return", 17 | "records": [ 18 | { 19 | "name": "和家宾馆连锁(北京阜外医院店)(原百万庄店)", 20 | "type": "经济型", 21 | "address": "北京西城区百万庄大街23号(外交学院北门)", 22 | "subway": "车公庄西地铁站C口", 23 | "phone": "010-52605118", 24 | "facilities": [ 25 | "公共区域和部分房间提供wifi", 26 | "免费市内电话", 27 | "24小时热水", 28 | "无烟房", 29 | "早餐服务免费", 30 | "行李寄存", 31 | "叫醒服务" 32 | ], 33 | "price": 310.0, 34 | "rating": 4.6, 35 | "hotel_id": 277 36 | }, 37 | { 38 | "name": "锦江之星(北京奥体中心店)", 39 | "type": "经济型", 40 | "address": "北京朝阳区安定门外安苑里1号院", 41 | "subway": "安贞门地铁站A口", 42 | "phone": "010-64917666", 43 | "facilities": [ 44 | "公共区域提供wifi", 45 | "宽带上网", 46 | "国际长途电话", 47 | "24小时热水", 48 | "中式餐厅", 49 | "会议室", 50 | "早餐服务", 51 | "接待外宾", 52 | "洗衣服务", 53 | "行李寄存", 54 | "叫醒服务" 55 | ], 56 | "price": 351.0, 57 | "rating": 4.5, 58 | "hotel_id": 44 59 | }, 60 | { 61 | "name": "锦江之星(北京奥运村大屯路店)", 62 | "type": "经济型", 63 | "address": "北京朝阳区安外大屯220号", 64 | "subway": "大屯路东地铁站B2口", 65 | "phone": "010-84835588", 66 | "facilities": [ 67 | "公共区域提供wifi", 68 | "宽带上网", 69 | "国际长途电话", 70 | "24小时热水", 71 | "中式餐厅", 72 | "会议室", 73 | "无烟房", 74 | "早餐服务", 75 | "接待外宾", 76 | "洗衣服务", 77 | "行李寄存", 78 | "叫醒服务" 79 | ], 80 | "price": 374.0, 81 | "rating": 4.5, 82 | "hotel_id": 298 83 | } 84 | ] 85 | }, 86 | { 87 | "role": "assistant", 88 | "content": "有好多符合的酒店,包括锦江之星(北京奥体中心店)、和家宾馆连锁(北京阜外医院店)(原百万庄店)、锦江之星(北京奥运村大屯路店)。" 89 | } 90 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0034.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "太好了,游玩结束后我需要一个提供宽带上网和无烟房的经济型酒店休息,你有值得推荐的地方吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "宽带上网", 11 | "无烟房" 12 | ], 13 | "type": "经济型" 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "中安之家北京东单宾馆", 21 | "type": "经济型", 22 | "address": "北京东城区东单北大街120号", 23 | "subway": "东单地铁站5号线F口", 24 | "phone": "010-65250569", 25 | "facilities": [ 26 | "酒店各处提供wifi", 27 | "宽带上网", 28 | "国际长途电话", 29 | "24小时热水", 30 | "中式餐厅", 31 | "无烟房", 32 | "早餐服务", 33 | "接待外宾", 34 | "行李寄存", 35 | "叫醒服务" 36 | ], 37 | "price": 446.0, 38 | "rating": 4.5, 39 | "hotel_id": 244 40 | } 41 | ] 42 | }, 43 | { 44 | "role": "assistant", 45 | "content": "我知道一个酒店,中安之家北京东单宾馆是一个非常不错的地方,你想去吗?" 46 | } 47 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0035.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "然后我还要找个酒店住宿,我想要的是经济型酒店,然后评分也要在4.5分以上。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "rating_range_lower": 4.5, 10 | "type": "经济型" 11 | } 12 | }, 13 | { 14 | "role": "return", 15 | "records": [ 16 | { 17 | "name": "锦江之星(北京奥体中心店)", 18 | "type": "经济型", 19 | "address": "北京朝阳区安定门外安苑里1号院", 20 | "subway": "安贞门地铁站A口", 21 | "phone": "010-64917666", 22 | "facilities": [ 23 | "公共区域提供wifi", 24 | "宽带上网", 25 | "国际长途电话", 26 | "24小时热水", 27 | "中式餐厅", 28 | "会议室", 29 | "早餐服务", 30 | "接待外宾", 31 | "洗衣服务", 32 | "行李寄存", 33 | "叫醒服务" 34 | ], 35 | "price": 351.0, 36 | "rating": 4.5, 37 | "hotel_id": 44 38 | } 39 | ] 40 | }, 41 | { 42 | "role": "assistant", 43 | "content": "那我推荐您锦江之星(北京奥体中心店),它正好满足您住宿的标准。" 44 | }, 45 | { 46 | "role": "user", 47 | "content": "对了,酒店提供会议室吗。" 48 | }, 49 | { 50 | "role": "search", 51 | "arguments": { 52 | "rating_range_lower": 4.5, 53 | "type": "经济型", 54 | "facilities": [ 55 | "会议室" 56 | ] 57 | } 58 | }, 59 | { 60 | "role": "return", 61 | "records": [] 62 | }, 63 | { 64 | "role": "assistant", 65 | "content": "有,酒店设施里有会议室。" 66 | } 67 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0036.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,我出差想去酒店住宿。请帮我找一家评分是4.5分以上的舒适型酒店。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "rating_range_lower": 4.5, 10 | "type": "舒适型" 11 | } 12 | }, 13 | { 14 | "role": "return", 15 | "records": [ 16 | { 17 | "name": "北京国图宾馆", 18 | "type": "舒适型", 19 | "address": "北京海淀区中关村南大街33号", 20 | "subway": "国家图书馆地铁站A口", 21 | "phone": "010-88545012", 22 | "facilities": [ 23 | "酒店各处提供wifi", 24 | "宽带上网", 25 | "吹风机", 26 | "24小时热水", 27 | "残疾人设施", 28 | "会议室", 29 | "无烟房", 30 | "商务中心", 31 | "接站服务", 32 | "接机服务", 33 | "洗衣服务", 34 | "行李寄存", 35 | "叫醒服务" 36 | ], 37 | "price": 598.0, 38 | "rating": 4.6, 39 | "hotel_id": 148 40 | }, 41 | { 42 | "name": "北京天龙饭店", 43 | "type": "舒适型", 44 | "address": "北京东城区黄寺大街甲6号", 45 | "subway": "安德里北街地铁站", 46 | "phone": "010-84138866", 47 | "facilities": [ 48 | "酒店各处提供wifi", 49 | "宽带上网", 50 | "免费市内电话", 51 | "吹风机", 52 | "24小时热水", 53 | "中式餐厅", 54 | "会议室", 55 | "无烟房", 56 | "商务中心", 57 | "棋牌室", 58 | "早餐服务", 59 | "接站服务", 60 | "接机服务", 61 | "行李寄存", 62 | "租车", 63 | "叫醒服务" 64 | ], 65 | "price": -1.0, 66 | "rating": 4.5, 67 | "hotel_id": 118 68 | } 69 | ] 70 | }, 71 | { 72 | "role": "assistant", 73 | "content": "推荐您去北京国图宾馆或者北京天龙饭店住宿,服务都不错。" 74 | } 75 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0037.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "您好,我要为客户订一家酒店,希望评分是4.5分以上、提供行李寄存、提供免费市内电话,求推荐。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "免费市内电话", 11 | "行李寄存" 12 | ], 13 | "rating_range_lower": 4.5 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "北京康莱德酒店", 21 | "type": "豪华型", 22 | "address": "北京朝阳区东三环北路29号", 23 | "subway": "呼家楼地铁站B口", 24 | "phone": "010-65846000", 25 | "facilities": [ 26 | "公共区域和部分房间提供wifi", 27 | "宽带上网", 28 | "免费市内电话", 29 | "国际长途电话", 30 | "吹风机", 31 | "24小时热水", 32 | "暖气", 33 | "西式餐厅", 34 | "中式餐厅", 35 | "残疾人设施", 36 | "室内游泳池", 37 | "会议室", 38 | "健身房", 39 | "SPA", 40 | "无烟房", 41 | "酒吧", 42 | "早餐服务", 43 | "接机服务", 44 | "接待外宾", 45 | "行李寄存", 46 | "叫醒服务" 47 | ], 48 | "price": 1691.0, 49 | "rating": 4.6, 50 | "hotel_id": 47 51 | } 52 | ] 53 | }, 54 | { 55 | "role": "assistant", 56 | "content": "为您推荐北京康莱德酒店。" 57 | }, 58 | { 59 | "role": "user", 60 | "content": "这些酒店中有最低价格是500-600元的、提供宽带上网、提供部分房间提供wifi的吗?" 61 | }, 62 | { 63 | "role": "search", 64 | "arguments": { 65 | "rating_range_lower": 4.5, 66 | "facilities": [ 67 | "宽带上网", 68 | "部分房间提供wifi" 69 | ], 70 | "price_range_lower": 500, 71 | "price_range_upper": 600 72 | } 73 | }, 74 | { 75 | "role": "return", 76 | "records": [ 77 | { 78 | "name": "瑞尔威连锁饭店(北京西客站店)", 79 | "type": "舒适型", 80 | "address": "北京丰台区莲花池东路116-2号", 81 | "subway": "北京西站地铁站A口", 82 | "phone": "010-63959988", 83 | "facilities": [ 84 | "酒店各处提供wifi", 85 | "宽带上网", 86 | "国际长途电话", 87 | "吹风机", 88 | "24小时热水", 89 | "暖气", 90 | "会议室", 91 | "无烟房", 92 | "接待外宾", 93 | "行李寄存", 94 | "叫醒服务" 95 | ], 96 | "price": 558.0, 97 | "rating": 4.3, 98 | "hotel_id": 1 99 | } 100 | ] 101 | }, 102 | { 103 | "role": "assistant", 104 | "content": "报歉,这三家酒店价格都比较高,为您推荐瑞尔威连锁饭店(北京西客站店),价格558元,有您需要的服务。" 105 | } 106 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0038.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "哦,那你帮我找一个吧,评分4分以上,要有公共区域和部分房间提供wifi还有叫醒服务的。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "公共区域和部分房间提供wifi", 11 | "叫醒服务" 12 | ], 13 | "rating_range_lower": 4.0 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "北京鹏润国际大酒店", 21 | "type": "豪华型", 22 | "address": "北京朝阳区霄云路26号", 23 | "subway": "三元桥地铁站C2口", 24 | "phone": "010-51086688", 25 | "facilities": [ 26 | "公共区域和部分房间提供wifi", 27 | "宽带上网", 28 | "国际长途电话", 29 | "吹风机", 30 | "24小时热水", 31 | "西式餐厅", 32 | "中式餐厅", 33 | "残疾人设施", 34 | "室内游泳池", 35 | "会议室", 36 | "健身房", 37 | "SPA", 38 | "无烟房", 39 | "商务中心", 40 | "酒吧", 41 | "早餐服务", 42 | "接机服务", 43 | "接待外宾", 44 | "洗衣服务", 45 | "行李寄存", 46 | "叫醒服务" 47 | ], 48 | "price": 762.0, 49 | "rating": 4.6, 50 | "hotel_id": 2 51 | } 52 | ] 53 | }, 54 | { 55 | "role": "assistant", 56 | "content": "推荐北京鹏润国际大酒店,评分4.6哦。" 57 | } 58 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0039.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "您好,能为我推荐一个最低价格是400-500元的酒店吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 400, 10 | "price_range_upper": 500 11 | } 12 | }, 13 | { 14 | "role": "return", 15 | "records": [ 16 | { 17 | "name": "北京京泰龙国际大酒店", 18 | "type": "高档型", 19 | "address": "北京东城区珠市口东大街19号", 20 | "subway": "珠市口地铁站C口", 21 | "phone": "010-67075888", 22 | "facilities": [ 23 | "酒店各处提供wifi", 24 | "宽带上网", 25 | "国际长途电话", 26 | "吹风机", 27 | "24小时热水", 28 | "西式餐厅", 29 | "中式餐厅", 30 | "残疾人设施", 31 | "会议室", 32 | "无烟房", 33 | "商务中心", 34 | "酒吧", 35 | "早餐服务", 36 | "接站服务", 37 | "接机服务", 38 | "接待外宾", 39 | "洗衣服务", 40 | "行李寄存", 41 | "叫醒服务" 42 | ], 43 | "price": 440.0, 44 | "rating": 4.6, 45 | "hotel_id": 17 46 | } 47 | ] 48 | }, 49 | { 50 | "role": "assistant", 51 | "content": "很高兴为您服务!为您推荐北京京泰龙国际大酒店,价格440元。" 52 | } 53 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0040.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "您好,我想找一家评分是5分、经济型的酒店,安排朋友,求推荐。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "rating_range_lower": 5.0, 10 | "rating_range_upper": 5.0, 11 | "type": "经济型" 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "7天优品酒店(北京国贸劲松地铁站店)", 19 | "type": "经济型", 20 | "address": "北京朝阳区劲松南路5号院", 21 | "subway": "劲松地铁站D口", 22 | "phone": "010-87722388", 23 | "facilities": [ 24 | "部分房间提供wifi", 25 | "宽带上网", 26 | "24小时热水", 27 | "早餐服务" 28 | ], 29 | "price": 288.0, 30 | "rating": 5.0, 31 | "hotel_id": 272 32 | } 33 | ] 34 | }, 35 | { 36 | "role": "assistant", 37 | "content": "为您推荐7天优品酒店(北京国贸劲松地铁站店)。" 38 | } 39 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0041.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "给我推荐一个经济型的酒店,价格在300-400元的。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 300, 10 | "price_range_upper": 400, 11 | "type": "经济型" 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "锦江之星(北京奥体中心店)", 19 | "type": "经济型", 20 | "address": "北京朝阳区安定门外安苑里1号院", 21 | "subway": "安贞门地铁站A口", 22 | "phone": "010-64917666", 23 | "facilities": [ 24 | "公共区域提供wifi", 25 | "宽带上网", 26 | "国际长途电话", 27 | "24小时热水", 28 | "中式餐厅", 29 | "会议室", 30 | "早餐服务", 31 | "接待外宾", 32 | "洗衣服务", 33 | "行李寄存", 34 | "叫醒服务" 35 | ], 36 | "price": 351.0, 37 | "rating": 4.5, 38 | "hotel_id": 44 39 | } 40 | ] 41 | }, 42 | { 43 | "role": "assistant", 44 | "content": "推荐您去锦江之星(北京奥体中心店)。" 45 | } 46 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0042.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "您好,我想找个经济型、评分在4.5分以上酒店住宿,帮我查询一下哪个酒店符合我的需求。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "rating_range_lower": 4.5, 10 | "type": "经济型" 11 | } 12 | }, 13 | { 14 | "role": "return", 15 | "records": [ 16 | { 17 | "name": "中安之家连锁(北京中安宾馆)", 18 | "type": "经济型", 19 | "address": "北京东城区北京站东街大羊毛胡同盔甲厂6号", 20 | "subway": "北京站地铁站C口", 21 | "phone": "010-65221122", 22 | "facilities": [ 23 | "公共区域和部分房间提供wifi", 24 | "宽带上网", 25 | "国际长途电话", 26 | "吹风机", 27 | "24小时热水", 28 | "中式餐厅", 29 | "会议室", 30 | "无烟房", 31 | "早餐服务", 32 | "接待外宾", 33 | "行李寄存", 34 | "叫醒服务", 35 | "收费停车位" 36 | ], 37 | "price": 294.0, 38 | "rating": 4.5, 39 | "hotel_id": 61 40 | }, 41 | { 42 | "name": "格林豪泰(北京首都机场新国展地铁站店)", 43 | "type": "经济型", 44 | "address": "北京顺义区空港工业园A区天柱西路24号", 45 | "subway": "国展地铁站B口", 46 | "phone": "010-80485188", 47 | "facilities": [ 48 | "公共区域和部分房间提供wifi", 49 | "宽带上网", 50 | "吹风机", 51 | "24小时热水", 52 | "暖气", 53 | "中式餐厅", 54 | "会议室", 55 | "无烟房", 56 | "早餐服务", 57 | "接站服务", 58 | "接机服务", 59 | "接待外宾", 60 | "洗衣服务" 61 | ], 62 | "price": 188.0, 63 | "rating": 4.5, 64 | "hotel_id": 65 65 | }, 66 | { 67 | "name": "金广快捷酒店(北京首都机场新国展店)", 68 | "type": "经济型", 69 | "address": "北京顺义区天柱东路10号", 70 | "subway": "国展地铁站C口", 71 | "phone": "010-88511588", 72 | "facilities": [ 73 | "公共区域和部分房间提供wifi", 74 | "宽带上网", 75 | "24小时热水", 76 | "中式餐厅", 77 | "残疾人设施", 78 | "无烟房", 79 | "早餐服务", 80 | "接机服务", 81 | "行李寄存", 82 | "叫醒服务" 83 | ], 84 | "price": 135.0, 85 | "rating": 4.6, 86 | "hotel_id": 57 87 | }, 88 | { 89 | "name": "锦江之星(北京奥体中心店)", 90 | "type": "经济型", 91 | "address": "北京朝阳区安定门外安苑里1号院", 92 | "subway": "安贞门地铁站A口", 93 | "phone": "010-64917666", 94 | "facilities": [ 95 | "公共区域提供wifi", 96 | "宽带上网", 97 | "国际长途电话", 98 | "24小时热水", 99 | "中式餐厅", 100 | "会议室", 101 | "早餐服务", 102 | "接待外宾", 103 | "洗衣服务", 104 | "行李寄存", 105 | "叫醒服务" 106 | ], 107 | "price": 351.0, 108 | "rating": 4.5, 109 | "hotel_id": 44 110 | } 111 | ] 112 | }, 113 | { 114 | "role": "assistant", 115 | "content": "符合您需求的酒店有锦江之星(北京奥体中心店)、金广快捷酒店(北京首都机场新国展店)、中安之家连锁(北京中安宾馆)、格林豪泰(北京首都机场新国展地铁站店),看您喜欢哪家,选择一个。" 116 | } 117 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0043.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "不错哦,景点还蛮多的呢,吃完饭可以帮我找一个价格是900-1000元,提供接站服务的酒店吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "接站服务" 11 | ], 12 | "price_range_lower": 900, 13 | "price_range_upper": 1000 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "北京蔓兰酒店", 21 | "type": "豪华型", 22 | "address": "北京东城区东直门外香河园路1号当代MOMA内T6号楼", 23 | "subway": "柳芳地铁站B口", 24 | "phone": "010-52049666", 25 | "facilities": [ 26 | "酒店各处提供wifi", 27 | "宽带上网", 28 | "国际长途电话", 29 | "免费国内长途电话", 30 | "吹风机", 31 | "24小时热水", 32 | "中式餐厅", 33 | "室内游泳池", 34 | "会议室", 35 | "健身房", 36 | "SPA", 37 | "无烟房", 38 | "商务中心", 39 | "酒吧", 40 | "早餐服务", 41 | "接站服务", 42 | "接机服务", 43 | "洗衣服务", 44 | "行李寄存", 45 | "叫醒服务" 46 | ], 47 | "price": 980.0, 48 | "rating": 4.8, 49 | "hotel_id": 163 50 | } 51 | ] 52 | }, 53 | { 54 | "role": "assistant", 55 | "content": "当然了,你可以去北京蔓兰酒店,服务很到位的。" 56 | } 57 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0044.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,我想去一个提供叫醒服务,价格400-500元的酒店住宿,有没有值得推荐的地方啊?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "叫醒服务" 11 | ], 12 | "price_range_lower": 400, 13 | "price_range_upper": 500 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "北京建国门宜必思酒店", 21 | "type": "舒适型", 22 | "address": "北京朝阳区建华南路6号院1号楼卓明大厦", 23 | "subway": "永安里地铁站A口", 24 | "phone": "010-65671588", 25 | "facilities": [ 26 | "公共区域和部分房间提供wifi", 27 | "宽带上网", 28 | "吹风机", 29 | "24小时热水", 30 | "西式餐厅", 31 | "无烟房", 32 | "商务中心", 33 | "早餐服务", 34 | "接站服务", 35 | "洗衣服务", 36 | "行李寄存", 37 | "叫醒服务" 38 | ], 39 | "price": 433.0, 40 | "rating": 4.3, 41 | "hotel_id": 256 42 | } 43 | ] 44 | }, 45 | { 46 | "role": "assistant", 47 | "content": "当然有啊,北京建国门宜必思酒店就是一个非常好的选择呀。" 48 | } 49 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0045.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "然后,我想入住一家评分是4.5分以上的餐馆,请推荐。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "rating_range_lower": 4.5 10 | } 11 | }, 12 | { 13 | "role": "user", 14 | "content": "哦,不好意思,请推荐一家评分是4.5分以上的酒店。" 15 | }, 16 | { 17 | "role": "search", 18 | "arguments": { 19 | "rating_range_lower": 4.5 20 | } 21 | }, 22 | { 23 | "role": "return", 24 | "records": [ 25 | { 26 | "name": "北京贵都大酒店", 27 | "type": "高档型", 28 | "address": "北京西城区广安门内大街217号", 29 | "subway": "菜市口地铁站D口", 30 | "phone": "010-51979888", 31 | "facilities": [ 32 | "公共区域和部分房间提供wifi", 33 | "宽带上网", 34 | "吹风机", 35 | "24小时热水", 36 | "西式餐厅", 37 | "中式餐厅", 38 | "会议室", 39 | "健身房", 40 | "无烟房", 41 | "商务中心", 42 | "接站服务", 43 | "接机服务", 44 | "洗衣服务", 45 | "行李寄存", 46 | "叫醒服务" 47 | ], 48 | "price": 1354.0, 49 | "rating": 4.7, 50 | "hotel_id": 0 51 | } 52 | ] 53 | }, 54 | { 55 | "role": "assistant", 56 | "content": "那您可以到北京贵都大酒店入住,那里环境很不错的。" 57 | } 58 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0046.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "好的,够用了,哈哈,玩累了,接下来我想去一家有健身房服务的4分酒店去,你知道哪家酒店可以满足我的需求吗?" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "健身房" 11 | ], 12 | "rating_range_lower": 4.0 13 | } 14 | }, 15 | { 16 | "role": "return", 17 | "records": [ 18 | { 19 | "name": "北京国际饭店", 20 | "type": "豪华型", 21 | "address": "北京东城区建国门内大街9号", 22 | "subway": "建国门地铁站A口", 23 | "phone": "010-65126688", 24 | "facilities": [ 25 | "公共区域和部分房间提供wifi", 26 | "宽带上网", 27 | "国际长途电话", 28 | "吹风机", 29 | "24小时热水", 30 | "西式餐厅", 31 | "中式餐厅", 32 | "残疾人设施", 33 | "室内游泳池", 34 | "会议室", 35 | "健身房", 36 | "SPA", 37 | "无烟房", 38 | "商务中心", 39 | "酒吧", 40 | "桑拿", 41 | "棋牌室", 42 | "早餐服务", 43 | "接站服务", 44 | "接机服务", 45 | "接待外宾", 46 | "洗衣服务", 47 | "行李寄存", 48 | "租车", 49 | "叫醒服务" 50 | ], 51 | "price": 648.0, 52 | "rating": 4.4, 53 | "hotel_id": 49 54 | } 55 | ] 56 | }, 57 | { 58 | "role": "assistant", 59 | "content": "北京国际饭店就行,你要的他家都有。" 60 | } 61 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0047.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "好嘞,再帮我推荐一家酒店,最好是最低价格700-800元,评分在4分以上。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 700, 10 | "price_range_upper": 800, 11 | "rating_range_lower": 4.0 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "北京唐拉雅秀酒店", 19 | "type": "豪华型", 20 | "address": "北京西城区西长安街复兴门外大街19号", 21 | "subway": "木樨地地铁站B1口", 22 | "phone": "010-58576688", 23 | "facilities": [ 24 | "公共区域和部分房间提供wifi", 25 | "宽带上网", 26 | "国际长途电话", 27 | "吹风机", 28 | "24小时热水", 29 | "西式餐厅", 30 | "中式餐厅", 31 | "残疾人设施", 32 | "室内游泳池", 33 | "会议室", 34 | "健身房", 35 | "SPA", 36 | "无烟房", 37 | "商务中心", 38 | "酒吧", 39 | "桑拿", 40 | "早餐服务", 41 | "接待外宾", 42 | "洗衣服务", 43 | "行李寄存", 44 | "租车", 45 | "叫醒服务" 46 | ], 47 | "price": 787.0, 48 | "rating": 4.5, 49 | "hotel_id": 38 50 | }, 51 | { 52 | "name": "北京西苑饭店", 53 | "type": "豪华型", 54 | "address": "北京海淀区三里河路1号", 55 | "subway": "动物园地铁站D口", 56 | "phone": "010-68313388", 57 | "facilities": [ 58 | "酒店各处提供wifi", 59 | "宽带上网", 60 | "国际长途电话", 61 | "吹风机", 62 | "24小时热水", 63 | "西式餐厅", 64 | "中式餐厅", 65 | "室内游泳池", 66 | "会议室", 67 | "健身房", 68 | "无烟房", 69 | "商务中心", 70 | "棋牌室", 71 | "早餐服务", 72 | "接站服务", 73 | "接机服务", 74 | "洗衣服务", 75 | "行李寄存", 76 | "租车", 77 | "叫醒服务" 78 | ], 79 | "price": 705.0, 80 | "rating": 4.3, 81 | "hotel_id": 31 82 | }, 83 | { 84 | "name": "北京鹏润国际大酒店", 85 | "type": "豪华型", 86 | "address": "北京朝阳区霄云路26号", 87 | "subway": "三元桥地铁站C2口", 88 | "phone": "010-51086688", 89 | "facilities": [ 90 | "公共区域和部分房间提供wifi", 91 | "宽带上网", 92 | "国际长途电话", 93 | "吹风机", 94 | "24小时热水", 95 | "西式餐厅", 96 | "中式餐厅", 97 | "残疾人设施", 98 | "室内游泳池", 99 | "会议室", 100 | "健身房", 101 | "SPA", 102 | "无烟房", 103 | "商务中心", 104 | "酒吧", 105 | "早餐服务", 106 | "接机服务", 107 | "接待外宾", 108 | "洗衣服务", 109 | "行李寄存", 110 | "叫醒服务" 111 | ], 112 | "price": 762.0, 113 | "rating": 4.6, 114 | "hotel_id": 2 115 | } 116 | ] 117 | }, 118 | { 119 | "role": "assistant", 120 | "content": "推荐您去北京鹏润国际大酒店、北京西苑饭店、北京唐拉雅秀酒店。" 121 | } 122 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0048.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,我想找一家酒店,我希望酒店评分在5分,且配有桑拿,能帮我找一下吗" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "facilities": [ 10 | "桑拿" 11 | ], 12 | "rating_range_lower": 5.0, 13 | "rating_range_upper": 5.0 14 | } 15 | }, 16 | { 17 | "role": "return", 18 | "records": [ 19 | { 20 | "name": "北京国家会议中心大酒店", 21 | "type": "豪华型", 22 | "address": "北京朝阳区北辰西路8号院1号楼", 23 | "subway": "奥林匹克公园地铁站E口", 24 | "phone": "010-84372008", 25 | "facilities": [ 26 | "公共区域和部分房间提供wifi", 27 | "宽带上网", 28 | "国际长途电话", 29 | "吹风机", 30 | "24小时热水", 31 | "西式餐厅", 32 | "中式餐厅", 33 | "残疾人设施", 34 | "室内游泳池", 35 | "会议室", 36 | "健身房", 37 | "SPA", 38 | "无烟房", 39 | "商务中心", 40 | "桑拿", 41 | "棋牌室", 42 | "早餐服务", 43 | "接站服务", 44 | "接机服务", 45 | "接待外宾", 46 | "洗衣服务", 47 | "行李寄存", 48 | "租车", 49 | "叫醒服务" 50 | ], 51 | "price": 734.0, 52 | "rating": 4.7, 53 | "hotel_id": 46 54 | } 55 | ] 56 | }, 57 | { 58 | "role": "assistant", 59 | "content": "你好,北京国家会议中心大酒店您可以了解一下,符合你的要求乐" 60 | } 61 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data/0049.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "role": "user", 4 | "content": "你好,你能帮我找一家酒店,最低消费在1000元以上的经济型酒店,评分要在4.5分以上的。" 5 | }, 6 | { 7 | "role": "search", 8 | "arguments": { 9 | "price_range_lower": 1000.0, 10 | "rating_range_lower": 4.5, 11 | "type": "经济型" 12 | } 13 | }, 14 | { 15 | "role": "return", 16 | "records": [ 17 | { 18 | "name": "时光漫步怀旧主题酒店(北京雍和宫店)", 19 | "type": "舒适型", 20 | "address": "北京东城区安定门内大街方家胡同46号创意园", 21 | "subway": "北新桥地铁站A口", 22 | "phone": "010-64032288", 23 | "facilities": [ 24 | "公共区域和部分房间提供wifi", 25 | "宽带上网", 26 | "吹风机", 27 | "24小时热水", 28 | "暖气", 29 | "中式餐厅", 30 | "无烟房", 31 | "酒吧", 32 | "早餐服务", 33 | "行李寄存", 34 | "叫醒服务" 35 | ], 36 | "price": 1063.0, 37 | "rating": 4.8, 38 | "hotel_id": 27 39 | } 40 | ] 41 | }, 42 | { 43 | "role": "assistant", 44 | "content": "经济型的酒店都满足不了你的需求,你看我给你介绍一家舒适型的,时光漫步怀旧主题酒店(北京雍和宫店)行吗?他家其它方面都能达到你的要求。" 45 | } 46 | ] -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/raw_data_all.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/dataAugmentation/enhanceBasic/raw_data_all.zip -------------------------------------------------------------------------------- /dataAugmentation/enhanceBasic/rewrite.py: -------------------------------------------------------------------------------- 1 | from langchain_core.prompts import PromptTemplate 2 | from langchain.output_parsers import PydanticOutputParser, OutputFixingParser 3 | import re 4 | from pydantic import BaseModel, Field 5 | # 导入本应用程序提供的方法 6 | from my_llm import myLLM 7 | 8 | 9 | 10 | 11 | class Utterance(BaseModel): 12 | text: str = Field(description="重写后的句子文本") 13 | 14 | 15 | PROMPT_TEMPLATE = """ 16 | 给定句子: 17 | {utterance} 18 | 请将句中的"{phrase}"替换为"{replacement}"。 19 | 并重新组织该句子,保证其意思不变的前提下,语言通顺。 20 | 确保你输出与原句语言保持一致。 21 | 按以下形式输出结果: 22 | {format_instruction} 23 | """ 24 | 25 | 26 | # 替换句子中的短语,并重写句子使其通顺 27 | class UtteranceRewriter: 28 | def __init__(self): 29 | # 设置大模型 30 | self.llm = myLLM() 31 | self.output_parser = PydanticOutputParser(pydantic_object=Utterance) 32 | self.robust_parser = OutputFixingParser.from_llm(parser=self.output_parser, llm=self.llm) 33 | self.prompt = PromptTemplate.from_template(PROMPT_TEMPLATE).partial( 34 | format_instruction=self.output_parser.get_format_instructions(), 35 | ) 36 | 37 | # 定义chain 38 | self.chain = self.prompt | self.llm 39 | 40 | # 重写语句 41 | def rewrite(self, utterance: str, phrase: str, replacement: str) -> str: 42 | response = self.chain.invoke( 43 | { 44 | "utterance": utterance, 45 | "phrase": phrase, 46 | "replacement": replacement, 47 | } 48 | ) 49 | # 使用正则表达式从返回信息中结构出完成对话 50 | response = re.search(r'```json\n(.*?)\n```', response.content, re.S).group(1) 51 | utterance = self.robust_parser.parse(response) 52 | return utterance.text 53 | 54 | if __name__ == "__main__": 55 | # 示例数据 56 | # [ 57 | # { 58 | # "role": "user", 59 | # "content": "好的,时间还是可以的,吃完饭我可能会在这边住下,能帮我推荐一个提供国际长途电话的高档型酒店吗?" 60 | # }, 61 | # { 62 | # "role": "search", 63 | # "arguments": { 64 | # "facilities": [ 65 | # "暖气" 66 | # ], 67 | # "type": "高档型" 68 | # } 69 | # }, 70 | # { 71 | # "role": "return", 72 | # "records": [ 73 | # { 74 | # "name": "北京东方花园饭店", 75 | # "type": "高档型", 76 | # "address": "北京东城区东直门南大街6号", 77 | # "subway": "东直门地铁站D口", 78 | # "phone": "010-64168866", 79 | # "facilities": [ 80 | # "公共区域和部分房间提供wifi", 81 | # "宽带上网", 82 | # "国际长途电话", 83 | # "吹风机", 84 | # "24小时热水", 85 | # "暖气", 86 | # "西式餐厅", 87 | # "中式餐厅", 88 | # "残疾人设施", 89 | # "会议室", 90 | # "健身房", 91 | # "无烟房", 92 | # "商务中心", 93 | # "酒吧", 94 | # "棋牌室", 95 | # "早餐服务", 96 | # "接机服务", 97 | # "接待外宾", 98 | # "洗衣服务", 99 | # "行李寄存", 100 | # "租车", 101 | # "叫醒服务" 102 | # ], 103 | # "price": 677.0, 104 | # "rating": 4.6, 105 | # "hotel_id": 87 106 | # } 107 | # ] 108 | # }, 109 | # { 110 | # "role": "assistant", 111 | # "content": "那就建议你去北京东方花园饭店好了,比较经济实惠。" 112 | # } 113 | # ] 114 | 115 | utterance = '好的,时间还是可以的,吃完饭我可能会在这边住下,能帮我推荐一个提供国际长途电话的高档型酒店吗?' 116 | phrase = '国际长途电话' 117 | replacement = '国际电话' 118 | 119 | new_text = UtteranceRewriter().rewrite(utterance, phrase, replacement) 120 | print('new_text is :', new_text) 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /dataAugmentation/enhanceMore/api_keys.env: -------------------------------------------------------------------------------- 1 | OPENAI_API_BASE="https://api.wlai.vip" 2 | OPENAI_API_KEY="sk-dsLvfvO3OLzr6jKpjgFBaEra3sZVM5UWVCpYlZ34QIjmIbVs" -------------------------------------------------------------------------------- /dataAugmentation/enhanceMore/generate_by_filter_search.py: -------------------------------------------------------------------------------- 1 | import json 2 | import random 3 | import re 4 | from langchain_core.prompts import PromptTemplate 5 | from tqdm import tqdm 6 | # 导入本应用程序提供的方法 7 | from my_llm import myLLM 8 | 9 | 10 | 11 | 12 | PROMPT_TEMPLATE = """ 13 | 你的任务是根据用户对酒店的选择条件,生成用户查询的问句 14 | 尽量覆盖口语化的说法,#注意不要说的太机械重复# 15 | 酒店包含属性分别是: 酒店类型(type)、价格(price)、评分(rating)、酒店设施(facilities)。 16 | 在JSON格式输入中的key有:type, facilities, price_range_upper, price_range_lower, rating_range_lower, rating_range_upper 17 | 18 | 以JSON格式输出,只包含字段content: string类型,即用户的查询问句 19 | 20 | examples: 21 | {examples} 22 | 23 | input: 24 | {input_text} 25 | 26 | output: 27 | 28 | """ 29 | 30 | # 写好的一些例子 31 | examples = [ 32 | [{"price_range_upper": 500, "type": "豪华型" }, 33 | { "content": "帮我找个价格在500元之内的豪华酒店。" }], 34 | [{"price_range_lower": 400, "rating_range_lower": 4}, 35 | { "content": "我要订一个价格在400元之上的不低于4分的宾馆" }], 36 | [{"price_range_upper": 500, "facilities": ["热水","wifi"]}, 37 | { "content": "给我查查酒店,有热水和wifi的,价格在500以里的" }], 38 | [{"price_range_upper": 500, "type": "经济型"}, 39 | { "content": "你好,有价格在500以内的酒店可以订吗,经济型的就行" }], 40 | [{"price_range_upper": 200, "rating_range_lower": 4}, 41 | { "content": "请给我订个评分高于4,价格在200元以上酒店。" }], 42 | [{"price_range_lower": 300, "facilities": ["洗衣", "洗澡"] }, 43 | { "content": "有人吗,订一个在300元之上的能洗衣洗澡的宾馆噢" }], 44 | [{"price_range_upper": 400, "type": "经济型"}, 45 | { "content": "帮我找个价格比400低的经济酒店。" }], 46 | [{"price_range_upper": 900, "facilities": ["停车"] }, 47 | { "content": "我要找一个比900元便宜的酒店,最好能停车的啊" }], 48 | [{"price_range_upper": 500, "facilities": ["棋牌室"]}, 49 | { "content": "帮个忙,找一下价格在500内的酒店,要有棋牌室的噢" }], 50 | [{"price_range_upper": 800, "type":"舒适型"}, 51 | { "content": "我要找价格在800以内的酒店,给我查查有舒适的吗" }], 52 | ] 53 | 54 | # 可选筛选条件范围如下 55 | keys = ['type', 'facilities', 'price_range_upper', 'price_range_lower', 'rating_range_lower', 'rating_range_upper'] 56 | types = ['豪华型','舒适型','经济型'] 57 | facilities = ['热水','wifi','停车场','按摩','棋牌室','洗衣机','泳池'] 58 | 59 | 60 | 61 | # 对大模型返回的内容进行格式化处理 62 | # 格式化响应,对输入的文本进行段落分隔、添加适当的换行符,以及在代码块中增加标记,以便生成更具可读性的输出 63 | def format_response(response): 64 | # 使用正则表达式 \n{2, }将输入的response按照两个或更多的连续换行符进行分割。这样可以将文本分割成多个段落,每个段落由连续的非空行组成 65 | paragraphs = re.split(r'\n{2,}', response) 66 | # 空列表,用于存储格式化后的段落 67 | formatted_paragraphs = [] 68 | # 遍历每个段落进行处理 69 | for para in paragraphs: 70 | # 检查段落中是否包含代码块标记 71 | if '```' in para: 72 | # 将段落按照```分割成多个部分,代码块和普通文本交替出现 73 | parts = para.split('```') 74 | for i, part in enumerate(parts): 75 | # 检查当前部分的索引是否为奇数,奇数部分代表代码块 76 | if i % 2 == 1: # 这是代码块 77 | # 将代码块部分用换行符和```包围,并去除多余的空白字符 78 | parts[i] = f"\n```\n{part.strip()}\n```\n" 79 | # 将分割后的部分重新组合成一个字符串 80 | para = ''.join(parts) 81 | else: 82 | # 否则,将句子中的句点后面的空格替换为换行符,以便句子之间有明确的分隔 83 | para = para.replace('. ', '.\n') 84 | # 将格式化后的段落添加到formatted_paragraphs列表 85 | # strip()方法用于移除字符串开头和结尾的空白字符(包括空格、制表符 \t、换行符 \n等) 86 | formatted_paragraphs.append(para.strip()) 87 | # 将所有格式化后的段落用两个换行符连接起来,以形成一个具有清晰段落分隔的文本 88 | return '\n\n'.join(formatted_paragraphs) 89 | 90 | # 调用大模型生成数据 91 | def generate_data(arguments): 92 | # 初始化大模型 93 | llm = myLLM() 94 | # 为了保证生成问句的多样性,prompt中的例子是从写好的一些例子中做随机挑选的 95 | example_str = "" 96 | for i in range(4): # 这里挑选了4条例子给到prompt 97 | example = random.choice(examples) 98 | example_str += json.dumps(example[0], ensure_ascii=False)+"\n" 99 | example_str += json.dumps(example[1], ensure_ascii=False)+"\n" 100 | # 构造prompt 101 | prompt = PromptTemplate.from_template(PROMPT_TEMPLATE) 102 | # 构造chain 103 | chain = prompt | llm 104 | # 运行chain 105 | result = chain.invoke( 106 | { 107 | "examples": example_str, 108 | "input_text": arguments 109 | } 110 | ) 111 | response = str(format_response(result.content)) 112 | # print(f"格式化的搜索结果format_response: {response}") 113 | try: 114 | # 构造返回数据 115 | result = [ 116 | {'role':'user','content':json.loads(response)}, 117 | {'role':'search','arguments':arguments} 118 | ] 119 | return result 120 | except: 121 | return [] 122 | 123 | 124 | # 生成只有价格上限或下限的数据 125 | def generate_price_bound(nums): 126 | results = [] 127 | for i in tqdm(range(nums)): 128 | arguments = { 129 | random.choice(['price_range_upper','price_range_lower']): random.randint(2,12)*100, 130 | } 131 | results.append(generate_data(arguments)) 132 | return results 133 | 134 | 135 | # 生成价格范围的数据 136 | def generate_price_range(nums): 137 | results = [] 138 | for i in tqdm(range(nums)): 139 | price_range_lower = random.randint(2,12)*100 140 | price_range_upper = price_range_lower + random.randint(1,8)*100 141 | arguments = { 142 | 'price_range_lower': price_range_lower, 143 | 'price_range_upper': price_range_upper, 144 | } 145 | results.append(generate_data(arguments)) 146 | return results 147 | 148 | 149 | # 生成各种条件组合查询的数据 150 | def generate_misc_filter(nums): 151 | results = [] 152 | for i in tqdm(range(nums)): 153 | arguments = { 154 | 'price_range_upper': random.randint(2,12)*100, # 限价格上限的多 155 | 'rating_range_lower': random.randint(2,4), # 限评分下限的多 156 | 'facilities': random.sample(facilities, k=2), 157 | 'type': random.choice(types), 158 | } 159 | # 从 arguments 字典的键中随机选择 2 个键 160 | keys_to_remove = random.sample(list(arguments.keys()), 2) 161 | # 移除选中的键,以生成多样化的筛选条件组合 162 | for key in keys_to_remove: 163 | arguments.pop(key) 164 | results.append(generate_data(arguments)) 165 | return results 166 | 167 | 168 | 169 | if __name__ == "__main__": 170 | results = generate_price_bound(20) 171 | with open('price_bound.json', 'w') as f: 172 | f.write(json.dumps(results, ensure_ascii=False, indent=4)) 173 | print('完成生成只有价格上限或下限的数据,共写入 20 条到price_bound.json') 174 | 175 | results = generate_price_range(20) 176 | with open('price_range.json', 'w') as f: 177 | f.write(json.dumps(results, ensure_ascii=False, indent=4)) 178 | print('完成生成价格范围的数据,共写入 20 price_range.json') 179 | 180 | results = generate_misc_filter(20) 181 | with open('misc_filter.json', 'w') as f: 182 | f.write(json.dumps(results, ensure_ascii=False, indent=4)) 183 | print('完成生成各种条件组合查询的数据,共写入 20 misc_filter.json') 184 | -------------------------------------------------------------------------------- /dataAugmentation/enhanceMore/generate_by_hotel_name.py: -------------------------------------------------------------------------------- 1 | import json 2 | import random 3 | import re 4 | from langchain_core.prompts import PromptTemplate 5 | from tqdm import tqdm 6 | # 导入本应用程序提供的方法 7 | from db_client import HotelDB 8 | from my_llm import myLLM 9 | 10 | 11 | 12 | 13 | PROMPT_TEMPLATE = """ 14 | 你的任务是根据酒店名称生成查询的语句 15 | 并结合查到的结果,加工生成回复文本 16 | 尽量覆盖口语化的说法,#注意不要说的太机械重复# 17 | 选择条件为酒店名称, 在JSON格式输入中的key是name 18 | 19 | 以JSON格式输出,包含字段 20 | - content: string类型,即用户的查询问句 21 | - reply: string类型,回复给用户的话术 22 | 23 | examples: 24 | {examples} 25 | 26 | input: 27 | 酒店名称:{name} 28 | 查询记录:{searched} 29 | 30 | output: 31 | 32 | """ 33 | 34 | 35 | 36 | # 检索业务数据库 37 | def search(db, name): 38 | result = db.search({'name':name}, limit=3) 39 | final = [] 40 | for r in result: 41 | if all(char in r['name'] for char in name): 42 | final.append(r) 43 | return final 44 | 45 | 46 | # 对大模型返回的内容进行格式化处理 47 | # 格式化响应,对输入的文本进行段落分隔、添加适当的换行符,以及在代码块中增加标记,以便生成更具可读性的输出 48 | def format_response(response): 49 | # 使用正则表达式 \n{2, }将输入的response按照两个或更多的连续换行符进行分割。这样可以将文本分割成多个段落,每个段落由连续的非空行组成 50 | paragraphs = re.split(r'\n{2,}', response) 51 | # 空列表,用于存储格式化后的段落 52 | formatted_paragraphs = [] 53 | # 遍历每个段落进行处理 54 | for para in paragraphs: 55 | # 检查段落中是否包含代码块标记 56 | if '```' in para: 57 | # 将段落按照```分割成多个部分,代码块和普通文本交替出现 58 | parts = para.split('```') 59 | for i, part in enumerate(parts): 60 | # 检查当前部分的索引是否为奇数,奇数部分代表代码块 61 | if i % 2 == 1: # 这是代码块 62 | # 将代码块部分用换行符和```包围,并去除多余的空白字符 63 | parts[i] = f"\n```\n{part.strip()}\n```\n" 64 | # 将分割后的部分重新组合成一个字符串 65 | para = ''.join(parts) 66 | else: 67 | # 否则,将句子中的句点后面的空格替换为换行符,以便句子之间有明确的分隔 68 | para = para.replace('. ', '.\n') 69 | # 将格式化后的段落添加到formatted_paragraphs列表 70 | # strip()方法用于移除字符串开头和结尾的空白字符(包括空格、制表符 \t、换行符 \n等) 71 | formatted_paragraphs.append(para.strip()) 72 | # 将所有格式化后的段落用两个换行符连接起来,以形成一个具有清晰段落分隔的文本 73 | return '\n\n'.join(formatted_paragraphs) 74 | 75 | 76 | 77 | if __name__ == "__main__": 78 | # 初始化大模型 79 | llm = myLLM() 80 | # 根据名字只查到单条记录的例子 81 | examples1 = [ 82 | [ 83 | {"str": "盛厦宾馆"}, 84 | {"str": "我想订一下那个盛厦宾馆,帮我查查"}, 85 | [{"address": "北京朝阳区东三环北路16号农展馆新馆南路", "facilities": "酒店提供的设施:公共区域和部分房间提供wifi;国际长途电话;吹风机;24小时热水;无烟房;行李寄存", "hotel_id": 584, "name": "北京盛厦宾馆", "phone": "010-65916188", "price": 258, "rating": 4.4, "subway": "团结湖地铁站B口", "type": "舒适型"}], 86 | {"str": "欢迎您选择北京盛厦宾馆,祝您入住愉快"} 87 | ], 88 | [ 89 | {"str": "新世贸大酒店"}, 90 | {"str": "我要订个酒店,那个新世贸大酒店"}, 91 | [{"address": "北京丰台区永外东罗园九号楼", "facilities": "酒店提供的设施:公共区域和部分房间提供wifi;宽带上网;吹风机;24小时热水;中式餐厅;会议室;无烟房;商务中心;棋牌室;早餐服务免费;洗衣服务;行李寄存;租车;叫醒服务", "hotel_id": 715, "name": "北京新世贸大酒店", "phone": "010-52268555", "price": 223, "rating": 4.2, "subway": "景泰站地铁站D口", "type": "舒适型"}], 92 | {"str": "为您查到北京新世贸大酒店,您要选择这家吗" } 93 | ], 94 | [ 95 | {"str": "孔府酒店"}, 96 | {"str": "帮我找个酒店,叫孔府酒店"}, 97 | [{"address": "北京海淀区马甸西路月季园18号", "facilities": "酒店提供的设施:酒店各处提供wifi;宽带上网;免费市内电话;吹风机;24小时热水;中式餐厅;无烟房;早餐服务;行李寄存;叫醒服务;收费停车位", "hotel_id": 1062, "name": "北京孔府酒店", "phone": "010-68980808", "price": 402, "rating": 4, "subway": "牡丹园地铁站C口", "type": "舒适型"}], 98 | {"str": "为您找到北京孔府酒店。"} 99 | ], 100 | ] 101 | # 根据名字查到多条记录的例子 102 | examples2 = [ 103 | [ 104 | {"str": "如家快捷酒店"}, 105 | {"str": "给我订个住的地方,找找如家快捷酒店"}, 106 | [{"address": "北京朝阳区左家庄中街4号", "facilities": "酒店提供的设施:所有房间提供wifi;国际长途电话;24小时热水;中式餐厅;无烟房;商务中心;早餐服务;接待外宾;洗衣服务", "hotel_id": 883, "name": "如家快捷酒店(北京国展左家庄店)", "phone": "010-64686868", "price": 257, "rating": 4.4, "subway": "柳芳地铁站B口", "type": "经济型"}, {"address": "北京朝阳区劲松八区805号楼", "facilities": "酒店提供的设施:酒店各处提供wifi;宽带上网;国际长途电话;吹风机;24小时热水;无烟房;接待外宾;行李寄存;叫醒服务", "hotel_id": 937, "name": " 如家快捷酒店(北京劲松店)", "phone": "010-87776766", "price": -1, "rating": 4.6, "subway": "劲松地铁站A口", "type": "经济型"}, {" address": "北京朝阳区安立路甲52号", "facilities": "酒店提供的设施:部分房间提供wifi;宽带上网;免费市内电话;国际长途电话;吹风机;24小时热水;会议室;无烟房;接待外宾;行李寄存;叫醒服务", "hotel_id": 1015, "name": "如家快捷酒店(北京鸟巢店)", "phone": "010-84802999", "price": 315, "rating": 4.7, "subway": "安立路地铁站B口", "type": "经济型"}], 107 | {"str": "为您找到如家快捷酒店(北京鸟巢店)、如家快捷酒店(北京劲松店)、如家快捷酒店(北京国展左家庄店),请您选择" } 108 | ], 109 | [ 110 | {"str": "汉庭酒店"}, 111 | {"str": "我想住汉庭酒店,你帮我查一下都有哪些店"}, 112 | [{"address": "北京朝阳区劲松九区907号楼东二环辅路路东", "facilities": "酒店提供的设施:酒店各处提供wifi;宽带上网;国际长途电话;吹风机;24小时热水;中式餐厅;无烟房;商务中心;接待外宾;行李寄存;叫醒服务", "hotel_id": 407, "name": "汉庭酒店(北京站店)", "phone": "010-67765566", "price": 267, "rating": 4.5, "subway": "广渠门外地铁站D口", "type": "经济型"}, {"address": "北京朝阳区北苑路18号院4号楼", "facilities": "酒店提供的设施:公共区域和部分房间提供wifi;宽带上网;国际长途电话;吹风机;24小时热水;中式餐厅;无烟房;行李寄存;叫醒服务", "hotel_id": 953, "name": "汉庭酒店(北京北苑店)", "phone": "010-60606099", "price": 324, "rating": 4.4, "subway": "立水桥南地铁站C口", "type": "经济型"}, {"address": "北京西城区西绦胡同15号", "facilities": "酒店提供的设施:公共区域和部分房间提供wifi;宽带上网;吹风机;24小时热水;中式餐厅;无烟房;商务中心;早餐服务;接待外宾;洗衣服务;行李寄存;叫醒服务", "hotel_id": 648, "name": "汉庭酒店(北京鼓楼店)", "phone": "010-64000123", "price": 403, "rating": 4.3, "subway": "鼓楼大街地铁站A1口", "type": "经济型"}], 113 | {"str": "找到了汉庭酒店(北京鼓楼店)、汉庭酒店(北京北苑店)、汉庭酒店(北京站店)这三家,请您选择" }], 114 | [ 115 | {"str": "7天酒店"}, 116 | {"str": "你帮我查一下7天酒店都有哪些店"}, 117 | [{"address": "北京朝阳区德胜门外黄寺大街28号", "facilities": "酒店提供的设施:所有房间提供wifi;宽带上网;24小时热水;无烟房", "hotel_id": 778, "name": "7天优品酒店(北京黄寺店)(原7天连锁酒店)", "phone": "010-59260366", "price": 332, "rating": 4.4, "subway": "安华桥地铁站D2口", "type": "经济型"}, {"address": "北京朝阳区望京南湖北路107号", "facilities": "酒店提供的设施:部分房间提供wifi;宽带上网;24小时热水;接待外宾", "hotel_id": 677, "name": "7天优品酒店(北京望京南湖东园店)(原7天连锁酒店望京南湖东园店)", "phone": "010-64725777", "price": 332, "rating": 4.1, "subway": "东湖渠地铁站D口", "type": "经济型"}, {"address": "北京海淀区定慧东里18号楼", "facilities": "酒店提供的设施:公共区域和部分房间提供wifi;宽带上网;免费国内长途电话;24小时热水;无烟房;洗衣服务", "hotel_id": 748, "name": "7天连锁酒店(北京航天桥店)", "phone": "010-88111977", "price": 316, "rating": 4.5, "subway": "西钓鱼台地铁站C口", "type": "经济型"}], {"str": "为您找到7天连锁酒店(北京航天桥店)、7天优品酒店(北京望京南湖东园店)(原7天连锁酒店望京南湖东园店)和7天优品酒店(北京黄寺店)(原7天连锁酒店),请选择" }], 118 | ] 119 | # 读取酒店数据集中所有的酒店名字 120 | with open('names.json', 'r') as f: 121 | names = json.load(f) 122 | db = HotelDB() 123 | results = [] 124 | for name in tqdm(names): 125 | # 从单条和多条记录的例子中各选一个 126 | example_str = "" 127 | example = random.choice(examples1) 128 | example_str += "input:\n" 129 | example_str += "酒店名称:"+example[0]['str']+"\n" 130 | example_str += "查询记录:"+json.dumps(example[2],ensure_ascii=False)+"\n" 131 | result = {'content':example[1]['str'],'reply':example[3]['str']} 132 | example_str += "output:\n"+json.dumps(result,ensure_ascii=False)+"\n" 133 | example = random.choice(examples2) 134 | example_str += "input:\n" 135 | example_str += "酒店名称:"+example[0]['str']+"\n" 136 | example_str += "查询记录:"+json.dumps(example[2],ensure_ascii=False)+"\n" 137 | result = {'content':example[1]['str'],'reply':example[3]['str']} 138 | example_str += "output:\n"+json.dumps(result,ensure_ascii=False)+"\n" 139 | records = search(db, name) 140 | searched = json.dumps(records,ensure_ascii=False) 141 | 142 | # 构造prompt 143 | prompt = PromptTemplate.from_template(PROMPT_TEMPLATE) 144 | # 构造chain 145 | chain = prompt | llm 146 | # 运行chain 147 | result = chain.invoke( 148 | { 149 | "name": name, 150 | "searched": searched, 151 | "examples": example_str 152 | } 153 | ) 154 | response = str(format_response(result.content)) 155 | 156 | try: 157 | response = json.loads(response) 158 | result = [ 159 | {'role':'user','content':response['content']}, 160 | {'role':'search','arguments':{'name':name}}, 161 | {'role':'return','records': records}, 162 | {'role':'assistant','content':response['reply']} 163 | ] 164 | # print(json.dumps(result, ensure_ascii=False, indent=4)) 165 | results.append(result) 166 | except: 167 | pass 168 | # print(json.dumps(results, ensure_ascii=False, indent=4)) 169 | with open('results.json', 'w') as f: 170 | f.write(json.dumps(results, ensure_ascii=False, indent=4)) 171 | print('生成数据成功并保存在results.json') 172 | -------------------------------------------------------------------------------- /dataAugmentation/enhanceMore/my_llm.py: -------------------------------------------------------------------------------- 1 | import os 2 | from langchain_openai import ChatOpenAI 3 | 4 | # 模型全局参数配置 根据自己的实际情况进行调整 5 | # openai模型相关配置 根据自己的实际情况进行调整 6 | OPENAI_API_BASE = "https://api.wlai.vip/v1" 7 | OPENAI_CHAT_API_KEY = "sk-dsLvfvO3OLzr6jKpjgFBaEra3sZVM5UWVCpYlZ34QIjmIbVs" 8 | OPENAI_CHAT_MODEL = "gpt-4o-mini" 9 | # 非gpt大模型相关配置(oneapi方案 通义千问为例) 根据自己的实际情况进行调整 10 | ONEAPI_API_BASE = "http://139.224.72.218:3000/v1" 11 | ONEAPI_CHAT_API_KEY = "sk-iEokjc8sQa9yvf8c655eCa8b0b834aB2Ab67213e639259Df" 12 | ONEAPI_CHAT_MODEL = "qwen-max" 13 | # 本地大模型相关配置(Ollama方案 qwen2.5:7b为例) 根据自己的实际情况进行调整 14 | OLLAMA_API_BASE = "http://localhost:11434/v1" 15 | OLLAMA_CHAT_API_KEY = "ollama" 16 | OLLAMA_CHAT_MODEL = "qwen2.5:7b" 17 | 18 | # 选择使用哪一个大模型 19 | # openai:调用gpt大模型 20 | # oneapi:调用非gpt大模型(国产大模型等) 21 | # ollama:调用本地大模型 22 | LLM_TYPE = "openai" 23 | 24 | # 定函数 模型初始化 25 | def myLLM(): 26 | llmType = LLM_TYPE 27 | 28 | if llmType == "oneapi": 29 | # 实例化一个oneapi客户端对象 30 | llm = ChatOpenAI( 31 | base_url=ONEAPI_API_BASE, 32 | api_key=ONEAPI_CHAT_API_KEY, 33 | model=ONEAPI_CHAT_MODEL, # 本次使用的模型 34 | temperature=0.8, # 发散的程度 35 | # timeout=None,# 服务请求超时 36 | # max_retries=2,# 失败重试最大次数 37 | ) 38 | 39 | elif llmType == "ollama": 40 | # 实例化一个ChatOpenAI客户端对象 41 | os.environ["OPENAI_API_KEY"] = "NA" 42 | llm = ChatOpenAI( 43 | base_url=OLLAMA_API_BASE, # 请求的API服务地址 44 | api_key=OLLAMA_CHAT_API_KEY, # API Key 45 | model=OLLAMA_CHAT_MODEL, # 本次使用的模型 46 | temperature=0.8, # 发散的程度 47 | # timeout=None,# 服务请求超时 48 | # max_retries=2,# 失败重试最大次数 49 | ) 50 | 51 | else: 52 | # 实例化一个ChatOpenAI客户端对象 53 | llm = ChatOpenAI( 54 | base_url=OPENAI_API_BASE, # 请求的API服务地址 55 | api_key=OPENAI_CHAT_API_KEY, # API Key 56 | model=OPENAI_CHAT_MODEL, # 本次使用的模型 57 | # temperature=0.7,# 发散的程度,一般为0 58 | # timeout=None,# 服务请求超时 59 | # max_retries=2,# 失败重试最大次数 60 | ) 61 | 62 | return llm -------------------------------------------------------------------------------- /dataAugmentation/requirements.txt: -------------------------------------------------------------------------------- 1 | langchain==0.3.3 2 | langchain-openai==0.2.2 3 | tqdm==4.67.0 4 | weaviate-client==3.26.7 5 | python-dotenv==1.0.1 6 | requests==2.32.3 7 | pydantic==2.9.2 8 | -------------------------------------------------------------------------------- /qwen2/arguments.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass, field 2 | from typing import Optional 3 | 4 | 5 | @dataclass 6 | class ModelArguments: 7 | """ 8 | Arguments pertaining to which model/config/tokenizer we are going to fine-tune from. 9 | """ 10 | model_name_or_path: str = field( 11 | metadata={"help": "Path to pretrained model or model identifier from huggingface.co/models"} 12 | ) 13 | 14 | 15 | @dataclass 16 | class PeftArguments: 17 | # lora args 18 | lora_rank: int = field( 19 | default=8, 20 | metadata={"help": "LoRA rank number"} 21 | ) 22 | lora_alpha: int = field( 23 | default=32, 24 | metadata={"help": "LoRA alpha weight"} 25 | ) 26 | lora_dropout: float = field( 27 | default=0.1, 28 | metadata={"help": "LoRA dropout probability"} 29 | ) 30 | lora_checkpoint: str = field( 31 | default=None, 32 | metadata={"help": "Path to LoRA checkpoints"} 33 | ) 34 | # fourier args 35 | n_frequency: int = field( 36 | default=1000, 37 | metadata={"help": "the num_frequency of the Fourier adapters"} 38 | ) 39 | scale: float = field( 40 | default=300.0, 41 | metadata={"help": "the scale of the Fourier adapters"} 42 | ) 43 | 44 | @dataclass 45 | class DataTrainingArguments: 46 | """ 47 | Arguments pertaining to what data we are going to input our model for training and eval. 48 | """ 49 | prompt_column: Optional[str] = field( 50 | default=None, 51 | metadata={"help": "The name of the column in the datasets containing the full texts (for summarization)."}, 52 | ) 53 | response_column: Optional[str] = field( 54 | default=None, 55 | metadata={"help": "The name of the column in the datasets containing the summaries (for summarization)."}, 56 | ) 57 | history_column: Optional[str] = field( 58 | default=None, 59 | metadata={"help": "The name of the column in the datasets containing the history of chat."}, 60 | ) 61 | train_file: Optional[str] = field( 62 | default=None, metadata={"help": "The input training data file (a jsonlines or csv file)."} 63 | ) 64 | validation_file: Optional[str] = field( 65 | default=None, 66 | metadata={ 67 | "help": ( 68 | "An optional input evaluation data file to evaluate the metrics (rouge) on (a jsonlines or csv file)." 69 | ) 70 | }, 71 | ) 72 | test_file: Optional[str] = field( 73 | default=None, 74 | metadata={ 75 | "help": "An optional input test data file to evaluate the metrics (rouge) on (a jsonlines or csv file)." 76 | }, 77 | ) 78 | overwrite_cache: bool = field( 79 | default=False, metadata={"help": "Overwrite the cached training and evaluation sets"} 80 | ) 81 | preprocessing_num_workers: Optional[int] = field( 82 | default=None, 83 | metadata={"help": "The number of processes to use for the preprocessing."}, 84 | ) 85 | max_source_length: Optional[int] = field( 86 | default=2048, 87 | metadata={ 88 | "help": ( 89 | "The maximum total input sequence length after tokenization. Sequences longer " 90 | "than this will be truncated, sequences shorter will be padded." 91 | ) 92 | }, 93 | ) 94 | max_target_length: Optional[int] = field( 95 | default=1024, 96 | metadata={ 97 | "help": ( 98 | "The maximum total sequence length for target text after tokenization. Sequences longer " 99 | "than this will be truncated, sequences shorter will be padded." 100 | ) 101 | }, 102 | ) 103 | ignore_pad_token_for_loss: bool = field( 104 | default=True, 105 | metadata={ 106 | "help": "Whether to ignore the tokens corresponding to padded labels in the loss computation or not." 107 | }, 108 | ) 109 | -------------------------------------------------------------------------------- /qwen2/data_preprocess.py: -------------------------------------------------------------------------------- 1 | import json 2 | from torch.utils.data import Dataset 3 | 4 | # 定义一个名为 InputOutputDataset 的新类,它继承自 Dataset 类 5 | # 这使得数据集能够与 PyTorch 的数据加载器兼容,支持批处理和其他数据加载功能 6 | class InputOutputDataset(Dataset): 7 | # 定义类的初始化方法,接收三个参数:data(数据集)、tokenizer(分词器)、args(其他参数配置) 8 | def __init__(self, data, tokenizer, args): 9 | # 调用父类 Dataset 的初始化方法,以确保数据集正确初始化。这是继承类的标准做法 10 | super(InputOutputDataset, self).__init__() 11 | self.data = data 12 | self.tokenizer = tokenizer 13 | self.prompt_column = args.prompt_column 14 | self.response_column = args.response_column 15 | self.max_source_length = args.max_source_length 16 | self.max_target_length = args.max_target_length 17 | 18 | # 用于返回数据集的长度,满足 Python 的长度协议 19 | def __len__(self): 20 | return len(self.data) 21 | 22 | # 通过索引访问数据集中的样本 23 | def __getitem__(self, i): 24 | item = self.data[i] 25 | # add_special_tokens 不在开头加 special_tokens 26 | # 调用分词器,对构建的提示文本进行编码 27 | context = self.tokenizer( 28 | build_prompt(item[self.prompt_column]), 29 | max_length=self.max_source_length, 30 | add_special_tokens=False) 31 | response = self.tokenizer( 32 | build_response(item[self.response_column]), 33 | max_length=self.max_target_length, 34 | add_special_tokens=False) 35 | # 将上下文和响应的 input_ids 连接起来,形成一个完整的输入序列 36 | input_ids = context["input_ids"] + response["input_ids"] 37 | # 将上下文和响应的注意力掩码连接起来,确保模型在计算注意力时能够正确地关注输入序列的相关部分 38 | attention_mask = context["attention_mask"] + response["attention_mask"] 39 | # 创建标签数组,标记上下文部分为 -100(表示在计算损失时忽略),而响应部分使用真实的 input_ids 40 | labels = [-100] * len(context["input_ids"]) + response["input_ids"] 41 | # 确保输入 ID 和标签的长度一致,如果不一致,将抛出断言错误,提供长度信息以便调试 42 | assert len(input_ids) == len(labels), f"length mismatch: {len(input_ids)} vs {len(labels)}" 43 | # 返回一个字典,其中包含编码后的输入 ID、注意力掩码和标签,供模型训练使用 44 | return { 45 | "input_ids": input_ids, 46 | "attention_mask": attention_mask, 47 | "labels": labels 48 | } 49 | 50 | 51 | # 用于构建提示字符串,按特定格式拼接输入输出 52 | def build_prompt(context): 53 | # 检查上下文是否为字符串类型,如果是,则将其解析为 JSON 对象 54 | if isinstance(context,str): 55 | context = json.loads(context) 56 | # 初始化一个空字符串,用于存储构建的提示文本 57 | prompt = '' 58 | # 遍历上下文中的每个对话轮次 59 | for turn in context: 60 | # 检查角色是否为用户或助手 61 | if turn["role"] in ["user","assistant"]: 62 | # 将当前对话的角色和内容以指定格式添加到提示字符串中 63 | prompt += f'<|im_start|>{turn["role"]}\n{turn["content"]}<|im_end|>\n' 64 | # 处理角色不为用户或助手的情况 65 | else: 66 | # 检查角色是否为 search 67 | if turn["role"] == "search": 68 | # 提取搜索参数对象 69 | obj = turn["arguments"] 70 | # 过滤掉值为 None 的参数,创建新的字典 71 | filtered_obj = {k: v for k, v in obj.items() if v is not None} 72 | # 添加搜索的开始标记 73 | prompt += '<|im_start|>search\n' 74 | # 将过滤后的搜索参数转换为格式化的 JSON 字符串,并添加到提示中 75 | prompt += json.dumps(filtered_obj,indent=4,ensure_ascii=False) 76 | # 处理角色为返回(return)的情况 77 | else: 78 | # 提取记录数据 79 | obj = turn["records"] 80 | # 添加返回数据的结束标记,完成这一轮对话的提示构建 81 | prompt += '<|im_start|>return\n' 82 | prompt += json.dumps(obj,indent=4,ensure_ascii=False) 83 | prompt += '<|im_end|>\n' 84 | # 返回构建好的完整提示字符串 85 | return prompt 86 | 87 | 88 | # 用于构建响应字符串 89 | def build_response(response): 90 | # 检查响应是否为字符串类型,若是则解析为 JSON 对象 91 | if isinstance(response,str): 92 | response = json.loads(response) 93 | # 判断角色是否为助手 94 | if response["role"] == "assistant": 95 | # 构建助手的响应字符串,格式为 96 | return '<|im_start|>assistant\n' + response["content"] + '<|im_end|>' 97 | # 处理角色不是助手的情况 98 | else: 99 | # 提取响应中的参数对象 100 | obj = response["arguments"] 101 | # 过滤掉值为 None 的参数,创建新的字典 102 | filtered_obj = {k: v for k, v in obj.items() if v is not None} 103 | # 构建搜索的响应字符串,格式为 104 | return '<|im_start|>search\n' + json.dumps(filtered_obj,indent=4,ensure_ascii=False) + '<|im_end|>' 105 | 106 | # 接受一个字符串并尝试从中解析出 JSON 对象 107 | def parse_json(string): 108 | # 初始化搜索起始位置为 0 109 | search_pos = 0 110 | # 寻找字符串中第一个 { 的位置,用于标识 JSON 对象的开始 111 | start = string.find('{', search_pos) 112 | # 如果未找到 {,返回 None 113 | if start == -1: 114 | return None 115 | # 从找到的 { 位置开始,寻找最后一个 } 的位置,标识 JSON 对象的结束 116 | end = string.rfind('}', start) 117 | # 如果未找到 },返回 None 118 | if end == -1: 119 | return None 120 | # 提取出 JSON 字符串,从找到的 { 到 } 的部分 121 | json_string = string[start:end + 1] 122 | try: 123 | # 将字符串解析为 Python 对象 124 | obj = json.loads(json_string) 125 | return obj 126 | except json.JSONDecodeError: 127 | return None 128 | -------------------------------------------------------------------------------- /qwen2/eval.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | MODEL_DIR="/root/autodl-tmp/Qwen2.5-7B-Instruct" 3 | CHECKPOINT_DIR="output/model_train-20241103-132703/checkpoint-2150" 4 | 5 | CUDA_VISIBLE_DEVICES=0 python evaluate.py \ 6 | --model $MODEL_DIR \ 7 | --ckpt $CHECKPOINT_DIR \ 8 | --data dataset/test.full.jsonl 9 | -------------------------------------------------------------------------------- /qwen2/finetune.py: -------------------------------------------------------------------------------- 1 | import json 2 | # 导入 torch 模块,这是 PyTorch 深度学习框架的核心库 3 | # 提供了构建和训练神经网络所需的基本功能,如张量操作、模型定义、优化器等 4 | import torch 5 | # AutoTokenizer:用于自动加载与特定模型对应的分词器。分词器将输入文本转换为模型可接受的格式 6 | # AutoModelForCausalLM:用于自动加载用于因果语言建模的预训练模型。因果语言模型用于生成任务,比如文本生成 7 | # BitsAndBytesConfig:用于设置模型的低精度计算配置(如 8-bit 或 4-bit 量化),以减少内存使用和加速推理过程 8 | # DataCollatorForSeq2Seq:用于处理序列到序列模型的数据整理,它可以处理批次数据并填充到相同的长度 9 | # HfArgumentParser:用于从命令行解析参数的工具,方便用户在运行时提供各种参数设置 10 | # TrainingArguments:用于定义训练过程的参数,如学习率、批次大小、评估策略等 11 | # Trainer:用于封装模型训练过程的高阶API,简化了训练和评估过程的实现 12 | from transformers import ( 13 | AutoTokenizer, 14 | AutoModelForCausalLM, 15 | BitsAndBytesConfig, 16 | DataCollatorForSeq2Seq, 17 | HfArgumentParser, 18 | TrainingArguments, 19 | Trainer 20 | ) 21 | # 从 peft 库中导入 LoRA 相关的组件 22 | # LoraConfig:用于配置 LoRA 微调过程的参数,包括低秩矩阵的秩、缩放系数等 23 | # TaskType:定义任务类型的枚举,用于指定微调任务的类别(例如文本生成、文本分类等) 24 | # get_peft_model:用于获取带有 LoRA 配置的模型的方法,用于将 LoRA 参数应用到基础模型上 25 | from peft import LoraConfig, TaskType, get_peft_model 26 | # 从自定义模块 arguments 中导入自定义参数类 27 | # ModelArguments:用于存储与模型相关的参数 28 | # DataTrainingArguments:用于存储与数据训练相关的参数 29 | # PeftArguments:用于存储与 PEFT(参数高效微调)相关的参数 30 | from arguments import ModelArguments, DataTrainingArguments, PeftArguments 31 | # # 从自定义模块 data_preprocess 中导入自定义方法,是一个自定义的数据集类,用于将原始数据转换为模型的输入格式 32 | from data_preprocess import InputOutputDataset 33 | 34 | 35 | 36 | def main(): 37 | # 创建一个 HfArgumentParser 实例,用于解析命令行参数 38 | parser = HfArgumentParser((ModelArguments, DataTrainingArguments, PeftArguments, TrainingArguments)) 39 | # 将命令行参数解析为相应的数据类实例 40 | model_args, data_args, peft_args, training_args = parser.parse_args_into_dataclasses() 41 | # 加载一个预训练模型 42 | # 指定模型的计算精度为 bfloat16。这是一种优化内存使用的数值格式,特别适合在支持 bfloat16 的硬件(如某些 GPU)上运行,可以降低内存需求和提高计算效率 43 | model = AutoModelForCausalLM.from_pretrained(model_args.model_name_or_path, torch_dtype=torch.bfloat16) 44 | # 加载与模型对应的分词器(tokenizer) 45 | # 分词器的作用是将文本转化为模型能够理解的 token 序列(即数值化表示),这是将自然语言输入传递到模型中的必要步骤 46 | tokenizer = AutoTokenizer.from_pretrained(model_args.model_name_or_path) 47 | 48 | # 设置LoRA的配置,用于控制 LoRA 在特定模型和任务中的应用 49 | lora_config = LoraConfig( 50 | # 设置该 LoRA 配置用于训练模式,而非推理模式 51 | inference_mode=False, 52 | # 设置任务类型为 TaskType.CAUSAL_LM,表示这是一个因果语言建模任务 53 | task_type=TaskType.CAUSAL_LM, 54 | # 设置模型中应用 LoRA 的模块为 q_proj、k_proj 和 v_proj 55 | # 在常见的 Transformer 结构中,q_proj(查询投影)、k_proj(键投影)和 v_proj(值投影)是多头自注意力机制的重要组成部分 56 | # 使用 LoRA 只在这些投影矩阵中引入低秩更新,能够减少模型参数数量的增长,同时对注意力机制进行微调。这种方式能高效地调整模型参数,而不会显著增加训练时的计算负担 57 | target_modules=["q_proj", "k_proj", "v_proj"], 58 | # 设置LoRA 中低秩矩阵的秩(rank) 59 | # 低秩矩阵的秩是 LoRA 的核心超参数之一,它定义了新增参数的数量。秩越高,LoRA 可以学习到的特征表达就越多,但也会增加额外参数量和计算量 60 | r=peft_args.lora_rank, 61 | # 设置 LoRA 的缩放系数,控制低秩矩阵对原始模型参数更新的影响 62 | # 它起到“调节器”的作用,将学习到的低秩更新进行放缩,使 LoRA 在适应新任务时不会过度影响原始模型的表现 63 | lora_alpha=peft_args.lora_alpha, 64 | # 设置 LoRA 训练过程中使用的 dropout 概率 65 | # 用于防止模型过拟合。在训练过程中,会随机丢弃部分神经元(按指定的概率),从而减弱模型对特定路径的依赖,提高模型在未见数据上的泛化能力 66 | lora_dropout=peft_args.lora_dropout 67 | ) 68 | 69 | # 将原始模型 model 转换为 LoRA 模型,并将其移动到 GPU 上 70 | model = get_peft_model(model, lora_config).to("cuda") 71 | # 打印模型中可训练的参数数量,以便检查 72 | # 由于 LoRA 的设计是通过低秩矩阵在特定层上进行微调,因此输出结果会显示只有少部分参数是“可训练的” 73 | # 可以确认 LoRA 只修改了选定的层,而非整个模型。这对于调试 LoRA 配置是否正确非常有用 74 | model.print_trainable_parameters() 75 | 76 | # 创建数据规整器实例,对数据进行批次处理 77 | # tokenizer=tokenizer,指定使用的分词器,用于处理输入文本并将其转化为模型理解的 token 格式。分词器会确保在每个批次中对输入文本进行相同的编码,以便与模型兼容 78 | # padding=True,启用自动填充(padding),使得每个批次的输入序列长度一致。这意味着对于较短的序列,DataCollatorForSeq2Seq 会填充到当前批次中的最大序列长度,确保数据在批处理中可以对齐 79 | data_collator = DataCollatorForSeq2Seq( 80 | tokenizer=tokenizer, 81 | padding=True 82 | ) 83 | 84 | # 控制是否加载和准备训练数据。这样可以根据需求灵活地决定是否进行训练,尤其适用于在同一脚本中设置不同模式(如仅训练、仅评估或同时进行) 85 | if training_args.do_train: 86 | # 该步骤将训练数据文件中的每一行解析为一个字典,并将所有行合并到一个列表中。通常,训练数据文件中的每一行包含一个样本的 JSON 格式数据,这样可以逐行处理大文件,节省内存 87 | # json.loads(line):逐行读取文件,每行内容使用 json.loads() 将 JSON 字符串解析为 Python 字典 88 | # [json.loads(line) for line in f]:将所有行解析为一个包含多个字典的列表 train_data 89 | with open(data_args.train_file, "r", encoding="utf-8") as f: 90 | train_data = [json.loads(line) for line in f] 91 | # 将训练数据 train_data 转换为模型可接受的数据集对象 train_dataset 92 | # InputOutputDataset 是一个自定义的数据集类,用于将原始数据转换为模型的输入格式 93 | # train_data 是从训练文件读取并解析的数据 94 | # tokenizer 用于对数据进行分词和编码 95 | # data_args 传入的其他数据参数,用于控制数据处理的行为 96 | train_dataset = InputOutputDataset(train_data, tokenizer, data_args) 97 | 98 | # 控制是否加载和准备验证数据,逻辑与训练数据相同 99 | if training_args.do_eval: 100 | with open(data_args.validation_file, "r", encoding="utf-8") as f: 101 | eval_data = [json.loads(line) for line in f] 102 | eval_dataset = InputOutputDataset(eval_data, tokenizer, data_args) 103 | 104 | # 创建了一个 Trainer 对象,并传入了模型、分词器、数据规整器、训练参数、训练数据集和验证数据集 105 | # 这个对象负责后续的训练、评估等任务 106 | trainer = Trainer( 107 | # 功能:指定 Trainer 要训练或评估的模型 108 | # 解释:这里传入的 model 是已经加载的模型,并且应用了 LoRA(低秩适配)配置,以便进行高效微调 109 | # 作用:让 Trainer 直接使用这个模型进行训练或评估 110 | model=model, 111 | # 功能:指定分词器 tokenizer,用于处理输入数据 112 | # 解释:tokenizer 会被 Trainer 用来对输入数据进行编码,以确保输入符合模型的要求 113 | # 作用:在训练和评估时,Trainer 会自动使用 tokenizer 将文本数据转换为模型理解的 token 格式,简化了输入处理步骤 114 | tokenizer=tokenizer, 115 | # 功能:指定数据规整器 data_collator,用于批次化输入数据 116 | # 解释:在批次处理时,对数据进行填充(padding),确保每个批次中的序列长度一致,使得模型输入结构整齐 117 | # 作用:可以有效地批次化数据,提高训练效率,同时确保批次中的每个样本大小相同,适配模型的输入需求 118 | data_collator=data_collator, 119 | # 功能:指定训练参数 training_args 120 | # 解释:training_args 是一个 TrainingArguments 实例,包含训练中的超参数配置,如学习率、批次大小、训练轮数等 121 | # 作用:training_args 控制 Trainer 的训练行为,设置超参数、日志输出、是否保存模型、模型存储路径等,为训练过程提供全局配置 122 | args=training_args, 123 | # 功能:指定训练数据集 train_dataset 124 | # train_dataset 是已经经过分词器处理的训练数据集 125 | # 只有当 do_train=True 时,才会传入 train_dataset,否则为 None。这意味着如果不执行训练,就不需要传入训练数据集 126 | # 作用:根据 training_args.do_train 参数的值灵活地加载训练数据集。这允许在不需要训练时跳过训练数据集的加载,减少内存开销 127 | train_dataset=train_dataset if training_args.do_train else None, 128 | # 功能:指定验证数据集 eval_dataset 129 | # eval_dataset 是已经经过分词器处理的验证数据集 130 | # 只有当 do_eval=True 时,才会传入 eval_dataset,否则为 None。这意味着如果不执行评估,就不需要传入验证数据集 131 | # 作用:根据 training_args.do_eval 参数的值灵活地加载验证数据集。这允许在不需要评估时跳过验证数据集的加载,避免不必要的资源消耗 132 | eval_dataset=eval_dataset if training_args.do_eval else None, 133 | ) 134 | 135 | # 首先判断是否需要训练,然后在需要时执行如下操作: 136 | # (1)梯度检查点 以降低内存使用 137 | # (2)输入梯度计算 以确保模型可以在训练中被更新 138 | # (3)最后调用 trainer.train() 来启动训练流程,使得模型根据训练数据集进行权重调整 139 | if training_args.do_train: 140 | # 功能:启用梯度检查点(gradient checkpointing)技术 141 | # gradient_checkpointing_enable() 是 transformers 中的一项内存优化技术,尤其适合大模型的训练 142 | # 它通过在前向传播时保存部分中间激活值而不是全部激活值,减少内存占用;在反向传播时再动态计算需要的激活值 143 | # 作用:启用梯度检查点可以大幅降低显存(GPU memory)需求,使得更大批次或更大模型可以在有限的显存中训练,适合在资源受限情况下进行大模型训练 144 | model.gradient_checkpointing_enable() 145 | # 功能:启用输入梯度(input gradient)计算 146 | # enable_input_require_grads() 设置模型的输入张量(tensor)需要计算梯度,以便在反向传播中更新权重 147 | # 该方法通常用于精调(fine-tuning)任务中,确保模型的所有部分在训练中能够被更新 148 | # 作用:此设置对 LoRA 等微调任务特别重要,确保输入的梯度可以被计算,从而允许训练过程中的反向传播更新模型参数 149 | model.enable_input_require_grads() 150 | # 功能:启动模型训练 151 | # trainer.train() 是 Trainer 对象的核心方法,负责执行整个训练过程 152 | # Trainer 内部会根据配置好的参数(如学习率、批次大小、迭代次数等)自动运行训练循环 153 | # 该方法还会在训练过程中自动进行日志记录、模型保存、评估等任务(如果在 training_args 中配置了相应选项) 154 | # 作用:实际执行模型的训练过程。在 train() 方法运行期间,Trainer 会读取 train_dataset,将数据输入模型,并更新模型权重,从而进行模型的优化 155 | trainer.train() 156 | 157 | # 首先通过 training_args.do_eval 判断是否需要进行模型评估 158 | # 若需要,调用 trainer.evaluate() 来执行模型的评估过程 159 | # 这一操作会自动计算模型在验证集上的表现指标,帮助确定模型在验证集上的效果,从而判断模型是否具有良好的泛化能力 160 | if training_args.do_eval: 161 | # 功能:执行模型的评估过程 162 | # trainer.evaluate() 是 Trainer 对象中的一个方法,用于评估模型的性能 163 | # evaluate() 方法会自动加载之前传入的验证数据集(eval_dataset),并对模型进行评估 164 | # Trainer 会计算常见的评估指标,如损失(loss)、精度(accuracy)、困惑度(perplexity)等,具体取决于任务和配置 165 | # 作用:evaluate() 方法可以在验证数据集上评估模型的表现,帮助了解模型在训练集之外的数据上的效果。这在评估模型的泛化能力和调整模型超参数时非常有用 166 | trainer.evaluate() 167 | 168 | if __name__ == "__main__": 169 | main() 170 | -------------------------------------------------------------------------------- /qwen2/image/001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/001.png -------------------------------------------------------------------------------- /qwen2/image/002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/002.png -------------------------------------------------------------------------------- /qwen2/image/003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/003.png -------------------------------------------------------------------------------- /qwen2/image/004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/004.png -------------------------------------------------------------------------------- /qwen2/image/005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/005.png -------------------------------------------------------------------------------- /qwen2/image/006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/006.png -------------------------------------------------------------------------------- /qwen2/image/007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/007.png -------------------------------------------------------------------------------- /qwen2/image/008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/008.png -------------------------------------------------------------------------------- /qwen2/image/009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/009.png -------------------------------------------------------------------------------- /qwen2/image/010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/010.png -------------------------------------------------------------------------------- /qwen2/image/011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/011.png -------------------------------------------------------------------------------- /qwen2/image/012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/012.png -------------------------------------------------------------------------------- /qwen2/image/013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/013.png -------------------------------------------------------------------------------- /qwen2/image/014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/014.png -------------------------------------------------------------------------------- /qwen2/image/015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/015.png -------------------------------------------------------------------------------- /qwen2/image/016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/016.png -------------------------------------------------------------------------------- /qwen2/image/017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/017.png -------------------------------------------------------------------------------- /qwen2/image/018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/018.png -------------------------------------------------------------------------------- /qwen2/image/019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/019.png -------------------------------------------------------------------------------- /qwen2/image/020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/020.png -------------------------------------------------------------------------------- /qwen2/image/021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/021.png -------------------------------------------------------------------------------- /qwen2/image/022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/022.png -------------------------------------------------------------------------------- /qwen2/image/023.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/023.png -------------------------------------------------------------------------------- /qwen2/image/024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/024.png -------------------------------------------------------------------------------- /qwen2/image/025.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/qwen2/image/025.png -------------------------------------------------------------------------------- /qwen2/merge.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import argparse 3 | # 用于处理LoRA(Low-Rank Adaptation)模型 4 | from peft import PeftModel 5 | from peft import LoraConfig, TaskType, get_peft_model 6 | # 功能:从自定义模块中导入 load_model 函数 7 | # from evaluate import load_model:从名为 evaluate 的模块中导入 load_model 函数,用于加载和初始化模型 8 | from evaluate import load_model 9 | 10 | 11 | 12 | 13 | # 功能:全局变量的初始化 14 | # 初始化一个 ArgumentParser 对象,用于定义和解析命令行参数 15 | parser = argparse.ArgumentParser() 16 | parser.add_argument("--model", type=str, default=None, required=True, help="main model weights") 17 | parser.add_argument("--ckpt", type=str, default=None, required=True, help="The checkpoint path") 18 | parser.add_argument("--output_dir", type=str, default=None, required=True, help="output path") 19 | # 功能:调用 parse_args() 方法,解析命令行输入的参数,并将结果存储在 args 变量中。args 是一个命名空间对象,包含所有定义的参数及其值 20 | args = parser.parse_args() 21 | 22 | 23 | # 功能:加载模型和分词器 24 | # load_model(args.model, args.ckpt):调用之前定义的 load_model 函数,传入用户从命令行提供的模型路径 args.model 和检查点路径 args.ckpt,返回一个分词器和模型 25 | # tokenizer, model:将返回的分词器和模型分别赋值给 tokenizer 和 model 变量,以便后续使用 26 | tokenizer, model = load_model(args.model, args.ckpt) 27 | 28 | 29 | # 合并LoRA模型与基础模型,并卸载LoRA模型的参数,返回合并后的模型 30 | # 这是 model 的方法,执行合并和卸载操作 31 | # merge:将 LoRA 微调的权重与原始模型的权重合并。这一步将 LoRA 适配器中的权重应用到模型的原始权重上,以获得一个新的权重集合,该集合可以直接用于推理和使用 32 | # unload:从内存中卸载 LoRA 适配器。这一步是为了释放资源,因为在合并权重后,适配器不再需要保存在内存中 33 | model = model.merge_and_unload() 34 | # 将合并后的模型保存到指定的输出路径 35 | model.save_pretrained(args.output_dir) 36 | # 将模型上传到HuggingFace Hub 37 | # model.push_to_hub("zhuzhu01/Qwen2.5-7B-Instruct-Merge", token = "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") 38 | # 将分词器保存到相同的输出路径 39 | tokenizer.save_pretrained(args.output_dir) 40 | # 将分词器上传到HuggingFace Hub 41 | # base_tokenizer.push_to_hub("zhuzhu01/Qwen2.5-7B-Instruct-Merge", token = "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") 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /qwen2/merge.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | DATESTR=`date +%Y%m%d-%H%M%S` 4 | RUN_NAME=model_merge 5 | OUTPUT_DIR=output/${RUN_NAME}-${DATESTR} 6 | mkdir -p $OUTPUT_DIR 7 | 8 | MODEL_DIR="/root/autodl-tmp/Qwen2.5-7B-Instruct" 9 | CHECKPOINT_DIR="output/model_train-20241103-132703/checkpoint-2150" 10 | 11 | CUDA_VISIBLE_DEVICES=0 python merge.py \ 12 | --model $MODEL_DIR \ 13 | --ckpt $CHECKPOINT_DIR \ 14 | --output_dir $OUTPUT_DIR 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /qwen2/requirements.txt: -------------------------------------------------------------------------------- 1 | accelerate==0.29.2 2 | astunparse==1.6.3 3 | bitsandbytes==0.41.3 4 | cpm-kernels==1.0.11 5 | datasets==2.20.0 6 | nltk==3.8.1 7 | peft==0.11.1 8 | sentencepiece==0.1.99 9 | torch==2.1.0 10 | transformers==4.44.2 11 | scipy==1.10.1 12 | gradio==3.50.2 13 | tiktoken==0.7.0 14 | tensorboard==2.16.2 15 | weaviate-client==3.26.7 16 | python-dotenv==1.0.1 17 | ruamel_yaml>=0.18.6 -------------------------------------------------------------------------------- /qwen2/train.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | set -ex 4 | 5 | LR=2e-4 6 | 7 | DATESTR=`date +%Y%m%d-%H%M%S` 8 | RUN_NAME=model_train 9 | OUTPUT_DIR=output/${RUN_NAME}-${DATESTR} 10 | mkdir -p $OUTPUT_DIR 11 | 12 | MODEL_PATH="/root/autodl-tmp/Qwen2.5-7B-Instruct" 13 | 14 | CUDA_VISIBLE_DEVICES=0 python finetune.py \ 15 | --do_train \ 16 | --do_eval \ 17 | --train_file dataset/train.full.jsonl \ 18 | --validation_file dataset/dev.full.jsonl \ 19 | --prompt_column context \ 20 | --response_column response \ 21 | --model_name_or_path "${MODEL_PATH}" \ 22 | --output_dir $OUTPUT_DIR \ 23 | --max_source_length 2048 \ 24 | --max_target_length 1024 \ 25 | --per_device_train_batch_size 1 \ 26 | --per_device_eval_batch_size 1 \ 27 | --gradient_accumulation_steps 4 \ 28 | --evaluation_strategy steps \ 29 | --eval_steps 300 \ 30 | --num_train_epochs 2 \ 31 | --logging_steps 30 \ 32 | --logging_dir $OUTPUT_DIR/logs \ 33 | --save_steps 300 \ 34 | --learning_rate $LR \ 35 | --lora_rank 8 \ 36 | --lora_alpha 32 \ 37 | --lora_dropout 0.1 2>&1 | tee ${OUTPUT_DIR}/train.log 38 | -------------------------------------------------------------------------------- /weaviate/README.md: -------------------------------------------------------------------------------- 1 | # 1、内容介绍 2 | 酒店推荐垂直业务数据的存储这里使用Weaviate向量数据库 3 | Weaviate (we-vee-eight) 是一个开源的AI原生向量数据库,可同时存储对象和向量,这样就可以将向量搜索与结构化过滤结合使用 4 | 官网地址: https://weaviate.io/ 5 | github地址:https://github.com/weaviate/weaviate 6 | 这里为大家演示如何安装部署、国内如何配置使用embedding模型、业务数据写入和查询测试 7 | 8 | 9 | # 2、准备工作 10 | ## 2.1 Docker安装和部署 11 | ### 2.1.1 本地部署 12 | **(1)安装Docker** 13 | 官网链接 https://www.docker.com/ 14 | 这里以Mac系统为例,windows无本质差别,根据自己的操作系统选择下载安装包,直接安装即可 15 | 安装完成后,找到Docker图标双击运行,Docker服务启动成功后如下截图所示 16 | 17 | **(2)拉取并运行镜像** 18 | 打开命令行终端,执行如下命令拉取weaviate的镜像 19 | `docker run cr.weaviate.io/semitechnologies/weaviate:1.27.2 ` 20 | 注意:经多次测试,这里需要科学上网,否则容易拉取失败(**若无条件,不影响后续操作,可直接跳到步骤(4)继续**) 21 | 拉取完成后,会自动启动该服务,如下截图所示 22 | 23 | **(3)将镜像文件保存到本地** 24 | 使用docker commit命令将现有的容器状态保存为新的镜像,这个过程类似于创建一个镜像的快照 25 | `docker commit '当前的容器名称' ‘设置的新的镜像文件weaviate’` 26 | 27 | 然后再执行如下命令进行镜像本地保存,保存的文件为weaviate.tar 28 | `mkdir weaviate` 29 | `cd weaviate` 30 | `docker save -o weaviate.tar weaviate` 31 | 32 | **(4)加载本地镜像文件** 33 | 为了对比测试,这里注意将科学上网给关闭,并将之前拉取的镜像全部删除 34 | 按照如下截图删除容器 35 | 36 | 按照如下截图删除镜像 37 | 38 | 删除完成后,进入到压缩文件所在的目录,执行如下命令加载本地镜像文件 39 | **注意:** 这里镜像文件使用上步生成的(若无条件生成文件可点击下面链接下载提前准备好的文件) 40 | 链接: 通过网盘分享的文件:weaviate.zip 41 | 链接: https://pan.baidu.com/s/1mp2VFVBbb3vxJ2qnlscD8w?pwd=a8tm 提取码: a8tm 42 | `docker load -i weaviate.tar` 43 | 命令执行后,再执行`docker images`查看是否加载成功,如下截图 44 | 45 | **(5)使用Configurator工具生成docker-compose.yml文件** 46 | 使用weaviate官方提供的Configurator工具生成docker-compose.yml文件 47 | 工具链接 https://weaviate.io/developers/weaviate/installation/docker-compose#configurator 48 | 相关配置参数需根据自己的实际需求进行设置,这里可按照如下截图顺序进行配置 49 | (a)选择版本,这里选择1.27.0 50 | 51 | (b)选择数据持久化方案,这里设置为host-binding方式 52 | 53 | (c)选择是否加载使用其他模块,这里选择加载模块 54 | 55 | (d)设置需要进行向量检索的媒体类型,这里选择文本 56 | 57 | (e)设置embedding模型,这里选择openai方案 58 | 59 | (f)设置openai环境变量参数加载方案,选择每次请求时提供 60 | 61 | (g)后续的配置全部默认即可 62 | 63 | (h)最后一项选择输出为Docker Compose 64 | 65 | 到这里全部配置完成,会在页面下方生成docker-compose.yml文件相关的下载指令信息,如下截图 66 | 67 | **(6)下载docker-compose.yml文件并启动服务** 68 | 将上个步骤根据配置生成的指令拷贝,粘贴到命令行终端中执行,如下截图 69 | 70 | 文件下载成功后,按照如下截图修改文件内容,主要修改镜像文件名为weaviate 71 | `sudo vim docker-compose.yml` 72 | 73 | 修改成功后保存退出,然后执行如下命令启动服务 74 | `docker-compose up -d (后台运行)` 75 | `docker-compose up` 76 | 77 | 78 | ### 2.1.2 服务器部署 79 | **(1)安装Docker** 80 | 这里使用的服务器是阿里云服务器,系统为Ubuntu22.04 LTS 81 | 安装步骤可参考:https://www.cnblogs.com/carmi/p/17939025 82 | **(2)将文件上传到服务器** 83 | 远程登录到服务器,执行如下命令在opt目录下创建weaviate文件夹 84 | `cd /opt` 85 | `sudo mkdir weaviate` 86 | 87 | 然后使用SFTP将本地PC中创建的weaviate文件夹中的两个文件上传到服务器/opt/weaviate 88 | 89 | **(3)加载本地镜像文件** 90 | `cd /opt/weaviate` 91 | `docker load -i weaviate.tar` 92 | 加载成功后,再执行`docker images`查看是否加载成功 93 | 94 | **(4)启动服务** 95 | `docker-compose up -d (后台运行)` 96 | `docker-compose up` 97 | 98 | **(5)在阿里云服务器中的安全组中添加8080端口** 99 | 100 | 101 | 102 | # 4、项目测试 103 | (1)打开命令行终端,执行 `cd weaviate` 指令进入到weaviate文件夹 104 | (2)执行如下命令安装依赖包 105 | `pip install -r requirements.txt` 106 | 每个软件包后面都指定了本次视频测试中固定的版本号 107 | **注意:** 本项目weaviate使用的版本3.26.7,建议先使用要求的对应版本进行本项目测试,避免因版本升级造成的代码不兼容。测试通过后,可进行升级测试 108 | (3)执行如下命令运行脚本测试写入数据和数据查询功能 109 | `python db_client.py` 110 | 在运行脚本前进行如下代码的调整: 111 | url地址:url="http://IP:8080" 112 | 打开写入数据代码块,注释查询数据代码块 113 | (4)执行如下命令运行脚本测试数据查询功能 114 | `python db_client.py` 115 | 在运行脚本前进行如下代码的调整: 116 | url地址:url="http://IP:8080" 117 | 打开查询数据代码块,注释写入数据代码块 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /weaviate/api_keys.env: -------------------------------------------------------------------------------- 1 | OPENAI_API_BASE="https://api.wlai.vip" 2 | OPENAI_API_KEY="sk-dsLvfvO3OLzr6jKpjgFBaEra3sZVM5UWVCpYlZ34QIjmIbVs" 3 | -------------------------------------------------------------------------------- /weaviate/image/001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/001.png -------------------------------------------------------------------------------- /weaviate/image/002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/002.png -------------------------------------------------------------------------------- /weaviate/image/003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/003.png -------------------------------------------------------------------------------- /weaviate/image/004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/004.png -------------------------------------------------------------------------------- /weaviate/image/005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/005.png -------------------------------------------------------------------------------- /weaviate/image/006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/006.png -------------------------------------------------------------------------------- /weaviate/image/007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/007.png -------------------------------------------------------------------------------- /weaviate/image/008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/008.png -------------------------------------------------------------------------------- /weaviate/image/009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/009.png -------------------------------------------------------------------------------- /weaviate/image/010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/010.png -------------------------------------------------------------------------------- /weaviate/image/011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/011.png -------------------------------------------------------------------------------- /weaviate/image/012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/012.png -------------------------------------------------------------------------------- /weaviate/image/013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/013.png -------------------------------------------------------------------------------- /weaviate/image/014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/014.png -------------------------------------------------------------------------------- /weaviate/image/015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/015.png -------------------------------------------------------------------------------- /weaviate/image/016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/016.png -------------------------------------------------------------------------------- /weaviate/image/017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/017.png -------------------------------------------------------------------------------- /weaviate/image/018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/018.png -------------------------------------------------------------------------------- /weaviate/image/019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/019.png -------------------------------------------------------------------------------- /weaviate/image/020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/020.png -------------------------------------------------------------------------------- /weaviate/image/021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/021.png -------------------------------------------------------------------------------- /weaviate/image/022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/022.png -------------------------------------------------------------------------------- /weaviate/image/023.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/023.png -------------------------------------------------------------------------------- /weaviate/image/024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/weaviate/image/024.png -------------------------------------------------------------------------------- /weaviate/requirements.txt: -------------------------------------------------------------------------------- 1 | weaviate-client==3.26.7 2 | python-dotenv==1.0.1 3 | requests==2.32.3 4 | tqdm==4.67.0 -------------------------------------------------------------------------------- /webApiDemo/README.md: -------------------------------------------------------------------------------- 1 | # 模型推理接口应用 2 | ## (1)运行API接口服务 3 | 在运行测试之前执行如下命令安装依赖包 4 | `cd /root/autodl-tmp/FineTuningLab/webApiDemo` 5 | `pip install -r requirements.txt` 6 | 每个软件包后面都指定了本次视频测试中固定的版本号 7 | 打开一个命令行终端,执行如下命令 8 | `cd /root/autodl-tmp/FineTuningLab/webApiDemo` 9 | `sudo vim api.sh` 10 | 11 | 修改如下参数,根据实际情况进行替换为合并后的模型 12 | 13 | 修改后保存退出,然后执行 14 | `bash api.sh` 15 | 16 | 17 | ## (2)运行web服务 18 | 再开启一个新的命令行终端,执行如下指令 19 | `cd /root/autodl-tmp/FineTuningLab/webApiDemo` 20 | `python webui.py` 21 | 22 | 服务运行成功后,在AutoDL实例中可以通过自定义服务访问到web页,单击跳转后进入如下截图所示web测试页面 23 | 如:给我推荐一个不低于1000的酒店 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /webApiDemo/__pycache__/db_client.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/webApiDemo/__pycache__/db_client.cpython-311.pyc -------------------------------------------------------------------------------- /webApiDemo/api.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import argparse 3 | import json 4 | from transformers import AutoTokenizer, AutoModelForCausalLM 5 | import uvicorn 6 | from contextlib import asynccontextmanager 7 | from fastapi import FastAPI, HTTPException, Request 8 | from fastapi.middleware.cors import CORSMiddleware 9 | from typing import List, Tuple, Dict, Union, Optional 10 | from pydantic import BaseModel 11 | 12 | 13 | 14 | 15 | # 定义输入数据模型 16 | class ChatRequest(BaseModel): 17 | context: List[Dict[str, Union[str, Dict[str, Union[int, str, float]], List[Dict[str, Union[int, str, float]]]]]] 18 | 19 | 20 | # 功能:全局变量的初始化 21 | # 初始化一个 ArgumentParser 对象,用于定义和解析命令行参数 22 | parser = argparse.ArgumentParser() 23 | parser.add_argument("--model", type=str, default=None, required=True, help="main model weights") 24 | # 功能:调用 parse_args() 方法,解析命令行输入的参数,并将结果存储在 args 变量中。args 是一个命名空间对象,包含所有定义的参数及其值 25 | args = parser.parse_args() 26 | 27 | 28 | # 功能:使用 AutoTokenizer 加载分词器 29 | # AutoTokenizer.from_pretrained 是 transformers 库中的一个方法,能够根据指定路径自动加载适配的分词器 30 | # model_path 提供了分词器的路径,通常与模型路径一致,以确保分词器和模型兼容 31 | # 作用:为模型准备分词器,能够将输入文本处理成模型所需的张量格式,方便后续推理使用 32 | tokenizer = AutoTokenizer.from_pretrained(args.model) 33 | # 功能:使用 AutoModelForCausalLM 加载预训练模型 34 | # AutoModelForCausalLM.from_pretrained 根据路径加载预训练模型,适用于生成任务(如因果语言建模,Causal Language Modeling) 35 | # torch_dtype=torch.bfloat16 设置模型权重的精度为 bfloat16,这是一种节省内存的浮点数格式,通常在 GPU 上用于降低显存占用而不损失太多精度 36 | # 作用:将模型加载到内存中,准备好用于后续加载微调权重,且通过 bfloat16 的数据类型节省内存 37 | model = AutoModelForCausalLM.from_pretrained(args.model, torch_dtype=torch.bfloat16).to("cuda") 38 | 39 | 40 | # 用于构建提示字符串,按特定格式拼接输入输出 41 | def build_prompt(context): 42 | # 检查上下文是否为字符串类型,如果是,则将其解析为 JSON 对象 43 | if isinstance(context,str): 44 | context = json.loads(context) 45 | # 初始化一个空字符串,用于存储构建的提示文本 46 | prompt = '' 47 | # 遍历上下文中的每个对话轮次 48 | for turn in context: 49 | # 检查角色是否为用户或助手 50 | if turn["role"] in ["user","assistant"]: 51 | # 将当前对话的角色和内容以指定格式添加到提示字符串中 52 | prompt += f'<|im_start|>{turn["role"]}\n{turn["content"]}<|im_end|>\n' 53 | # 处理角色不为用户或助手的情况 54 | else: 55 | # 检查角色是否为 search 56 | if turn["role"] == "search": 57 | # 提取搜索参数对象 58 | obj = turn["arguments"] 59 | # 过滤掉值为 None 的参数,创建新的字典 60 | filtered_obj = {k: v for k, v in obj.items() if v is not None} 61 | # 添加搜索的开始标记 62 | prompt += '<|im_start|>search\n' 63 | # 将过滤后的搜索参数转换为格式化的 JSON 字符串,并添加到提示中 64 | prompt += json.dumps(filtered_obj,indent=4,ensure_ascii=False) 65 | # 处理角色为返回(return)的情况 66 | else: 67 | # 提取记录数据 68 | obj = turn["records"] 69 | # 添加返回数据的结束标记,完成这一轮对话的提示构建 70 | prompt += '<|im_start|>return\n' 71 | prompt += json.dumps(obj,indent=4,ensure_ascii=False) 72 | prompt += '<|im_end|>\n' 73 | # 返回构建好的完整提示字符串 74 | return prompt 75 | 76 | 77 | # 功能:定义一个名为 get_completion 的函数,该函数接受一个提示文本并生成响应 78 | # 参数 prompt 是输入的提示文本,通常是要模型生成响应的上下文 79 | async def get_completion(context): 80 | prompt = build_prompt(context) 81 | # 功能:将输入的提示文本转换为模型可接受的格式,并将其转移到GPU 82 | # tokenizer([prompt], return_tensors="pt"):使用 tokenizer 对输入的 prompt 进行编码,返回PyTorch张量格式(return_tensors="pt"),这样可以直接输入到模型中 83 | # to("cuda"):将张量移动到GPU上,以加速计算 84 | inputs = tokenizer([prompt], return_tensors="pt").to("cuda") 85 | # 功能:在不计算梯度的情况下执行后续代码 86 | # 使用torch.no_grad()上下文管理器,这意味着在这个上下文中不会跟踪梯度,从而节省内存并提高推理速度,适用于模型评估或推理时 87 | with torch.no_grad(): 88 | # 功能:生成模型的输出 89 | # 调用模型的 generate 方法生成输出,**inputs 是之前准备的输入张量,max_new_tokens=1024 限制生成的最大 token 数量为1024。模型将根据提供的提示生成相应的输出 90 | outputs = model.generate(**inputs, max_new_tokens=1024) 91 | # 功能:解码生成的输出,得到人类可读的响应 92 | # outputs[:,inputs['input_ids'].shape[1]:][0]:从生成的输出中提取模型的生成部分,inputs['input_ids'].shape[1] 获取输入的长度,[:, ...] 用于切片,获取生成的文本部分 93 | # tokenizer.decode(..., skip_special_tokens=True):使用分词器将生成的 token 转换为字符串,skip_special_tokens=True 表示在解码时跳过特殊的 token(如结束符等) 94 | response = tokenizer.decode(outputs[:,inputs['input_ids'].shape[1]:][0], skip_special_tokens=True) 95 | # 功能:返回生成的响应 96 | # return response:将生成的文本响应返回给调用者,供后续使用或展示 97 | return response 98 | 99 | 100 | @asynccontextmanager 101 | async def lifespan(app: FastAPI): 102 | # 启动时执行 103 | print("服务初始化完成") 104 | # yield 关键字将控制权交还给FastAPI框架,使应用开始运行 105 | # 分隔了启动和关闭的逻辑。在yield 之前的代码在应用启动时运行,yield 之后的代码在应用关闭时运行 106 | yield 107 | # 关闭时执行 108 | print("正在关闭...") 109 | 110 | 111 | # 实例化一个FastAPI实例 112 | # lifespan 参数用于在应用程序生命周期的开始和结束时执行一些初始化或清理工作 113 | app = FastAPI(lifespan=lifespan) 114 | 115 | # 启用CORS,允许任何来源访问以 /api/ 开头的接口 116 | app.add_middleware( 117 | CORSMiddleware, 118 | allow_origins=["*"], 119 | allow_credentials=True, 120 | allow_methods=["*"], 121 | allow_headers=["*"], 122 | ) 123 | 124 | 125 | # POST接口 /api/chat,开启一次模型推理 126 | @app.post("/api/chat") 127 | async def run_chat(request: ChatRequest): 128 | print(f'接收到的数据:{request.context}') 129 | try: 130 | # 调用模型推理函数 131 | response = await get_completion(request.context) 132 | print(f'推理完成,已返回数据:{response}') 133 | return {"response": response} 134 | 135 | except Exception as e: 136 | print(f"模型推理时出错:\n\n {str(e)}") 137 | raise HTTPException(status_code=500, detail=str(e)) 138 | 139 | 140 | 141 | if __name__ == '__main__': 142 | # 服务访问的端口 143 | PORT = 8012 144 | print(f"在端口 {PORT} 上启动服务器") 145 | # uvicorn是一个用于运行ASGI应用的轻量级、超快速的ASGI服务器实现 146 | # 用于部署基于FastAPI框架的异步PythonWeb应用程序 147 | uvicorn.run(app, host="0.0.0.0", port=PORT) 148 | -------------------------------------------------------------------------------- /webApiDemo/api.sh: -------------------------------------------------------------------------------- 1 | MODEL_DIR="../qwen2/output/model_merge-20241118-113242" 2 | 3 | CUDA_VISIBLE_DEVICES=0 python api.py \ 4 | --model $MODEL_DIR 5 | -------------------------------------------------------------------------------- /webApiDemo/api_keys.env: -------------------------------------------------------------------------------- 1 | OPENAI_API_BASE="https://api.wlai.vip" 2 | OPENAI_API_KEY="sk-dsLvfvO3OLzr6jKpjgFBaEra3sZVM5UWVCpYlZ34QIjmIbVs" -------------------------------------------------------------------------------- /webApiDemo/image/001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/webApiDemo/image/001.png -------------------------------------------------------------------------------- /webApiDemo/image/002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/webApiDemo/image/002.png -------------------------------------------------------------------------------- /webApiDemo/image/003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/webApiDemo/image/003.png -------------------------------------------------------------------------------- /webApiDemo/image/004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/webApiDemo/image/004.png -------------------------------------------------------------------------------- /webApiDemo/image/005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/webApiDemo/image/005.png -------------------------------------------------------------------------------- /webApiDemo/image/006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/webApiDemo/image/006.png -------------------------------------------------------------------------------- /webApiDemo/requirements.txt: -------------------------------------------------------------------------------- 1 | pydantic==2.9.2 2 | fastapi==0.115.0 3 | uvicorn==0.31.0 4 | requests==2.32.3 -------------------------------------------------------------------------------- /webDemo/README.md: -------------------------------------------------------------------------------- 1 | # 模型应用测试 2 | 打开一个命令行终端,执行如下命令 3 | `cd /root/autodl-tmp/FineTuningLab/webDemo` 4 | `sudo vim qwen2_lora.sh` 5 | 6 | 修改如下参数,根据实际情况进行替换为合并后的模型 7 | 8 | 修改后保存退出,然后执行bash qwen2_lora.sh 9 | 10 | 服务运行成功后,在AutoDL实例中可以通过自定义服务访问到web页(记得把之前打开的tensorboard服务关掉),单击跳转后进入如下截图所示web测试页面 11 | 如:给我推荐一个不低于1000的酒店 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /webDemo/api_keys.env: -------------------------------------------------------------------------------- 1 | OPENAI_API_BASE="https://api.wlai.vip" 2 | OPENAI_API_KEY="sk-dsLvfvO3OLzr6jKpjgFBaEra3sZVM5UWVCpYlZ34QIjmIbVs" -------------------------------------------------------------------------------- /webDemo/image/001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/webDemo/image/001.png -------------------------------------------------------------------------------- /webDemo/image/002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/webDemo/image/002.png -------------------------------------------------------------------------------- /webDemo/image/003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/webDemo/image/003.png -------------------------------------------------------------------------------- /webDemo/image/004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/webDemo/image/004.png -------------------------------------------------------------------------------- /webDemo/image/005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanGePlus/FineTuningLab/c5c28c2f09ce31c7153fd59cfdb0fce9efad2fae/webDemo/image/005.png -------------------------------------------------------------------------------- /webDemo/qwen2_lora.sh: -------------------------------------------------------------------------------- 1 | MODEL_DIR="../qwen2/output/model_merge-20241118-113242" 2 | 3 | CUDA_VISIBLE_DEVICES=0 python webui_qwen2.py \ 4 | --model $MODEL_DIR 5 | --------------------------------------------------------------------------------