GPT 护理机器人 - 让护士的工作变简单

news2024/11/27 0:29:55

引子   

  书接上文《GPT接入企微应用 - 让工作快乐起来》,我把GPT接入了企微应用,不少同事都开始尝试起来了。有的浅尝辄止,有的刨根问底,五花八门,无所不有。这里摘抄几份:

  “帮我写一份表白信,我们是大学同学,暗恋十年”

  ”顺产后多久可以用收腹带?生完宝宝用收腹带好还是不用好“ (背景:公司主营月子中心,护理相关的领域知识是公司对于护士培训的重点内容

  ”我的工资是多少“ (这个有点强机器人所难了,不过如果机器人有了公司的人事语料数据,应该是可以回答的)

   ......

   总的来说,除了一些尝鲜,猎奇之外,有相当一部分还是咨询公司的内部的相关信息,比如HR方面的育儿假等,再就是母婴护理方面的问题了(公司有近60%的是护理人员,日常工作就是与宝宝,宝妈一起,这就不奇怪了)。

  看到这些问题后,我就开始尝试通过Fine-tune训练公司内部的护理机器人,希望他可以为护士们的工作带来一些便利。诸多尝试失败后,索性就放了一些时间。

  恰逢五一假,回了媳妇娘家,掐指一算,已经3年6个月没有回来过了,二娃子都快3岁了,还没见过外婆。想不到娃子亲舅舅,我到清闲了,又捡起护理机器人捣鼓起来了。于是有了这篇文章。

Fine-tune可能真的不合适

  刚看到Fine-tune的介绍时就想,如果通过fine-tune构建个性化的模型,导入公司的母婴护理知识,并且在未来了问答中进化,变成企业内部专家。所以一开始就是向这样的路子摸索着。毕竟介绍里也说了通过少量样本即可完成训练,分类这样的任务可能只需要200个左右的样本即可。(其实问答模型的样本要求至少要有几千个可能会有点效果)

   

  当然,文档中也有一些关于Fine-tune的一些指南和准则。一来是全是英文文档,理解不太深入;二来就是无知无畏,不尝试下就是不死心。这是文档原文,大概的意思Fine-tune可以用来解决一些类似分类(判断对错,情绪判断(乐观,悲观),邮件分类),以及扩写总结之类的场景。 文档也有提到案例”Customer support chatbot“,这可能也是大家这样尝试的原因之一吧。 在其demo推荐使用 emebedding 来实现,也是本文的重点内容。这是后

  虽然通过Fine-tune的方式最终也没有好的效果,一来可能是样本太少,或者样本质量不好;也或者过程中有疏漏的地方。在这里也和大家一起探讨下。毕竟fine-tune的方式还是让人非常神往的。实现代码基本是参考了 openai-cookbook 中的 fine-tuned_qa Demo。大致流程如入:

  • 环境配置就不多说了(版本 python 3.10.4 整个过程基本还是流畅的。除了v-p-n自身原因折腾好久(原来用的是mono),换个客户端居然好了)
  • 收集文本数据并根据token的限制,合理分段落。(我自己则是找到内部了母婴护理培训的电子版本。)
  • 用模型text-davinci-003 为每个段落自动生成若干问题,并根据段落及问题自动生成答案。
  • 使用所有生成问题及答案组织成fine-tuen所需要的数据集。
  • 创建新模型并使用。

  1,文本分段 - 因为拿到的资料是word,并且有标题,就直接根据标题他分段了,超过2048的再分一次,代码如下(现学现用,比较粗漏)

 

import docx
import pandas as pd

def getText(fileName):
    doc = docx.Document(fileName)
    TextList = []

    data = {"title":"","content":""}
    for paragraph in doc.paragraphs:
        if paragraph.style.name == 'Heading 1':
            print("title %s " % paragraph.text)
            if (len(data['content']) > 0):
                datax = {}
                datax['title'] = data['title']
                datax['content'] = data['content']

                TextList.append(datax)
            data['title'] = paragraph.text
            data['content'] = ''
        else:
            data['content'] += paragraph.text+"\n"
    TextList.append(data)
    return TextList

## 根据doc 转 csv
if __name__ == '__main__':
    fileName = '/Users/jijunjian/openai/test2.docx'

    articList = getText(fileName)
    count = 0
    for article in articList:
        if len(article['content']) > 800:
            print("%s,%s,\n%s" % (article['title'], len(article['content']),article['content']))
        count += 1

    header = ['title', 'content']
    print("总共 %s 篇文章" % count)
    pd.DataFrame(articList, columns=header).to_csv('data_oring.csv', index=False, encoding='utf-8')


  2,生成问题与答案 - 这样生成的质量可能不是太高,可能实际使用时还是要对生成的问题和答案,让领域专家进行修正比较好。

  据官方文档介绍,建议生成的数据集中,prompt与completion都要有固定的结尾,且尽量保证其他地方不会出现这个,所以我们这里使用了”\n\n###\n\n“作为结束标志。


import pandas as pd
import openai
import sys
sys.path.append("..")
from tools.OpenaiInit import openai_config
from transformers import GPT2TokenizerFast


tokenizer = GPT2TokenizerFast.from_pretrained("gpt2")

def count_tokens(text: str) -> int:
    """count the number of tokens in a string"""
    return len(tokenizer.encode(text))


COMPLETION_MODEL = "text-davinci-003"
FILE_TUNE_FILE = "search_data.jsonl"


# 获取训练数据
def     get_training_data():
    file_name = "data_oring.csv"
    df = pd.read_csv(file_name)
    df['context'] = df.title + "\n\n" + df.content
    print(f"{len(df)} rows in the data.")
    return df


# 根据内容,生成问题
def get_questions(context):
    print("正在生成问题")
    try:
        response = openai.Completion.create(
            engine=COMPLETION_MODEL,
            prompt=f"基于下面的文本生成问题\n\n文本: {context}\n\n问题集:\n1.",
            temperature=0,
            max_tokens=500,
            top_p=1,
            frequency_penalty=0,
            presence_penalty=0,
            stop=["\n\n"]
        )
        return response['choices'][0]['text']
    except Exception as e:
        print("创建问题错误 %s"  % e)
        return ""


# 根据问题,生成答案
def get_answers(row):
    print("正在生成答案")
    try:
        response = openai.Completion.create(
            engine=COMPLETION_MODEL,
            prompt=f"基于下面的文本生成答案\n\n文本: {row.context}\n\n问题集:\n{row.questions}\n\n答案集:\n1.",
            temperature=0,
            max_tokens=500,
            top_p=1,
            frequency_penalty=0,
            presence_penalty=0
        )
        return response['choices'][0]['text']
    except Exception as e:
        print (e)
        return ""


# 获取训练数据 /Users/jijunjian/tuningdata.xlsx
if __name__ == '__main__':
     openai_config()
     df = get_training_data()
     df['tokens'] = df.context.apply(count_tokens)
     # questions 根据返回生成
     df['questions']= df.context.apply(get_questions)
     df['questions'] = "1." + df.questions

     df['answers']= df.apply(get_answers, axis=1)
     df['answers'] = "1." + df.answers
     df = df.dropna().reset_index().drop('index',axis=1)

     print("正在保存数据")
     df.to_csv('nursing_qa.csv', index=False)



     df['prompt'] = df.context + "\n\n###\n\n"
     df['completion'] = " yes\n\n###\n\n"

     df[['prompt', 'completion']].to_json(FILE_TUNE_FILE, orient='records', lines=True)

     search_file = openai.File.create(
        file=open(FILE_TUNE_FILE),
        purpose='fine-tune'
     )
     qa_search_fileid = search_file['id']
     print("上传文件成功,文件ID为:%s" % qa_search_fileid)

     # file_id = file-Bv5gP2******

  3,根据生成数据集,创建新的模型。

  官方的demo,还有生成验证集,测试集,生成相识的文本,同样的问题与答案来增加一些对抗性,因为最终效果不太好,再是文档中有使用search 模块,但是这已经下线了,我用prompt-completion的数据结构模拟了下,也不知道有没有效果, 因为使用openai tools 创建模型可以有一些交互动作,也方便看一些执行结果,花费数据,这里就使用这这工具作了演示,执行一段时间后,可以通过”openai.Model.list()“查看我们创建的模型。当时大概有1000来个问题与答案,花费了0.78刀。(这是4月13尝试的,因为效果不好,结果一放就是半月有余了。时间真是如白驹过隙一般)  

 1 openai api fine_tunes.create -t "discriminator_train.jsonl" -v "discriminator_test.jsonl" --batch_size 16  --compute_classification_metrics --classification_positive_class yes --model ada --suffix 'discriminator'
 2 
 3 Uploaded file from discriminator_train.jsonl: file-5OeHx3bMDqk******
 4 Uploaded file from discriminator_test.jsonl: file-AnOiDwG1Oqv3Jh******
 5 Created fine-tune: ft-cQBMLPzqVNml1ZWqkGYQKUdO
 6 Streaming events until fine-tuning is complete...
 7 
 8 (Ctrl-C will interrupt the stream, but not cancel the fine-tune)
 9 [2023-04-13 23:17:05] Created fine-tune: ft-cQBMLPz********
10 [2023-04-13 23:17:22] Fine-tune costs $0.78
11 [2023-04-13 23:17:23] Fine-tune enqueued. Queue number: 3

   最后,效果不太理想,一番尝试后,看到文档中的提示信息:

  ”Note: To answer questions based on text documents, we recommend the procedure in Question Answering using Embeddings. Some of the code below may rely on deprecated API endpoints.“  于是借着五一的空闲,开始尝试emebedding 方式 了

emebedding可能是当下最好的选择

  GPT擅长回答训练数据中存在的问题,对于一些不常见的话题,或者企业内部的语料信息,则可以通过把相关信息放在上下文中,传给GPT,根据上下问进行回答。因为不同模型对于token的限制,以及Token本身的成本因素。

  具体实现时,我们需要把文本信息Chunk(分块)并Embed(不知道如何翻译)得到一个值,收到问题时,同样进行Embed,找到最相近的Chunk,做为上下文传给GPT。官方文档如下: 

  Specifically, this notebook demonstrates the following procedure:

  1. Prepare search data (once)
    1. Collect: We'll download a few hundred Wikipedia articles about the 2022 Olympics
    2. Chunk: Documents are split into short, mostly self-contained sections to be embedded
    3. Embed: Each section is embedded with the OpenAI API
    4. Store: Embeddings are saved (for large datasets, use a vector database)
  2. Search (once per query)
    1. Given a user question, generate an embedding for the query from the OpenAI API
    2. Using the embeddings, rank the text sections by relevance to the query
  3. Ask (once per query)
    1. Insert the question and the most relevant sections into a message to GPT
    2. Return GPT's answer

  一开始本想参考这个demo Question_answering_using_embeddings.ipynb 编写代码,后来有意无意看到使用llama_index的实现,并且对于语料信息格式无要求,就摘抄过来了,感谢代码的贡献者,节省了大家好些时间。

#!/usr/bin/env python
# coding=utf-8

from langchain import OpenAI
from llama_index import SimpleDirectoryReader, LangchainEmbedding, GPTListIndex,GPTSimpleVectorIndex, PromptHelper
from llama_index import LLMPredictor, ServiceContext
import gradio as gr
import sys
import os
os.environ["OPENAI_API_KEY"] = 'sk-fHstI********************'

#MODEL_NAME = "text-davinci-003"
MODEL_NAME = "ada:ft-primecare:*************"

def construct_index(directory_path):
    max_input_size = 2048
    num_outputs = 512
    max_chunk_overlap = 20
    chunk_size_limit = 600
    prompt_helper = PromptHelper(max_input_size, num_outputs, max_chunk_overlap, chunk_size_limit=chunk_size_limit)
    llm_predictor = LLMPredictor(llm=OpenAI(temperature=0.7, model_name=MODEL_NAME, max_tokens=num_outputs))
    documents = SimpleDirectoryReader(directory_path).load_data()
    #index = GPTSimpleVectorIndex(documents, llm_predictor=llm_predictor, prompt_helper=prompt_helper)

    service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor, prompt_helper=prompt_helper)
    index = GPTSimpleVectorIndex.from_documents(documents, service_context=service_context)

    index.save_to_disk('index.json')
    return index
