Разработка SQL Expert Bot: подробный гайд по использованию Vercel AI SDK и API OpenAI

—

от автора

OpenAI заложила фундамент для революции в сфере искусственного интеллекта с появлением ChatGPT, открывая новую эру в области AI, которую активно используют как отдельные люди, так и бизнес-сообщества. OpenAI даже предоставила API для разработки персонализированных AI-решений, включая чат-ботов, виртуальных помощников и многого другого. Доступ к этому API можно получить через SDK, которые OpenAI выпустила для разных языков программирования, а также через оболочки, разработанные для удобства создания интерфейсов.

Компания Vercel внесла свой вклад, разработав AI SDK для создания интерактивных пользовательских интерфейсов с использованием TypeScript и JavaScript. Примечательно, что этот SDK является проектом с открытым исходным кодом и поддерживает Vercel Edge runtime.

В рамках данной статьи мы создадим SQL Expert ChatBot, применив API OpenAI и SDK от Vercel. Мы рассмотрим вопросы стриминговых ответов, настройки запросов и многое другое.

Получение API ключа

Первым шагом будет создание аккаунта на OpenAI и получение ключа для API. Сперва мы проходим регистрацию и после того, как мы выполнили вход в свой аккаунт, нам нужно перейти в раздел управления API-ключами. Здесь мы можем сгенерировать новый ключ и дать ему имя, в моем случае — vercel-ai-sdk, но вы можете выбрать другое наименование на свое усмотрение.

Предлагаю не медлить и перейти к обзору Vercel AI SDK и процессу настройки на устройстве.

Конфигурация Vercel AI SDK

Vercel AI SDK предназначен для взаимодействия с API OpenAI и обладает рядом инструментов для эффективного использования функционала OpenAI API.

Для старта мы создаем приложение на базе Next.js и подключаем необходимые зависимости: пакет ai для Vercel AI SDK и пакет openai для клиента OpenAI API:

pnpm dlx create-next-app ai-sql-expert  cd ai-sql-expert  pnpm install ai openai

Проверьте, чтобы конфигурация вашего проекта была следующей:

Создаем файл .env в корневой директории проекта и добавим в него сгенерированный ранее OpenAI API ключ:

OPENAI_API_KEY=xxxxxxxxx

На этом настройка SDK OpenAI и Vercel AI подходит к завершению, а значит мы можем перейти к настройке API-маршрутов.

Настройка API-маршрутов

Мы организуем API-маршрут для обработки сообщений от пользователей таким образом, чтобы после отправки сообщения пользователем OpenAI API обрабатывал запрос и возвращал ответ в Next.js.

В начале создаем файл route.ts в папке api/chatиз директории src/app и пропишем в нем следующий код:

# app/api/chat/route.ts  import OpenAI from 'openai'; import { OpenAIStream, StreamingTextResponse } from 'ai';  const openai = new OpenAI({   apiKey: process.env.OPENAI_API_KEY, });  export const runtime = 'edge';  export async function POST(req: Request) {   const { messages } = await req.json();    const response = await openai.chat.completions.create({     model: 'gpt-3.5-turbo',     stream: true,     messages,   });    const stream = OpenAIStream(response);   return new StreamingTextResponse(stream); }

Немного пояснений:

  1. Сперва мы предоставляем ключ API для настройки экземпляра OpenAI:

    const openai = new OpenAI({   apiKey: process.env.OPENAI_API_KEY, });
  2. С помощью этой строки мы указываем Next.js использовать среду выполнения на краю (edge runtime) для обработки API-запросов:

    export const runtime = 'edge';
  3. Для извлечения данных из поля messages, , которые приходят в теле JSON-запроса мы используем POST -функцию.

  4. Далее мы применяем метод openai.chat.completions.create для отправки этих сообщений в модель gpt-3.5-turbo для дальнейшей обработки. Этот метод генерирует ответы, основываясь на введенных сообщениях.

  5. Параметр stream мы устанавливаем в значение true, поскольку это позволяет передавать ответы в формате реального времени.

  6. ППолучив ответ от OpenAI, код трансформирует его в формат удобного текстового потока с использованием функции OpenAIStream.

  7. И в завершение, функция формирует ответ, включающий в себя текстовые потоки, созданные OpenAI в качестве реакции на запросы пользователя, через класс StreamingTextResponse и отправляет его обратно:

    export async function POST(req: Request) {   const { messages } = await req.json();    const response = await openai.chat.completions.create({     model: 'gpt-3.5-turbo',     stream: true,     messages,   });    const stream = OpenAIStream(response);   return new StreamingTextResponse(stream); }

