函数式调用是怎么使用的

gpt-4-1106-vision-preview 模型出来的时候我还在埋头撸代码,然后在公众号中看到了chatgpt已经开放了图片上传并识别对话的功能,想起年初的时候openai 的gpt4 放出来的时候,拍一张图片上传给它就可以帮你写一个简单的html页面的新闻

不得不感概,人间一天 AI百年啊,人工智能的飞速发展让我等码农感受到了威胁。

在使用chatgpt官网的页面的时候,我发现了它还有一个图片生成的模型 dall-e-3 单独用它时候发现生成的质量还不错,最重要的是它支持中文自然语言描述,mj的使用,在我看来还是不够人性化,它其中涉及到了大量专业参数,需要一定的使用门槛,如果opanai 的 dall-e-3模型持续

迭代的话,可能有一天就不太需要单独开通一个Midjourney账户了,回到正文,我在单独使用 dall-e-3 后,忘记了自己是在哪个模型下提问了,就误打误撞的让chatgpt4 来生成图片,没想到它也可以给我生成图片,这就引发了我的思考,这种模型调模型的方式是怎么实现的?

openai 的接口有没有提供过类似的功能? 该如何实现? 我们的AI机器人应用是不是也能集成进去?这样是不是就无需等待gpt4的进一步开放,我们都可以使用上最新的跟官网一样的功能了。

带着这些问题,我开始在社区上查找,啧啧,别说调用生成图片的例子了,连图文对话的客户端实现都没有看到有,放弃搜索开始琢磨openai 的文档,直到我看到这段代码

发生了什么??? 它在响应的结果返回这里,调用了一个本地函数?? 这是什么操作??

带着这个疑问,我重新用nestjs搭建了一个项目,前端的话,就用公司的chat-web项目吧,我也不准备再重新画一个页面了,准备用官方提供的sdk来重新接入下openai的接口

nestjs 是mvc架构后端nodejs服务框架,提供了一整套的后端开发解决方案,比较适合开发io密集型的服务,在海外相当流行,很多创业公司是用它来进行后端开发的,我在之前了解使用过,没想到它现在更完善了,如果你之前写过angler2 或者使用过spring-boot 的话,相信上手应该会很快

  1. 首先安装nestjs 的脚手架 npm i -g @nestjs/cli
  2. 创建项目nest new get_nest_server, 然后再安装下依赖
  3. 一切顺利,现在我的目录结构是这样的

4.再安装两个依赖 npm i openai https-proxy-agent, 其中 openai 是官方的sdk包,https-proxy-agent用于本地联调接口的时候代理用的

  1. 先来新建模块和service ,nest-cli 提供了快捷新建模块和service的命令行,先来扫一眼都有什么吧

嗯,很齐全,首先我们新建openai模块,nest g mo openai

不仅模块目录建好了,还顺带帮你引入到了app模块下,ok 我们继续执行,nest g service openai && nest g controller openai 执行完后你的openai目录大概会是像这样的,模块已经帮你自动引入了,是不是很方便

6.模块建好了,准备撸代码了,那就从service开始吧

其中最核心的还是 streamChat 方法,主要是用来进行对话的,这个方法里面的核心是这里

这便是我们实现流式对话的基础了,其他的方法都是用来辅助的

  1. 基本的流式对话实现了,但是在用流式对话的时候,注意不要去参照官方的来,他是非流式对话的,但是文档中也没有发现有流式对话的函数式调用例子,

怎么办呢?去官方的github仓库扫一眼,还真让我找到了

它在根目录下有一个examples 的目录,里面是各种调用的demo,里面有一个 function-call-stream.ts 的文件,这不就是我们想要的吗。ok,咱们先看看它做了啥

大致的意思就是它在代码中使用了函数式调用并模拟了db 的读取和搜索能力,主要是为了告诉我们,它有能力接入你自己的系统, 知道怎么用了后,一切都好办了,比葫芦画瓢,撸代码

ts 复制代码
import { Injectable } from '@nestjs/common';  
import { OpenAI } from 'openai';

  
  
import {  
ChatCompletionChunk,  
ChatCompletionMessageParam,  
ChatCompletionMessage,  
} from 'openai/resources/chat/completions';  
import { HttpsProxyAgent } from 'https-proxy-agent';  
import ChatMessageStreamDto from './dto/ChatMessageStreamDto';  
import {  
getCurrentWeather,  
functions,  
getCurStockByName,  
getToutiao,  
getLottery,  
} from './functions';  
  
