文章内容生成大语言模型训练的qa语料集

在lora训练大语言模型的时候,需要严格的qa语料集,但是我们一般的文章内容并不是提问和回答,这时候我们就需要人为的对文章进行分割和提问。这种方式十分耗费人力物力。我开发了一套将文章自动拆分成语料集的ai工作流。

我们用到内容为dify,ollama,java 程序

dify工作流

将yaml文件导入到工作流中

复制代码
app:
  description: ''
  icon: 🤖
  icon_background: '#FFEAD5'
  mode: workflow
  name: qa获取
  use_icon_as_answer_icon: false
kind: app
version: 0.1.2
workflow:
  conversation_variables: []
  environment_variables: []
  features:
    file_upload:
      allowed_file_extensions:
      - .JPG
      - .JPEG
      - .PNG
      - .GIF
      - .WEBP
      - .SVG
      allowed_file_types:
      - image
      allowed_file_upload_methods:
      - local_file
      - remote_url
      enabled: false
      fileUploadConfig:
        audio_file_size_limit: 50
        batch_count_limit: 5
        file_size_limit: 15
        image_file_size_limit: 10
        video_file_size_limit: 100
      image:
        enabled: false
        number_limits: 3
        transfer_methods:
        - local_file
        - remote_url
      number_limits: 3
    opening_statement: ''
    retriever_resource:
      enabled: true
    sensitive_word_avoidance:
      enabled: false
    speech_to_text:
      enabled: false
    suggested_questions: []
    suggested_questions_after_answer:
      enabled: false
    text_to_speech:
      enabled: false
      language: ''
      voice: ''
  graph:
    edges:
    - data:
        isInIteration: false
        sourceType: start
        targetType: http-request
      id: 1742432991068-source-1742441313376-target
      source: '1742432991068'
      sourceHandle: source
      target: '1742441313376'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        sourceType: http-request
        targetType: tool
      id: 1742441313376-source-1742441430248-target
      source: '1742441313376'
      sourceHandle: source
      target: '1742441430248'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        sourceType: tool
        targetType: code
      id: 1742441430248-source-1742441888151-target
      source: '1742441430248'
      sourceHandle: source
      target: '1742441888151'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        sourceType: code
        targetType: iteration
      id: 1742441888151-source-1742442381550-target
      source: '1742441888151'
      sourceHandle: source
      target: '1742442381550'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        sourceType: iteration
        targetType: end
      id: 1742442381550-source-1742441453118-target
      source: '1742442381550'
      sourceHandle: source
      target: '1742441453118'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: true
        iteration_id: '1742442381550'
        sourceType: iteration-start
        targetType: llm
      id: 1742442381550start-source-1742442494479-target
      source: 1742442381550start
      sourceHandle: source
      target: '1742442494479'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: true
        iteration_id: '1742442381550'
        sourceType: llm
        targetType: http-request
      id: 1742442494479-source-1742453246589-target
      source: '1742442494479'
      sourceHandle: source
      target: '1742453246589'
      targetHandle: target
      type: custom
      zIndex: 1002
    nodes:
    - data:
        desc: ''
        selected: false
        title: 开始
        type: start
        variables:
        - label: url
          max_length: 256
          options: []
          required: true
          type: text-input
          variable: url
      height: 90
      id: '1742432991068'
      position:
        x: 30
        y: 274
      positionAbsolute:
        x: 30
        y: 274
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        authorization:
          config: null
          type: no-auth
        body:
          data: []
          type: none
        desc: ''
        headers: ''
        method: get
        params: url:{{#1742432991068.url#}}
        selected: false
        timeout:
          max_connect_timeout: 0
          max_read_timeout: 0
          max_write_timeout: 0
        title: HTTP 请求
        type: http-request
        url: http://192.168.100.199:8080/test/spiltText
        variables: []
      height: 110
      id: '1742441313376'
      position:
        x: 334
        y: 274
      positionAbsolute:
        x: 334
        y: 274
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        provider_id: json_process
        provider_name: json_process
        provider_type: builtin
        selected: false
        title: JSON 解析
        tool_configurations:
          ensure_ascii: 0
        tool_label: JSON 解析
        tool_name: parse
        tool_parameters:
          content:
            type: mixed
            value: '{{#1742441313376.body#}}'
          json_filter:
            type: mixed
            value: data
        type: tool
      height: 90
      id: '1742441430248'
      position:
        x: 638
        y: 274
      positionAbsolute:
        x: 638
        y: 274
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        outputs:
        - value_selector:
          - '1742441888151'
          - result
          variable: text
        selected: false
        title: 结束
        type: end
      height: 90
      id: '1742441453118'
      position:
        x: 1858.5714285714287
        y: 618.2857142857143
      positionAbsolute:
        x: 1858.5714285714287
        y: 618.2857142857143
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        code: "import json\n\ndef main(input_str: str) -> dict:\n    # 直接将JSON格式字符串转换为Python列表\n\
          \    result_array = json.loads(input_str)\n\n    return {\n        \"result\"\
          : result_array,\n    }"
        code_language: python3
        desc: ''
        outputs:
          result:
            children: null
            type: array[string]
        selected: false
        title: 代码执行
        type: code
        variables:
        - value_selector:
          - '1742441430248'
          - text
          variable: input_str
      height: 54
      id: '1742441888151'
      position:
        x: 942
        y: 274
      positionAbsolute:
        x: 942
        y: 274
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        height: 441
        iterator_selector:
        - '1742441888151'
        - result
        output_selector:
        - '1742442494479'
        - text
        output_type: array[string]
        selected: false
        start_node_id: 1742442381550start
        title: 迭代
        type: iteration
        width: 717
      height: 441
      id: '1742442381550'
      position:
        x: 1035.9999999999998
        y: 516.8571428571428
      positionAbsolute:
        x: 1035.9999999999998
        y: 516.8571428571428
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 717
      zIndex: 1
    - data:
        desc: ''
        isInIteration: true
        selected: false
        title: ''
        type: iteration-start
      draggable: false
      height: 48
      id: 1742442381550start
      parentId: '1742442381550'
      position:
        x: 24
        y: 68
      positionAbsolute:
        x: 1059.9999999999998
        y: 584.8571428571428
      selectable: false
      sourcePosition: right
      targetPosition: left
      type: custom-iteration-start
      width: 44
      zIndex: 1002
    - data:
        context:
          enabled: true
          variable_selector:
          - '1742442381550'
          - item
        desc: ''
        isInIteration: true
        iteration_id: '1742442381550'
        model:
          completion_params:
            num_predict: 9998
            response_format: JSON
            temperature: 0.7
          mode: chat
          name: qwen2.5:14b
          provider: ollama
        prompt_template:
        - id: e2fd2d22-4c4e-4929-803c-045830e1fa58
          role: system
          text: 有一段文本,按照句子分割,你就是作者需要你对着每个句子结合上下文提出问题。然后再以request 和answer输出answer是句子原本内容,request是你提出的问题
            最多提出 30 个问题
        - id: 92f72d68-feab-4efb-a184-acb5f80af9c8
          role: user
          text: '{{#1742442381550.item#}}是这段文本,以 JSON 的形式输出,输出的 JSON 需遵守以下的格式

                {

                    "request": "xxxx",

                    "answer": "xxxx"

                },

                {

                    "request": "xxxx",

                    "answer": "xxxx"

                }

            ]

            除了json你不需要输出其他任何内容'
        selected: true
        title: LLM
        type: llm
        variables: []
        vision:
          enabled: false
      height: 98
      id: '1742442494479'
      parentId: '1742442381550'
      position:
        x: 128
        y: 68
      positionAbsolute:
        x: 1163.9999999999998
        y: 584.8571428571428
      selected: true
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        authorization:
          config: null
          type: no-auth
        body:
          data:
          - id: key-value-33
            key: ''
            type: text
            value: '{{#1742442494479.text#}}'
          type: json
        desc: ''
        headers: ''
        isInIteration: true
        iteration_id: '1742442381550'
        method: post
        params: ''
        selected: false
        timeout:
          max_connect_timeout: 0
          max_read_timeout: 0
          max_write_timeout: 0
        title: HTTP 请求 2
        type: http-request
        url: http://192.168.100.199:8080/qa/qa/setQa
        variables: []
      height: 110
      id: '1742453246589'
      parentId: '1742442381550'
      position:
        x: 434.8571428571429
        y: 65.14285714285722
      positionAbsolute:
        x: 1470.8571428571427
        y: 582
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    viewport:
      x: 98.85000000000014
      y: -5.149999999999864
      zoom: 0.7

http接口的java文件

这个文件可以将文章安装以句子为最小单位不超过textNum的字数切割。这样子就不会将句子切割开产生歧义。

复制代码
public static String[] readFilesV2(String filePath, boolean delete, Integer textNum) {
            ArrayList<String> stringList = new ArrayList<>();
            try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(Files.newInputStream(Paths.get(filePath)), StandardCharsets.UTF_8))) {

                StringBuilder currentFragment = new StringBuilder();
                StringBuilder currentSentence = new StringBuilder();

                int charInt;
                while ((charInt = reader.read()) != -1) {
                    char c = (char) charInt;
                    currentSentence.append(c);

                    // 检测到句子结束(以句号结尾)
                    if (c == '。') {
                        String sentence = currentSentence.toString();
                        currentSentence.setLength(0); // 重置当前句子

                        // 判断是否超过字符限制
                        if (currentFragment.length() + sentence.length() > textNum) {
                            if (currentFragment.length() > 0) {
                                stringList.add(currentFragment.toString());
                                currentFragment.setLength(0);
                            }
                            // 处理超长句子(单独成段)
                            if (sentence.length() > textNum) {
                                stringList.add(sentence);
                            } else {
                                currentFragment.append(sentence);
                            }
                        } else {
                            currentFragment.append(sentence);
                        }
                    }
                }

                // 处理最后一个未满的片段
                if (currentFragment.length() > 0) {
                    stringList.add(currentFragment.toString());
                }

            } catch (IOException e) {
                e.printStackTrace();
            }

            // 打印结果验证
            for (String s : stringList) {
                System.out.println(s + " | Length: " + s.length());
            }

            // 删除文件逻辑
            if (delete) {
                try {
                    Files.delete(Paths.get(filePath));
                    System.out.println("文件已成功删除。");
                } catch (IOException e) {
                    System.err.println("无法删除文件: " + e.getMessage());
                }
            }

            return stringList.toArray(new String[0]);
        }

