从Openai返回JSON以构建AI增强API
#javascript #网络开发人员 #编程 #openai

在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的讨论。