def chatbot(input_text):
    index = GPTSimpleVectorIndex.load_from_disk('data/index.json')
    response = index.query(input_text, response_mode="compact")
    return response.response

if __name__ == '__main__':

    iface = gr.Interface(fn=chatbot,inputs=gr.inputs.Textbox(lines=7, label="输入你的问题"),outputs="text",title="护理智能机器人")
    ## 用于生成数据, 放在docs文件夹下
    ##index = construct_index("docs")
    iface.launch(share=True, server_name='0.0.0.0', server_port=8012)

  使用了gradio 作为演示,效果如下,基本可以根据我们的内部培训资料中回复,美中不足的就是通过要10几秒才可以完成回复,至少比之前fine-tune有了很大的进步了。至此,总算可以安抚下这半月的苦恼了。(下图中的output 如果变成自定义的文本,尝试多次一起没有成功,也是有点遗憾)

曲折的部署之路

  孟子有云:独乐乐不如众乐乐。如何让同事们一起体验,又是一个艰巨任务开始了。再则也需要让护理专家们看看回复的质量,以及如何优化文本内容。原本以为部署是一件简答的事儿,但是对于python菜-鸡的我,每一步都是坎坷。

  一开始以为直接用pyinstaller 打包就可以直接放在服务器上执行,结果 pyinstaller -F, -D 尝试很久都无法打包依赖,  --hidden-import 也用了, .spec也用了,都不好使。索性放弃了。

  到了晚上12点半时,毫无进展,索性直接放原在码放上去。结果又提示无法安装指定版本的langchain。然后开始捣腾pip版本升级到最新,python版本升级到3.10.4(和本地一样)。

  python升级后,又是提示ModuleNotFoundError: No module named '_bz2',总算是错误信息变了。这个错误大概就是原来自带中的版本中有_bz2模块,重安装的3.10中没有,解决版本都是复制这个文件到新的版本中。

