欢迎阅读本系列文章!我将带你一起探索如何使用OpenAI API来开发GPT应用。无论你是编程新手还是资深开发者,都能在这里获得灵感和收获。

本文将继续展示AI助手的开发方式,在OpenAPI中它的名字是Assistants。

什么是Assistants?

在之前的文章中我演示了插件的使用方法,比如查询实时天气、进行数学运算等,这些都是大模型自身做不到的事情,因此可以说插件的主要作用是扩展了大模型的处理能力。那么Assistants能干什么呢?

Assistants的主要作用是强化大模型在某方面的应用能力,比如目前已经大范围使用的AI客服和知识库助手,它们可以准确的理解用户的问题,并在限定的知识范围内进行精准回答。另外借助Assistants的能力,我们还可以做更多有趣的事情,比如让它按照指定的规范对代码进行Review,按照某种指定的风格或者模式来进行文学创作,等等。

本文我们将通过一个AI客服来演示Assistants的使用方法。先看效果:

这里我开发了一个空气净化器的AI客服,然后用户向AI客服提了四个问题,前三个问题AI都理解准确并回答正确,回答内容全部来源于产品手册,最后一个问题脱离了产品手册的内容范围,AI只能拒绝回答。

Assistants的运行原理

工欲善其事,必先知其理。在编写Assistants的代码之前,我们先要搞清楚它是怎么运行的,然后写代码的时候才能有的放矢、逻辑清晰。

请看下边这张图:

1、创建智能助手(Assistant):这一步我们要给智能助手下个定义,包括起个名字、声明它的能力、使用的大模型版本、增强能力的方式(执行代码、从知识库检索、调用外部函数)等。

2、创建用户会话(Thread):会话就是用户和智能助手之间的一次聊天,GPT可以通过会话方便的管理聊天上下文。

3、添加用户消息到会话(Message):就是用户向智能助手说的话,必须添加到会话中。

4、在会话中运行智能助手(Run):将会话和智能助手进行绑定,运行智能助手来处理用户的消息。这一步实际上会创建一个智能助手的执行对象,然后把这个执行对象添加到一个处理队列中,最终处理状态会更新到运行对象中。

5、获取GPT响应的消息(Response):通过不断检查运行对象的状态,获取智能助手的响应结果。

实现AI客服

我们这里就按照Assistant的运行原理来实现一个AI客服。

产品手册

首先我们要准备一个产品手册,随便写点什么都行,为了方便大家,可以直接下载我这个:

https://github.com/bosima/openai-api-demo/blob/main/niubiclean-book.txt

然后我们需要将这个文件上传到OpenAI,注意把文件放到程序能够访问到的地方。

niubiclean_book = client.files.create(
file=open("niubiclean-book.txt", "rb"),
purpose="assistants"
)

purpose 可选的值有两个:fine-tune 和 assistants。

创建助手

这里使用的是 client.beta.assistants.create 来创建客服,因为assistants还没有正式发布,所以这里的包空间名称中包含了一个beta,正式发布时会去掉。具体代码如下:

waiter = client.beta.assistants.create(
name="牛逼净化器智能客服",
description="24小时为您服务",
instructions="你是牛逼净化器公司的智能客服,请引用文件中的内容回答问题,表达要通俗易懂、尽量简短;若问题超出文件内容,请委婉拒绝。",
model="gpt-3.5-turbo-1106",
tools=[
{
"type": "retrieval",
}
],
# 知识文件,通过File接口上传的
file_ids=[niubiclean_book.id]
)

简单说下这几个参数:

name:智能助手的名字,随便起。

description:智能助手的简介描述,最长 512 字符。

instructions:给智能助手的指令,也就是提示词,让智能助手按照这里的提示词提供服务。这里我用了一个常见的提示词套路,让它扮演一个角色,有什么样的能力,如何回答用户的问题等。最长 32768 字符。

model:使用的GPT大模型,这里用便宜的3.5,你也可以换成GPT-4。

