🌀Jarson Cai's Blog
头脑是日用品,不是装饰品
《金融大模型2023挑战赛》思路学习
根据金融大模型挑战赛学习方案。

SMP 2023金融大模型挑战赛思路分析

任务简介

以ChatGLM2-6B模型为中心制作一个问答系统,回答用户的金融相关的问题。

  • 初级:基本数据查询:参赛者需要利用提供的ChatGLM2-6B开源模型和上市公司年报原始数据,并以此为基础创建信息问答系统。系统需能够解决基本查询,如:某公司2021年的研发费用是多少?等问题。

  • 中级:数据统计分析查询:在初级阶段的基础上,参赛者需要进行金融数据的统计分析和关联指标查询。系统需基于各类指标,提供问题和答案,如:某公 司2021年研发费用增长率为多少?等问题。

  • 高级:开放性问题:某公司2021年主要研发项目是否涉及国家创新领域,如新能源技术、人工智能等?

  • 示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
问题: 2019年中国工商银行财务费用是多少元?

 关键词: 财务费用、2019

 prompt: "财务费用": "12345678.9元"

 答案: 12345678.9

 示例答案: ["2019年中国工商银行财务费用是12345678.9元。", "2019年工商银行财务费用是12345678.9元。", "中国工商银行2019年的财务费用是 12345678.9元。" ]

评测计算示例:

 答案一:工商银行2019年财务费用是12345678.9元。

 most similar sentences:

2019年工商银行财务费用是12345678.9元。 (Score: 0.9915) 
中国工商银行2019年的财务费用是12345678.9元。 (Score: 0.9820)
2019年中国工商银行财务费用是12345678.9元。 (Score: 0.9720)

 评分:0.25+0.25+0.9915*0.5=0.9958分。

 评分解释:prom_answer正确、包含所有key_word、相似度最高0.9915

整体方案设计

这里只看了第一组馒头科技的部分,其余思路都是相差不大的,可以自行去github查看:

  • PDF解析与信息抽取步骤:

pdf文本抽取 -> 页面召回 -> 表格识别 -> 信息过滤

pdf文本抽取使用了官方提供的脚本:

  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
import glob
import pdfplumber
import re
from collections import defaultdict
import json
from multiprocessing import Pool

