提起长连接,我们并不陌生,最常见的长连接非websocket莫属了。即使没有在项目中实际用过,至少也应该有所接触。长连接指在一次网络通信中,客户端与服务器之间建立一条持久的连接,可以在多次请求和响应中重复使用该连接。这种方式的优点是减少了连接建立和关闭的开销,提高了通信效率,但需要注意控制连接的数量,避免资源浪费。短连接则是每次请求和响应都建立一个新的连接,完成后立即关闭,需要频繁进行连接建立和关闭,效率相对较低。但是这种方式更加灵活,适用于请求量较小、请求频率不高的场景。
最近项目在引用ChatGPT智能小助手,最开始采用的是当ChatGPT回答完成后一次性返回答案。但这种方式受限于网络及服务较慢的原因导致用户需要等待较长时间,极大的降低了用户的使用体验。经过项目组成员商议决定采取答案逐字返回的形式,以便于用户能更快的得到反馈。?
关于长连接技术,主要考虑两种方案websocket和sse
1.websocket概念:WebSocket是HTML5定义的新协议,实现了服务器与客户端之间的全双工通信。WebSocket连接一旦建立,客户端和服务器端处于平等地位,可以相互发送数据,不存在请求和响应的区别。
?2、websocket优劣势:优势在于实现了双向通信,劣势在于服务器端的逻辑非常复杂。现在针对不同的后台语言有不同的插件可以使用。
3、sse概念:SSE(Server-Sent Events)是HTML5新增的功能,允许服务器将数据推送到客户端。与长轮询和短轮询不同,SSE不需要客户端先发送请求,而是在服务器端数据有更新时立即发送到客户端
4、sse优劣势:优势在于节约资源,提升应用性能。SSE可以实现只要服务器端数据有更新,就可以马上发送到客户端,不需要建立或保持大量的客户端发往服务器端的请求。另外,SSE的实现非常简单,并且不需要依赖其他插件。劣势在于不是双向通信,只能后台向前台推送。
5、相同点:都是基于tcp,都是可靠的传输协议
6、不同点:
1、sse在chatgpt中的应用
前端代码
import { fetchEventSource } from '@microsoft/fetch-event-source'
let answerContent=''
fetchEventSource('/chatgptApi/chatgpt_qa_stream', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ messages }),
async onopen(response) {
if (response.ok && response.status===200) {
console.log('连接成功')
} else {
console.log('连接异常')
}
},
async onmessage(event) {
// 表示整体结束
if (event.data==='[DONE]') {
console.log('结束')
return
}
if (event.data) {
const data=JSON.parse(event.data)
answerContent +=data.content
}
},
async onerror(error) {
console.error('Error:', error)
},
async onclose() {
console.log('关闭连接')
}
})
后端代码
const http=require('http');
const yun=express();
const eventServer=http.createServer((req, res)=> {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': "*",
'Access-Control-Allow-Headers': 'Content-Type,Content-Length,Authorization,Accept,X-Requested-With',
'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS'
});
setInterval(()=> {
// 事件要用两个\n结束
res.write('data: The server time is: ' + new Date() + '\n\n');
}, 1000);
req.connection.addListener('close', ()=> {
console.log('SSE connection closed!');
}, false);
}).listen(4001);
??2、websockt在即时聊天中的应用
前端代码
// 创建WebSocket对象
let ws=new WebSocket('ws://localhost:8888')
// 连接成功后的回调函数
ws.onopen=function (params) {
console.log('客户端连接成功')
// 向服务器发送消息
ws.send('hello')
};
// 从服务器接受到信息时的回调函数
ws.onmessage=function (e) {
console.log('收到服务器响应', e.data)
};
// 连接关闭后的回调函数
ws.onclose=function(evt) {
console.log("关闭客户端连接");
};
// 连接失败后的回调函数
ws.onerror=function (evt) {
console.log("连接失败了");
};
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,这样服务端会抛异常。
window.onbeforeunload=function() {
ws.close();
}
后端代码
/ 引入插件
const ws=require('nodejs-websocket')
// 只要有用户链接,函数就会执行,会给当前链接的用户创建一个connect对象
const server=ws.createServer((connect)=>{
console.log('连接成功')
// console.log(connect)
// 注册text事件 ,接收用户传递过来的数据
connect.on('text',data=>{
console.log('接收客户端数据---->', data)
// 给所有用户发送消息
broadcast(server,data+"--返回数据")
})
// 连接断开,触发事件close
connect.on('close',()=>{
console.log('用户链接断开--close')
})
// 用户链接断开
connect.on('error',err=>{
console.log('err', err)
})
}).listen(3001,()=>{
console.log('websocket服务启动成功了')
})
// 给所有人发消息
function broadcast(server,msg){
server.connections.forEach(element=> {
element.send(msg)
});
}
sse在chatgpt案例中的应用
作者:京东物流 田雷雷
来源:京东云开发者社区 自猿其说Tech
I激荡70载,身处操作系统演变的中心位置,在ChatGPT、文心一言等AIGC产品,GPT-4、Stable Diffusion、Midjourney等AI大模型的加持下,程序员现有的编程范式将会遭到怎样的冲击?面向的全新AI应用时代,开发者的思维、开发方式、工具又该做出怎样的改变?
继“新程序员:人工智能新十年”大会探讨程序员进入下一个AI十年的准则之后,3月25日,CSDN、《新程序员》联合主办的“新程序员大会(NPCon):AIGC 与大模型技术应用峰会”于北京环球贸易中心正式拉开帷幕。
在本次大会上午场的主论坛现场,CSDN创始人&董事长、极客帮创投创始合伙人蒋涛,创新工场AI工程院执行院长、SeedV实验室创始人王咏刚,华为云智能化软件研发首席专家王千祥,42章经创始人曲凯,在CSDN副总裁邹欣的主持下,就技术人如何利用通用人工智能、ChatGPT、AIGC、大模型、AI编程等重要话题,给出了干货满满的解答。
直播回放:https://live.csdn.net/room-iframe/programmer_editor/2OmZkkQB
以下是“AIGC与大模型技术应用峰会”主论坛的演讲精华。
GPT是人工智能时代的Windows
在CSDN创始人&董事长、极客帮创投创始合伙人蒋涛发表的《大模型时代的新应用开发者》主题演讲中,他提出AI时代的到来,为开发者产业带来了三大红利:人人都是开发者,家家都是技术公司,万亿技术云大生态。
CSDN创始人&董事长、极客帮创投创始合伙人 蒋涛
据蒋涛介绍:“CSDN的最新开发者数据也证实了这一点。目前CSDN注册用户数超过4200万,去年新增了600万用户,新增用户中有60%都是大学生和高中生,高校计算机专业学生覆盖度90%,非常的年轻化。”
事实上,技术的演进所经历的阶段宛如一个轮回,回顾2011年,全球化移动应用市场大门打开之际,掘金海外还是瞄准国内市场、专注iOS还是Android亦或者是HTML5跨平台开发等都成为开发者抉择的方向。
12年后,开发者再次站在选择的十字路口,正如技术社区三倍速定律所彰显的那样,“一个技术要进入到真正的生态应用里,首先是在学术界被大家认可,接着进入到工程界,最后才进入大众视野。因此技术社区的动向往往能反映出未来的技术趋势”。从数据中,可以明显感知到GPT正在以前所未有的速度成为人工智能时代的Windows,AI发展也正处于iPhone 4时刻。
而为真实呈现ChatGPT等自动化编程工具对开发者的影响,蒋涛也分享了CSDN 最新上线的AI编程测试方法。同时,在大会现场,CSDN面向所有用户群体,重磅发布了一款快速开发GPT应用工具——InsCod(https://inscode.csdn.net)。
最后,蒋涛对于想要加入这场AI浪潮的开发者建议道,首先要去学表达,学会善用Prompt;第二要学英文,因为前沿技术的英文资料更新速度更快;第三,发挥想象力,开始行动。
学会Prompt,就能完成AI开发?
“我发现我们这些老一代程序员今天被AI技术的发展拉到了一个和刚毕业的大学生一样的门槛上,我不认为我做了十几年的自然语言处理技术,比一个今天刚毕业的大学生使用ChatGPT、GPT开发的应用有任何优势,这是一个我非常焦虑的时代和时刻”,创新工场AI工程院执行院长,SeedV实验室创始人王咏刚在主论坛上如是说道。
创新工场AI工程院执行院长,SeedV实验室创始人 王咏刚
王咏刚表示,今天所有的计算机、系统都会被 AI 去重新改写,重新定义。这也引发了无数人思考:未来的程序员真的会被简化为提示词的编写员吗?然后由提示词操纵 AI?是不是这样一个非常简单的范式,就可以总结未来所有的 AI 开发?
就个人观点来看,王咏刚给出了否定的答案,其表示,“未来的 AI 开发应该是一种多范式的开发流程”。在他看来,世界上的任务天然地分为两类,一类是天生的不确定性任务,一类就是天生的确定性任务。这也让未来 AI 编程呈现出两种典型的范式:
第一种编程范式是适用于端到端的感知类任务、创造性任务、探索性任务,它可以通过提示词得到结果。
第二个范式是强调控制力、结果确定性、计算精准性的应用任务。在这个任务里面,我们不能放任所有的事情都交给大模型一次来解决问题,大模型可能需要通过引入插件的方式,调用非常多的后台服务。
最后,王咏刚也分享道,“人类工程师在这个范式里被降级了,我觉得没办法,我们只能承认我的命运,我们也只能去拥抱这个时代,所以现在的我们,应该尽量少说话,早日开始行动起来。”
AI编程的边界在何处?
紧接着,华为云智能化软件研发首席专家王千祥在发表《AI编程:无尽的前沿》主题演讲中表示,AI编程基于GPT的代码生成取得了很大的突破。
华为云智能化软件研发首席专家 王千祥
在王千祥看来,GPT代码生成原理主要分为两个阶段:训练阶段,关键问题在于学什么和怎么学;生成阶段,通过自然语言输入,经过线上GPT模型,然后生成代码。
对于AI编程的边界究竟在哪里,王千祥通过GPT-4技术报告和微软研究院的报告发现,AI大模型在多数情况下超越了人类的编程能力,但是其距离顶尖程序员还有很大的差距。
王千祥认为,AI编程肯定会超越Coding编程,因为现有的ChatGPT、GPT-4大模型工具的能力覆盖到了代码补全、翻译代码、解释代码、DeBug等多个维度。未来,这些工具必将覆盖到设计、搜索、迁移、运营等多流程中。
同时,王千祥也希望AI编程背后的新模型可以将统计方法与规则方法(常识)融合起来,并能适时地进行反馈学习,以及通过健康的生态得到良好的发展。
用生成式AI打通商业
在ChatGPT、大模型彻底改变开发者编程方式之际,大家可以用它实现出什么,站在需求的角度来看,42章经创始人曲凯带来了《生成式 AI 的商业化落地思考》的主题演讲。
42章经创始人 曲凯
他认为,中国肯定会有自己的大模型,也可以有。因为可以把大模型这个事情定性成为一个工程问题,而不是一个技术问题,发现新大陆难,抵达新大陆实则没那么难。
具体来说,现如今大模型主要带来了三个维度的能力与改变:
在实际的落地场景和机会上,曲凯认为简单讲不外乎这三类:大模型、中间层、应用层。其中,最大的机会集中在应用层:
不过,在开发者、企业尝试过程中,曲凯也分享了可能会面临的五大壁垒,包括:自己做大模型、自己有私有化数据、用户使用过程中有数据飞轮效应、用户有网络效应、有复杂的业务流系统等。
圆桌对话:ChatGPT 大航海时代
在上午主论坛的圆桌对话环节,由CSDN战略合作总监闫辉主持,CSDN 创始人&董事长、极客帮创投创始合伙人蒋涛,创新工场 AI 工程院执行院长、SeedV 实验室创始人王咏刚,华为云智能化软件研发首席专家王千祥,42 章经创始人曲凯作为嘉宾的圆桌对话正式展开,五位技术专家以“ ChatGPT 大航海时代”为主题,共论 ChatGPT 开辟的新领域、新应用、新机遇。
“我特别同意这是一个ChatGPT大航海时代,这是一个新时代的开始,如果再加一点,我觉得这不是一个在地球上的大航海时代,而是一个星际旅行的大航海时代”,创新工场 AI工程院执行院长、SeedV 实验室创始人王咏刚分享道。
他表示,人类发现美洲之后,然后在上面去建工厂、做开发,包括美国的西部大开发,实际都是以欧洲规则来进行的。因此,这也有可能引发一些担忧,目前大家用GPT开发程序,都是在PC、移动终端上进行开发,以及遵循相关的规则。不过,再过3-5年规则有可能会发生变化。宛如在星际旅行时,到了一个星球,这个星球可能像在电影上看到了,它可能特别接近一个黑洞,它的引力场、时间、行为全都不一样了,在这个时候,如果开发者的应用开发还在按照在移动时代、PC时代那样的方式继续做,可能就不适用了,这是3-5年后可能会出现的局面。
当谈及在开辟出大航海时代之后,ChatGPT反向会推动哪些维度进步时,CSDN创始人&董事长、极客帮创投创始合伙人蒋涛表示,GPT的能力汇集了所有的知识库,此时人类与它比拼的不是已有的知识,而是看它能否为我们产生新的知识,当然,这里新的知识并不是说让GPT写一篇科幻小说等等。更为重要的是,如果它的增量是科学发现,那么,我们现在社会的进步都是无尽的前沿。因此,他认为,未来我们可能会经历3-5年的前GPT时代,GPT会通过人类的提示等不断改进,但是5年之后,也许GPT会产生我们根本无法想象的事情,就如十几年前,众人无法想象出现在我们使用智能手机的现状。
华为云智能化软件研发首席专家王千祥则认为,ChatGPT 中可以将不同语言之间实现无缝转换的功能,具有两面性。一方面,大航海时代的确促进了很多交流;另一方面,也导致强势文化更强,有很多弱势文化可能被压缩了。这一点在大模型方面也是类似的,包括我们在训练大模型时,有时用中文语料训练的效果不行,但带上英文的效果就好。所以,ChatGPT 到来对我们文化影响力如何,还是需要持两面看待。
对于未来可能会创造的机遇,42章经创始人曲凯表示,“很多东西在当下是很难推出来的,就像十年前,我们很难想到现在最流行的应用是抖音之类的产品、最早的小红书只不过就是一个PDF……因此,我认为当前大家需要做的就是,先用起来,不用想那么多,还是站在用户需求的角度,看看当下的技术到底能实现什么东西,在这个过程当中再不断去调整。”
除了对大模型技术和AI新时代开发者未来发展的思考,在本次AIGC与大模型技术应用峰会上,我们还特设了“AIGC与大模型技术应用”与“AI编程技术应用”两大论坛,以及ChatGPT应用创新营特色活动。
分论坛1:大模型是通往AGI的必由之路吗?
其中,在“AIGC与大模型技术应用论坛”上,五位深入大模型应用的产业界代表分别带来了他们对于AIGC和大模型的思考,以及行业多年的实践经验,深入展现国内大模型技术生态。
首先带来演讲的是文因互联工程VP兼首席科学家宋劼。在她看来,ChatGPT的出现宣示着新的人工智能发展契机的到来。具体到金融领域,她发表了《探索新技术之大模型在金融AIGC领域的前景与应用》的主题演讲。
文因互联工程VP兼首席科学家 宋劼
“在过去一段时间内,我们主动、被动接受到了有关ChatGPT和AIGC的各类讨论,大多围绕趋势、影响等维度展开。在强监管背景下,ChatGPT在金融领域落地有哪些局限性?金融机构应该如何构建自己的优势,以应对当下发展 ?”
在本次分享中,宋劼从技术分析及场景应用方面,对AIGC商业化落地的可行性和路径进行探讨,从中寻找可能的业务增长点。
此外,在宋劼看来:“金融领域的大模型终将实现,我们会成为整个历史浪潮中微小但有力的一份子。哥伦布就曾经错误地认为自己到达了印度,但他开辟的新航路依旧影响了全人类。无论这一次科技浪潮的最后能否完全实现通用人工智能(AGI),我们都已经走出了重要的一步。”
紧接着,来自网易伏羲实验室的资深研究员,NLP研究组及多模态算法负责人张荣升,以多年在这一技术领域的积累发表了《文本及多模态预训练技术的研究与应用》的演讲,介绍了网易伏羲在大模型上的技术积累,包括文本、多模态理解和生成预训练模型的建设,同时分享了大模型在歌词辅助创作、智能对话、文字游戏、互联网搜索推荐、AI绘画等落地场景的应用。
“ChatGPT的交互方式是大众化的,它真正理解使用者意图的能力也是革命性的。预训练模型在未来的趋势会朝多模态方向发展,大模型的使用会越来越流行。”张荣升如是表示。
网易伏羲实验室资深研究员,NLP研究组及多模态算法负责人 张荣升
超对称技术首席科学家吴恒魁则在演讲中基于“重整化理论”,对大语言模型的涌现现象建立数学框架。据他表示,超大参数语言模型遵循scaling law,即将参数和训练量扩大,能看到模型产生接近人类的逻辑和复杂推理能力,这样的现象属于复杂系统的涌现。而通过提出基于统计力学的连续相变理论来解释语言模型的涌现行为,为引入量子场论的重整化机制建立数学框架,这是他此次演讲的主要内容。
“大模型出现人类级别的逻辑和复杂推理能力是一种涌现行为,而随着模型复杂度增加,预测下一个词的GPT模型可能遵从“连续相变”的规律出现新的涌现行为。”吴恒魁讲道。
来自华院计算人工智能实验室资深研究员蔡华,在本场论坛发表了《让数字人更具个性和情感:ChatGPT技术的思考启示》的演讲。
他的演讲聚焦在ChatGPT为通用语音技术带来的变革上,其中的重点便是如何能够为数字人赋予个性和情感。同时,以华院计算实施的具体实践为例,说明了对话式框架的搭建,以及如何将对话与知识融合。同时,也指出了知识图谱如何能够让对话交互变得有感情和富有个性。
华院计算人工智能实验室资深研究员 蔡华
“大模型提供了更强大、更智能的交互方式,让虚拟数字人更有温度。未来的数字人将能理解他人的感受和情感,与他人进行个性化的互动。”蔡华表示。
最后,本场论坛主持人,句子互动创始人 & CEO,微软人工智能最具价值专家 (AI MVP)李佳芮从开发者切实应用的角度,说明了她对于ChatGPT如何从0到1的构思,从技术原理、发展背景、应用场景和prompt等多个角度,说明了未来AGI时代的开发者需要哪些思维和技能。
句子互动创始人&CEO,微软人工智能最具价值专家 (AI MVP)李佳芮
“工业革命解决了‘重复体力劳动’的事情,人工智能未来解决‘重复脑力劳动’的事情。对话式人工智能已经到来,人类最终会与AI「共生」,让机器做机器擅长的事情,让人类发挥人类的特长,让人工智能拓展人类智能。”李佳芮最后总结道。
从AIGC、大模型,到通用人工智能 主题圆桌对话
了解更多,请查看回放链接:
https://live.csdn.net/room/programmer_editor/Nc8cfWuo
分论坛2:AI编程的现状与未来
另一场主题为“AI编程技术应用论坛”主要为给开发者提供更多产学研界的前沿技术和实践案例。为此,论坛邀请到五位深入AI编程的卓越开发者,分享他们技术实践。
首先,由微软亚洲研究院高级研究工程师卢帅带来主题为《基于预训练的代码理解与生成》的讲解。他的演讲聚焦于“代码智能”,包括剖析基于人工智能技术的自动化程序理解和生成极大地提高程序开发者的生产力,如何开发出大规模通用预训练模型,并将其使用到软件开发生命周期的各个方面,包括代码补全、代码搜索、代码审查、缺陷检测及修复等方面。
微软亚洲研究院高级研究工程师 卢帅
“未来AI编程的发展趋势是一方面探讨如何利用大模型来完成任务,另一方面思考如何进化它,以覆盖更广泛的智能代码场景。”卢帅如是表示。
接着,aiXcoder联合创始人郝逸洋分享了大语言模型时代下应该如何进行代码的生成。包括如何利用LLM的技术进行代码开发辅助、代码模型和自然语言模型的区别,以及对交互式多模态LLM(如ChatGPT,GPT4)加持下的智能化软件开发的畅想。
在他看来:“如果 AI 作为操作系统可以直接控制硬件,程序员就能解放双手去编写驱动、操作系统和软件或是研发新的硬件,这就是软件 3.0 的图景。”
aiXcoder联合创始人 郝逸洋
华为云PaaS技术创新LAB 技术专家申博基于华为云CodeArts Snap的实践,作了《GPT-4时代,重新思考AI编程》的分享。他的思考涉及包括生成式AI能做什么、边界在哪里,以及如何落地实现的各个方面。在他看来,我们需要重新思考AI编程,通过与现有工具的结合,软件分析及语言模型的实现,未来增强型的AI编程助手一定会出现。
华为云PaaS技术创新LAB技术专家 申博
“当模型越来越大,对硬件性能要求越来越高,有可能会遇到“数据荒”的问题,我们能否让 AI 自我演进,通过自我生成数据的方式学习,以达到与大数据同样的效果?未来自我创造智能是个有前途的方向。”申博表示。
来自清华大学知识工程实验室研究助理郑勤锴则分享了关于CodeGeeX的实践。和很多大模型是通过海外的架构和硬件进行训练不同,CodeGeeX最大的特点是通过国产AI框架和硬件来实现训练,减少了核心技术被卡的风险。在本次报告中,郑勤锴分享了这款插件自动代码生成与预训练模型的产生背景、如何进行模型实现、VS Code与JetBrains IEDs插件介绍与功能,以及未来开源开发计划等方面。
关于程序员需要提升的能力,郑勤锴认为,“在将来,程序员需要具备一些更高级的技能和思维,比如Geek(极客)思维,开发者应该更加注重这方面的培养。”
清华大学知识工程实验室研究助理 郑勤锴
最后,中国科学院软件研究所研究员、博士生导师王俊杰,分享了基于Pre-trained Large Language Model(LLM)的软件自动化测试的主题演讲,包括指出自动化测试仍存在哪些导致效率低下的问题,以及如何利用大规模的预训练模型来自动生成测试输入等。
中国科学院软件研究所研究员、博士生导师 王俊杰
“现在的大模型可能有些时候对开发人员来说有点‘不太专业’,但对测试人员来说‘刚刚好’。”王俊杰如此表示。
AI编程现状与未来,成就大模型时代应用开发者 主题圆桌对话
了解更多,请查看回放链接:
https://live.csdn.net/room/csdnlive5/CCEAhsEs
同时,随着人工智能和大数据技术的不断发展,AIGC和大模型技术已经成为了各行各业的重要发展方向。在本次AIGC与大模型技术应用峰会上,我们还特设了ChatGPT应用创新营特色活动。
ChatGPT应用创新营活动现场
小组讨论
此次,我们深入探讨了大模型技术对开发者的影响与潜在的研发应用场景、未来发展趋势,也不难看出,我们正在AIGC、大模型的引领下站在AI智能感知阶段的C位,而属于AIGC、大模型的时代也才刚刚开始。
未来,我们也期待AIGC和大模型技术将为我们带来更加智能化和高效化的工作流程、更加精准和个性化的服务、更加安全和可靠的系统,以及更加优秀和有趣的人机交互体验。
在去年年底 ChatGPT 刚火的时候我就有一个想法,它能不能帮我读一下晦涩难懂的保险条款,告诉我它到底在讲什么?到底什么病能赔多少钱?甚至能告诉我里面是不是藏有一些坑?但是当我把条款内容复制到 ChatGPT 时,我们会发现,它直接告诉你:“太长了,它受不了”。
当我们自己打开 openai 的文档,我们才明白:哦,原来它接受的最大长度是 4096个 tokens。但这个 一个 token 到底是多长呢?暂时还不知道,反正就是有这么个上限。很显然,我们的保险条款远远的超过了它的上限,因为我才复制两三页的内容它就 Error 了。
但我们还是纳闷,不应该啊,ChatGPT 不应该很强吗?它的官方例子可是摆了几十个案例,看网上的各种文章,它似乎在文字与编码领域,远超绝大数人类,怎么会连个保险条款都无法承受。
我想从这个案例中看看有没有其他路子,可惜确实没有合适的案例能解决我这种超长文本的诉求。于是我停止了这个想法,并先回家过了个快乐的新年。
但在最近,在我的不屑但可能没啥意义的努力下,我几乎完成了这个想法。先放几个截图给大家看看。
问蚂蚁爆款「好医保长期医疗」几个问题的答案:
问市面上很火的「达尔文7号重疾」的问题及答案:
如果你仔细看,你会发现,它已经能非常准确的回答这几个很多保险小白常问的问题了。那我到底是怎么实现的呢?这篇文章来一探究竟。
在我开始正文之前,先让 ChatGPT 跟大家做个简单介绍。
所以本文标题其实不对,准确说应该是「如何让 openai 的 API 帮我读懂保险条款」。因为我其实是调用了 openai 提供的 API 能力来满足需求的。更准确来说是调用了其 GPT-3 的一些模型,而不是挂代理直接问 ChatGPT。但为了大部分读者容易理解,就先取一个不恰当的标题了。
后文中,我将会以 GPT 通用指代我所调用的 openai 的 API 服务。
话说在新年回来后,ChatGPT 仍愈演愈烈,因此我又来了点儿兴趣,并尝试把 GPT 接入我一个年久失修的个人公众号。就在这个接入的过程中,为了解决接入遇到的不少问题,我看了不少文档。果然是开卷有益,实干兴邦啊。过程中我又接触学习了一些有用知识。其中最重要的是两个点知识:
其一是:GPT 的多轮对话是如何实现的?其实很简单,就是把历史对话都存起来,然后按照时序重新拼接,再加上这次的问题,合并一起作为 prompt再传给 GPT 即可。
其二就是,如何让 GPT 理解超长文本知识并做问题回答?我在逛 openai 官方文档的时候,发现了其实人家早早就想到了这个问题,并贴心的准备好了教程文档。这在我上一篇 ChaGPT 的文章中也已提到:公众号如何快速接入 ChatGPT & DALL.E
How to build an AI that can answer questions about your website:https://platform.openai.com/docs/tutorials/web-qa-embeddings
Question Answering using Embeddings:https://github.com/openai/openai-cookbook/blob/main/examples/Question_answering_using_embeddings.ipynb
它的思路其实很好理解,详细来说,主要是分几步:
原来如此,那么我只要把保险条款分段向量化,再根据用户提问匹配到相应的那段内容再回答不就好了吗。简单,上手吧。
这个问题似乎正如「把大象放入冰箱」。描述起来很简单,真正要做起来就举步维艰。
在我们面前最大的问题就是,到底怎么把这个文档做分割?
最简单的方案自然是,把保险条款按页码一页一页分块,如果一页内容也超了,那我们就半页半页分块。但这忽略了一个最大的问题,就像大象的各个器官并非水平均分分布一样,知识内容并非是按页码分割的。一个知识可能第三页正好起了个标题,第四页才是详细的描述。而向量化匹配的时候,却可能只匹配到第三页的内容。比如这个「好医保长期医疗」的责任免除条款,就很容易丢失下半部分的免除责任,造成回答准确性降低。
除此外,这样的分割还容易让 GPT “学坏”。因为粗暴的按页分割,很容易把无关的知识传给 GPT,导致它可能会因为这些无关的信息返回错误的答案。比如如下关于用户信息告知的条款:前一页内容如下:
后一页内容如下:
如果你询问的问题是:“如果投保时年龄填写错误,理赔时会怎么样”。那很有可能你只会将第一页内容传给 GPT,它将会告诉你保司不承担任何责任,并不退回保险费。
而用我实现的服务所拼接的知识块,得到的版本答案如下:
显然这个问题得到了准确回答。
以上两个案例比较生动的说明了分割的重要性。
懂得了很多道理,也依旧过不好这一生。 - ChatGPT也不知道是谁说的
如何分割文档?其实这个也很好想方案,只是比较难搞。**保险条款是有文章结构的,只要咱们可以按文章标题给文档做结构化就好了。**最终文档就会成为这样的一个文档树:
interface INode {
title: string;
content: string;
children: INode[]
}
type DocTree=INode[]
然后我们在深度遍历这个文档树,去识别每个节点所包含的所有内容的长度,达到一定阈值就剪下来作为一个「知识块」。这就像剪一个西兰花 ,按自己可以含进去的大小,一朵朵剪下来。
通过这样的手段,我们就能在满足知识文本长度的限制下,切下最为连续完整的知识内容。这其实很简单,但如果一定要装逼取个算法名的话,那我称之为:西兰花算法。
但在我们切割西兰花之前,还有一个棘手的问题,怎么把一个条款文档先变成一棵西兰花(一颗文档树)?
因为后文很多内容都跟这个tokens相关,所以我必须得提前介绍一下。有时间的同学可以直接看官网介绍文档:没时间的同学可以继续听我简单总结一下:
OK,掌握这些知识就足够理解我们后文的内容了。
我们可以先看看市面比较火爆的医疗与重疾险产品的条款。发现其实保险大部分条款是有一定格式标准的。几乎都是嵌套数字标题 + 内容。那是否可以依据一定的规则,识别出那部分是标题,然后根据标题做切割即可?比如说,根据 「数字 + ·? + 数字?」的正则做匹配。虽然我正则写不来,但是 ChatGPT 写的来呀:
const text='1 React 1.1 react hooks 的使用技巧 1.2 react suspense 的作用 2 Vue 2.1 Vue compostion api 的使用技巧';
const regex=/(\d+\.?\d*)\s(\w+)/g;
const matches=text.matchAll(regex);
const result=[];
for (const match of matches) {
result.push(match[1] + ' ' + match[2]);
}
console.log(result);
// output
['1 React', '1.1 react', '1.2 react', '2 Vue', '2.1 Vue']
虽然它的回答不够完美,但是基本够我们继续下一步编码了。于是我尝试把 PDF 的全文内容复制出来,并做分割。然后我就会发现几个很麻烦的地方:
所以我们复制出来的文本是这样的:
module.exports=`2.3 等待期
自本合同生效(或最后复效)之日起 90 日内,被保险人因意外伤害4以外的原因, 被保险人因意外伤害发生上述情形的,无等待
被确诊患有本合同约定的轻症疾病5、中症疾病6、重大疾病7的,我们不承担保险
责任,这 90 日的时间称为等待期。
期。
轻症疾病 中症疾病
重大疾病
本合同的保险责任分为基本部分和可选部分。
,本合 ,退还
等待期内,我们的具体做法见下表:
等待期内发生的情形
我们的做法
不承担本合同“2.4 保险责任”中约定的保险责任
同继续有效
不承担本合同“2.4 保险责任”中约定的保险责任
您已交的本合同保险费8(不计利息),
本合同终止
2.4 保险责任
1 保单生效对应日:本合同生效日每年(或半年、季、月)的对应日为保单年(或半年、季、月)生效对应日。若当月 无对应的同一日,则以该月最后一日为保单生效对应日。
2 保单年度:自本合同生效日或年生效对应日零时起至下一个年生效对应日零时止为一个保单年度。
3 保险费约定交纳日:分期交纳保险费的,首期保险费后的年交、半年交、季交或月交保险费约定交纳日分别为本合同
的保单年生效对应日、半年生效对应日、季生效对应日或月生效对应日。`
所以,如果只是粗暴的根据某种标题规则来做分割,那我们只会得到错乱的结果。
那我们人眼是如何从页面中知道它是标题的呢?我们自然是根据这个文案的位置、大小,综合了我们的历史经验来判断它是不是标题。也就是说,要想真正从一段文本中做很好的标题识别以及内容分割,必须要获取这段文本的其他元数据。
我的下意识,自然是希望还有 AI 的能力。我把 PDF 转图片,都传给某个 AI,它很聪明,帮我 OCR 识别文档并做好了充分的文档结构化。
但我在 openai 官网并没有找到这样的 api 能力提供。由于我的 AI 储备非常薄弱,我也很难在网上找到可以满足我诉求的开源工具。而且根据我很可能不成熟的感觉,我感觉现在训练出来的开源 AI 模型,顶多只是识别出文字以及文字所在的绝对位置,也很难帮我直接把文档给按照标题结构化了。真有这样的需求,可能需要我自己准备大量材料来训练。这似乎再一次难倒了我。
于是我又想到了 pdf.js这个工具。我们 C端 部分投保协议就是利用这个工具包,把 PDF 文档转成 DOM 渲染到页面上。虽然我之前并没有使用过,但我相信它肯定可以拿到 PDF 上很多元数据,否则不可能做到还原成 DOM 去渲染。我甚至想,它有没有可能直接帮我转成一颗 根据标题已经结构化好的 DOM 树。
在我使用pdf.js后,我发现,刚才稍微想的有点多了,但也足够用了。它能把 PDF 文档的文字块以及这个文字块的文字与大小信息 解构出来。比如这样:
[{
"str": "2.4",
"dir": "ltr",
"width": 13.2,
"height": 10.56,
"transform": [10.56, 0, 0, 10.56, 346.03, 285.05],
"fontName": "g_d0_f1",
"hasEOL": false,
"pageNum": 4
},
{
"str": " 保险责任",
"dir": "ltr",
"width": 42.24,
"height": 10.56,
"transform": [10.56, 0, 0, 10.56, 364.39, 285.05],
"fontName": "g_d0_f12",
"hasEOL": false,
"pageNum": 4
}]
其中的 width与height决定了文字块的大小,transform决定了文字块在文档上的绝对位置信息。pdf.js也是根据这些信息,把 PDF 内容以绝对位置与大小一个个的转成 DOM 并绘制在网页上。它不理解前后语序与内容结果,它只是粗暴的拼装。
但这对我来说已经够用了,有了这些信息,我就能分析出哪些文字块是标题,哪些文字块是正文的正常数字,哪些内容块是底部的注释内容。比如说:
等等等等吧,除此外,我们还需要判断什么时候到注释内容,什么是页码内容。因为这些内容都要做一些特殊处理。另外就是不同文档可能有些特殊的边界情况要处理一下。
虽然说这依旧很人肉,不智能,但至少能把路走通了。至于有些不是以 x.x.x 这样的数字做标题的文档,比如:第一章、第一节什么的,还是能拓展的,但就先不考虑了。
事情走到这一步,大问题就没有了。但实际应用的时候,我们还是会发现一个小问题,就是很多小节的内容其实比较长,我们能做相似性映射的知识块其实往往不仅一块。当我们拼接多块知识的时候,内容又超出了。而如果我们只拼接一块内容,知识又不够完整。这又让我们抓耳挠腮了。
我仔细看了看这些小节的内容,我觉得,其实这段文本,要是用文言文来说,可能还可以再短一点(汉语真是博大精深)。但是我觉得如果让 GPT 帮我把它转成文言文的话,用户提问的问题很可能就映射不到了。当然,我也真的试了一下,发现 text-davinci-003这个模型似乎在文言文领域也不太行,保险条款它很难转成文言文。
但我有了另外一个思路,就是保险条款其实废话还是有些多的,我可以让 GPT 帮我做一些摘要性的总结,且尽量不丢失最核心的有效知识。在我网上搜索这块相关的知识时,发现 NLP 领域有一种叫「命名实体识别(https://baike.baidu.com/item/%E5%91%BD%E5%90%8D%E5%AE%9E%E4%BD%93%E8%AF%86%E5%88%AB/6968430)」的技术,常用于搜索引擎、信息提取、问答系统中。不管三七二十一了,openai 这么强大,那我就这么让它帮我这么做吧。
async function getSummary({ content, tokenLength }) {
const promptContext=`'''{{content}}'''基于命名实体识别构建内容摘要:`;
const contentTokenLength=tokenLength || encode(content).length;
const promptContextTokenLength=encode(promptContext).length;
const completion=await openai.createCompletion({
model: 'text-davinci-003',
prompt: promptContext.replace('{{content}}', content),
// 1000 ~ 4096,最大也不能超过1000
max_tokens: Math.min(
4096 - contentTokenLength - promptContextTokenLength,
1000,
),
temperature: 0,
});
return strip(completion?.data?.choices?.[0].text, ['\n']);
}
实际测试下来,这样的方式相比直接总结摘要,从最终效果来看,返回的结果会稳定很多,且返回的知识不会只说到一半。具体原因也不懂,有资深的大佬可以帮忙指点一下。
经过这样摘要化以后,我们就能把一段较长的知识文本给有效缩短。当用户问起相关知识时,可以调用更多的知识块来回答用户。
事情走到这一步,你可能以为就真没啥问题了。但实际上我们又遇到了个小麻烦。就是有部分小节的内容依旧还是太长了。就像一颗基因变异的西兰花 。
我已经剪到最小的分支了,但这个最小的分支依旧超过了max_tokens的限制。这又难倒我了,现在我该怎么分割它?这似乎回到了我最开始遇到的问题。不过好在,这些变异的西兰花并没有动画灵能百分百中的那么夸张,大部分还只是 略超 max_tokens一些,几乎不会超过其两倍。而自己观察这些超出去的内容,往往是两种类型。
我们发现这些小节的内容,其实并不适合分割。比如药品列表要是分割成两块接近max_tokens的知识内容,一次性问答只能获取其中一块知识。这就会导致回答错误。比如你问有多少种药品可以报销,它自然会算错。责任也是一样。
但这些小节有另外一个方向,就是压缩内容。里面有很多文字其实是相似的,比如一堆的社保目录内/外。比如责任内容中频繁出现的:恶性肿瘤``保险金``被保险人等等。我们只要做一本字典,把这些很长的重复性文字,用另外一种特殊的较短的字符指代。这段长文本就会瞬间被压缩到较短的文本,我们再连同字典一起发给 GPT,让它再翻译回来并做摘要化,于是就绕过了max_tokens的限制。
但问题又来了,说的容易,代码怎么知道哪些文字是一段词语?如果代码不知道哪些文字是一段词语,又怎么做字典映射。总不能自己先把所有可能的词汇都预先想好吧。虽然保险有一些专业术语可以提前预设,但总归有更多的未知的。
这就引出了 NLP 领域的另外一门技术,分词。很开心的是,在中文领域,且在 node.js 生态中,有一个比较好用的分词工具「结巴分词-https://github.com/yanyiwu/nodejieba」。不出意外,这也是 ChatGPT 告诉我的。
运用这个结巴分词,我们就可以把一段内容分割成一个个词汇,同时也支持传入用户预设的词汇字典。这样我们就能知道哪些词汇在一段文本中被重复使用多次。对于这些词汇,我们再用一个最短的字符去映射它。
const nodejieba=require('nodejieba');
nodejieba.load({
userDict: './userdict.utf8',
});
const longText='相学长白天吃饭,相学长中午也吃饭,相学长晚上还吃饭';
const words=nodejieba.cut(longText);
console.log(words);
// output
['相学长','白天','吃饭',',','相学长','中午','也','吃饭',',','相学长','晚上','还','吃饭'];
为了映射的字符尽量的短,我也是挠了一下脑袋,本来最简单就是一个特殊字符加上从1递增的数字就好了,比如这样:*${index}。但是这个方式经过我实测,压缩完的tokens效果还不够极致。考虑到我们都是基本是中文环境,我最终选择了 26个字母大小写 + 24个拉丁字母大小写作为索引:
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZαβγδεζηθικλμνξοπρστυφχψωΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ
根据第 0 步的知识,我们知道,千万别用 emoji 去做字典索引。
这样我们就得到最多100个索引,当然如果内容中已有出现具体的字母,最好还是针对该段内容剔除该字母。经过实际测试,这样的压缩效果会比数字映射法稍微好一些。且经过实测,这样问 openai 依旧能得到正确答案。举个例子:上文中的,相学长白天吃饭,相学长中午也吃饭,相学长晚上还吃饭会被转化成,a白天b,a中午也b,a晚上还b|上文中,a:相学长,b:吃饭我们把这句话拿去问 GPT:相学长每天都在做什么。它能给出正确的回答:相学长每天都在吃饭。
除了字典法压缩外,其实还有一个也比较显著的手段。就是把全角字符全部转成半角字符。在我的实际测试中,一段 8247 个tokens长度的内容。换半角相比不换半角,能多压缩 580 个tokens,简直是效果惊人!
其实不仅仅超过max_tokens的文本需要压缩。我建议超过 3000 tokens的文本都得压缩一下。因为 openai 最大的 4096 个token限制。并非是限制 prompt。而是限制 prompt+ 它的答案。也就是说,当我们做摘要化的时候,如果我们提供的原始内容越长,它能返回的摘要就越短。这显然不符合我们的诉求。所以,虽然文章中这里写着是第三步,但实际操作时,压缩其实是第二步,压缩需要在摘要化之前。
也是因为max_tokens的计算涵盖了 GPT 的回答内容,所以当我们根据用户提问拼接知识块的时候,不能按照 max_tokens的限制去打满内容,尽量留出 几百到一千的 tokens给 GPT 做回答。
在我实操过程中呢,其实还存在一个文档的内容,怎么压缩也压缩不到预期的长度。我确实选择了逃避,因为这段内容是无数个疾病的详细介绍,我骗自己说这些详细介绍并没太大用。因此最终我做了一个特殊处理,如果是这个超长的疾病介绍,我就只保留了疾病标题,去掉了疾病的内容。
针对这种,再压缩也解决不了的问题,我目前确实还没找到非常好的解法。
最终经过我们对 PDF 文档的分割、压缩、小节内容摘要化、转成嵌套文档树,最终再上一个西兰花算法。我们就能完成对这个 PDF 文档的合理分割了。最终我们再把分割后的内容做向量化处理,就能实现一个比较好的基于超长保单文档的保险产品问答服务。
其实其他领域的文档也差不多,只要这个文档结构比较好切割。
相关代码开源,有兴趣的同学自己下载继续研究吧~ https://github.com/wuomzfx/pdfGPT
关于到底怎么做向量化、怎么做匹配,我在本文就不多说了,这个还是比较容易了。包括其他还有一些特殊的处理,比如怎么把注释内容拼接到正文里。这些都可以在源码中方便寻找到。其他可能还稍微需要一点工具知识的,就是 node 中如何做两个 embedding 向量的相似性匹配。用 @stblib/blas这个 npm 包就行。DEMO 示例:
const ddot=require('@stdlib/blas/base/ddot');
const x=new Float64Array(questionEmbedding);
const y=new Float64Array(knowledgeEmbedding);
const result=ddot(x.length, x, 1, y, 1),
如果还有哪里不明白的,欢迎评论区或者先尝试问下 ChatGPT~
感觉人工智能的时代真的要到来了,连我这种 AI 小白,似乎都已经能完成一个可能真的能投入使用的服务。我再整个小程序,糊个页面,把一些异常容错机制再完善完善。再稍微整个爬虫,从保险行业协会网站帮用户快捷找到相关的保险条款。我几乎就能实现一个帮助用户回答保险产品的应用了。
亦或者,我可以自己预设一些问题。通过这些问题,我可以从保险条款中结构化出很多有效的信息,比如保额保费、责任细节、投保年限、续保年限等等。结构化之后,我又可以直接做不同产品的对比,根据用户的要求推荐比较合适的保险产品。这是一件挺有可能的事情,我尝试把之前的两个问答作为对比再次问 GPT 推荐哪款产品,它的回答比较中肯且有用。
总之,新的 AI 基础设施,已经能成为现在大部分工程师的有利工具。在某些垂直领域做一些深入研究,通过这些工具,AI 就能发挥出意想不到的作用,我们可以快速的产出各种有意思的产品。就好像 HTML5 跟 小程序 带来一系列有意思的 轻量APP 一样。相信,AI 浪潮在这两年就要席卷而来了~~
作者:相学长
来源:微信公众号:相学长
出处:https://mp.weixin.qq.com/s/xZrNlyqT67oQy6Tpf7LGZQ
*请认真填写需求信息,我们会在24小时内与您取得联系。