tools:assistants开启的工具,共有三种类型:code_interpreter、retrieval、function。

  • code_interpreter:是代码解释器,能让GPT在一个沙盒环境中执行python代码,能从文件读取数据,也能生成文件,需要通过instructions提示assistant可以执行代码。
  • retrieval:从文件检索内容,这里我们的AI客服只能根据产品手册回答问题,所以这里只开启了retrieval的能力。
  • function:和聊天插件的使用方法一样,调用执行函数,根据执行结果向用户返回内容。

file_ids:指定GPT要检索的文件Id,可以设置多个。这里设置为我们上一步上传的手册。

创建用户会话

使用 client.beta.threads.create 创建用户会话,具体代码如下。

thread_userjia = client.beta.threads.create(
metadata={
"姓名": "用户甲",
"年龄": 36,
"性别": "男"
}
)

metadata是可选的,可以设置一些附加信息,无固定属性,key-value格式即可。

添加用户消息到会话

我们其实可以在创建 thread 时初始化一些消息,不过既然要对话,演示下如何添加消息更有意义。

使用 client.beta.threads.messages.create 来创建一条用户消息,并绑定到某个会话,代码如下:

message = client.beta.threads.messages.create(
thread_id=thread_userjia.id,
role="user",
content="净化器有什么功能?",
)

这里有三个参数:

  • thread_id:消息绑定到的会话Id。
  • role:消息的角色,目前只支持 user,只能向其中添加用户消息。至于完整的聊天上下文,GPT内部会自动维护。
  • content:消息内容,这个很好理解。

在会话中运行智能助手

使用 client.beta.threads.runs.create 来运行智能助手,代码如下:

run = client.beta.threads.runs.create(
thread_id=thread_userjia.id,
assistant_id=waiter.id,
)

这里有两个关键的参数:

  • thread_id:要在哪个会话中运行智能助手。
  • assistant_id:要运行哪个智能助手。

这里还有一些其它的参数,比如model、instructions、tools等,使用它们会覆盖我们在创建 assistant 设置的参数。

获取智能助手的回应

运行智能助手后得到的返回值 run 是一个对象,代表运行在会话中的一个执行,这个执行是通过队列异步处理的,我们不能立即得到执行结果,需要定期检查 run 的状态,处理完毕了才能获取到GPT的回应消息。

先看检查状态的处理:

while run.status == "queued" or run.status == "in_progress":
time.sleep(1)
run = client.beta.threads.runs.retrieve(
thread_id=thread_userjia.id,
run_id=run.id,
)

run 有多个状态: queued, in_progress, requires_action, cancelling, cancelled, failed, completed, expired,这个例子中如果不是 queued 或者 in_progress 状态就代表已经有结果了。requires_action 是智能助手使用 function 工具时才会存在的状态,这个例子不涉及。

状态

含义

queued

创建run之后 或者 使用function时确定了要调用的function及其参数 之后,就会进入这个状态,这个状态很短,马上会进入 in_progress状态。

in_progress

使用模型或者tools处理消息。

completed

本次运行成功完成,可以读取GPT响应的消息了。

requires_action

使用function时,一旦模型确定要调用的function及其参数,run将进入这个状态。

expired

function执行的时间太长或者整个run运行的时间太长,达到了过期阈值(大约10分钟)。

cancelling

可以在queued和in_progress状态时发起取消,将进入这个状态。

cancelled

已成功取消。

failed

您运行失败了,可以在 run.last_error 中获得失败原因。

使用 client.beta.threads.messages.list 获取GPT响应消息,代码如下:

 if run.status=="failed":
print(run.last_error.message)
else:
messages = client.beta.threads.messages.list(
thread_id=thread_userjia.id, order="asc", after=message.id
)
print("牛逼智能客服:",extract_message_content(messages.data[0]),'\n')

获取响应消息时用到了3个参数:

  • thread_id:会话Id。
  • order:消息排序,asc代表正序,也就是先产生的消息在前边。
  • after:指定消息的起始位置,因为我们要获取GPT针对某条用户消息的响应,所以这里通过after指定获取某条用户消息之后的消息,也就是GPT的响应消息。

最后我们还使用了一个函数来提取消息内容:extract_message_content,代码如下:

def extract_message_content(message):
# Extract the message content
message_content = message.content[0].text
annotations = message_content.annotations # Iterate over the annotations and add footnotes
for index, annotation in enumerate(annotations):
# Replace the text with a footnote
# print(annotation.text)
message_content.value = message_content.value.replace(annotation.text, ' ') return message_content.value

注意这里有一个annotation的概念,中文就是注解的意思。因为AI客服生成的内容可能来自多个产品文档,有了注解,用户就可以通过它跳转到相关的文档进行详细阅读。这个和论文中的引用注解是同一种方式。

不过我们这里的产品手册比较简单,所以就把注解都替换成空字符串了。完整的处理方法可以参考下边这个:

# Extract the message content
message_content = message.content[0].text
annotations = message_content.annotations
citations = [] # Iterate over the annotations and add footnotes
for index, annotation in enumerate(annotations):
# Replace the text with a footnote
message_content.value = message_content.value.replace(annotation.text, f' [{index}]') # Gather citations based on annotation attributes
if (file_citation := getattr(annotation, 'file_citation', None)):
cited_file = client.files.retrieve(file_citation.file_id)
citations.append(f'[{index}] {file_citation.quote} from {cited_file.filename}')
elif (file_path := getattr(annotation, 'file_path', None)):
cited_file = client.files.retrieve(file_path.file_id)
citations.append(f'[{index}] Click <here> to download {cited_file.filename}')
# Note: File download functionality not implemented above for brevity # Add footnotes to the end of the message before displaying to user
message_content.value += '\n' + '\n'.join(citations)

完整示例

我在完整的示例程序中向智能助手循环提出了四个问题,每个问题都需要重新创建一个run,然后再检查状态,获取响应结果。

需要完整代码的同学请访问Github:

https://github.com/bosima/openai-api-demo/blob/main/assistants_demo.ipynb


以上就是本文的主要内容,有兴趣的同学快去试试吧,效果绝对震惊你的小伙伴!

如需GPT账号、学习陪伴群、AI编程训练营,推荐关注小册:大模型应用开发 | API 实操

关注萤火架构,加速技术提升!

大模型应用开发:为产品创建一个AI客服/智能助手的更多相关文章

  1. Android Wear 开发入门——怎样创建一个手机与可穿戴设备关联的通知(Notification)

    创建通知 为了创建在手机与可穿戴设备中都能展现的通知,能够使用 NotificationCompat.Builder.通过该类创建的通知,系统会处理该通知是否展如今手机或者穿戴设备中. 导入必要的类库 ...

  2. Delphi for iOS开发指南(3):创建一个FireMonkey iOS应用程序

    http://cache.baiducontent.com/c?m=9d78d513d9d431a94f9d92697d60c015134381132ba1d0020fa48449e3732b4b50 ...

  3. ItelliJ IDEA开发工具使用—创建一个web项目

    转   http://blog.csdn.net/wangyang1354/article/details/50452806 最近想用IDEA编辑器开发,但是平时都用MyEclipse和eclipse ...

  4. ItelliJ IDEA开发工具使用—创建一个web项目(转)

    最近想用IDEA编辑器开发,但是平时都用MyEclipse和eclipse习惯了,突然间用IDEA到处碰壁的感觉.在不断的摸索之后终于苦尽甘来,学会了基本的web程序如何创建以及运行了.期间在网上找了 ...

  5. 是时候给你的产品配一个AI问答助手了!

    本文由云+社区发表 | 导语 问答系统是信息检索的一种高级形式,能够更加准确地理解用户用自然语言提出的问题,并通过检索语料库.知识图谱或问答知识库返回简洁.准确的匹配答案.相较于搜索引擎,问答系统能更 ...

  6. 百度AI开放平台 UNIT平台开发在线客服 借助百度的人工智能如何开发一个在线客服系统

    这段时间在研究一些人工智能的产品,对比了国内几家做人工智能在线客服的,有些接口是要收费的,有些是免费的,但是做了很多限制,比如每天调用的接口次数限制是100次.后来就找到了百度的AI,大家也知道,目前 ...

  7. 动手实践记录(利用django创建一个博客系统)

    1.添加一个分类的标签,和主表的关系是 外键 class Category(models.Model): """ 分类 """ name = ...

  8. (原创)用.NET Core实现一个在线客服系统(上篇)

    前言 没有视频的介绍显得尤为空白仓促.所以,如果你不赶时间,看看视频先 → → 戳我看视频 ← ←  在线演示访客端:http://role.fuyue.xyz/visitor/index客服端:ht ...

  9. AI人工客服开发 小程序智能客服 智能客服微信小程序 智能客服系统怎么做 如何设计智能客服系统

    今天我们就来给大家分享下如何做 小程序的智能客服问答系统. 首先请确保你的小程序在线客服已经开通使用,并使用代码自己对接好了,将客户的提问自动做了拦截,拦截到了你自己开发的接口上. 做好了拦截以后,我 ...

  10. 创建一个新的解耦的Orchard Core CMS网站

    引言本文将介绍创建一个功能齐全.解耦的CMS网站的过程,该网站允许您编辑博客帖子并呈现它们.解耦是一种开发模型,其中站点的前端和后端(管理)托管在同一个Web应用程序中,但只有后端由CMS驱动.然后, ...