class PDFProcessor:
    def __init__(self, filepath):
        self.filepath = filepath
        self.pdf = pdfplumber.open(filepath)
        self.all_text = defaultdict(dict)
        self.allrow = 0
        self.last_num = 0

    def check_lines(self, page, top, buttom):
        lines = page.extract_words()[::]
        text = ''
        last_top = 0
        last_check = 0
        for l in range(len(lines)):
            each_line = lines[l]
            check_re = '(?:。|;|单位:元|单位:万元|币种:人民币|\d|报告(?:全文)?(?:(修订版)|(修订稿)|(更正后))?)$'
            if top == '' and buttom == '':
                if abs(last_top - each_line['top']) <= 2:
                    text = text + each_line['text']
                elif last_check > 0 and (page.height * 0.9 - each_line['top']) > 0 and not re.search(check_re, text):

                    text = text + each_line['text']
                else:
                    text = text + '\n' + each_line['text']
            elif top == '':
                if each_line['top'] > buttom:
                    if abs(last_top - each_line['top']) <= 2:
                        text = text + each_line['text']
                    elif last_check > 0 and (page.height * 0.85 - each_line['top']) > 0 and not re.search(check_re,
                                                                                                          text):
                        text = text + each_line['text']
                    else:
                        text = text + '\n' + each_line['text']
            else:
                if each_line['top'] < top and each_line['top'] > buttom:
                    if abs(last_top - each_line['top']) <= 2:
                        text = text + each_line['text']
                    elif last_check > 0 and (page.height * 0.85 - each_line['top']) > 0 and not re.search(check_re,
                                                                                                          text):
                        text = text + each_line['text']
                    else:
                        text = text + '\n' + each_line['text']
            last_top = each_line['top']
            last_check = each_line['x1'] - page.width * 0.85

        return text

    def drop_empty_cols(self, data):
        # 删除所有列为空数据的列
        transposed_data = list(map(list, zip(*data)))
        filtered_data = [col for col in transposed_data if not all(cell is '' for cell in col)]
        result = list(map(list, zip(*filtered_data)))
        return result

    def extract_text_and_tables(self, page):
        buttom = 0
        tables = page.find_tables()
        if len(tables) >= 1:
            count = len(tables)
            for table in tables:
                if table.bbox[3] < buttom:
                    pass
                else:
                    count -= 1
                    top = table.bbox[1]
                    text = self.check_lines(page, top, buttom)
                    text_list = text.split('\n')
                    for _t in range(len(text_list)):
                        self.all_text[self.allrow] = {'page': page.page_number, 'allrow': self.allrow,
                                                      'type': 'text', 'inside': text_list[_t]}
                        self.allrow += 1

                    buttom = table.bbox[3]
                    new_table = table.extract()
                    r_count = 0
                    for r in range(len(new_table)):
                        row = new_table[r]
                        if row[0] is None:
                            r_count += 1
                            for c in range(len(row)):
                                if row[c] is not None and row[c] not in ['', ' ']:
                                    if new_table[r - r_count][c] is None:
                                        new_table[r - r_count][c] = row[c]
                                    else:
                                        new_table[r - r_count][c] += row[c]
                                    new_table[r][c] = None
                        else:
                            r_count = 0

                    end_table = []
                    for row in new_table:
                        if row[0] != None:
                            cell_list = []
                            cell_check = False
                            for cell in row:
                                if cell != None:
                                    cell = cell.replace('\n', '')
                                else:
                                    cell = ''
                                if cell != '':
                                    cell_check = True
                                cell_list.append(cell)
                            if cell_check == True:
                                end_table.append(cell_list)
                    end_table = self.drop_empty_cols(end_table)

                    for row in end_table:
                        self.all_text[self.allrow] = {'page': page.page_number, 'allrow': self.allrow,
                                                      'type': 'excel', 'inside': str(row)}
                        # self.all_text[self.allrow] = {'page': page.page_number, 'allrow': self.allrow, 'type': 'excel',
                        #                               'inside': ' '.join(row)}
                        self.allrow += 1

                    if count == 0:
                        text = self.check_lines(page, '', buttom)
                        text_list = text.split('\n')
                        for _t in range(len(text_list)):
                            self.all_text[self.allrow] = {'page': page.page_number, 'allrow': self.allrow,
                                                          'type': 'text', 'inside': text_list[_t]}
                            self.allrow += 1

        else:
            text = self.check_lines(page, '', '')
            text_list = text.split('\n')
            for _t in range(len(text_list)):
                self.all_text[self.allrow] = {'page': page.page_number, 'allrow': self.allrow,
                                              'type': 'text', 'inside': text_list[_t]}
                self.allrow += 1

        first_re = '[^计](?:报告(?:全文)?(?:(修订版)|(修订稿)|(更正后))?)$'
        end_re = '^(?:\d|\\|\/|第|共|页|-|_| ){1,}'
        if self.last_num == 0:
            try:
                first_text = str(self.all_text[1]['inside'])
                end_text = str(self.all_text[len(self.all_text) - 1]['inside'])
                if re.search(first_re, first_text) and not '[' in end_text:
                    self.all_text[1]['type'] = '页眉'
                    if re.search(end_re, end_text) and not '[' in end_text:
                        self.all_text[len(self.all_text) - 1]['type'] = '页脚'
            except:
                print(page.page_number)
        else:
            try:
                first_text = str(self.all_text[self.last_num + 2]['inside'])
                end_text = str(self.all_text[len(self.all_text) - 1]['inside'])
                if re.search(first_re, first_text) and '[' not in end_text:
                    self.all_text[self.last_num + 2]['type'] = '页眉'
                if re.search(end_re, end_text) and '[' not in end_text:
                    self.all_text[len(self.all_text) - 1]['type'] = '页脚'
            except:
                print(page.page_number)

        self.last_num = len(self.all_text) - 1


    def process_pdf(self):
        for i in range(len(self.pdf.pages)):
            self.extract_text_and_tables(self.pdf.pages[i])

    def save_all_text(self, path):
        for key in self.all_text.keys():
            with open(path, 'a+', encoding='utf-8') as file:
                file.write(json.dumps(self.all_text[key], ensure_ascii=False) + '\n')

def process_file(file_path):
    try:
        print('start ', file_path)
        processor = PDFProcessor(file_path)
        processor.process_pdf()
        save_path = 'alltxt2/' + file_path.split('/')[-1].replace('.pdf', '.txt')
        processor.save_all_text(save_path)
        print('finish ', save_path)
    except:
        print('check')