mv _bz2.cpython-36m-x86_64-linux-gnu.so /usr/local/python/lib/python3.10/lib-dynload/_bz2.cpython-310-x86_64-linux-gnu.so

  再次运行终于启动了,太不容易了。配置好防火墙,腾讯云的安全组, 输入外网ip:8012,潇洒的一回车 - 还是无法访问。 借用毛爷爷的一句话描述下当下的心情:它是站在海岸遥望海中已经看得见桅杆尖头了的一只航船,它是立于高山之巅远看东方已见光芒四射喷薄欲出的一轮朝日,它是躁动于母腹中的快要成熟了的一个婴儿。加之夜确实太深了,才踏实的睡下了。

1 /usr/local/python/lib/python3.10/site-packages/gradio/inputs.py:27: UserWarning: Usage of gradio.inputs is deprecated, and will not be supported in the future, please import your component from gradio.components
2   warnings.warn(
3 /usr/local/python/lib/python3.10/site-packages/gradio/deprecation.py:40: UserWarning: `optional` parameter is deprecated, and it has no effect
4   warnings.warn(value)
5 /usr/local/python/lib/python3.10/site-packages/gradio/deprecation.py:40: UserWarning: `numeric` parameter is deprecated, and it has no effect
6   warnings.warn(value)
7 Running on local URL:  http://127.0.0.1:8012
8 Running on public URL: https://11d5*****.gradio.live

  第二天,找到gradio 中Interface.launch 的参数有个 server_name 设置成 通过设置server_name=‘0.0.0.0’ 即可通过IP访问。 通过ss -tnlp | grep ":8012" 也可以看到端口的监听从   ”127.0.0.1:8012“ 就成了 ”0.0.0.0:8012 “。

LISTEN 0      128          0.0.0.0:8012      0.0.0.0:*    users:(("python",pid=2801254,fd=7))

 展望一下

  从目前测试的情况来,每问一个问题成本在10美分左右(成本还是比较高),优化的方向可能Chunk的大小,太小无法包含住够的上下问,太大成本又比较高。再回头看Fine-tune的方式,应该是前期训练话费的成本会比较高,后期回答的成本会比较少,只是目前训练效果不太好,看其他文章也是同样的问题。从目前的情况来可能 emebedding的是一个较为合适的落地方式。

      接下看看使用的情况,如果效果不错,考虑增加语音转文字,用GPT回复答案,甚至可以再文字转语音播报出来,这样护士们的工作可能会更加便利与快乐了。

   成为一名优秀的程序员!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/475216.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Github 的使用

3. Github 在版本控制系统中,大约90%的操作都是在本地仓库中进行的:暂存,提交,查看状态或者历史记录等等。除此之外,如果仅仅只有你一个人在这个项目里工作,你永远没有机会需要设置一个远程仓库。只有当你…

嗯,这个树怎么和往常不一样?

文章目录 前言一、二叉树的链式存储二、二叉树链式结构的实现二叉树的结构设计手动构建二叉树二叉树的前序遍历二叉树的中序遍历二叉树的后序遍历二叉树的层序遍历计算二叉树大小计算叶子节点个数计算二叉树高度计算第K层的节点个数查找某个值对应的节点二叉树的销毁 三、完整代…

全球首个存量手机直连卫星天地语音通话,打通了!

4月25日,美国卫星通信初创公司——AST SpaceMobile,宣布打通了全球首个天基蜂窝语音通话。 对于卫星通信乃至整个通信行业来说,这是一个重大新闻,非常值得关注。 去年,我们还只是实现了手机和卫星之间的双向短消息通信…

Page管理机制

Page页分类 Buffer Pool 的底层采用链表数据结构管理Page。在InnoDB访问表记录和索引时会在Page页中缓存,以后使用可以减少磁盘IO操作,提升效率 Page根据状态可以分为三种类型: - free page : 空闲page,未被使用 - …

1.3 HBase 基本架构

架构角色: 1)Master 实现类为 HMaster,负责监控集群中所有的 RegionServer 实例。主要作用如下: (1)管理元数据表格 hbase:meta,接收用户对表格创建修改删除的命令并执行 (2&#x…

【C++ Primer(第5版) 课后习题题目及答案 第一章】

C Primer5th 课后习题答案 第一章 1.1:查阅你使用的编译器的文档,确定它所使用的文件命名约定。编译并运行main程序。1.2:改写程序,让它返回-1。返回值-1通常被当作程序错误的标识。重新编译并运行你的程序,观察你的系…

C#弹出消息对话框,增加输入框,接受输入信息

效果图: 代码: using Microsoft.VisualBasic;string intext Interaction.InputBox("请输入密码","输入密码","",Screen.PrimaryScreen.Bounds.Width/4,Screen.PrimaryScreen.Bounds.Height/4);MessageBox.Show("in…

多商户商城系统开发功能有哪些?

多商户商城系统开发功能有哪些? 1、商品管理。商品管理是多商户商城系统的必备功能。商家需要能够轻松地添加、修改和删除商品。这个功能还应该包括商品图片、价格、描述和库存等信息的管理。消费者也需要能够通过小程序浏览商品并下订单。 2、订单管…

图形编辑器:历史记录设计

大家好,我是前端西瓜哥。今天讲一下图形编辑器如何实现历史记录,做到撤销重做。 其实就是版本号的更替。每个版本保存一个状态。 数据结构 要记录图形编辑器的历史记录,支持撤销重做功能,需要两个栈:撤销&#xff0…

【计算机网络】学习笔记:第三章 数据链路层【王道考研】持续更新中....

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…

《编码——隐匿在计算机软硬件背后的语言》精炼——第14章(边沿触发器,计数器)

学习不是一次性的投资&#xff0c;而是一份长期稳定的收益。 文章目录 8位锁存器边沿触发器计数器改进的边沿触发器 8位锁存器 上篇文章讲到了1位存储器的组成&#xff0c;将8个1位存储器的时钟端连在一起就形成了一个8位锁存器&#xff0c;如下所示&#xff1a; 这个锁存器一…

vbscript+asp编写接口

1、前言 因为目前工作在对内网老系统用reactjava微服务进行升级改造&#xff0c;因为一些老的业务逻辑都是用vbscript编写的&#xff0c;很复杂&#xff0c;因此持久层和业务层代码不能动&#xff0c;以asp接口的形式给到数据。java接口调用asp接口&#xff0c;然后前端再调用j…

Elasticsearch --- DSL、RestClient查询文档、搜索结果处理

一、DSL查询文档 elasticsearch的查询依然是基于JSON风格的DSL来实现的。 1.1、DSL查询分类 Elasticsearch提供了基于JSON的DSL&#xff08;Domain Specific Language&#xff09;来定义查询。常见的查询类型包括&#xff1a; 查询所有&#xff1a;查询出所有数据&#xff0c…

他工作10年,老板却让他走人

大家好&#xff0c;我是五月&#xff0c;一个编程街溜子。 二狗被裁了&#xff0c;他在公司待了快十年&#xff0c;他想留下来&#xff0c;老板却让他走。 我和他一样困惑。 他985毕业&#xff0c;工作中有从0开始一个项目直到日活过千万&#xff0c;也有过参与顶级产品核心…

【数据结构】算法的时间复杂度和空间复杂度(含代码分析)

文章目录 一、算法的效率1.1 如何衡量一个算法的好坏1.2 算法的复杂度的概念 二、大O的渐进表示法三、时间复杂度2.1 时间复杂度的概念2.2常见时间复杂度计算举例 四、空间复杂度2.1 空间复杂度的概念2.2常见空间复杂度计算举例五、解决问题的思路LeetCode-exercise 总结 一、算…

【Java笔试强训 7】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;Fibona…

Android BuildConfig不生成的解决办法

为了验证一些问题新建了一个demo&#xff0c;其依赖的AGP版本是8.0.0 但是在运行过程中报了一个错误就是找不到BuildConfig。 重新build了下代码&#xff0c;然后找编译后的代码&#xff0c;发现确实没有生成BuildConfig. 给我整的直接怀疑人生&#xff0c;以为是自己的AS有问…

QT、事件处理机制

闹钟 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimer> //定时器 #include <QTime> //shijian #include <QTimerEvent> //定时器事件类 #include <QDateTime> //日期实间类 #include <QTextToSpeech> …

【C++】特殊类设计+单例模式+类型转换

目录 一、设计一个类&#xff0c;不能被拷贝 1、C98 2、C11 二、设计一个类&#xff0c;只能在堆上创建对象 1、将构造设为私有 2、将析构设为私有 三、设计一个类&#xff0c;只能在栈上创建对象 四、设计一个类&#xff0c;不能被继承 1、C98 2、C11 五、设计一个…

UNIX环境高级编程——进程控制

8.1 引言 本章介绍UNIX系统的进程控制&#xff0c;包括&#xff1a; 创建新进程、执行程序、进程终止进程属性ID——实际、有效、保存的用户ID和组ID解释器文件system函数进程会计机制 8.2 进程标识 进程ID&#xff1a;一个非负整数&#xff0c;进程的唯一标识。 进程ID可…