随机推荐

  1. 超90万个K8S实例可被发现暴露在公网上,14%位于中国

    翻译: SEAL安全 原标题: Over 900,000 Kubernetes instances found exposed online 原文链接: https://www.bleepingcom ...

  2. 超详细的 Jenkins 安全tips

    Jenkins 作为一个开放的.可定制的平台,即使在默认状态下也提供了不错的安全性.但是鉴于 Jenkins 连接了许多行业工具,因此也存在一定安全隐患.本篇文章将会介绍一些方法和工具,来确保 Jen ...

  3. 火山引擎 DataTester:如何用 A/B 测试做产品增长?

    技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 随着如今越来越高的获客成本,用户拉新变得不再容易:而且由于获客成本的增高,让用户留存也变得更加重要.同时,一个产品的使 ...

  4. cxf 动态调用 WebService No compiler detected, make sure you are running on top of a JDK instead of a JRE

    WebService cxf No compiler detected, make sure you are running on top of a JDK instead of a JRE [202 ...

  5. MVCC多版本并发控制和幻读问题的解决

    首先我们先介绍一下锁的分类,再进入今天的正题. 一.锁分类: 1.从性能上分:乐观锁.悲观锁.乐观锁(用版本号对比或CAS机制)适用于读比较多的场景,悲观锁适用于写比较多的场景.如果在写比较多的场景使 ...

  6. 【Django-Vue】手机号是否存在接口 多方式登录接口 腾讯云短信介绍和申请 api与sdk

    目录 昨日回顾 今日内容 0 登录注册功能设计 1 短信登录接口 视图类 2 多方式密码登录接口 视图类 序列化类 路由 3 腾讯云短信介绍和申请 3.1api与sdk 补充 练习 昨日回顾 # 你的 ...

  7. 【HZERO】feign调用

    feign调用 https://open.hand-china.com/community/detail/603204901962649600 # Hiam获取用户信息示例

  8. 【OpenSSL】​Visual Studio 2019配置OpenSSL 3.0开发环境

    OpenSSL从1.0.2版本升级为3.0.3版本后,需要对代码进行重构.如果不可用的代码太多,需要重新开一个项目.重新配置开发环境. [第一步]登录http://slproweb.com/,下载Wi ...

  9. Ubuntu20.04上安装MySQL8.0(绝对保证能够正常使用)

    今天在学习 Spark 连接 MySQL时发现还没安装,便参考了厦门大学实验室的Blog进行操作.但安装完成之后发现没有显示设置密码的选择,但又改不掉root密码(头开始痛起来). 故记录一下安装My ...

  10. OJ中的语言选项里G++ 与 C++的区别

    概念上: C++是一门计算机编程语言,而G++则是C++的编译器. GCC和G++都是GUN的编译器,cc是Unix系统的C Compiler,而gcc则是GNU Compiler Collectio ...