folder_path = 'allpdf'
file_paths = glob.glob(f'{folder_path}/*')
file_paths = sorted(file_paths, reverse=True)
with Pool(processes=15) as pool:
    results = pool.map(process_file, file_paths)

最终呈现的效果如下:

 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
{"page": 1, "allrow": 0, "type": "text", "inside": ""}
{"page": 1, "allrow": 1, "type": "页眉", "inside": "江苏安靠智能输电工程科技股份有限公司2019年年度报告全文"}
{"page": 1, "allrow": 2, "type": "text", "inside": "江苏安靠智能输电工程科技股份有限公司"}
{"page": 1, "allrow": 3, "type": "text", "inside": "2019年年度报告"}
{"page": 1, "allrow": 4, "type": "text", "inside": "2020-008"}
{"page": 1, "allrow": 5, "type": "text", "inside": "2020年01月"}
{"page": 1, "allrow": 6, "type": "页脚", "inside": "1"}
{"page": 2, "allrow": 7, "type": "text", "inside": ""}
{"page": 2, "allrow": 8, "type": "页眉", "inside": "江苏安靠智能输电工程科技股份有限公司2019年年度报告全文"}
{"page": 2, "allrow": 9, "type": "text", "inside": "第一节重要提示、目录和释义"}
{"page": 2, "allrow": 10, "type": "text", "inside": "公司董事会、监事会及董事、监事、高级管理人员保证年度报告内容的真实、准确、完整,不存在虚假记载、误导性陈述或重大遗漏,并承担个别和连带的法律责任。"}
{"page": 2, "allrow": 11, "type": "text", "inside": "公司负责人陈晓晖、主管会计工作负责人陈晓凌及会计机构负责人(会计主管人员)王春梅声明:保证年度报告中财务报告的真实、准确、完整。"}
{"page": 2, "allrow": 12, "type": "text", "inside": "所有董事均已出席了审议本报告的董事会会议。"}
{"page": 2, "allrow": 13, "type": "text", "inside": "本报告中如有涉及未来的计划、业绩预测等方面内容,均不构成公司对任何投资者及相关人士的承诺,投资者及相关人士应对此保持足够的风险认识,并且应当理解计划、预测与承诺之间的差异。"}
{"page": 2, "allrow": 14, "type": "text", "inside": "本公司敬请广大投资者认真阅读本报告,并注意以下风险:"}
{"page": 2, "allrow": 15, "type": "text", "inside": "1、宏观经济增速放缓带来的行业风险"}
{"page": 2, "allrow": 16, "type": "text", "inside": "当前国内国际宏观经济环境下,增长放缓,需求下降。公司所处行业发展与宏观经济环境及下游行业景气度密切相关。当宏观经济处于上升阶段时,新开工上升,电力需求增加,输配电系统投资增加;反之,当宏观经济处于下降阶段时,供需逆转,电力需求减少,输配电系统投资减少。若宏观经济形势发生变化或产业经济发展方向发生重大调整,导致国家电力网络建设投资规模相应缩减,将对公司所处行业经营环境产生较大的不利影响,导致行业市场容量缩减,对公司业绩造成不利影响。"}
{"page": 2, "allrow": 17, "type": "text", "inside": "2、客户高度集中风险"}
{"page": 2, "allrow": 18, "type": "text", "inside": "公司主要通过参与国家电网、南方电网、五大发电集团、地方政府或下属"}
{"page": 2, "allrow": 19, "type": "页脚", "inside": "2"}
{"page": 3, "allrow": 20, "type": "text", "inside": ""}
{"page": 3, "allrow": 21, "type": "页眉", "inside": "江苏安靠智能输电工程科技股份有限公司2019年年度报告全文"}
{"page": 3, "allrow": 22, "type": "text", "inside": "机构等客户招标的方式进行销售,部分投标采取与电缆厂商合作的方式。而我国发电企业及输配电企业高度集中的格局决定了公司客户集中度较高。鉴于国家电网、南方电网及五大发电集团在产业链中的主导地位以及市场高度集中的格局,如果公司主要客户发生重大变化,可能对公司经营造成不利影响。"}
{"page": 3, "allrow": 23, "type": "text", "inside": "3、市场竞争风险"}
{"page": 3, "allrow": 24, "type": "text", "inside": "随着行业的不断发展,政策及监管环境等可能发生变化,市场竞争方式可能发生改变,公司产品面临的市场竞争环境也将日趋激烈,产品售价存在下降风险。随着客户对高压、超高压产品需求的不断提升,潜在生产厂商可能积极进入,现有生产厂商投资力度可能加大,亦可能取得技术上的实质突破;国外厂商也可能采取降价等手段加剧市场竞争状况。如公司不能维持技术竞争力及价格竞争力等方面的优势,将面临竞争力下降、毛利率降低等风险。"}
{"page": 3, "allrow": 25, "type": "text", "inside": "4、产品质量风险"}
{"page": 3, "allrow": 26, "type": "text", "inside": "公司生产的产品是输配电环节重要的组成部分,若产品发生质量问题,将很有可能对电力输送产生重大影响,造成严重损失。未来,若公司相关产品出现质量问题,可能面临退货、民事赔偿以及行政处罚等不利影响,情形严重的,可能导致公司不再满足国家电网、南方电网或五大发电集团等客户的投标资格,上述情况的发生将会对公司声誉和经营业绩带来不利影响。"}
{"page": 3, "allrow": 27, "type": "text", "inside": "公司经本次董事会审议通过的利润分配预案为:以截至2019年12月31日扣除回购专户上已回购股份(已回购股份2,209,650股)后的总股本97,795,350"}
{"page": 3, "allrow": 28, "type": "text", "inside": "股为基数,向全体股东每10股派发现金红利5元(含税),送红股0股(含税),以资本公积金向全体股东每10股转增3股,共计转增29,338,605股,转增后总股本为129,343,605股(不扣除已回购的股份2,209,650股)。"}
{"page": 3, "allrow": 29, "type": "页脚", "inside": "3"}
{"page": 4, "allrow": 30, "type": "text", "inside": ""}
{"page": 4, "allrow": 31, "type": "页眉", "inside": "江苏安靠智能输电工程科技股份有限公司2019年年度报告全文"}
{"page": 4, "allrow": 32, "type": "text", "inside": "目录"}
{"page": 4, "allrow": 33, "type": "text", "inside": "第一节重要提示、目录和释义.......................................................................................................7"}
{"page": 4, "allrow": 34, "type": "text", "inside": "第二节公司简介和主要财务指标.................................................................................................11"}
{"page": 4, "allrow": 35, "type": "text", "inside": "第三节公司业务概要.....................................................................................................................19"}
{"page": 4, "allrow": 36, "type": "text", "inside": "第四节经营情况讨论与分析.........................................................................................................47"}
{"page": 4, "allrow": 37, "type": "text", "inside": "第五节重要事项...........................................................................................................................130"}
{"page": 4, "allrow": 38, "type": "text", "inside": "第六节股份变动及股东情况.......................................................................................................137"}
{"page": 4, "allrow": 39, "type": "text", "inside": "第七节优先股相关情况...............................................................................................................137"}
{"page": 4, "allrow": 40, "type": "text", "inside": "第八节可转换公司债券相关情况...............................................................................................137"}
{"page": 4, "allrow": 41, "type": "text", "inside": "第九节董事、监事、高级管理人员和员工情况.......................................................................138"}
{"page": 4, "allrow": 42, "type": "text", "inside": "第十节公司治理...........................................................................................................................139"}
{"page": 4, "allrow": 43, "type": "text", "inside": "第十一节公司债券相关情况.......................................................................................................148"}
{"page": 4, "allrow": 44, "type": "text", "inside": "第十二节财务报告.......................................................................................................................156"}
{"page": 4, "allrow": 45, "type": "text", "inside": "第十三节备查文件目录...............................................................................................................157"}
{"page": 4, "allrow": 46, "type": "页脚", "inside": "4"}
{"page": 5, "allrow": 47, "type": "text", "inside": ""}
{"page": 5, "allrow": 48, "type": "页眉", "inside": "江苏安靠智能输电工程科技股份有限公司2019年年度报告全文"}
{"page": 5, "allrow": 49, "type": "text", "inside": "释义"}
{"page": 5, "allrow": 50, "type": "excel", "inside": "['释义项', '指', '释义内容']"}
{"page": 5, "allrow": 51, "type": "excel", "inside": "['一、简称', '指', '']"}
{"page": 5, "allrow": 52, "type": "excel", "inside": "['安靠智电、本公司、公司、发行人', '指', '江苏安靠智能输电工程科技股份有限公司']"}
{"page": 5, "allrow": 53, "type": "excel", "inside": "['河南安靠', '指', '河南安靠电力工程设计有限公司']"}
{"page": 5, "allrow": 54, "type": "excel", "inside": "['溧阳常瑞', '指', '溧阳市常瑞电力科技有限公司']"}
{"page": 5, "allrow": 55, "type": "excel", "inside": "['江苏凌瑞', '指', '江苏凌瑞电力科技有限公司']"}
{"page": 5, "allrow": 56, "type": "excel", "inside": "['安靠创投', '指', '江苏安靠创业投资有限公司']"}
{"page": 5, "allrow": 57, "type": "excel", "inside": "['安云创投', '指', '江苏安云创业投资有限公司']"}
{"page": 5, "allrow": 58, "type": "excel", "inside": "['安靠有限', '指', '江苏安靠超高压电缆附件有限公司']"}
{"page": 5, "allrow": 59, "type": "excel", "inside": "['安靠光热', '指', '江苏安靠光热发电系统科技有限公司']"}
{"page": 5, "allrow": 60, "type": "excel", "inside": "['ABB', '指', 'ABB(中国)有限公司']"}
{"page": 5, "allrow": 61, "type": "excel", "inside": "['3M', '指', '明尼苏达矿务及制造业公司']"}
{"page": 5, "allrow": 62, "type": "excel", "inside": "['建创能鑫', '指', '建创能鑫(天津)创业投资有限责任公司']"}
{"page": 5, "allrow": 63, "type": "excel", "inside": "['曲水增益、卓辉增益', '指', '曲水卓辉增益投资管理中心(有限合伙)']"}
{"page": 5, "allrow": 64, "type": "excel", "inside": "['国家电网', '指', '国家电网有限公司']"}
{"page": 5, "allrow": 65, "type": "excel", "inside": "['南方电网', '指', '中国南方电网有限责任公司']"}
{"page": 5, "allrow": 66, "type": "excel", "inside": "['', '', '中国华能集团公司、中国大唐集团公司、中国华电集团公司、中国']"}
{"page": 5, "allrow": 67, "type": "excel", "inside": "['五大发电集团', '指', '国电集团公司、国家电力投资集团公司']"}
{"page": 5, "allrow": 68, "type": "excel", "inside": "['中国证监会、证监会', '指', '中国证券监督管理委员会']"}
{"page": 5, "allrow": 69, "type": "excel", "inside": "['深交所', '指', '深圳证券交易所']"}
{"page": 5, "allrow": 70, "type": "excel", "inside": "['公司法', '指', '中华人民共和国公司法']"}
{"page": 5, "allrow": 71, "type": "excel", "inside": "['证券法', '指', '中华人民共和国证券法']"}
{"page": 5, "allrow": 72, "type": "excel", "inside": "['股东大会', '指', '江苏安靠智能输电工程科技股份有限公司股东大会']"}
{"page": 5, "allrow": 73, "type": "excel", "inside": "['董事会', '指', '江苏安靠智能输电工程科技股份有限公司董事会']"}
{"page": 5, "allrow": 74, "type": "excel", "inside": "['监事会', '指', '江苏安靠智能输电工程科技股份有限公司监事会']"}
{"page": 5, "allrow": 75, "type": "excel", "inside": "['公司章程', '指', '江苏安靠智能输电工程科技股份有限公司章程']"}
{"page": 5, "allrow": 76, "type": "excel", "inside": "['报告期', '指', '2019年1月1日至2019年12月31日']"}
{"page": 5, "allrow": 77, "type": "text", "inside": ""}
...