Теперь у нас есть API-маршрут для приема и обработки пользовательских запросов с помощью API OpenAI. Перейдем к созданию UI для нашего бота.

Разработка пользовательского интерфейса

Перед тем как приступить к работе с UI, определим константы для начальный сообщений чата, которые мы будем использовать в качестве настраиваемого промта для направления поведения разрабатываемого бота.

Создаем файл chat.constants.ts в папке constant, расположенной в директории src/app и напишем следующий код:

import { Message } from 'ai/react';  export const INITIAL_MESSAGES: Message[] = [   {     id: '',     role: 'system',     content: 'Вы эксперт по SQL и можете создать генерируемые SQL-запросы для любой проблемы.          Убедитесь, что возвращаемый вами запрос с правильным форматированием и отступом.         Убедитесь, что возвращаемый запрос снабжен корректным объяснением и комментариями.         Если вы не в силах решить проблему, вы вправе запросить дополнительные сведения.         Если пользователь не может понять запрос, вы можете объяснить запрос простыми словами.         Если пользователь предоставляет неправильную подсказку, вы можете запросить правильную подсказку.         `,   }, ];

Мы задаем системе руководящие принципы поведения в различных ситуациях, формулируем соответствующие модели ответов и определяем механизм их доставки.

Далее вставим следующий код в src/app/pages.tsx:

'use client';  import { useChat } from 'ai/react'; import Markdown from 'react-markdown'; import { INITIAL_MESSAGES } from './constant/chat.constants';  export default function Chat() {   const { messages, input, handleInputChange, handleSubmit } = useChat({     initialMessages: INITIAL_MESSAGES,   });   return (     <div>       <div className="text-center py-8">         <h2 className="text-center text-2xl font-bold mb-2">Эксперт SQL</h2>         <p>           Добро пожаловать в Эксперта SQL. Вы можете задать любые вопросы, связанные с SQL, и эксперт вам поможет.         </p>       </div>   <div className="flex flex-col w-full max-w-2xl pb-24 mx-auto stretch gap-4">         {messages           .filter((m) => m.role !== 'system')           .map((m) => (             <div               key={m.id}               className="bg-gray-100 p-4 rounded flex gap-2 flex-col"             >               <span className="font-medium">                 {m.role === 'user' ? 'Вы' : 'Эксперт'}               </span>               <Markdown>{m.content}</Markdown>             </div>           ))}          <form           className="flex gap-4 fixed bottom-0 w-full mb-8"           onSubmit={handleSubmit}         >           <input             autoFocus             className="p-2 border border-gray-300 rounded shadow-xl outline-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-500 flex-grow max-w-xl"             value={input}             placeholder="Задайте свой вопрос по SQL.."             onChange={handleInputChange}           />            <button             className="border p-2 px-4 rounded shadow-xl border-gray-300 bg-purple-500 text-white"             type="submit"           >              Отправить            </button>         </form>       </div>     </div>   ); }

Добавим немного пояснений:

  1. Мы применяем компонент для визуализации сообщений и форму для отправки сообщений пользователем:

    'use client';
  2. Так как API возвращает ответы в формате markdown, мы используем библиотеку react-markdown для их интерпретации.

    import Markdown from 'react-markdown';
  3. Хук useChat предназначен для создания интерфейса чата в нашем приложении с интеграцией чат-бота. Он облегчает процесс отображения сообщений от нашего AI-провайдера, управления вводом в чате и обновления UI при поступлении новых сообщений. Хук также поддерживает различные опции, и в нашем случае мы используем параметр initialMessages для настройки начального поведения системы.

    import { useChat } from 'ai/react';  const { messages, input, handleInputChange, handleSubmit } = useChat({     initialMessages: INITIAL_MESSAGES,   });
  4. Также мы настраиваем отображение сообщений, пришедших от API. Учитывая, что мы задали системе настраиваемый промт, мы отсееваем его и оставляем только сообщения пользователя и эксперта:

    <div className="flex flex-col w-full max-w-2xl pb-24 mx-auto stretch gap-4">         {messages           .filter((m) => m.role !== 'system')           .map((m) => (             <div               key={m.id}               className="bg-gray-100 p-4 rounded flex gap-2 flex-col"             >               <span className="font-medium">                 {m.role === 'user' ? 'Вы' : 'Эксперт'}               </span>               <Markdown>{m.content}</Markdown>             </div>           ))} ... </div>
  5. Мы реализуем форму для отправки сообщений пользователями. Для обработки события отправки формы применяем функцию handleSubmit, которую предоставляет хук useChat. 

  6. В качестве механизма управления вводом данных в текстовое поле используем функцию handleInputChange в сочетании с состоянием input. 

  7. Кроме того, мы оснащаем форму кнопкой, предназначенной для ее отправки:

    <div className="flex flex-col w-full max-w-2xl pb-24 mx-auto stretch gap-4">         ...         <form           className="flex gap-4 fixed bottom-0 w-full mb-8"           onSubmit={handleSubmit}         >           <input             autoFocus             className="p-2 border border-gray-300 rounded shadow-xl outline-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-500 flex-grow max-w-xl"             value={input}             placeholder="Задайте свой вопрос по SQL.." "             onChange={handleInputChange}           />            <button             className="border p-2 px-4 rounded shadow-xl border-gray-300 bg-purple-500 text-white"             type="submit"           >              Отправить            </button>         </form> </div>

Благодаря Vercel AI SDK у нас есть такие инструменты, как хук useChat, облегчающий работу, начиная от отображения сообщений до управления пользовательским вводом.

Мы успешно разработали UI для нашего SQL Expert bot, а это значит, что пора запустить сервер разработки и провести тестирование.

Тест бота

Запустим сервер следующей командой в терминале:

pnpm run dev

ИЛИ

yarn run dev

ИЛИ

npm run dev

Перейдем по адресу http://localhost:3000 в нашем браузере.

Вы можете опробовать бота в работе со следующими примерами промтов:

  1. «Сформулируй SQL‑запрос для выявления суммарного числа заказов, сделанных каждым клиентом за прошедший год, с сортировкой по убыванию количества заказов.»

  2. «Напиши SQL‑запрос для идентификации клиентов, чьи расходы превысили $1000 за последние три месяца.»

  3. «Разработай SQL‑запрос для определения среднего времени выполнения заказа, исходя из временных отметок его размещения и завершения.»

  4. «Спроектируй SQL‑запрос для выявления продуктов с самой высокой прибыльностью, учитывая их себестоимость и цену продажи.»

  5. «Сконструируй SQL‑запрос для анализа тренда ежемесячного дохода за последний год, с разбивкой по месяцам.»

  6. «Определи через SQL‑запрос клиентов, которые не совершали покупок за последние 6 месяцев.»

  7. «Составь SQL‑запрос для выявления пяти категорий товаров с наибольшим объемом продаж за последний квартал.»

  8. «Разработай SQL‑запрос для определения заказов, включающих товары, отсутствующие на складе в момент покупки.»

  9. «Вычисли через SQL‑запрос общий доход от постоянных клиентов по сравнению с новыми за последний месяц.»

  10. «Сформулируй SQL‑запрос для выявления аномалий или отклонений в количестве заказов по сравнению со средними показателями каждого товара за определенные исторические периоды.»

Для наглядности, взгляните на демонстрацию работы следующего промта:

"Представим, твоей задачей стоит оптимизация производительности базы данных крупной компании в сфере электронной коммерции. Составь SQL-запрос для выявления десяти наиболее продаваемых товаров по доходу за последний месяц, учитывая количество продаж и цену за единицу."

Заключение

В этом гайде мы с вами написали функционирующий SQL Expert Bot. Попробуйте настроить его, согласно своим предпочтениям, экспериментируйте и делитесь своими результатами!

Полезные ссылки:

Благодарю за внимание!


ссылка на оригинал статьи https://habr.com/ru/articles/800505/