背景
随着语言大模型的快速发展,相关的AI应用也如雨后春笋一样起来,如何快速开发就成为了大家比较关心的问题,而 Vercel AI SDK 就是一个构件 AI 用户界面的开发利器,帮助开发者快速开发类 ChatGPT 应用,内置对 LangChain、OpenAI、Anthropic、Hugging Face 的支持、支持主流前端框架的模板(Next.js、SvelteKit、Nuxt)。
使用
快速开发 ChatGPT 应用
与 Next.js 结合,50行代码就能写一个 ChatGPT 应用
安装依赖库
pnpm install openai-edge ai
服务端代码,Next.js App Route
// ./app/api/chat/route.js
import { Configuration, OpenAIApi } from 'openai-edge'
import { OpenAIStream, StreamingTextResponse } from 'ai'
// 配置 OpenAI 的 Key
const config = new Configuration({
apiKey: process.env.OPENAI_API_KEY
})
const openai = new OpenAIApi(config)
export const runtime = 'edge'
export async function POST(req) {
const { messages } = await req.json()
// 请求模型 gpt-4
const response = await openai.createChatCompletion({
model: 'gpt-4',
stream: true,
messages
})
// 将响应 Response 转换成 stream,并且会对返回信息进行处理,剥离出字段 content
const stream = OpenAIStream(response)
// 将 stream 转换成 Response,配置 status code=200,Content-Type='text/plain; charset=utf-8'
return new StreamingTextResponse(stream)
}
客户端代码
// ./app/page.js
'use client'
import { useChat } from 'ai/react'
export default function Chat() {
// useChat 是快速创建对话用户界面的工具类,messages 是返回的消息列表,input 是请求的 Prompt
const { messages, input, handleInputChange, handleSubmit } = useChat()
return (
<div>
{messages.map(m => (
<div key={m.id}>
{m.role}: {m.content}
</div>
))}
<form onSubmit={handleSubmit}>
<input
value={input}
placeholder="Say something..."
onChange={handleInputChange}
/>
</form>
</div>
)
}
阻塞式响应
有些场景中需要的不是流式响应,而是阻塞式响应,比如非用户主动触发,由服务端自动生成内容。
import {Configuration, OpenAIApi} from 'openai-edge'
import {OpenAIStream, StreamingTextResponse} from 'ai'
const config = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
})
const openai = new OpenAIApi(config)
const response = await openai.createChatCompletion({
model: 'gpt-3.5-turbo',
messages: [{
"role": "assistant",
"content": "请帮我生成一个训练计划",
}]
})
const ret = await response.json()
console.error('返回内容:', ret.choices[0].message.content)
生命周期回调
我们往往需要把对话数据保存下来,比如放到数据库中,这时候就可以使用 OpenAIStream 的 callbacks 参数
const stream = OpenAIStream(response, {
// 接收对话开始
onStart: () => {
// 保存 Prompt
console.info('onStart')
},
// 接收对话中
onToken: (token) => {
console.info('onToken', token)
},
// 接收对话结束
onCompletion: (token) => {
// 保存 conversation
console.info('onCompletion', token)
}
})
支持 function calling
在我上一篇文章如何使用 OpenAI Chat Completions API 新参数 functions里有提到,在模型 gpt-3.5-turbo 开始支持 function calling,而 ai 库也及时提供了支持,让我们可以非常方便的使用该能力。
import {Configuration, OpenAIApi} from 'openai-edge'
import {OpenAIStream, StreamingTextResponse} from 'ai'
const config = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
})
const openai = new OpenAIApi(config)
const messages = [{
"role": "assistant",
"content": "杭州今天天气如何?",
}]
const functions = [
{
name: 'get_current_weather',
description: 'Get the current weather',
parameters: {
type: 'object',
properties: {
location: {
type: 'string',
description: 'The city and state, e.g. San Francisco, CA'
},
format: {
type: 'string',
enum: ['celsius', 'fahrenheit'],
description:
'The temperature unit to use. Infer this from the users location.'
}
},
required: ['location', 'format']
}
}
]
const response = await openai.createChatCompletion({
model: 'gpt-3.5-turbo',
stream: true,
messages,
functions
})
const stream = OpenAIStream(response, {
experimental_onFunctionCall: ({ name, arguments: args }, createFunctionCallMessages) => {
// {name: get_current_weather, args: { location: '杭州', format: 'celsius' }}
// 接收到 openai 返回,选择使用函数 get_current_weather
if (name === 'get_current_weather') {
// 实现函数 get_current_weather
const weatherData = {
temperature: 20,
unit: args.format === 'celsius' ? 'C' : 'F'
}
// 生成 assistant 和 function 消息
const newMessages = createFunctionCallMessages(weatherData)
// newMessages [
// {
// role: 'assistant',
// content: '',
// function_call: {
// name: 'get_current_weather',
// arguments: '{\n"location": "杭州",\n"format": "celsius"\n}'
// }
// },
// {
// role: 'function',
// name: 'get_current_weather',
// content: '{"temperature":20,"unit":"C"}'
// }
// ]
// 再次发送给 openAI 进行总结
return openai.createChatCompletion({
messages: [...messages, ...newMessages],
stream: true,
model: 'gpt-3.5-turbo',
functions
})
}
}
})
const streamingTextResponse = new StreamingTextResponse(stream)
// 接受结果: 杭州今天的天气是20℃
与 openai-sdk 对比
openai 也提供了官方库 openai-node,但只是对 HTTP API 接口进行了封装,缺少对 Stream、UI界面、生命周期回调的支持,都需要自行实现。
PS: Stream 可以通过How to use stream: true?进行实现