最终呈现效果如上,根据文本的类型进行分类,分为textexcel页眉页脚

页面的召回也是使用较为简单的方式,使用关键词找到对应的页去召回对应的页。

表格识别则使用了基于图像识别的表格提取(年报中的横线和竖线去提取,然后做ocr)。

信息过滤则对每个报表的文本中的非合并报表、调整报表、母公司报表进行过滤。

  • 问题分类: 迭代过程: 基于规则 -> 大模型prompt -> P-Tuning

记录一下他们使用的大模型Prompt内容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
请问“{}”是属于下面哪个类别的问题?
A:基本信息查询,例如证券信息、股票简称、股票代码、外文名称、法定代表人、注册地址、办公地址、公司网址、电子信箱等
B:公司员工人数统计,例如员工人数、员工专业、员工教育程度等
C:财务相关,例如金额、费用、资产、收入等
D:以上都不是
例如:
1. XXXX的费用收入是多少元?
输出:C
2. XX公司法定代表人是谁?
输出:A
3. 请简要介绍分析XX公司的XXX情况。 
输出:D
4. XX公司硕士人数是什么?
输出:B
你只需要回答编号,不要回答其他内容.

模型微调的问题分类情况:

字母分类编号 分类选项名称 分类描述
A 公司基本信息 可以通过检索【公司基本信息表】来获取结果
B 公司员工信息 可以通过检索【公司员工信息表】来获取结果
C 财务报表相关内容 可以通过检索【财务三大报表】来获取结果
D 计算题 可以通过问题类型检索计算因子来完成计算
E 统计题 需要根据问题类型分析条件检索来获取结果
F 开放性问题 根据问题关键词来检索全文相关匹配来回答问题