@Injectable()  
export class OpenaiService {  
api = new OpenAI({  
httpAgent: new HttpsProxyAgent(process.env.PROXY_URL),  
apiKey: process.env.OPENAI_API_KEY,  
});  
constructor() {}  
  
// 获取模型列表  
async getModels() {  
const list = await this.api.models.list();  
return list.data;  
}  
  
// 流式对话  
async streamChat(  
input: ChatMessageStreamDto,  
cb: (item: ChatCompletionChunk) => void,  
) {  
const messages: Array<ChatCompletionMessageParam> = [  
{  
role: 'user',  
content: input.prompt,  
},  
];  
const stream = this.api.chat.completions.create({  
model: 'gpt-3.5-turbo',  
stream: true,  
messages: messages,`  `
functions: functions,  
});  
let chatMessage = {} as ChatCompletionMessage;  
for await (const chunk of await stream) {  
cb && cb(chunk);  
chatMessage = this.messageReducer(chatMessage, chunk);  
}  
  
messages.push(chatMessage);  
  
if (chatMessage.function_call) {  
const result = await this.callFunction(chatMessage.function_call);  
const newMessage = {  
role: 'function' as const,  
name: chatMessage.function_call.name!,  
content: JSON.stringify(result),  
};  
messages.push(newMessage);  
const stream = this.api.chat.completions.create({  
model: 'gpt-3.5-turbo',  
stream: true,  
messages: messages,  
});  
  
for await (const chunk of await stream) {  
cb && cb(chunk);  
chatMessage = this.messageReducer(chatMessage, chunk);  
}  
}  
}  
  
messageReducer(  
previous: ChatCompletionMessage,  
item: ChatCompletionChunk,  
): ChatCompletionMessage {  
const reduce = (acc: any, delta: any) => {  
acc = { ...acc };  
for (const [key, value] of Object.entries(delta)) {  
if (acc[key] === undefined || acc[key] === null) {  
acc[key] = value;  
} else if (typeof acc[key] === 'string' && typeof value === 'string') {  
(acc[key] as string) += value;  
} else if (typeof acc[key] === 'object' && !Array.isArray(acc[key])) {  
acc[key] = reduce(acc[key], value);  
}  
}  
return acc;  
};  
  
return reduce(previous, item.choices[0]!.delta) as ChatCompletionMessage;  
}  
  
async callFunction(  
function_call: ChatCompletionMessage.FunctionCall,  
): Promise<any> {  
const args = JSON.parse(function_call.arguments!);  
switch (function_call.name) {  
case 'get_current_weather':  
return getCurrentWeather(args['location']);  
case 'get_cur_stock_by_name':  
return getCurStockByName();  
case 'get_toutiao':  
return getToutiao();  
case 'get_lottery':  
return getLottery();  
default:  
throw new Error('No function found');  
}  
}  
}

差点忘记了,我们还有函数的定义,我自己准备了几个函数,连同给gpt的入参我也一并贴出来吧

ok 一切都准备好了,开始准备接口了,chat-web 前端有一个必须要给的接口,先定义出来

然后是对话的接口

![]( "研发学习指南 > GPT4 的函数调用是怎么使用的? > image2023-11-24_14-22-26.png")

对话接口里面长这样

ok 一切看起来都准备好了,前端配置下反向代理的接口地址,再改下接口路径

ok,现在开始测试我们定义的函数

至此。我们实现了四个基本的函数式调用,并且从返回的结果来看,似乎内容质量还可以。

让gpt来帮我总结下今天这篇文章吧

  1. OpenAI定价信息:我查阅了一些关于图片接口和新模型的定价信息,特别是关于gpt-4-1106-preview和gpt-4-1106-vision-preview模型的费用。
  2. DALL-E 3论文:我阅读了一篇有关DALL-E 3模型的研究论文,该论文讨论了这一模型如何生成图像及其相关技术。
  3. 函数调用接口文档:我翻阅了OpenAI官方提供的关于如何实现函数调用的接口文档。
  4. OpenAI GitHub示例:我在OpenAI的官方GitHub仓库中发现了一个名为function-call-stream.ts的示例文件,学习了如何利用OpenAI的SDK进行函数式流调用。
  5. Midjourney使用教程:我观看了一个介绍Midjourney使用的视频教程,这可能是一个提供与DALL-E 3相似服务或工具的指导视频。
  6. NestJS文档:我还深入了解了NestJS的官方文档,它是一个流行的后端Node.js框架,适合开发IO密集型服务,在海外创业公司广泛使用。
  7. OpenAI功能和集成:我对人工智能技术的快速进展表示惊叹,并且我探讨了如何将OpenAI的多种功能集成进我的AI机器人应用。
  8. 代码实践:我利用NestJS框架构建了一个项目,并计划使用官方的SDK重新接入OpenAI的接口。在此过程中,我定义了一些必要的函数和模块,并尝试实现了流式对话。
  9. 函数式调用和测试:我成功地完成并测试了四个基本的函数式调用,内容质量也达到了预期。

综上所述,我在技术探索和实践中深入研究了OpenAI的各个方面,包括API的调用、模型的集成以及后端服务的构建,这充分展现了我对AI和软件开发的浓厚兴趣和不断追求的精神。

相关推荐
这个男人是小帅17 分钟前
【GAT】 代码详解 (1) 运行方法【pytorch】可运行版本
人工智能·pytorch·python·深度学习·分类
__基本操作__19 分钟前
边缘提取函数 [OPENCV--2]
人工智能·opencv·计算机视觉
Martin -Tang20 分钟前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发21 分钟前
解锁微前端的优秀库
前端
Doctor老王23 分钟前
TR3:Pytorch复现Transformer
人工智能·pytorch·transformer
热爱生活的五柒24 分钟前
pytorch中数据和模型都要部署在cuda上面
人工智能·pytorch·深度学习
王解1 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
我不当帕鲁谁当帕鲁1 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂1 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架