File size: 11,040 Bytes
d573b56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# 悟了悟了数据制作教程



## 一、前言

高质量的数据集是训练和微调模型的关键,数据制作一般会借用一些大模型的API(如InterLM、DeepSeek、Qwen、OpenAI等),可以去对应官网查看或者用第三方的如[硅基流动](https://siliconflow.cn/)(注册会送一定量token,足够用来做数据)等,一般付费的效果更好。

本模型数据制作包含**增量预训练数据和微调数据**两部分,最终格式是适配了Xtuner训练格式的数据:

增量预训练数据是从网络上收集到的和《黑神话:悟空》、《西游记》、《悟空传》等相关的文本数据。

微调数据是用来给模型指令微调的问答对数据,制作难点在于**知识的实时性和准确性**,本模型借助[茴香豆](https://github.com/InternLM/HuixiangDou/tree/main)RAG功能,从收集的文本资料中提取准确的知识信息。



## 二、增量预训练数据

这一部分比较简单,不需要API,对收集到的原始文本数据切分后存为对应格式就行,可以参考 wulewule/data/generate_incremental_pretraining.py 这个脚本。

```
cd wulewule/data
python3 generate_incremental_pretraining.py --root-path ./ --save-path ./incremental_pretraining.jsonl
```

### 实现细节

#### **文本切分**

把原始数据切分成一个个小块给到模型训练(类似RAG中的chunking),使用了langchain中RecursiveCharacterTextSplitter方法对文本字符递归切分,额外增加了一些中文标点用来断句。

默认参数为:chunk-size(每个文本块的大小)为1024,chunk-overlap(相邻两个文本框重叠长度,防止丢失上下文信息)为50。

**最终数据格式**

xtuner 定义的增量预训练数据格式如下,"input"为空就行,文本块放在"output"里,想了解更多细节可以看[xtuner官方增量预训练数据文档](https://github.com/InternLM/xtuner/blob/main/docs/en/user_guides/incremental_pretraining.md):

```
    [
        {
            "conversation":[
                {
                    "input": "",  ## 空的,未使用
                    "output": "xxx" ## 切分后的文本
                },
            ]
        },
        {
            "conversation":[
                {
                    "input": "",
                    "output": "xxx"
                },
            ]
        }
    ]
```

最终保存为jsonl格式,每行是一个字典,对应内容如下:

```
{"conversation": [{"input": "", "output": "《西游记白话文》\n\n\n 第1回 惊天地美猴王出世\n\n    这是一个神话故事,传说在很久很久以前,..."}]}
```



## 三、指令微调数据

普通大模型API只能基于训练时的知识库生成回答,很多知识都停留在过去,比如调用API问“黑神话悟空什么时候发布的”,大多数的都无法给出准确的答案(发布时间2024年08月20日),因为训练资料都是比这个日期之前的。

![Qwen2.5-72B-Instruct_api_example](../assets/Qwen2.5-72B-Instruct_api_example.png)

本模型先使用大模型API生成问题,然后借助[茴香豆](https://github.com/InternLM/HuixiangDou/tree/main)RAG功能,从收集的文本资料中提取对应问题准确的答案(如果本地资料未检索到,则联网检索答案)。

具体实现可以参考 wulewule/data/huixiangdou_rag_QA.py 这个脚本,使用前需要将data_utils.py中的"api_key"换成自己的,同时开启茴香豆server服务

### 实现细节

#### **问题生成**

借用大模型从【 "游戏概述", "章节与故事情节", "主要角色", "人物剧情梳理", "游戏世界观", "建筑与环境", "战斗系统", "游戏玩法", "艺术与音乐", "文化内涵", "市场影响", "彩蛋、网络梗" 】11个角度生成不同的问题:

```python
aspects = [ "游戏概述", "章节与故事情节", "主要角色", "人物剧情梳理", "游戏世界观", "建筑与环境", "战斗系统", "游戏玩法", "艺术与音乐", "文化内涵", "市场影响", "彩蛋、网络梗" ]
question_number = 10
for ascpect in aspects:
    messages=[
        {"role":"system", "content": f"""你是一名提问助手,专注于围绕游戏《黑神话:悟空》的特定方面(例如主要角色、战斗机制或故事情节)提出问题,20个字以内。根据用户的指示,调整你的提问内容,引导玩家深入思考该方面的背景、动机及其在游戏中的作用和发展。不需要序号,最终返回为一个list,格式为['问题', '问题', ...]"""},
        {"role": "user", "content": f"请你就《黑神话:悟空》的‘{ascpect}’方面提出{question_number}个不同的问题,帮助玩家了解游戏在该方面的信息。"},
    ]
    text_res = response(messages, temperature=0.7)
```

messages中就是要给API的数据,基于上述prompt让它成为一个专门生成问题的助手,再从不同方面生成对应问题。

#### **调用模型api**

response函数就是调用API生成回答了,这边使用的是[硅基流动](https://siliconflow.cn/)平台(也可以用其他平台或者本地的模型),[官网有很详细的文档](https://docs.siliconflow.cn/api-reference/chat-completions/chat-completions),下面是一个使用requests的例子,需要将"<token>" 换成你自己的:

```python
import requests

url = "https://api.siliconflow.cn/v1/chat/completions"

payload = {
    "model": "deepseek-ai/DeepSeek-V2.5",
    "messages": [
        {
            "role": "user",
            "content": "SiliconCloud推出分层速率方案与免费模型RPM提升10倍,对于整个大模型应用领域带来哪些改变?"
        }
    ],
    "stream": False,
    "max_tokens": 512,
    "stop": ["<string>"],
    "temperature": 0.7,
    "top_p": 0.7,
    "top_k": 50,
    "frequency_penalty": 0.5,
    "n": 1,
    "response_format": {"type": "json_object"}
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)
```

或者是用OpenAI的方式,api_key换成你自己的

```python
from openai import OpenAI

client = OpenAI(
    base_url='https://api.siliconflow.cn/v1',
    api_key='your-api-key'
)

def response(messages, max_tokens=512, temperature=0.5):
    res = client.chat.completions.create(
        model="deepseek-ai/DeepSeek-V2.5",
        messages=messages,
        max_tokens=max_tokens,
        temperature=temperature,
    ).choices[0].message.content
    return res
```

最终API返回的数据都是string类型,虽然prompt中说明了固定格式,但如果API模型效果没那么好,可能不会按这个格式输出,所以最好用正则处理一下结果,这里用的"deepseek-ai/DeepSeek-V2.5"好像没遇到这种情况。



#### **开启茴香豆RAG服务**

参考实战营-[茴香豆本地标准版搭建](https://github.com/InternLM/Tutorial/tree/camp3/docs/L2/Huixiangdou#2-%E8%8C%B4%E9%A6%99%E8%B1%86%E6%9C%AC%E5%9C%B0%E6%A0%87%E5%87%86%E7%89%88%E6%90%AD%E5%BB%BA)的讲解,进行环境和模型配置即可,不再赘述。

用data目录下的文本数据创建自己的知识库后,开启服务端,监听 23333 端口,使用 `chat_in_group` pipeline:

```
python3 -m huixiangdou.server --pipeline chat_in_group

# cURL 测试状态回调接口
curl -X POST http://127.0.0.1:23333/huixiangdou_stream  -H "Content-Type: application/json" -d '{"text": "how to install mmpose","image": ""}'
# cURL 测试同步接口
curl -X POST http://127.0.0.1:23333/huixiangdou_inference  -H "Content-Type: application/json" -d '{"text": "how to install mmpose","image": ""}'
```

如果需要开启网络检索,当模型本地检索不到结果时进行联网检索,需要注册Serper,参考[开启网络搜索](https://github.com/InternLM/Tutorial/tree/camp3/docs/L2/Huixiangdou#31-%E5%BC%80%E5%90%AF%E7%BD%91%E7%BB%9C%E6%90%9C%E7%B4%A2)

#### **调用RAG生成回答**

将API得到的问题给到茴香豆RAG,然后得到最终答案即可,参考下方函数

```python
def generate_answers(questions="黑神话悟空什么时候发布的",  english=False):
    """
        参考https://github.com/InternLM/HuixiangDou/blob/main/README_zh.md 先开启对应的服务
    """
    # 定义请求的URL
    url = 'http://127.0.0.1:23333/huixiangdou_inference'

    # 定义你要发送的数据
    data = {
        "text": f"{questions}",
        "image": ""
    }

    # 将数据转换成json格式
    payload = json.dumps(data)

    # 设置请求头
    headers = {
        'Content-Type': 'application/json'
    }

    # 发送POST请求
    rag_response = requests.post(url, data=payload, headers=headers)
    # 检查请求是否成功
    if rag_response.status_code != 200:
        logger.error(f"请求失败,状态码:{rag_response.status_code}")

    res_txt = rag_response.text
    res = json.loads(res_txt, strict=False)
    answer = ""
    for step in res["step"]:
        if step["state"] == "success":
            answer = step["response"]
            logger.info(f"got response: {answer}")
    if answer == "":
        logger.error(f'no answer: {res_txt}')
    return answer
```



#### **最终数据格式**

以下时xtuner使用的指令微调数据格式,如果是多轮对话,只需要再第一次对话中加入"system",最好这个system prompt和你最终使用时给模型的prompt保持一致

```
[{
    "conversation":[
        {
            "system": "xxx",
            "input": "xxx",
            "output": "xxx"
        }
    ]
},
{
    "conversation":[
        {
            "system": "xxx",
            "input": "xxx",
            "output": "xxx"
        },
        {
            "input": "xxx",
            "output": "xxx"
        }
    ]
}]
```

最终保存为jsonl格式,每行是一个字典,以下是一个例子

```python
{"conversation": [{"system": "你是悟了悟了,...", "input": "游戏世界观的设定灵感来源是什么?", "output": "《黑神话:悟空》的游戏世界观深受《西游记》的影响,但在此基础上进行了大胆的创新和扩展。游戏构建了一个佛道衰败、妖魔横行的末法时代背景,其中许多角色和地点都源自《西游记》,如孙悟空、牛魔王、蜘蛛精等,这些角色在游戏世界中被赋予了新的故事和性格。同时,游戏还增加了新的神话元素和角色,如黄眉老祖、黑熊精等,这些新角色的加入丰富了游戏的世界观和剧情。因此,游戏世界观的设定灵感来源主要是《西游记》,但通过创新和扩展,构建了一个既熟悉又新奇的神话世界。"}, {"input": "在《黑神话:悟空》中,孙悟空的棍法技能在不同战斗场景中如何应用?请简要回答", "output": "在《黑神话:悟空》中,孙悟空的棍法技能在不同战斗场景中有着不同的应用方式,以下是简要回答:..."}]}
```