微调使用的prompt:

1
2
3
4
5
6
7
8
9
prompt_classify_question = """请问"{question_text}"是属于下面哪个类别的问题?
A:公司基本信息,包含股票简称,公司名称人外文名称,法定代表人,注册地址,办公地址,公司网址网站,电子信箱等.
B:公司员工信息,包含员工人数,员工专业,员工类别,员工教育程度等.
C:财务报表相关内容,包含资产负债表,现金流量表,利润表中存在的字段,包括费用,资产,金额,收入等.
D:计算题,无法从年报中直接获得,需要根据计算公式获得,包括增长率,率,比率,比重,占比等.
E:统计题,需要从题目获取检索条件,在数据集/数据库中进行检索、过滤、排序后获得结果.
F:开放性问题,包括介绍情况,介绍方法,分析情况,分析影响,什么是xxx.
你只需要回答字母编号,不要回答字母编号及选项文本外的其他内容.
""".format(question_text=question_text)

P-Tuning v2微调使用的方法可以看https://github.com/THUDM/ChatGLM3/tree/main/finetune_demo

这里我们也可以用lora的方法进行微调,微调之后可以直接合并为一个模型,更为方便。将prompt_classify_question作为输入,回答的字母作为输出,instruction字段设置为合适的任务指引即可。