最后的接口就是将qa数据集持久化

复制代码
    @PostMapping()
    public R<Void> add(@Validated(AddGroup.class) @RequestBody QaBo bo) {
        return toAjax(qaService.insertByBo(bo));
    }

例子

注入数据

复制代码
说实话,小学最困扰我的问题就是考清华还是考北大。我认真想过这个问题,清华这两个字有木有水,很绿色很治愈。而北大这两个字横横竖竖的像个刺头,太有棱角了。我不喜欢我初中的时候都不知道大学是要考的,我一直以为就和初中一样,是有一个离家近的保底大学念,所以我当时已经做好了念苏大的准备。直到中考出分之前,我才知道这个世界上还有职高的存在。直到我要念职高的那一刻,我真的崩溃了。我幻想的职高就是热血高校那样校霸在班里都得打老师的那种。像我这种小学就被打的人我爸不会让我给他洗内裤吧,我不会拿香烟在我的屁股上烫金字喜玩吧。那我可是我和我妈一起选完学校回家,我妈还庆幸我有学校念。我回到房间抱着我的书包开始哭,我真的以为这是我书包最后一次里面还能放教科书了。念了职高不得给校霸走私。德平呢,后来发现其实还好,大家只是成绩差一点,人还是挺好的。我高一高二成绩都很差,垫底的那种。直到高三的时候,我们拿到一份单子,里面有我们能考的院校名单。我一看不仅没有苏大,也没有清华。我们我我的最好的本科也是一个我从来没有听过的学校。我当时一下子醒悟了,我们能考的最好的院校可能都是普高生们都不会填报志愿的学校。我觉得我的智商没有问题,我不比他们差。于是我用了一个学期的时间重新学,回到宿舍拿台灯背书,最后还是以班级前十的成绩考到了这个学校。再加上二三年北大的身份,我应该是这个职高的荣誉校友才对。后来大学毕业,小时候看那种文章,说什么村里总算出来一个本科生,负责任的说,我觉得我的未来一片光明,我带着本科的毕业证和管理学的学士学位证回到家乡,我大学学的什么进出口贸易战术。4PS sat分析可口可乐公司的营销策略。我当时觉得对于一个三线的县级市来说,这两张证书应该能搞点金融诈骗。没想到通过关系也只能去卖汽车保险,去卖那些正常人根本不需要的汽车延保,也确实是金融诈骗,我负责诈骗,他负责金融。然后我干了三个月,因为没有开单被开掉了,后来又陆陆续续的干了很多销售工作都不行,然后我就在家呆着,那段时间在家浑浑噩噩的,我爸就来开导我,他说好男儿志在四方,儿子爸爸爱你,你想做什么爸爸都支持你我说我想创业,我爸说不行。我说我想当博主,我爸说也不行。我爸说他对我的爱只够支持我当一名光荣的化工厂化验员。我不喜欢化工这两个字,横横竖竖的像个北大,而我不喜欢北大。我说daddy,dad, dad, daddy. 你儿子气质出众能做idol,声音软糯能当歌手,风趣幽默能去陪酒,臀型软糯能盆多肉。反正绝对不可能去给资本当狗。我父母那段时间真的很着急我的工作问题,他们对我最大的要求就是有个班上就行,反正就开车带我去附近工厂介绍这个是外资的,这个是合资的,这个待遇好好这个班扳倒掏心窝子的说我不服气,我不服气,脱掉长衫,这长衫是我被哄着骗着打着袜子才穿上的这长衫是我花了16年穿上的这长衫是我们我穿上的这长衫我本可以不穿的长衫遮住了我的无能,能遮住了我的屁股上那盘没有下完的景字旗。但是我看着爸爸上的的皱纹,以前念书的时候总说燕雀安知鸿鹄之志。业后几年的努努力就用力憋憋了个屁屁。不不不不不不不不不,反正我出来我做的饭饭后谈资的资格都没有我看着面前夜不停息的大厂,也许有些人注定就是厌缺吧。我对我爸说,行,我去面试。第二天我带着简历就去那个化工厂面试,这是正经大厂。面试一共有两轮,第一轮我和另一个面试的人安排在一个房间里填表,填一些基本信息。我印象最深的一道题是问我英语字母表一共有多少个字母,并且让我默写下来。我真的我第一眼看到这个问题的时候,我还以为是道陷阱题,这不会是通过答案要对我进行心理测写吧。后来发现是我多虑了,因为和我一起面试的哥们还等着抄我答案呢。然后我顺利的去了第二轮面试,HR拿着我的简历看,然后这个HR对我说了改变我一生的话。他说你本科毕业从事过自媒体行业,你的特长爱好都表明你是一个思维很活跃的人,而且你不是化工专业的,所以你这辈子都不会有晋升的机会。但你面试的这个岗位,我说直接一点,我现在到马路上随便拉一个人,他只要能呼吸,他就能干,如果你想好了,想要这份工作,我现在就可以录用你,但是我觉得你的生活不该如此。听完这番话,我拿着简历站在厂子门口思考我的人生。我不知道我该干什么,我不知道该怎么跟我爸妈说,但我知道这样的生活不是我想过的。后来的一个月就有了叫我sky就好这个账号。朋友回顾这前面二十多年,有太多我都以为天塌了的瞬间。学生时期的每一次考试,失恋后觉得没了他就活不下去的时候,恋爱时候借的2万元网贷进入社会那些理想和现实有落差的时候,投出上百份简历辗转的那些夜晚,每一个我觉得天大的走不出来的事情,现在都成了我笔下拿来吐槽的素材。可能你现在也面临很多困扰你的问题,可能你也为了生活妥协的做着自己不喜欢的工作,甚至你可能就是当年抄我答案进场的小哥。我知道崩溃的情绪是真的,但也请你相信,一定都会过去的。而那个司马迁笔下的傻鸟厌倦,现在已经是三级保护动物了。嘿朋友,人生的容错率比你想的高得多,而你所在的行业也比你想的短命,而你我的朋友,你的命还长着呢。

产生的数据集效果

总之效果还是很不错的

相关推荐
2301_7644413343 分钟前
基于BERT的序列到序列(Seq2Seq)模型,生成文本摘要或标题
人工智能·python·深度学习·bert
说私域1 小时前
开源链动2+1模式与AI智能名片赋能的S2B2C共享经济新生态
人工智能·微信·小程序·开源
蹦蹦跳跳真可爱5891 小时前
Python----计算机视觉处理(Opencv:霍夫变换)
人工智能·python·opencv·计算机视觉
Angel Q.2 小时前
3D点云的深度学习网络分类(按照作用分类)
深度学习·3d·分类
livefan2 小时前
英伟达「虚拟轨道+AI调度」专利:开启自动驾驶3.0时代的隐形革命
人工智能·机器学习·自动驾驶
wd2099882 小时前
手绘的思维导图怎么转成电子版思维导图?分享今年刚测试出来的方法
人工智能·powerpoint
魔珐科技2 小时前
专访中兴通讯蒋军:AI数字人驱动企业培训,“内容生产”与“用户体验”双重提升
人工智能·aigc·ai数字人
果冻人工智能2 小时前
Linux 之父把 AI 泡沫喷了个遍:90% 是营销,10% 是现实。
人工智能