在OpenAI顶部构建API时,通常会退回纯文本。
当人类与API相互作用时,这很好,因为即使文本不是结构化的,他们也可以轻松地“解析”。
但是,在OpenAI之上构建API呢?
在仍在使用OpenAI生成响应的同时,我们如何构建API并使用OpenAPI进行记录?
问题:如何从OpenAI返回结构化数据(JSON)?
假设我们要建立一个返回给定国家天气的API。
我们不想手动编写集成代码,而是要使用OpenAI来生成响应。
但是,像GPT-3这样的LLM只是返回纯文本,而不是结构化数据(JSON)。
因此,我们如何强迫Openai返回一个符合JSON模式的答案,以便我们可以将其公开为API,
使用OpenApi?
解决方案:使用ZOD / JSON模式和OpenAI功能,您可以从OpenAI返回结构化数据(JSON)
OpenAI具有一个名为“功能”的新功能。
函数是定义可以从LLM中调用的操作的一种方法。
可以使用JSON模式来描述函数。
发生的事情是,LLM不会直接调用该函数,而是为该功能生成输入并将其返回给您。
因此,您可以创建一个提示并添加可用函数作为上下文。
然后,您调用OpenAI API,并且响应“可能”包含指令,以调用具有某些输入的函数。
这很难理解,所以让我们看一个例子。
const completions = await openai.createChatCompletion({
model: this.model,
messages: [
{
role: 'user',
// this is the actual prompt from the user
content: 'What is the weather like in Berlin?',
},
{
role: 'agent',
// this is the assumed response from the agent (LLM) in text form
content: 'The weather in Berlin is sunny and 25 degrees',
},
{
role: 'user',
// this is our "injected" prompt to trigger the agent to "send" the result to the out function
content: 'Set the result to the out function',
}
],
functions: [
{
name: 'out',
// here we define our function to get the result from the agent in JSON form
description: 'This is the function that returns the result of the agent',
// we use zod and a zod-to-json-schema converter to define the JSON Schema very easily
parameters: zodToJsonSchema(z.object({
temperature: z.number(),
city: z.string(),
description: z.string(),
})),
},
],
});
const structuredResponse = JSON.parse(completions.data.choices[0].message!.function_call!.arguments!);
const validatedOut = this.outputZodSchema.parse(structuredResponse);
console.dir(validatedOut); // { temperature: 25, city: 'Berlin', description: 'sunny' }
那么,这里发生了什么?
我们要求Openai为先前回答的提示创建聊天完成。
我们希望LLM使用功能将结果“发送”到。
该函数的参数是使用JSON模式(ZOD)定义的。
由于此提示,我们从Openai获得了一个响应,它想用JSON编码字符串作为输入(completions.data.choices[0].message!.function_call!.arguments!
)来调用该函数。
可以使用JSON.parse
解析此字符串,然后使用ZOD验证。
之后,我们可以确定响应在遵循我们定义的架构中有效。
剩下的是我们将所有碎片放在一起,
在其上添加代码生成,我们有一种完全自动化的方法来在OpenAI上构建API。
通过OpenAPI暴露AI增强API的最终解决方案
wundergraph代理SDK开箱即用。
使用打字稿定义操作,添加代理执行您的提示,然后完成。
该框架将从打字稿类型中推断出JSON模式并为您生成OpenAPI文档。
// .wundergraph/operations/openai/GetWeatherByCountry.ts
export default createOperation.query({
input: z.object({
country: z.string(),
}),
description: 'This operation returns the weather of the capital of the given country',
handler: async ({ input, openAI, log }) => {
const agent = openAI.createAgent({
// functions takes an array of functions that the agent can use
// these are our existing WunderGraph Operations that we've previously defined
// A WunderGraph Operation can interact with your APIs and databases
// You can use GraphQL and TypeScript to define Operations
// Typescript Operations (like this one right here) can host Agents
// So you can also call other Agents from within an Agent
functions: [{ name: 'CountryByCode' }, { name: 'weather/GetCityByName' }],
// We want to get structured data (JSON) back from the Agent
// so we define the output schema using zod again
structuredOutputSchema: z.object({
city: z.string(),
country: z.string(),
temperature: z.number(),
}),
});
// Finally, we execute the agent with a prompt
// The Agent will automatically fetch country data from the CountryByCode Operation
// and the weather data from the weather/GetCityByName Operation
// It will then generate a response using the schema we've defined
return agent.execWithPrompt({
prompt: `What's the weather like in the capital of ${parsed.country}?`,
});
},
});
我们现在可以使用任何OpenAPI客户端(例如Postman,甚至只是卷曲)使用此操作。
curl --request 'http://localhost:9991/operations/openai/GetWeatherByCountry?country=Germany'
响应将是一个符合我们定义的模式的JSON对象。
{
"city": "Berlin",
"country": "Germany",
"temperature": 25
}
您将在以下目录中生成OpenAPI文档:
.wundergraph/generated/wundergraph.openapi.json
了解有关WunderGraph Agent SDK的更多信息
如果您想了解更多有关代理SDK的信息,
看看公告博客文章here。
如果您正在寻找有关如何开始使用代理SDK的说明,
看看documentation。
结论
OpenAI是一种强大的工具,可用于在其顶部构建API。
有了新功能功能,我们甚至可以从OpenAI返回结构化数据(JSON)。
这使我们能够在OpenAI的顶部构建API,而其他机器可以消耗。
我们还展示了如何使用WunderGraph Agent SDK来编写代理并自动生成OpenAPI文档。
您可以在GitHub上查看源代码,如果您喜欢的话,请留下星星。
在Twitter上关注我,
或加入有关我们的Discord server的讨论。