对于意图识别任务来说,根据自己做过的项目经验来说,如果想要精准识别,32b以下的模型必须微调,32b级别的模型通过调整提示词,增加样例,可以实现精准分类。一般通过规则匹配+大模型(微调或者32b级别+提示词)基本可以做到98%以上的正确率。对于项目的迭代来说,32b级别的大模型会更加方便,减少任务增加带来的微调成本。

  • SQL生成任务:

数据构造使用了超大模型API服务来给小模型提供样例的方式进行。数据构造的具体过程如下:

可以看到该团队在微调的过程中还加入了对一些中文含义数字转化为实际数字的能力增强。

  • 关键词提取任务设计的提示词如下:

基本信息问答任务

  • 处理流程:

  • 回答示例:

根据基本信息计算任务

  • 处理流程:

  • 回答示例:

文本召回类任务

  • 处理流程:

  • 回答示例:

个人理解这里是用规则匹配(关键词 + 问题)召回的,没有做向量库相关的内容。

Prompt设计结构总结

  • 角色定义:精确,与完成任务所需背景知识匹配
  • 任务目标描述:简洁明了,避免使用模糊或歧义的词汇
  • 任务具体要求、思维链、步骤:多用枚举,少用否定句(也就是不要让大模型不做什么),如流程较长应考虑拆分为多个任务
  • 案例:具有代表性,分别代表不同类型
  • 输出要求:明确输出格式要求,可再次强调 重要的任务要求

模型微调总结

根据项目的经验是,提升基础模型的能力是最划算的,占用的显存也是最少的。因为为了保证模型的应对不同任务的回答速度,不同的模型实例都得提前加载,显存使用是叠加的。如果能不用微调就能解决,就代表可以使用高并发框架来使用一份32b级别的大模型资源来做不同的任务,省时省力省成本。


最后修改于 2024-07-19

知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。